dhtmlxGantt mit Salesforce LWC
Dieses Tutorial beschreibt, wie man dhtmlxGantt in eine Salesforce Lightning Web Component.
Schauen Sie sich die Online-Demo zur Integration von DHTMLX-Komponenten mit Salesforce LWC an (Anmeldung: user, Passwort: demo). Der Quellcode der Demo ist auf GitHub verfügbar.
Wenn Sie eine andere Technologie verwenden, prüfen Sie die untenstehende Liste der verfügbaren Integrationsvarianten:
- dhtmlxGantt mit ASP.NET Core
- dhtmlxGantt mit ASP.NET MVC
- dhtmlxGantt mit Node.js
- dhtmlxGantt mit Python
- dhtmlxGantt mit PHP: Laravel
- dhtmlxGantt mit PHP:Slim
- dhtmlxGantt mit Ruby on Rails
Wir verwenden die Salesforce CLI, um eine Lightning Web Component zu erstellen und sie in einer Organisation hochzuladen. Sie können auch das Salesforce Extension Pack installieren [Visual Studio Code], um mit Entwicklungs-Orggos zu arbeiten.
Der vollständige Quellcode der in diesem Tutorial erstellten Demo ist auf GitHub verfügbar.
Sie können sich die Videoanleitung ansehen, die zeigt, wie man ein Gantt-Diagramm mit Salesforce LWC erstellt.
Voraussetzungen
Installieren Sie die Salesforce CLI, falls Sie sie noch nicht haben. Siehe diesen Artikel für Installationsanleitungen.
Schritt 1. Ein Projekt erstellen
Registrieren Sie sich für ein kostenloses Entwicklerkonto, falls Sie noch keins besitzen. Siehe diesen Artikel für Installationsanleitungen.
Auf der linken Seite im Suchfeld finden Sie Dev Hub und wählen Sie es aus:

Im neuen Einstellungsfenster wählen Sie Dev Hub aktivieren:

Lassen Sie uns ein Basverzeichnis für das Salesforce DX-Projekt erstellen:
$ mkdir ~/salesforce
Erstellen Sie ein Salesforce DX-Projekt über die CLI:
$ cd ~/salesforce
$ sfdx project generate -n gantt-salesforce-app
target dir = C:UsersUsersalesforce
create gantt-salesforce-appconfigproject-scratch-def.json
create gantt-salesforce-appREADME.md
create gantt-salesforce-appsfdx-project.json
create gantt-salesforce-app.huskypre-commit
create gantt-salesforce-app.vscodeextensions.json
create gantt-salesforce-app.vscodelaunch.json
create gantt-salesforce-app.vscodesettings.json
create gantt-salesforce-appforce-appmaindefaultlwc.eslintrc.json
create gantt-salesforce-appforce-appmaindefaultaura.eslintrc.json
create gantt-salesforce-appscriptssoqlaccount.soql
create gantt-salesforce-appscriptsapexhello.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-appjest.config.js
create gantt-salesforce-apppackage.json
Gehen Sie zum erstellten Projekt:
$ cd gantt-salesforce-app
Schritt 2. Autorisierung
Organisieren Sie eine Orgnisation über den Web Server Flow:
$ sfdx org login web -d
Successfully authorized ... with org ID ...
Aktualisieren Sie Ihre Projektkonfigurationsdatei (sfdx-project.json). Setzen Sie den Parameter "sfdcLoginUrl" auf Ihre "My Domain URL". Die "My Domain URL" Ihres Organisations finden Sie auf der Seite "My Domain" in der Einrichtung. Zum Beispiel:

"sfdcLoginUrl" : "https://xbs2-dev-ed.my.salesforce.com"
Erstellen Sie eine 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.
Schritt 3. Gantt zu Salesforce hinzufügen
Um die Bibliothek zu verwenden, müssen wir sie innerhalb von Salesforce als Static Resource hochladen. Öffnen Sie daher Ihre Scratch Org:
$ sfdx org open
Öffnen Sie nun die Registerkarte "Static Resources" und klicken Sie auf die Schaltfläche "New"

