Gantt - copy/paste tasks

Request new features or modifications
User avatar
Dev_Coppelis
Premium Member
Premium Member
Posts: 172
Joined: Thu Oct 05, 2017 3:38 pm

Gantt - copy/paste tasks

Post by Dev_Coppelis » Wed Dec 13, 2017 2:06 pm

Hi,
I would like to check if a feature is already available (as I assume it is a must have function) :
• From the advanced view, the possibility to copy/paste a parent task (or a group of tasks), including sub tasks and all the related data (dates, resources, relations, ..).

BR

User avatar
Maxim Gorkovsky
Core Developer
Core Developer
Posts: 2788
Joined: Wed Jan 08, 2014 11:46 am

Re: Gantt - copy/paste tasks

Post by Maxim Gorkovsky » Wed Dec 13, 2017 2:49 pm

Hello.
There is a plugin allowing to copy/paste various data, but it cannot create new records: clipboard. It is enabled by default in our advanced demo.
I made a feature request for plugin with such functionality: https://app.assembla.com/spaces/bryntum/tickets/5331

User avatar
Dev_Coppelis
Premium Member
Premium Member
Posts: 172
Joined: Thu Oct 05, 2017 3:38 pm

Re: Gantt - copy/paste tasks

Post by Dev_Coppelis » Wed Dec 13, 2017 3:08 pm

Hi,
thanks for creating feature request.
Please note that this copy/paste should include sub tasks.
Any idea on when this is supposed to be available ?

User avatar
Maxim Gorkovsky
Core Developer
Core Developer
Posts: 2788
Joined: Wed Jan 08, 2014 11:46 am

Re: Gantt - copy/paste tasks

Post by Maxim Gorkovsky » Wed Dec 13, 2017 3:41 pm

I'm afraid I cannot say when exactly we will start on this feature, we have a lot on our plate now. You can subscribe to the ticket to get updates. We have some drafts of similar feature, so should not take very long.
Also there is always option to prioritize features by contacting sales at bryntum.com

Do you expect copy action to copy everything related to task, i.e. children, dependencies and resource assignments?

User avatar
Dev_Coppelis
Premium Member
Premium Member
Posts: 172
Joined: Thu Oct 05, 2017 3:38 pm

Re: Gantt - copy/paste tasks

Post by Dev_Coppelis » Wed Dec 13, 2017 3:54 pm

ok thanks for the information.

Yes copy everything related to task (like MS Project) .

There is also a related feature : When importing MS project file, to insert the content at the current position on the Gantt (currently this action deletes existing tasks).

Need to create a request for this too ?

User avatar
Maxim Gorkovsky
Core Developer
Core Developer
Posts: 2788
Joined: Wed Jan 08, 2014 11:46 am

Re: Gantt - copy/paste tasks

Post by Maxim Gorkovsky » Wed Dec 13, 2017 4:11 pm

I am not sure if this is worthy of feature request. This task should be pretty simple. Try following:
1) See #importData method of the Importer plugin
2) Instead of loading data into stores (dependencies, resources,..), append it. See this doc: http://docs.sencha.com/extjs/6.5.1/clas ... d-loadData
3) Instead of setting root use node.appendChild where node is task record that you want to import to
4) Avoid setting project calendar and do not set newRoot id to 'root'

This should do the trick.

User avatar
Dev_Coppelis
Premium Member
Premium Member
Posts: 172
Joined: Thu Oct 05, 2017 3:38 pm

Re: Gantt - copy/paste tasks

Post by Dev_Coppelis » Fri Jan 12, 2018 4:12 pm

Hi,
Any news about this copy/paste feature ?
Maxim Gorkovsky wrote:Hello.
There is a plugin allowing to copy/paste various data, but it cannot create new records: clipboard. It is enabled by default in our advanced demo.
I made a feature request for plugin with such functionality: https://app.assembla.com/spaces/bryntum/tickets/5331

User avatar
Terence
Core Developer
Core Developer
Posts: 1523
Joined: Tue Apr 01, 2014 2:23 pm

Re: Gantt - copy/paste tasks

Post by Terence » Fri Jan 12, 2018 5:15 pm

It's not prioritised or in the pipeline yet. If you want to speed things up, I suggest to contact sales@bryntum.com

User avatar
Dev_Coppelis
Premium Member
Premium Member
Posts: 172
Joined: Thu Oct 05, 2017 3:38 pm

Re: Gantt - copy/paste tasks

