Этот гид описывает процесс интеграции dhtmlxGantt в Salesforce Lightning Web Component.
Если вы работаете с другой технологией, существуют иные варианты интеграции, которые вы можете изучить:
Для этого руководства мы будем использовать Salesforce CLI для создания Lightning Web Component и его развертывания в организации. Также может быть полезным установить Salesforce Extension Pack для Visual Studio Code, если вы работаете с организациями разработки.
Полный исходный код этого примера доступен на GitHub.
Также доступен видеоурок, демонстрирующий, как настроить диаграмму Ганта с Salesforce LWC.
Убедитесь, что у вас установлен Salesforce CLI. Вы можете следовать этому руководству для инструкций по установке.
Если у вас еще нет аккаунта разработчика, вы можете зарегистрироваться для бесплатного. Руководство по созданию аккаунта можно найти здесь.
Начните с включения Dev Hub. Используйте строку поиска слева, чтобы найти и выбрать Dev Hub:
В окне настроек активируйте Enable Dev Hub:
Затем создайте базовый каталог для проекта Salesforce DX:
$ mkdir ~/salesforce
Создайте проект Salesforce DX с помощью CLI:
$ cd ~/salesforce
$ sfdx project generate -n gantt-salesforce-app
target dir = C:\Users\User\salesforce
create gantt-salesforce-app\config\project-scratch-def.json
create gantt-salesforce-app\README.md
create gantt-salesforce-app\sfdx-project.json
create gantt-salesforce-app\.husky\pre-commit
create gantt-salesforce-app\.vscode\extensions.json
create gantt-salesforce-app\.vscode\launch.json
create gantt-salesforce-app\.vscode\settings.json
create gantt-salesforce-app\force-app\main\default\lwc\.eslintrc.json
create gantt-salesforce-app\force-app\main\default\aura\.eslintrc.json
create gantt-salesforce-app\scripts\soql\account.soql
create gantt-salesforce-app\scripts\apex\hello.apex
create gantt-salesforce-app\.eslintignore
create gantt-salesforce-app\.forceignore
create gantt-salesforce-app\.gitignore
create gantt-salesforce-app\.prettierignore
create gantt-salesforce-app\.prettierrc
create gantt-salesforce-app\jest.config.js
create gantt-salesforce-app\package.json
Перейдите в папку проекта:
$ cd gantt-salesforce-app
Авторизуйте организацию, используя Web Server Flow. Дополнительную информацию можно найти здесь:
$ sfdx org login web -d
Successfully authorized ... with org ID ...
Обновите файл конфигурации проекта (sfdx-project.json). Установите параметр sfdcLoginUrl
в ваш "URL моего домена". Вы можете найти этот URL на странице настройки "My Domain". Например:
gantt-salesforce-app/sfdx-project.json
"sfdcLoginUrl" : "https://xbs2-dev-ed.my.salesforce.com"
Создайте Scratch Org:
$ sfdx org create scratch -f config/project-scratch-def.json -d
Creating Scratch Org...
RequestId: 2SR5j0000006JhCGAU
(https://xbsoftware2-dev-ed.my.salesforce.com/2SR5j0000006JhCGAU)
OrgId: 00DH40000000s0D
Username: test-tc0telfqhudt@example.com
✓ Prepare Request
✓ Send Request
✓ Wait For Org
✓ Available
✓ Authenticate
✓ Deploy Settings
Done
Your scratch org is ready.
Чтобы использовать библиотеку, загрузите ее в Salesforce как Static Resource. Начните с открытия вашего Scratch Org:
$ sfdx org open
Перейдите на вкладку "Static Resources" и нажмите кнопку "New":
Назовите ресурс значимым именем (например, "dhtmlxgantt7111"), загрузите ZIP-архив, содержащий файлы библиотеки (dhtmlxgantt.js и dhtmlxgantt.css), и установите "Cache Control" на "Public" для лучшей производительности. Сохраните изменения:
Библиотека dhtmlxGantt теперь доступна в Salesforce:
Основные сущности для dhtmlxGantt — это Задачи и Связи. Практичным подходом является хранение всех свойств этих сущностей в виде простого JSON в Salesforce. Начните с создания объектов Задач и Связей. Откройте Object Manager, нажмите "Create" и выберите "Custom Object":
Назовите объект задачи GanttTask/GanttTasks:
Убедитесь, что имя записи соответствует имени объекта. Например:
Имя объекта: GanttTask => Имя записи: GanttTask Name
Сохраните изменения.
После создания объекта переключитесь на вкладку "Fields & Relationships" и нажмите "New":
Duration
Parent
Progress
Start Date
В итоге должно получиться что-то вроде этого:
Для начала откройте Object Manager и выберите "Create", затем выберите "Custom Object":
Назовите объект связи GanttLink/GanttLinks.
Убедитесь, что имя записи соответствует имени объекта. Например:
Имя объекта: GanttLink => Имя записи: GanttLink Name
Теперь создайте необходимые поля.
Создайте поле с именем "Source" и выберите "Text" как тип данных.
Нажмите "Next" (оставив настройки по умолчанию), пока не появится кнопка "Save & New".
Создайте поле с именем "Target" и выберите "Text" как тип данных.
Нажмите "Next" (оставив настройки по умолчанию), пока не появится кнопка "Save & New".
Создайте поле с именем "Type" и выберите "Text" как тип данных.
Нажмите "Next" (оставив настройки по умолчанию), пока не появится кнопка "Save".
Когда вы закончите, это должно выглядеть так:
Чтобы создать Lightning Web Component, используйте эту команду:
$ sfdx lightning generate component --type lwc -n gantt -d force-app/main/default/lwc
target dir =
C:\Users\User\source\salesforce\gantt-salesforce-app\force-app\main\default\lwc
create force-app\main\default\lwc\gantt\gantt.js
create force-app\main\default\lwc\gantt\gantt.html
create force-app\main\default\lwc\gantt\gantt.js-meta.xml
Измените файл gantt.js-meta.xml, чтобы сделать его видимым в Lightning App Builder:
force-app/main/default/lwc/gantt/gantt.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>54.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__AppPage">
<property name="height" label="Height" type="Integer" default="800" />
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
В gantt.html добавьте этот код:
force-app/main/default/lwc/gantt/gantt.html
<template>
<div class="thegantt" lwc:dom="manual" style='width: 100%;'></div>
</template>
В gantt.js включите этот код:
force-app/main/default/lwc/gantt/gantt.js
/* eslint-disable guard-for-in */
/* eslint-disable no-undef */
import { LightningElement, api } from "lwc";
import { ShowToastEvent } from "lightning/platformShowToastEvent";
import { loadStyle, loadScript } from "lightning/platformResourceLoader";
import { createRecord, updateRecord, deleteRecord } from "lightning/uiRecordApi";
// Static resources
import GanttFiles from "@salesforce/resourceUrl/dhtmlxgantt7111";
// Controllers
import getTasks from "@salesforce/apex/GanttData.getTasks";
function unwrap(fromSF) {
const data = fromSF.tasks.map((a) => ({
id: a.Id,
text: a.Name,
start_date: a.Start_Date__c,
duration: a.Duration__c,
parent: a.Parent__c,
progress: a.Progress__c,
type: a.Task_Type__c,
}));
const links = fromSF.links.map((a) => ({
id: a.Id,
source: a.Source__c,
target: a.Target__c,
type: a.Type__c
}));
return { data, links};
}
export default class GanttView extends LightningElement {
static delegatesFocus = true;
@api height;
ganttInitialized = false;
renderedCallback() {
if (this.ganttInitialized) {
return;
}
this.ganttInitialized = true;
Promise.all([
loadScript(this, GanttFiles + "/dhtmlxgantt.js"),
loadStyle(this, GanttFiles + "/dhtmlxgantt.css")
])
.then(() => {
this.initializeUI();
})
.catch((error) => {
this.dispatchEvent(
new ShowToastEvent({
title: "Error loading Gantt",
message: error.message,
variant: "error"
})
);
});
}
initializeUI() {
const root = this.template.querySelector(".thegantt");
root.style.height = this.height + "px";
//uncomment the following line if you use the Enterprise or Ultimate version
//const gantt = window.Gantt.getGanttInstance();
gantt.templates.parse_date = (date) => new Date(date);
gantt.templates.format_date = (date) => date.toISOString();
gantt.init(root);
getTasks().then((d) => {
const chartData = unwrap(d);
gantt.parse({
tasks: chartData.data,
links: chartData.links
});
});
///↓↓↓ saving changes back to SF backend ↓↓↓
gantt.createDataProcessor({
task: {
create: (data) => {
console.log("createTask",data);
const insert = {
apiName: "GanttTask__c",
fields: {
Name: data.text,
Start_Date__c: data.start_date,
Duration__c: data.duration,
Parent__c: String(data.parent),
Progress__c: data.progress
}
};
gantt.config.readonly = true; // suppress changes
// until saving is complete
return createRecord(insert).then((res) => {
gantt.config.readonly = false;
return { tid: res.id, ...res };
});
},
update: (data, id) => {
console.log("updateTask",data);
const update = {
fields: {
Id: id,
Name: data.text,
Start_Date__c: data.start_date,
Duration__c: data.duration,
Parent__c: String(data.parent),
Progress__c: data.progress
}
};
return updateRecord(update).then(() => ({}));
},
delete: (id) => {
return deleteRecord(id).then(() => ({}));
}
},
link: {
create: (data) => {
const insert = {
apiName: "GanttLink__c",
fields: {
Source__c: data.source,
Target__c: data.target,
Type__c: data.type
}
};
return createRecord(insert).then((res) => {
return { tid: res.id };
});
},
update: (data, id) => {
const update = {
apiName: "GanttLink__c",
fields: {
Id: id,
Source__c: data.source,
Target__c: data.target,
Type__c: data.type
}
};
return updateRecord(update).then(() => ({}));
},
delete: (id) => {
return deleteRecord(id).then(() => ({}));
}
}
});
}
}
Теперь создайте класс для обработки взаимодействий между Lightning Component и моделью данных:
$ sfdx apex generate class -n GanttData -d force-app/main/default/classes
target dir =
C:\Users\User\salesforce\gantt-salesforce-app\force-app\main\default\classes
create force-app\main\default\classes\GanttData.cls
create force-app\main\default\classes\GanttData.cls-meta.xml
Откройте GanttData.cls и добавьте этот код:
force-app/main/default/classes/GanttData.cls
public with sharing class GanttData {
@RemoteAction
@AuraEnabled(cacheable=true)
public static Map<String, Object> getTasks() {
// fetching the Records via SOQL
List<GanttTask__c> Tasks = new List<GanttTask__c>();
Tasks = [SELECT Id, Name, Start_Date__c, Duration__c,
Parent__c FROM GanttTask__c];
List<GanttLink__c> Links = new List<GanttLink__c>();
Links = [SELECT Id, Type__c, Source__c, Target__c FROM GanttLink__c];
Map<String, Object> result = new Map<String, Object>{
'tasks' => Tasks, 'links' => Links };
return result;
}
}
Получите исходный код из Scratch Org:
$ sfdx project retrieve start
Затем отправьте исходный код обратно в Scratch Org:
$ sfdx project deploy start
Откройте "Lightning App Builder" и создайте новую Lightning Page.
Выберите “App Page”, затем задайте имя страницы и макет.
Теперь вы должны увидеть компонент Gantt в списке. Добавьте его в регион и сохраните.
Активируйте страницу.
Сохраните изменения.
Откройте страницу приложения. Вы можете найти ее в лаунчере приложений, введя "Gantt".
Если все настроено правильно, вы увидите простую демонстрацию Ганта, работающую на Lightning Page.
Компонент Gantt не включает встроенную защиту от угроз, таких как SQL-инъекции, XSS или CSRF-атаки. Важно обеспечить безопасность вашего приложения. Разработчики несут ответственность за внедрение надлежащих мер безопасности. Подробнее вы можете узнать в соответствующей статье. Salesforce также предоставляет надежные функции безопасности для защиты ваших данных и приложений. Для получения дополнительной информации обратитесь к Salesforce Security Guide или изучите Secure Coding Guide.
Если задачи и связи не отображаются на странице после завершения настройки, ознакомьтесь со статьей Troubleshooting Backend Integration Issues. Она содержит рекомендации по диагностике и разрешению возможных проблем.
Теперь у вас есть работающий компонент Gantt. Полный код доступен на GitHub. Вы можете клонировать или загрузить его для своих проектов.
Вы также можете изучить руководства по функциям Gantt или просмотреть учебные пособия по интеграции Gantt с другими бэкенд-фреймворками.
К началу