Our flexible Kanban board for managing tasks with drag drop


Post by sarojstha »

Thank you @Maxim, I uploaded the files and got files URLs as array from server, now how could I send these URL back to the server on sync.

This is my task modal

class Task extends TaskModel {
    static fields = [
        {name: 'name', type: 'string', defaultValue: 'New task'},
        {name: 'description', type: 'string', defaultValue: ''},
        {name: 'commit_date', type: 'date', defaultValue: null},
        {name: 'priority', type: 'string', defaultValue: 'low'},
        {name: 'status', type: 'string'},
        {name: 'completed', type: 'boolean', defaultValue: false},
        {name: 'uploaded_files[]', type: 'string'},
    ];
}

This is my items in task editor config

items : {
                    // Change the label for the name field
                    name        : { label : 'Title' },
                    description : { label : 'Description' , type : 'textarea', height : '10em'},
                    commit_date : { label : 'Commit date', type : 'date' },
                    priority    : {
                        type  : 'combo',
                        label : 'Priority',
                        items : [{
                            id   : 'low',
                            text : 'Low',
                        }, {
                            id   : 'medium',
                            text : 'Medium',
                        }, {
                            id   : 'high',
                            text : 'High',
                        }]
                    },
                    completed: { label: 'Completed', type: 'checkbox'},
                    color: null,
                    fileUpload : {
                        type : 'filepicker',
                        ref  : 'input',
                        fileFieldConfig : {
                            multiple : true,
                            // label    : 'Upload File',
                            // accept   : "image/*"
                        },
                        buttonConfig : {
                            text : 'Upload files',
                            icon : 'b-fa-folder-open'
                        },
                        listeners : {
                            change : ({ files }) => {
                                taskFileUpload(files);
                            },
                            clear : () => {

                            }
                        }
                    },

                }

and this is my taskFileUpload

const taskFileUpload = (files) => {
    let formData = new FormData();

    for (let i = 0; i < files.length; i++) {
        formData.append('files[]', files[i]);
    }


    $.ajax({
        url: "{{route('task-boards.uploadFiles')}}",
        method: 'POST',
        data: formData,
        contentType: false,
        processData: false,
        beforeSend: function (){
            mask('taskBoardContainer')
        },
        success: function (resp){
            if(resp.status){
              //need to place this stringify values to the upload_files
              //JSON.stringify(resp.data.files);
            }

        },
        error: function(xhr) {
            let obj = JSON.parse(xhr.responseText);
            Toast.show({html: obj.message,  cls : 'b-red text-white' });
        },
        complete: function (){
            unmask('taskBoardContainer')
        }
    });
}

now how can I set this JSON.stringify(resp.data.files);

need to place this stringified values to the upload_files field. so that it could send as well during sync


Post by sarojstha »

Any update on above?


Post by alex.l »

Hi,

need to place this stringified values to the upload_files field. so that it could send as well during sync

What's the problem with this? Did you declare your new added field in model fields definition?

All the best,
Alex


Post by sarojstha »

Yes, how could I update this uploaded_files field values once I receive from URL from server. Yes I have already declared, this field uploaded_files on fields as well.

class Task extends TaskModel {
    static fields = [
        {name: 'name', type: 'string', defaultValue: 'New task'},
        {name: 'description', type: 'string', defaultValue: ''},
        {name: 'commit_date', type: 'date', defaultValue: null},
        {name: 'priority', type: 'string', defaultValue: 'low'},
        {name: 'status', type: 'string'},
        {name: 'completed', type: 'boolean', defaultValue: false},
        {name: 'uploaded_files[]', type: 'string'},
    ];
}

but it is considering that uploaded_files is not changed and is not being send to server on 'udpate' action. How could I update this fields like, taskboard.items.values or .... ???


Post by alex.l »

Sorry, still can't get it. Something like

const task = new Task({...});

task.fieldName = newValue;

All the best,
Alex


Post by sarojstha »

Okay, let me try to explain all this with updated code again:

This is my task with static fields set up

    class Task extends TaskModel {
        static fields = [
            {name: 'name', type: 'string', defaultValue: 'New task'},
            {name: 'description', type: 'string', defaultValue: ''},
            {name: 'commit_date', type: 'date', defaultValue: null},
            {name: 'priority', type: 'string', defaultValue: 'low'},
            {name: 'status', type: 'string'},
            {name: 'completed', type: 'boolean', defaultValue: false},
            {name: 'uploaded_files', type: 'string', defaultValue: ''},
        ];
    }

Whenever I click on the '+' icon, it will automatically create a new task with the static fields https://tinyurl.com/25dlpla5

now, I will click on this newly created task, this window pop up https://tinyurl.com/2dfurara

and then updated the description and upload files, https://tinyurl.com/22xs249n