Post by Dev_Coppelis » Wed Jan 24, 2018 5:09 pm

Maxim Gorkovsky wrote:I am not sure if this is worthy of feature request. This task should be pretty simple. Try following:
1) See #importData method of the Importer plugin
2) Instead of loading data into stores (dependencies, resources,..), append it. See this doc: http://docs.sencha.com/extjs/6.5.1/clas ... d-loadData
3) Instead of setting root use node.appendChild where node is task record that you want to import to
4) Avoid setting project calendar and do not set newRoot id to 'root'

This should do the trick.
Hi Maxim,
i changed the loading data into stores (dependencies, resources) to append but i don't know how to get the id of task to append Child.
Kindly find the below code

Code: Select all

Ext.define('Gnt.examples.advanced.overrides.Importer', {
    extend: 'Ext.AbstractPlugin',

    alias: 'plugin.msproject_importer',

    taskStore: null,
    dependencyStore: null,
    assignmentStore: null,
    resourceStore: null,
    calendarManager: null,

    taskMap: null,
    resourceMap: null,

    syncBlock: function () {
        return false;
    },

    init: function (gantt) {
        this.taskStore = gantt.taskStore;
        this.dependencyStore = gantt.dependencyStore;
        this.resourceStore = gantt.resourceStore;
        this.assignmentStore = gantt.assignmentStore;
        this.calendarManager = this.taskStore.calendarManager;

        this.taskModelIdProperty = this.taskStore.model.prototype.idProperty;
        this.resourceModelIdProperty = this.resourceStore.model.prototype.idProperty;
        this.assignmentModelIdProperty = this.assignmentStore.model.prototype.idProperty;
        this.assignmentModelTaskIdProperty = this.assignmentStore.model.prototype.taskIdField;
        this.assignmentModelResourceIdProperty = this.assignmentStore.model.prototype.resourceIdField;
        this.dependencyModelIdProperty = this.dependencyStore.model.prototype.idProperty;
        this.dependencyModelFromProperty = this.dependencyStore.model.prototype.fromField;
        this.dependencyModelToProperty = this.dependencyStore.model.prototype.toField;

        // if we have CalendarManager onboard we do calendars importing as well
        if (this.calendarManager) {
            this.calendarModelIdProperty = this.calendarManager.model.prototype.idProperty;
            this.taskModelCalendarIdProperty = this.taskStore.model.prototype.CalendarIdField;
            this.resourceModelCalendarIdProperty = this.resourceStore.model.prototype.CalendarIdField;
        }
    },

    /*
     * @param {Object} data A custom data set with 'tasks', 'dependencies', 'assignments' and 'resources' properties.
     * */
    importData: function (data) {
        this.calendarMap = {};
        this.taskMap = {};
        this.resourceMap = {};
        this.projectCalendar = null;

        var taskStore = this.taskStore;

        taskStore.on('beforesync', this.syncBlock);

        taskStore.suspendEarlyDatesResetNotification();
        taskStore.suspendLateDatesResetNotification();

        // import calendars if we have CalendarManager
        this.calendarManager && this.processCalendars(data);

        var tasks = this.getTaskTree(Ext.isArray(data.tasks) ? data.tasks : [data.tasks]);

        this.processResources(data);
        this.processDependencies(data);
        this.processAssignments(data);

        var newRoot = Ext.isArray(data.tasks) ? {} : tasks[0];
        newRoot.children = tasks;

        if (newRoot.isNode) {
            // TODO: set root node id to "root" to comply w/ server side demos
            newRoot.setId('root');
            // seems extjs doesn't track root id change and children keep parentId intact
            Ext.Array.each(newRoot.childNodes, function (node) { node.data.parentId = 'root'; });

            // if instance is passed then getTreeStore will return null
            // http://www.sencha.com/forum/showthread.php?297640
            newRoot.join(taskStore);
        }

        // set project calendar if it's provided
        // we set project calendar in silent mode to not readjust all the tasks
        this.projectCalendar && taskStore.setCalendar(this.calendarMap[this.projectCalendar].getCalendar(), true);
        
        taskStore.setRoot(newRoot);

        taskStore.un('beforesync', this.syncBlock);

        taskStore.resumeEarlyDatesResetNotification();
        taskStore.resumeLateDatesResetNotification();
    },

    /* RESOURCES */
    processResources: function (data) {
        var resources = [];

        Ext.Array.map(data.resources, this.processResource, this);

        this.resourceStore.loadData(resources, true);
    },

    processResource: function (resData) {
        var id = resData[this.resourceModelIdProperty];
        delete resData[this.resourceModelIdProperty];

        resData[this.resourceModelCalendarIdProperty] = this.calendarMap[resData[this.resourceModelCalendarIdProperty]];

        var resource = new this.resourceStore.model(resData);

        this.resourceMap[id] = resource;
        return resource;
    },
    /* EOF RESOURCES */

    /* DEPENDENCIES */
    processDependencies: function (data) {
        var deps = Ext.Array.map(data.dependencies, this.processDependency, this);

        this.dependencyStore.loadData(deps, true);
    },

    processDependency: function (depData) {
        var fromId = depData[this.dependencyModelFromProperty];
        var toId = depData[this.dependencyModelToProperty];
        delete depData[this.dependencyModelFromProperty];
        delete depData[this.dependencyModelToProperty];
        delete depData[this.dependencyModelIdProperty];
        var dep = new this.dependencyStore.model(depData);

        dep.setSourceTask(this.taskMap[fromId]);
        dep.setTargetTask(this.taskMap[toId]);

        return dep;
    },
    /* EOF DEPENDENCIES */

    /* ASSIGNMENTS */
    processAssignments: function (data) {
        Ext.Array.each(data.assignments, this.processAssignment, this);
    },

    processAssignment: function (asData) {
        var resourceId = asData[this.assignmentModelResourceIdProperty];
        var taskId = asData[this.assignmentModelTaskIdProperty];
        delete asData[this.assignmentModelIdProperty];
        delete asData[this.assignmentModelResourceIdProperty];
        delete asData[this.assignmentModelTaskIdProperty];

        this.taskMap[taskId].assign(this.resourceMap[resourceId], asData.Units);
    },
    /* EOF ASSIGNMENTS */

    /* TASKS  */
    getTaskTree: function (tasks) {
        return Ext.Array.map(tasks, this.processTask, this);
    },

    processTask: function (data) {
        var id = data[this.taskModelIdProperty];
        var children = data.children;

        delete data.children;
        delete data[this.taskModelIdProperty];

        data[this.taskModelCalendarIdProperty] = this.calendarMap[data[this.taskModelCalendarIdProperty]];

        var t = new this.taskStore.model(data);
        t.taskStore = this.taskStore;

        if (children) {
            t.appendChild(this.getTaskTree(children));
        }

        t._Id = id;
        this.taskMap[t._Id] = t;

        return t;
    },
    /* EOF TASKS  */

    /* CALENDARS */
    processCalendarChildren: function (children) {
        return Ext.Array.map(children, this.processCalendar, this);
    },

    processCalendar: function (data) {
        var id = data[this.calendarModelIdProperty];
        var children = data.children;

        delete data.children;
        delete data[this.calendarModelIdProperty];

        var t = new this.calendarManager.model(data);

        if (children) {
            t.appendChild(this.processCalendarChildren(children));
        }

        t._Id = id;
        this.calendarMap[t._Id] = t;

        return t;
    },

    // Entry point of calendars loading
    processCalendars: function (data) {
        var calendarManager = this.calendarManager;

        var metaData = data.calendars.metaData;

        delete data.calendars.metaData;

        var processed = this.processCalendarChildren([data.calendars]),
            newRoot = processed[0];

        if (newRoot.isNode) {
            // TODO: set root node id to "root" to comply w/ server side demos
            newRoot.setId('root');
            // seems extjs doesn't track root id change and children keep parentId intact
            Ext.Array.each(newRoot.childNodes, function (node) { node.data.parentId = 'root'; });

            // if instance is passed then getTreeStore will return null
            // http://www.sencha.com/forum/showthread.php?297640
            newRoot.join(calendarManager);
        }

        calendarManager.setRoot(newRoot);

        // remember passed project calendar identifier ..we will set it later after tasks are loaded
        this.projectCalendar = metaData && metaData.projectCalendar;
    }
    /* EOF CALENDARS */

});

User avatar
mats
Core Developer
Core Developer
Posts: 14593
Joined: Sat Dec 19, 2009 11:41 pm
Location: Sweden
Contact:

Re: Gantt - copy/paste tasks

Post by mats » Wed Jan 24, 2018 5:39 pm

That's a bit too much code to review I'm afraid. To get the task id:

Code: Select all

task.getId();
Tired of debugging javascript errors in web applications? Try our new error logging service RootCause, or read more on the Sencha blog

@bryntum
Facebook
API documentation

Post Reply