Geben Sie ihr einen aussagekräftigen Namen (wir verwenden "dhtmlxgantt7111"), wählen Sie das ZIP-Archiv mit der Bibliothek selbst (das Archiv muss die Dateien dhtmlxgantt.js und dhtmlxgantt.css enthalten) und wählen Sie die Cache-Control-Option "Public" aus, um die Leistung zu verbessern. Drücken Sie die Schaltfläche "Save".

Jetzt haben wir dhtmlxGantt in Salesforce.

Schritt 4. Erstellen des Datenmodells
Die Kernentitäten von dhtmlxGantt sind Tasks (Aufgaben) und Links. Ein sinnvoller Ansatz ist, alle Eigenschaften der dhtmlxGantt-Entitäten als reines JSON in Salesforce zu speichern. Erstellen wir daher die Objekte Tasks und Links. Öffnen Sie den Objekt-Manager und wählen Sie "Create" dann "Custom Object":

Aufgaben-Objekt
Geben Sie dem Objekt den Namen, lassen Sie es GanttTask/GanttTasks heißen.

Der Datensatzname muss dem Objektnamen entsprechen, zum Beispiel:
Objektname: GanttTask => Datensatzname: GanttTask Name
Drücken Sie die Schaltfläche "Save".
Nachdem das Objekt erstellt wurde, öffnen Sie die Registerkarte "Fields & Relationships". Drücken Sie die Schaltfläche "New".

- Duration
Wählen Sie "Number" als Datentyp und drücken Sie die Schaltfläche "Next".

Nennen Sie es "Duration". Es speichert die JSON-serialisierten Task-Eigenschaften. Drücken Sie die Schaltfläche "Next" bis die Schaltfläche "Save & New" verfügbar ist.

Drücken Sie erneut "Next" (unter Akzeptieren aller Standardoptionen), bis die Schaltfläche "Save & New" verfügbar ist.
- Parent
Erstellen Sie ein Feld "Parent". Wählen Sie "Text" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen) bis "Save & New" verfügbar ist.
- Progress
Erstellen Sie ein Feld "Progress". Wählen Sie "Number" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen) bis "Save & New" verfügbar ist.
- Startdatum
Erstellen Sie ein Feld "Start Date". Wählen Sie "Date/Time" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen) bis "Save" verfügbar ist.
Am Ende sollte es so aussehen:

Link-Objekt
Öffnen Sie den Objekt-Manager und wählen Sie "Create" dann "Custom Object":
Geben Sie den Namen für das Link-Objekt an, lassen Sie es GanttLink/GanttLinks heißen.

Der Datensatzname muss dem Objektnamen entsprechen, zum Beispiel:
Objektname: GanttLink => Datensatzname: GanttLink Name
Als Nächstes erstellen Sie die erforderlichen Felder.
- Source
Erstellen Sie ein Feld "Source". Wählen Sie "Text" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen), bis "Save & New" verfügbar ist.
- Target
Erstellen Sie ein Feld "Target". Wählen Sie "Text" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen), bis "Save & New" verfügbar ist.
- Type
Erstellen Sie ein Feld "Type". Wählen Sie "Text" als Datentyp.

Drücken Sie erneut "Next" (Unter Akzeptieren aller Standardoptionen) bis "Save" verfügbar ist.
Am Ende sollte es so aussehen:

