Premium support for our pure JavaScript UI components


Post by seany84 »

Hi all,

We have extended the Gantt NumberColumn for 2 columns: issuesContraints and comment.

The inheritance chain is that CommentsColumn inherits IconColumn and IconColumn inherits NumberColumn.

Columns:

get columns() {
        const data = this.data;
        return [
            { id: "id", field : "id", text : 'ID', hidden: true },
            { id: "activityName", type: "name", field: 'activityName', text: 'Activity Name' },
            { id: "issueConstraints", type: "issue-column", width: "50px", text: "Issues/Constraints" },
            { id: "comment", type: "comment-column", width: "50px", text: "Comment"},
            { id: "startDate", type: "startdate", field : 'startDate', text : 'Start Date', format: bryntumDateFormat },
            { id: "endDate", type: "enddate", field : 'endDate', text : 'End Date', format: bryntumDateFormat },
            { id: "duration", type: "duration", text : "Duration", width: "50px"},
            {
                id: "discipline",
                field : 'tradeDisciplineId',
                type: 'number',
                text : 'Discipline',
                //editor: new Combo(this.tradeDisciplineComboConfig),
                renderer : ({ record }) => record.tradeDiscipline?.description
            },
            {
                id: 'responsible',
                field: 'responsible',
                text: 'Responsible'
            },
            { id: "progress", type: "percentdone", field:'progress', showCircle: true, width: 70, text: "Progress" }
        ];
    }
    
get filterFeature() { // The filter picker UI will draw its filterable fields from the grid's columns and their backing fields by default, // but for fields that include relations we need to provide some additional information, so we override those field configs // here. The fields defined here will be merged with the grid's column fields by the filter UI, with these taking precedence. const filterPickerFields = { tradeDisciplineId: { // Defines how to show a related record in the pick-list dropdown when setting up a filter limited to specific values. // In this case, when filtering the main record on its tradeDisciplineId field, we want to show the actual tradeDiscipline names in the dropdown. relatedDisplayField: 'description' } }; return { isMulti: { allowedFieldNames: ['activityName', 'startDate', 'endDate', 'fullDuration', 'responsible', 'tradeDisciplineId', 'progress', 'comment'], fields: filterPickerFields } } }

CommentsColumn (inherits IconColumn):

import Vue from "vue";
import CommentIcon from "@/Areas/PullPlan/Views/App/pages/viewer/comments/components/comment-icon";
import {IconColumn} from "@/Areas/PullPlan/Views/App/pages/viewer/gantt/IconColumn";

const CommentIconComponent = Vue.extend(CommentIcon);

export class CommentsColumn extends IconColumn {
    static get $name() {
        return "CommentsColumn";
    }

static get type() {
    return "comment-column";
}

createIconComponent(record, projectComponent) {
    const component = new CommentIconComponent({
        propsData: {
            activity: record,
            allComments: projectComponent.comments
        }
    });
    component.$on("click", () => projectComponent.$emit("comment-icon-click", record, component));

    return component;
}

getValueFromComponent(component) {
    return component?.activityComments?.length ?? 0;
}
}

IconColumn (inherits NumberColumn):

import {NumberColumn} from "@bryntum/gantt";

export class IconColumn extends NumberColumn {
    #components = {};

static get isGanttColumn() {
    return true;
}

static get defaults() {
    return {
        editor: false,
        cellCls: 'column-cell-icon',
        htmlEncode: false,
        filterable: true,
        sortable(record1, record2) {
            return this.getValueFromRecord(record1) < this.getValueFromRecord(record2) ? -1 : 1
        }
    };
}

getIconById(id) {
    return this.#components[id];
}

renderer({ record, cellElement }) {
    let component = this.#components[record.id];

    if (component != null) {
        component.$destroy();
    }

    component = this.createIconComponent(record, record.project.vueComponent);

    this.#components[record.id] = component;

    this.mountToGantt(component, cellElement);
}

mountToGantt(component, cell) {
    cell.innerHTML = "";
    const iconHolder = document.createElement("div");

    cell.prepend(iconHolder);
    component.$mount(iconHolder);
}

getValueFromRecord(record) {
    let component = this.#components[record.id]
    if (component == null) {
        component = this.createIconComponent(record, record.project.vueComponent)
        this.#components[record.id] = component
    }

    return this.getValueFromComponent(component);
}

// to be overridden
createIconComponent(record, projectComponent) {
    console.warn("This method should be overridden and not called directly");
    return  null;
}

// to be overridden
getValueFromComponent(component) {
    return 0;
}

}

As you can see from the link below, multi filtering on the custom column type is not working.

Untitled4.png
Untitled4.png (27.32 KiB) Viewed 304 times

Post by seany84 »

hi all, is there any feedback on the above item? I have tested this in v5.3.2 and the issue is still present.


Post by marcio »

Hey seany84,

Could you assemble a sample project with the configuration that you shared about your columns for us to check? Basically get one of our demos and add your configuration and custom columns with the issue and then share it here.

With that, would be faster and easier for us to assist you on this and confirm if it's a bug on our side or not.

You can get more info here https://www.bryntum.com/forum/viewtopic.php?f=1&t=772

Best regards,
Márcio


Post by emil »

Hi seany84,

Is there a single underlying field of a primitive type (text, number...) on the record that you can filter against with this comments column?

Thanks,

Emil


Post by seany84 »

Hi emil,

There was not, but we have modified it to expose a primitive type which is available in the class which extends TaskModel.

Adding this new property to the fields has resolved this issue.

Please mark this as resolved.

Thanks emil.

ActivityModel.js (extends TaskModel)

import {formatDate} from "@/Areas/PullPlan/Views/App/pages/viewer/gantt/GanttCalendarUtil";
import {TaskModel} from "@bryntum/gantt";
import tradeDisciplineStore from "@/Areas/.../Views/App/pages/viewer/gantt/storexxx";

export class ActivityModel extends TaskModel {
    #isUserDefinedPhantom = false;

//...
//... removed a lot of get and set for brevity...
//

get commentCount() {
    let parentCount = this.project.vueComponent.comments.filter(x => x.pullplanActivityId === this.id).length;
    if(this.isParent){
        let count = 0;
        for (const child of this.children) {
            count += child.commentCount;
        }
        return count + parentCount;
    }
    else{
        return parentCount;
    }
}

get issueCount() {
    let parentCount = this.project.vueComponent.issues.filter(x => x.pullplanActivityId === this.id).length;
    if(this.isParent){
        let count = 0;
        for (const child of this.children) {
            count += child.issueCount;
        }
        return count + parentCount;
    }
    else{
        return parentCount;
    }
}


static get fields() {
    return [
        // .... ..... 
        { name: "commentCount", type: "number"},
        // .....
    ];
}

static relations = {
    tradeDiscipline : {
        foreignKey   : 'tradeDisciplineId',
        foreignStore : tradeDisciplineStore
    }
}

}

Post Reply