Slate 고급 위젯
Advanced에는 Code Sandbox, File Import와 Iframe이 있습니다. Code Sandbox는 사용자 JavaScript 위젯을, File Import는 파일 입력을, Iframe은 다른 페이지를 삽입하는 기능을 제공합니다.
Code Sandbox
Code Sandbox는 사용자 시각화나 동작을 격리된 iframe에 구현합니다. 렌더링, 모델 상태와 이벤트를 정의하여 Slate 앱에 연결할 수 있습니다. 사용자 코드의 디버깅은 Palantir 지원 범위에 포함되지 않으므로 개발자가 기술적 복잡도와 유지보수를 책임져야 합니다.
JavaScript
JavaScript 탭의 코드는 위젯을 로드할 때 실행하며 선언한 라이브러리 코드 다음에 실행됩니다. 이 코드를 바꾸면 위젯 전체가 다시 로드됩니다.
데이터는 JavaScript 문자열에 Handlebars를 직접 넣기보다 Interactions의 state와 SlateFunctions로 전달합니다. JavaScript 안의 참조가 동작하는 경로도 있지만 값이 바뀔 때마다 위젯 전체를 다시 로드하므로 권장하지 않습니다.
위젯 JavaScript, 불러온 라이브러리 코드와 HTML에서 fetch 같은 임의 네트워크 요청은 지원하지 않습니다. 외부 데이터를 가져오는 요청은 미리 구성한 Queries에서 처리하고 결과를 state로 전달합니다. 위젯이 요청을 시작해야 한다면 이벤트를 발생시켜 Slate의 질의 실행에 연결합니다.
JavaScript 라이브러리
라이브러리 입력은 Foundry Project 경로 또는 CORS와 CSP가 허용한 URL들의 배열입니다. 두 방식을 섞을 수 있으며 순서대로 내려받아 실행합니다. 이 필드를 바꾸면 위젯 전체를 새로 로드합니다.
Foundry 안에서는 Blobster의 cookie 인증 API나 asset server로 제공할 수 있습니다. 브라우저가 라이브러리를 가져오므로 해당 CORS/CSP 조건을 충족해야 합니다. 라이브러리는 UMD 형식이거나 window에 기능을 등록하는 등 전역에서 참조할 수 있어야 합니다.
D3 v5의 예는 https://d3js.org/d3.v5.min.js를 내려받아 Foundry에 올린 뒤 리소스의 위치를 넣는 방식입니다.
["/Users/admin/d3.min.js"]
이 경로는 Foundry 리소스의 위치입니다. 리소스 RID로도 지정할 수 있습니다.
["ri.blobster.main.code.7a4a12a8-e9f5-46ef-8008-5c3f4bbd4abc"]
실제 위치와 RID는 파일의 디렉터리나 우클릭 메뉴의 Location/RID 복사로 얻습니다. 위 값들은 주소 형식의 예이므로 자신의 업로드 리소스로 바꿉니다.
HTML과 CSS
HTML은 위젯 로드 때 렌더링합니다. Handlebars를 넣지 않으며 script 태그는 실행하지 않습니다. 스크립트는 JavaScript 탭으로 분리합니다.
CSS 입력에도 Handlebars를 넣지 않습니다. 이 설정은 iframe의 경계 쪽 스타일을 조정하며, 위젯 상위 Styling의 Additional CSS Classes와 Custom Styles에서도 같은 경계 스타일을 적용할 수 있습니다.
위젯 안에서 사용할 CSS는 CSS libraries에 선언할 수 있습니다. JavaScript 라이브러리처럼 Project 경로와 허용된 URL의 배열을 순서대로 적용하며 변경하면 위젯을 다시 로드합니다. Blobster 또는 asset server로 제공할 수 있고 브라우저의 CORS/CSP 조건을 따릅니다. CSS 파일에는 style 태그 없이 CSS 자체만 넣습니다.
Interactions
Slate와 위젯 사이의 모든 연결은 state, events와 actions로 구성합니다. Handlebars를 사용할 위치도 이 탭으로 모읍니다.
| 항목 | 계약 |
|---|---|
| State | 위젯의 현재 구성과 값을 담는 JSON입니다. Handlebars로 입력하거나 내부에서 setState로 바꿀 수 있습니다. |
| Events | 위젯이 발생시킬 이름의 String 배열입니다. triggerEvent로 명시적으로 발생시켜야 합니다. |
| Actions | 다른 위젯이 호출할 이름의 String 배열입니다. 내부 JavaScript에서 onAction으로 처리기를 등록합니다. |
Events 패널에는 custom. 접두사가 붙어 보입니다. SlateFunctions의 인자에는 접두사 없이 등록한 이름을 전달합니다. State는 값과 구성을 위한 것이며 실행 코드를 넣어 뒤늦게 로드하는 용도로 사용하지 않는 것을 권장합니다.
SlateFunctions API
onAction
Slate 문맥에서 위젯으로 들어오는 액션의 callback을 등록합니다. 첫 인자는 액션 이름, 둘째는 body 하나를 인자로 받는 함수입니다.
Interactions > Actions에 다음을 등록합니다.
["checkbox"]
JavaScript 탭에서 처리합니다.
SlateFunctions.onAction("checkbox", (value) => {
var checkbox = document.createElement("div");
checkbox.textContent = String(value);
document.body.appendChild(checkbox);
});
Events 패널에서 Slate_widget.selectedValues.changed를 Code_Sandbox_widget.custom.checkbox에 연결합니다. 선택값을 body로 전달할 때에는 Action 본문에서 return {{slEventValue}};를 사용합니다.
watch
SlateFunctions.watch(path, callback)은 지정한 state 부분이 바뀔 때 callback을 호출합니다. callback에는 새 값과 이전값이 전달됩니다. path가 height이면 해당 필드를, 빈 문자열이면 전체 state 변경을 감시합니다.
Interactions > State에 입력 위젯의 값을 연결합니다.
{"Input State":"{{w_widget2.text}}"}
var el = document.createElement("div");
el.id = "display";
document.body.appendChild(el);
SlateFunctions.watch("Input State", (data, previousData) => {
el.textContent = "Code Sandbox widget: " + data;
});
getState
SlateFunctions.getState()는 호출 시점의 전체 state JSON 객체를 반환합니다. 계속 변경을 감지하는 watch와 달리 호출할 때 한 번 읽습니다. watch 안에서 다른 state 속성을 함께 읽을 때에도 사용할 수 있습니다.
state가 {"a":"cat","b":"hat"}이면 SlateFunctions.getState().a는 cat입니다. 다음 입력 연결 예에서는 a에 현재 텍스트가 들어갑니다.
{"a":"{{w_widget2.text}}","b":"random_state"}
var el = document.createElement("div");
el.id = "display";
document.body.appendChild(el);
var x = SlateFunctions.getState();
el.textContent = "Code Sandbox widget: " + x.a;
setState
SlateFunctions.setState(path, value)는 위젯에서 Slate 쪽으로 값을 갱신합니다. 다른 위젯의 Handlebars 참조와 이후 getState 호출도 새 값을 사용합니다.
SlateFunctions.setState("view.height", 4)는 다른 속성을 유지하며 해당 부분만 바꿉니다. 첫 인자를 빈 문자열로 주면 전체 state를 바꿉니다.
Interactions > State의 초기값입니다.
{"outval":"Initial Widget State"}
var button1 = document.createElement("button");
button1.textContent = "button1";
button1.onclick = () => {
SlateFunctions.setState("outval", "Updated widget state");
};
document.body.appendChild(button1);
triggerEvent
SlateFunctions.triggerEvent(name, body)는 위젯에서 Slate 이벤트를 발생시킵니다. 다음은 본문이 필요 없는 Toast 열기 예입니다.
Interactions > Events에 이름을 등록합니다.
["toast"]
var launchToast = document.createElement("button");
launchToast.textContent = "launch toast";
launchToast.onclick = () => {
SlateFunctions.triggerEvent("toast");
};
document.body.appendChild(launchToast);
Events 패널에서 Code_Sandbox_widget.custom.toast를 Slate_widget.open에 연결합니다.
로드 순서와 디버깅
- 부모 Slate 문맥과 위젯 iframe을 로드합니다.
- 부모가 state를 전달하고 CSS, HTML, 라이브러리와 JavaScript 구성을 전달합니다.
- iframe을 구성하고 라이브러리, 사용자 JavaScript 순서로 실행한 뒤 입력 SlateFunctions를 처리합니다.
- 사용자 상호작용의 state와 event/action 출력을 부모 Slate로 전달합니다.
코드는 sandbox iframe 안에서 실행하며 입출력은 postMessage로 전달합니다. 내부 document는 위젯의 문맥이며 부모 Slate의 DOM과 구분됩니다.
Chrome Console의 문맥 선택기에서 top 대신 codeSandboxIframe.html을 선택하면 해당 위젯 문맥을 조사할 수 있습니다. JavaScript 필드를 바꾸면 위젯이 재로드된다는 점을 고려합니다.
타사 코드를 도입할 때에는 라이선스를 확인하고 JavaScript 조각이 적은 단순한 예제부터 검토합니다. 필요한 라이브러리를 선언하고 HTML의 script 코드는 JavaScript 탭으로 옮깁니다. 입력은 getState/watch, 외부 알림은 triggerEvent, 들어오는 동작은 onAction으로 연결합니다. 선언된 라이브러리 로딩과 위젯 코드의 임의 네트워크 호출은 서로 다른 경로입니다.
File Import
가져온 파일을 Slate 안에서 참조하고 처리하는 입력 위젯입니다.
| 속성 | 자료형 | 필수 | 역할과 변경 |
|---|---|---|---|
| buttonCssClasses | String[] | 예 | Browse 버튼 class입니다. 설정값입니다. |
| buttonText | String | 예 | Browse 버튼 문구입니다. 설정값입니다. |
| message | String | 예 | 가져오기 영역의 안내입니다. 설정값입니다. |
| fileNames | String[] | 예 | 가져온 파일 이름입니다. 상호작용값입니다. |
| fileTypes | String[] | 예 | 파일 MIME 유형입니다. 상호작용값입니다. |
| fileContents | String[] | 예 | 파일 내용의 binary string입니다. 상호작용값입니다. |
| fileDataUrls | String[] | 예 | Base64 data URL입니다. 상호작용값입니다. |
파일을 Foundry 데이터 자산에 저장하는 흐름은 해당 쓰기 연동을 별도로 구성합니다.
Iframe
선택적인 uri(String)가 iframe src입니다. workspace를 통해 여는 앱에는 embedded=true 매개변수를 붙입니다. 기존 질의 매개변수가 없으면 ?embedded=true, 있으면 &embedded=true를 사용합니다.
| 액션/이벤트 | 계약 |
|---|---|
| sendMessage 액션 | 내부 iframe으로 source가 slate-iframe-action이고 message가 전달값인 객체를 보냅니다. |
| reload 액션 | iframe을 다시 로드합니다. |
| getMessage 이벤트 | 내부 iframe이 target을 slate-iframe-event로 지정하여 보낸 message를 받습니다. |
{"source":"slate-iframe-action","message":{"value":123}}
{"target":"slate-iframe-event","message":{"value":123}}
이는 Iframe 위젯 자체의 프로토콜입니다. Slate 앱 전체가 다른 앱 안에 삽입되는 경우의 slate.sendMessage/getMessage와 target/source 이름을 구분합니다.