Schritt 5. Erstellen einer Lightning Web Component
Um eine Lightning Web Component zu erstellen, führen Sie den Befehl aus:
$ sfdx lightning generate component --type lwc -n gantt -d force-app/main/default/lwc
target dir =
C:UsersUsersourcesalesforcegantt-salesforce-appforce-appmaindefaultlwc
create force-appmaindefaultlwcganttgantt.js
create force-appmaindefaultlwcganttgantt.html
create force-appmaindefaultlwcganttgantt.js-meta.xml
Ändern Sie die Komponentendefinition in gantt.js-meta.xml, um sie im Lightning App Builder freizugeben:
<?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>
Öffnen Sie gantt.html und fügen Sie den folgenden Code dort ein:
<template>
<div class="thegantt" lwc:dom="manual" style='width: 100%;'></div>
</template>
Öffnen Sie gantt.js und fügen Sie den folgenden Code dort ein:
/* 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: "Fehler beim Laden von 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(() => ({}));
}
}
});
}
}
Schritt 6. Eine Apex-Klasse erstellen
Der nächste Schritt besteht darin, eine Klasse zu erstellen, die Interaktionen zwischen der Lightning-Komponente und unserem Datenmodell ermöglicht.
$ sfdx apex generate class -n GanttData -d force-app/main/default/classes
target dir =
C:UsersUsersalesforcegantt-salesforce-appforce-appmaindefaultclasses
create force-appmaindefaultclassesGanttData.cls
create force-appmaindefaultclassesGanttData.cls-meta.xml
Nachdem sie erstellt wurde, öffnen Sie GanttData.cls und fügen Sie den folgenden Code ein:
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;
}
}
Quellcode aus dem Scratch-Org in Ihr Projekt ziehen
$ sfdx project retrieve start
und dann die Quellen in die Scratch-Org übertragen
$ sfdx project deploy start
Schritt 7. Eine Lightning-Seite erstellen
Öffnen Sie den "Lightning App Builder", erstellen Sie eine neue Lightning-Seite.

Wählen Sie "App Page" dann Seitennamen und Layout.



Sie sollten eine Gantt-Benutzerkomponente für die neue Seite sehen. Fügen Sie sie in einen Bereich ein und speichern Sie.

Aktivieren Sie die Seite.

Speichern Sie die Änderungen.



Öffnen Sie die Anwendungsseite. Sie sollte im App-Launcher verfügbar sein, wenn Sie darauf klicken und „Gantt“ eingeben.

Wenn alles gut gelaufen ist, sehen Sie eine einfache Gantt-Demo, die in der Lightning-Seite läuft.

Anwendungssicherheit
Gantt bietet keine Mittel, um eine Anwendung vor verschiedenen Bedrohungen zu schützen, wie SQL-Injections oder XSS- und CSRF-Angriffen. Wichtig ist, dass die Verantwortung für die Sicherheit einer Anwendung bei den Entwicklern liegt, die die Anwendung implementieren. Die Details finden Sie im entsprechenden Artikel. Salesforce ist sicherheitsorientiert gebaut, um Ihre Daten und Anwendungen zu schützen. Sie können auch ein eigenes Sicherheitskonzept implementieren, das der Struktur und den Bedürfnissen Ihrer Organisation entspricht. Für weitere Informationen lesen Sie bitte den Salesforce Security Guide. Hier erfahren Sie, was Sie benötigen, um sicher zu arbeiten.
Fehlerbehebung
Wenn Sie die obigen Schritte zur Integration von Gantt mit Salesforce abgeschlossen haben, Gantt jedoch keine Aufgaben und Verknüpfungen auf einer Seite rendert, schauen Sie sich den Artikel Troubleshooting Backend Integration Issues an. Er beschreibt die Möglichkeiten zur Identifizierung der Ursachen der Probleme.
Was kommt als Nächstes
Jetzt haben Sie ein vollständig funktionsfähiges Gantt. Den vollständigen Code können Sie auf GitHub einsehen, klonen oder herunterladen und für Ihre Projekte verwenden.
Sie können auch Guides zu den zahlreichen Funktionen von Gantt oder Tutorials zur Integration von Gantt mit anderen Backend-Frameworks (integrations/howtostart-guides.md) prüfen.