At this moment, as soon as I upload the files, the image will be uploaded to the server and return the URL of those uploaded images in the array.

This is the code for taskboard

const taskBoard = new TaskBoard({
    appendTo : 'taskBoardContainer',
    useDomTransition : true,
    features : {
        columnDrag : true,
        columnRename : true,
        taskEdit :  {
            // Config used to create the editor
            editorConfig : {
                // Will make it anchor to the task being edited
                centered : true,
                // Display it without masking the rest of the page
                modal    : true,
                autoUpdateRecord : false,
                width    : '75em',
                saveAndCloseOnEnter: false,
            },

            // Affect the editors items
            items : {
                // Change the label for the name field
                name        : { label : 'Title' },
                description : { label : 'Description' , type : 'textarea', height : '10em'},
                commit_date : { label : 'Commit date', type : 'date' },
                priority    : {
                    type  : 'combo',
                    label : 'Priority',
                    items : [{
                        id   : 'low',
                        text : 'Low',
                    }, {
                        id   : 'medium',
                        text : 'Medium',
                    }, {
                        id   : 'high',
                        text : 'High',
                    }]
                },
                completed: { label: 'Completed', type: 'checkbox'},
                color: null,
                uploaded_files : {
                    type : 'filepicker',
                    ref  : 'input',
                    fileFieldConfig : {
                        multiple : true,
                        // label    : 'Upload File',
                        // accept   : "image/*"
                    },
                    buttonConfig : {
                        text : 'Upload files',
                        icon : 'b-fa-folder-open'
                    },
                    listeners : {
                        change : ({ files }) => {
                            taskFileUpload(files);
                        },
                        clear : () => {

                        }
                    }
                },
            }
        },
        columnHeaderMenu : {
            items : {
                moveColumnLeft  : null,
                moveColumnRight : null,
                removeColumn : {
                    icon : 'b-fa-trash',
                    text : 'Remove',
                    onItem : (event) => {
                       let column = event.columnRecord;
                       let taskList = column.tasks;
                       if(taskList.length !== 0){
                            Toast.show({html: 'Please remove all the task before deleting a column', 'cls': 'b-red text-white'})
                           return;
                       }

                        columnSync('delete', {'id': column.data.id})
                            .then(response => {
                                column.remove();
                                taskBoardStatus = response.data.newColumnList;
                            })
                            .catch(error => {
                                console.log('error', error);
                            });

                    }
                },
            }
        }

    },

    // Url for resource avatar images
    // resourceImagePath : '../_shared/images/users/',

    // Columns to display

    columns : taskBoardStatus,

    // Field used to pair a task to a column
    columnField : 'status',

    // Custom task renderer, that adds priority as CSS class to the task element
    taskRenderer({ taskRecord, cardConfig }) {
        if (taskRecord.priority) {
            cardConfig.class[taskRecord.priority] = true;
        }
    },

    project : {
        transport : {
            load : {
                url : "{{route('task-boards.load')}}?pqq_region_id="+pqqRegionId,
                headers : {
                    Accept : 'application/json'
                }
            },
            sync : {
                url : "{{route('task-boards.sync')}}",
                method: 'POST',
                params      : {
                    '_token'  : "{{ csrf_token() }}",
                    'pqq_region_id' : pqqRegionId,
                },
            }
        },
        taskStore : {
            modelClass : Task,
            onChange   : updateSyncMsg,
            singleAssignment: false
        },
        assignmentStore : {
            onChange : updateSyncMsg
        },
        onSyncStart() {
            disableButtons(true);
            updateSyncMsg(true);
        },
        onSync() {
            disableButtons(false);
            updateSyncMsg();
        },
        autoSync : true,
        autoLoad : true,
        sendAsFormData : true,
    },

});

In above code, you can see this part

