이 튜토리얼에서는 dhtmlxScheduler를 SalesForce Lightning Web Component에 통합하는 방법을 안내합니다.
다른 기술을 사용 중이라면, 아래에 나열된 다른 통합 옵션도 참고하시기 바랍니다:
이 가이드에서는 SalesForce CLI를 사용하여 Lightning Web Component를 생성하고, 이를 조직에 배포하는 과정을 다룹니다. 설치 관련 자세한 내용은 이 문서를 참고하세요. 또한, Visual Studio Code에서 개발 환경을 더욱 편리하게 사용하려면 Salesforce Extension Pack을 설치할 수 있습니다.
전체 소스 코드는 GitHub에서 확인하실 수 있습니다.
아래 영상 가이드에서는 Salesforce LWC와 함께 Scheduler를 구축하는 방법을 시연합니다.
SalesForce CLI가 설치되어 있는지 확인하세요. 설치가 되어 있지 않다면, 이 문서를 참고하여 설치를 진행하세요.
아직 개발자 계정이 없다면, 여기에서 무료 개발자 계정에 가입하세요. 자세한 안내는 이 글을 참고하실 수 있습니다.
좌측 검색창에서 Dev Hub를 검색하여 선택하세요:
이후 나타나는 설정 창에서 Dev Hub를 활성화합니다:
Salesforce DX 프로젝트를 위한 기본 폴더를 생성합니다:
$ mkdir ~/salesforce
CLI를 사용하여 Salesforce DX 프로젝트를 생성합니다:
$ cd ~/salesforce
$ sfdx project generate -n scheduler-salesforce-app
target dir = C:\Users\User\salesforce
create scheduler-salesforce-app\config\project-scratch-def.json
create scheduler-salesforce-app\README.md
create scheduler-salesforce-app\sfdx-project.json
create scheduler-salesforce-app\.husky\pre-commit
create scheduler-salesforce-app\.vscode\extensions.json
create scheduler-salesforce-app\.vscode\launch.json
create scheduler-salesforce-app\.vscode\settings.json
create scheduler-salesforce-app\force-app\main\default\lwc\.eslintrc.json
create scheduler-salesforce-app\force-app\main\default\aura\.eslintrc.json
create scheduler-salesforce-app\scripts\soql\account.soql
create scheduler-salesforce-app\scripts\apex\hello.apex
create scheduler-salesforce-app\.eslintignore
create scheduler-salesforce-app\.forceignore
create scheduler-salesforce-app\.gitignore
create scheduler-salesforce-app\.prettierignore
create scheduler-salesforce-app\.prettierrc
create scheduler-salesforce-app\jest.config.js
create scheduler-salesforce-app\package.json
새로 생성된 프로젝트 폴더로 이동합니다:
$ cd scheduler-salesforce-app
다음 명령어를 실행하여 Web Server Flow를 통해 조직에 인증합니다:
$ sfdx org login web -d
Successfully authorized ...@...com with org ID ...
이제 프로젝트 설정 파일(sfdx-project.json)에서 "sfdcLoginUrl" 파라미터를 자신의 "My Domain URL"로 설정합니다. 해당 URL은 조직의 "My Domain" 설정 페이지에서 확인할 수 있습니다. 예시:
scheduler-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: 2SR8a000000PLf5GAG (https://xbs2-dev-ed.my.salesforce.com/2SR8a000000PLf5GAG)
OrgId: 00D8G000000EEMs
Username: test-3baxo2k0tpej@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" 버튼을 클릭하세요:
리소스 이름(예: dhtmlxscheduler)을 명확하게 지정하고, 라이브러리 파일(dhtmlxscheduler.js 및 dhtmlxscheduler.css)이 포함된 ZIP 압축 파일을 업로드합니다. Cache Control은 "Public"으로 설정하여 성능을 향상시킵니다. "Save"를 클릭하세요.
이제 dhtmlxScheduler가 Salesforce 내에서 사용 가능합니다.
dhtmlxScheduler의 핵심 엔터티는 이벤트입니다. 이들을 효과적으로 관리하기 위해, 모든 속성을 Salesforce 내에서 plain JSON 형태로 저장하는 것이 실용적입니다. 이를 위해 새로운 Event 오브젝트를 생성하세요. Object Manager를 열고, "Create" → "Custom Object"를 선택합니다:
이벤트 객체의 이름을 SchedulerEvent 또는 SchedulerEvents로 지정하세요.
레코드 이름이 객체 이름과 일치하는지 확인하세요. 예를 들어:
객체 이름: SchedulerEvent => 레코드 이름: SchedulerEvent Name
“저장” 버튼을 클릭하세요.
객체가 생성되면 "필드 및 관계" 탭으로 이동하여 "새로 만들기" 버튼을 클릭합니다.
데이터 유형으로 "날짜/시간"을 선택한 후 "다음"을 클릭하세요.
이 필드의 이름을 "Start Date"로 지정합니다. 이 필드는 JSON으로 직렬화된 Task 속성을 저장합니다.
"다음"을 클릭하고 "저장 및 새로 만들기" 버튼이 나타날 때까지 모든 기본 설정을 그대로 두세요.
"End Date" 필드를 추가하고, 데이터 유형으로 "날짜/시간"을 선택하세요.
"다음"을 클릭하고 "저장 및 새로 만들기" 버튼이 나타날 때까지 기본 설정을 그대로 두세요.
"Text" 필드를 만들고 데이터 유형으로 "Text"를 선택하세요.
"다음"을 클릭하고 "저장" 버튼이 활성화될 때까지 모든 기본 설정을 그대로 두세요.
마지막에는 필드가 다음과 같이 보여야 합니다:
Lightning Web Component를 생성하려면 다음 명령어를 사용하세요:
$ sfdx lightning generate component --type lwc -n scheduler -d force-app/main/default/lwc
target dir = C:\Users\User\source\salesforce\scheduler-salesforce-app\force-app\main\default\lwc
create force-app\main\default\lwc\scheduler\scheduler.js
create force-app\main\default\lwc\scheduler\scheduler.html
create force-app\main\default\lwc\scheduler\__tests__\scheduler.test.js
create force-app\main\default\lwc\scheduler\scheduler.js-meta.xml
Lightning App Builder에 노출되도록 scheduler.js-meta.xml에서 컴포넌트 정의를 수정하세요:
force-app/main/default/lwc/scheduler/scheduler.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.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>
scheduler.html을 열고 다음 코드를 입력하세요:
force-app/main/default/lwc/scheduler/scheduler.html
<template>
<div class="thescheduler" lwc:dom="manual" style='width: 100%;'></div>
</template>
이제 scheduler.js를 열고 다음 코드를 추가하세요:
force-app/main/default/lwc/scheduler/scheduler.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 SchedulerFiles from "@salesforce/resourceUrl/dhtmlxscheduler";
// Controllers
import getEvents from "@salesforce/apex/SchedulerData.getEvents";
function unwrap(fromSF) {
const data = fromSF.events.map((a) => ({
id: a.Id,
info: a.Name,
start_date: a.Start_Date__c,
end_date: a.End_Date__c,
text: a.Text__c,
}));
return { data };
}
export default class SchedulerView extends LightningElement {
static delegatesFocus = true;
@api height;
schedulerInitialized = false;
renderedCallback() {
if (this.schedulerInitialized) {
return;
}
this.schedulerInitialized = true;
Promise.all([
loadScript(this, SchedulerFiles + "/dhtmlxscheduler.js"),
loadStyle(this, SchedulerFiles + "/dhtmlxscheduler.css")
])
.then(() => {
this.initializeUI();
})
.catch((error) => {
this.dispatchEvent(
new ShowToastEvent({
title: "Error loading scheduler",
message: error.message,
variant: "error"
})
);
});
}
initializeUI() {
const root = this.template.querySelector(".thescheduler");
root.style.height = this.height + "px";
const scheduler = window.Scheduler.getSchedulerInstance();
scheduler.templates.parse_date = (date) => new Date(date);
scheduler.templates.format_date = (date) => date.toISOString();
scheduler.config.header = [
"day",
"week",
"month",
"date",
"prev",
"today",
"next"
];
scheduler.init(root, new Date(), "week");
getEvents().then((d) => {
const chartData = unwrap(d);
scheduler.parse({
events: chartData.data,
});
});
///↓↓↓ saving changes back to SF backend ↓↓↓
scheduler.createDataProcessor(function (entity, action, data, id) {
switch (action) {
case "create":
console.log("createEvent", data);
const insert = {
apiName: "SchedulerEvent__c",
fields: {
Name: data.info,
Start_Date__c: data.start_date,
End_Date__c: data.end_date,
Text__c: data.text
}
};
scheduler.config.readonly = true; // suppress changes
//until saving is complete
return createRecord(insert).then((res) => {
scheduler.config.readonly = false;
return { tid: res.id, ...res };
});
case "update":
console.log("updateEvent", data);
const update = {
fields: {
Id: id,
Name: data.info,
Start_Date__c: data.start_date,
End_Date__c: data.end_date,
Text__c: data.text
}
};
return updateRecord(update).then(() => ({}));
case "delete":
return deleteRecord(id).then(() => ({}));
}
});
}
}
다음 단계는 Lightning Component와 데이터 모델 간의 상호작용을 가능하게 하는 클래스를 만드는 것입니다.
$ sfdx apex generate class -n SchedulerData -d force-app/main/default/classes
target dir = C:\Users\User\salesforce\scheduler-salesforce-app\force-app\main\default\classes
create force-app\main\default\classes\SchedulerData.cls
create force-app\main\default\classes\SchedulerData.cls-meta.xml
생성 후, SchedulerData.cls를 열고 다음 코드를 추가하세요:
force-app/main/default/classes/SchedulerData.cls
public with sharing class SchedulerData {
@RemoteAction
@AuraEnabled(cacheable=true)
public static Map<String, Object> getEvents() {
// fetching the Records via SOQL
List<SchedulerEvent__c> Events = new List<SchedulerEvent__c>();
Events = [SELECT Id, Name, Start_Date__c, End_Date__c,
Text__c FROM SchedulerEvent__c];
Map<String, Object> result = new Map<String, Object>{'events' => Events };
return result;
}
}
Scratch Org에서 소스를 프로젝트로 가져옵니다:
$ sfdx project retrieve start
그런 다음 소스를 다시 Scratch Org로 푸시합니다:
$ sfdx project deploy start
"Lightning App Builder"를 열고 새 Lightning Page를 만드세요.
"App Page"를 선택한 후 페이지 이름을 입력하고 레이아웃을 선택하세요.
Scheduler 커스텀 컴포넌트가 새 페이지에서 사용 가능해야 합니다. 원하는 영역에 추가하고 저장하세요.
페이지를 활성화하세요.
변경 사항을 저장하세요.
애플리케이션 페이지를 엽니다. 앱 실행기에서 Scheduler를 입력하면 접근할 수 있습니다.
모든 설정이 올바르게 완료되었다면, Lightning Page에서 간단한 Scheduler 데모가 표시됩니다.
Scheduler 자체에는 SQL 인젝션, XSS 또는 CSRF 공격과 같은 위협에 대한 보호 기능이 포함되어 있지 않습니다. 애플리케이션의 보안은 개발자의 책임입니다. 자세한 내용은 관련 문서를 참고하세요. Salesforce는 데이터와 애플리케이션을 보호하는 보안 기능을 제공하며, 조직의 요구에 맞는 추가 보안 조치도 구현할 수 있습니다. 자세한 내용은 Salesforce Security Guide를 참고하세요. 또한, 이 리소스에서 필수적인 보안 실무를 확인할 수 있습니다.
통합 단계를 완료한 후 Scheduler가 이벤트를 표시하지 않는 경우, Troubleshooting Backend Integration Issues 문서를 참고하세요. 일반적인 문제를 식별하고 해결하는 방법을 안내합니다.
이 시점에서 Scheduler는 완전히 동작합니다. 전체 코드는 GitHub에서 복제하거나 다운로드하여 프로젝트에 사용할 수 있습니다.
또한 Scheduler의 기능을 다루는 가이드나 다른 백엔드 프레임워크와의 통합 튜토리얼도 참고할 수 있습니다.
맨 위로