uploaded_files : {
                    type : 'filepicker',
                    ref  : 'input',
                    fileFieldConfig : {
                        multiple : true,
                        // label    : 'Upload File',
                        // accept   : "image/*"
                    },
                    buttonConfig : {
                        text : 'Upload files',
                        icon : 'b-fa-folder-open'
                    },
                    listeners : {
                        change : ({ files }) => {
                            taskFileUpload(files);
                        },
                        clear : () => {

                        }
                    }

whenever a file is uploaded it triggers taskFileUpload(files) , and here is this function:

const taskFileUpload = (files) => {
    let formData = new FormData();

    for (let i = 0; i < files.length; i++) {
        formData.append('files[]', files[i]); // Append each file to the FormData object
    }


    $.ajax({
        url: "{{route('task-boards.uploadFiles')}}",
        method: 'POST',
        data: formData,
        contentType: false,
        processData: false,
        success: function (resp){
            if(resp.success){

                const task = new Task();

                task.uploaded_files = JSON.stringify(resp.data.files);

                console.log('task', task);
            }

        },
    });
}

Above in the response you can see that, I have tried to update the uploaded_files values as


if(resp.success){
                const task = new Task();
                task.uploaded_files = JSON.stringify(resp.data.files);
            }

However, when I click on the save button, https://tinyurl.com/24hlszok

the uploaded_files data are not being submitted to the server. https://tinyurl.com/2b6c6kol


Post by alex.l »

Hi,

CrudManager cannot track a randomly created instance of TaskModel. It should persist in a Store. It this case, in TaskStore.
you need to get taskRecord that your TaskEditor loaded and set new value to that record. To get more about Stores please see https://bryntum.com/products/gantt/docs/api/Core/data/Store
Here is about CrudManager in ProjectModel and data https://bryntum.com/products/gantt/docs/guide/Gantt/data/project_data
Best of all to review all of these https://bryntum.com/products/gantt/docs/api/guides-working-with-data

Here is how to customize TaskEditor https://bryntum.com/products/gantt/docs/guide/Gantt/customization/taskedit
Especially this part might give you inspiration how to get access to taskRecord in your custom field.
I hope uploaded_files has something else except file, just to keep in mind that String has limits of length.https://ecma-international.org/publications-and-standards/standards/ecma-262/

All the best,
Alex


Post by sarojstha »

Exactly this is my main point, you need to get taskRecord that your TaskEditor loaded and set new value to that record, how can I get the taskRecord that is currently loaded on TaskEditor. On this code:

taskEdit :  {
                // Config used to create the editor
                editorConfig : {
                    // Will make it anchor to the task being edited
                    centered : true,
                    // Display it without masking the rest of the page
                    modal    : true,
                    autoUpdateRecord : false,
                    width    : '75em',
                    saveAndCloseOnEnter: false,
                },

                // Affect the editors items
                items : {
                    // Change the label for the name field
                    name        : { label : 'Title' },
                    description : { label : 'Description' , type : 'textarea', height : '10em'},
                    commit_date : { label : 'Commit date', type : 'date' },
                    priority    : {
                        type  : 'combo',
                        label : 'Priority',
                        items : [{
                            id   : 'low',
                            text : 'Low',
                        }, {
                            id   : 'medium',
                            text : 'Medium',
                        }, {
                            id   : 'high',
                            text : 'High',
                        }]
                    },
                    completed: { label: 'Completed', type: 'checkbox'},
                    color: null,
                    uploaded_files : {
                        type : 'filepicker',
                        ref  : 'input',
                        fileFieldConfig : {
                            multiple : true,
                            // label    : 'Upload File',
                            // accept   : "image/*"
                        },
                        buttonConfig : {
                            text : 'Upload files',
                            icon : 'b-fa-folder-open'
                        },
                        listeners : {
                            change : ({ files }) => {

                                taskFileUpload(files);
                            },
                            clear : () => {

                            }
                        }
                    },
                }
            },

how is it loading the task at the moment?


Post by alex.l »

I recommend to check guides I've sent you. Here https://bryntum.com/products/gantt/docs/guide/Gantt/customization/taskedit#update-custom-fields-state-and-data
You can see code:

const gantt = new Gantt({
    features : {
        taskEdit : {
            items : {
                equipment : {
                    // custom field configuration
                },
                volume : {
                    // custom field configuration
                }
            }
        }
    },
    listeners : {
        beforeTaskEditShow({ editor, taskRecord }) {
            const
                equipmentCombo = editor.widgetMap.equipment,
                volumeField = editor.widgetMap.volume;

        // update data in combo list
        equipmentCombo.items = this.equipmentStore.getRange();
        // update field visibility state
        volumeField.hidden = !taskRecord.hasVolume;
    }
}
});

Just use https://bryntum.com/products/gantt/docs/api/Gantt/feature/TaskEdit#event-beforeTaskEditShow

Also it might be done here https://bryntum.com/products/gantt/docs/api/Gantt/feature/TaskEdit#event-beforeTaskSave

You can get your field within https://bryntum.com/products/gantt/docs/api/Core/widget/Container#property-widgetMap and set value to taskRecord that is available there.

All the best,
Alex


Post by sarojstha »

This beforeTaskEditShow is triggering correctly, however, I am unsure if it is of any use, because the value will be updated after the task edit modal is shown, and user upload the files on the filepicker, and once the response is received from the server, at this point I need the task record and update it.

So, it might seems beforeTaskEditSave is the logical one, however, this was not getting triggered.

So I tried instead onBeforeSync and somehow I have managed to send these data and stored on the server.

Now, My question is: Is it possible to show just the URL of the file name on the editor pop up? I would like to show the file name and download link. Basically, I just want to display extra text on the edit pop up, is there any related resources for that as well?

#PS: By the way I am working on taskboard, is it same across all widgets like Gantt? Because most of the examples you are sharing from from Gantt though.


Post Reply