@nuraly/runtime 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/dropdown.controller.d.ts +0 -1
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/dropdown.interface.d.ts +0 -2
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/theme.controller.d.ts +0 -1
- package/components/ui/nuraly-ui/packages/common/dist/shared/event-handler-mixin.d.ts +0 -1
- package/components/ui/nuraly-ui/packages/common/dist/shared/theme-mixin.d.ts +0 -1
- package/components/ui/nuraly-ui/packages/common/dist/shared/themes.d.ts +0 -1
- package/components/ui/nuraly-ui/packages/common/dist/shared/utils.d.ts +60 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/validation.types.d.ts +108 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.component.ts +1 -1
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.types.ts +1 -0
- package/dist/CodeEditor-BiNku87K.js +808 -0
- package/dist/{CodeEditor-Ch2tv9BE.js → CodeEditor-G6E8PUI7.js} +14593 -14607
- package/dist/{SmartAttributeHandler-hoSLpm1Y.js → SmartAttributeHandler-C9vS-cHW.js} +1 -1
- package/dist/SmartAttributeHandler-u-ZHGueR.js +193 -0
- package/dist/assets/editor.worker-C_S4Avdt.js +11 -0
- package/dist/assets/{html.worker-BSmGlhXp.js → html.worker-DfuQASUV.js} +18 -18
- package/dist/assets/json.worker-Cucz4wxY.js +42 -0
- package/dist/assets/{ts.worker-DyHHPhrh.js → ts.worker-Dme6S0YK.js} +78 -78
- package/dist/cssMode-B7NVlrDV.js +1443 -0
- package/dist/{freemarker2-DNc2IxPf.js → freemarker2-DS_7G9b8.js} +1 -1
- package/dist/{handlebars-CIbFckEw.js → handlebars-BDyyLkzw.js} +1 -1
- package/dist/{html-nRs_fneU.js → html-DphGFjig.js} +1 -1
- package/dist/{htmlMode-BjehA1YF.js → htmlMode-4zNnSWFo.js} +278 -281
- package/dist/index-B4yIOSMd.js +3847 -0
- package/dist/{javascript-Bn0HduZA.js → javascript-CC1jWyQy.js} +1 -1
- package/dist/{jsonMode-CfGfcJRX.js → jsonMode-Bfzb6wZf.js} +369 -372
- package/dist/{liquid-m4D_LCnC.js → liquid-lTBpqagR.js} +1 -1
- package/dist/{mdx-CakMRbCr.js → mdx-DX66Bp07.js} +1 -1
- package/dist/{micro-app-entry-CI1Rupdh.js → micro-app-entry-DDsAWUJh.js} +5138 -5322
- package/dist/micro-app.bundle.js +1 -1
- package/dist/micro-app.js +9775 -0
- package/dist/{python-oJwaiPUY.js → python-BGUhyO4G.js} +1 -1
- package/dist/{razor-u_dd4rqc.js → razor-DEVWQFSa.js} +1 -1
- package/dist/runtime.js +401 -0
- package/dist/style.css +1 -1
- package/dist/tsMode-CYFi80Jf.js +800 -0
- package/dist/{typescript-Bjs2N5Be.js → typescript-B1xIbH_T.js} +1 -1
- package/dist/{wgsl-Bv2xeo60.js → wgsl-C9yjop46.js} +1 -1
- package/dist/{xml-BCveATLl.js → xml-DmdvyqrE.js} +1 -1
- package/dist/{yaml-BfWQPJQi.js → yaml-LGNo48fy.js} +1 -1
- package/package.json +2 -2
- package/vite.config.ts +8 -8
- package/dist/.claude/settings.local.json +0 -9
- package/dist/assets/editor.worker-vBWydyGC.js +0 -11
- package/dist/assets/json.worker-Dqnoedz4.js +0 -42
- package/dist/cssMode-Bt2uK8XM.js +0 -1446
- package/dist/micro-app.bundle.umd.cjs +0 -5051
- package/dist/tsMode-DlZ38d3D.js +0 -813
|
@@ -0,0 +1,3847 @@
|
|
|
1
|
+
import { Subject, Observable } from 'rxjs';
|
|
2
|
+
import Database from '@nuraly/dbclient';
|
|
3
|
+
import * as acorn from 'acorn';
|
|
4
|
+
import * as walk from 'acorn-walk';
|
|
5
|
+
import { v4 } from 'uuid';
|
|
6
|
+
import deepEqual from 'fast-deep-equal';
|
|
7
|
+
import { atom, deepMap, keepMount, onMount, computed, onNotify } from 'nanostores';
|
|
8
|
+
import { persistentAtom } from '/Users/aymen/Desktop/projects/nuraly/stack/services/studio/node_modules/@nanostores/persistent/index.js';
|
|
9
|
+
import { html } from 'lit';
|
|
10
|
+
import { share } from 'rxjs/operators';
|
|
11
|
+
|
|
12
|
+
const isServer$4 = typeof window === "undefined";
|
|
13
|
+
if (!isServer$4) {
|
|
14
|
+
if (!window["__INITIAL_APPLICATION_STATE__"]) {
|
|
15
|
+
window["__INITIAL_APPLICATION_STATE__"] = JSON.stringify([]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const $context = atom({
|
|
19
|
+
"1": {
|
|
20
|
+
label_one_content: {
|
|
21
|
+
type: "string",
|
|
22
|
+
value: "value"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
global: {
|
|
26
|
+
showSecondsRow: {
|
|
27
|
+
type: "boolean",
|
|
28
|
+
value: false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
function getType(value) {
|
|
33
|
+
if (value === null) return "null";
|
|
34
|
+
if (Array.isArray(value)) return "array";
|
|
35
|
+
return typeof value;
|
|
36
|
+
}
|
|
37
|
+
function setVar(contextId, varName, varValue) {
|
|
38
|
+
const varType = getType(varValue);
|
|
39
|
+
const currentContext = $context.get();
|
|
40
|
+
currentContext[contextId]?.[varName]?.value;
|
|
41
|
+
const updatedContext = {
|
|
42
|
+
...currentContext,
|
|
43
|
+
[contextId]: {
|
|
44
|
+
...currentContext[contextId],
|
|
45
|
+
[varName]: {
|
|
46
|
+
type: varType,
|
|
47
|
+
value: varValue
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
$context.set(updatedContext);
|
|
52
|
+
}
|
|
53
|
+
function getVar(contextId, varName) {
|
|
54
|
+
const currentContext = $context.get();
|
|
55
|
+
if (currentContext[contextId] && currentContext[contextId][varName]) {
|
|
56
|
+
return currentContext[contextId][varName];
|
|
57
|
+
} else {
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
persistentAtom("persistentContext", {
|
|
62
|
+
global: {}
|
|
63
|
+
}, {
|
|
64
|
+
encode: JSON.stringify,
|
|
65
|
+
decode: JSON.parse
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const isServer$3 = typeof window === "undefined";
|
|
69
|
+
const INITIAL_APP_STATE_KEY = "__INITIAL_APPLICATION_STATE__";
|
|
70
|
+
const INITIAL_CURRENT_APP_STATE_KEY = "__INITIAL_CURRENT_APPLICATION_STATE__";
|
|
71
|
+
const coreApplications = [
|
|
72
|
+
{ uuid: "1", name: "app1" },
|
|
73
|
+
{ uuid: "2", name: "app2" },
|
|
74
|
+
{ uuid: "landing", name: "landing" }
|
|
75
|
+
];
|
|
76
|
+
if (!isServer$3 && !window[INITIAL_APP_STATE_KEY]) {
|
|
77
|
+
window[INITIAL_APP_STATE_KEY] = JSON.stringify([]);
|
|
78
|
+
}
|
|
79
|
+
const initialState$2 = isServer$3 ? [] : JSON.parse(window[INITIAL_APP_STATE_KEY] || "[]");
|
|
80
|
+
const initialAppState$1 = isServer$3 ? null : JSON.parse(window[INITIAL_CURRENT_APP_STATE_KEY] || "null");
|
|
81
|
+
const $applications = atom([...initialState$2, ...coreApplications]);
|
|
82
|
+
const $currentApplication = atom(initialAppState$1);
|
|
83
|
+
const $applicationPermission = atom([]);
|
|
84
|
+
deepMap({});
|
|
85
|
+
const $resizing = atom(false);
|
|
86
|
+
const $permissionsState = atom({ message: "" });
|
|
87
|
+
const $showCreateApplicationModal = atom(false);
|
|
88
|
+
const $showShareApplicationModal = atom(false);
|
|
89
|
+
const $editorState = atom({
|
|
90
|
+
currentTab: {
|
|
91
|
+
id: "0",
|
|
92
|
+
label: "Page editor",
|
|
93
|
+
type: "page"
|
|
94
|
+
},
|
|
95
|
+
tabs: [
|
|
96
|
+
{
|
|
97
|
+
id: "0",
|
|
98
|
+
label: "Page editor",
|
|
99
|
+
type: "page"
|
|
100
|
+
}
|
|
101
|
+
// {
|
|
102
|
+
// id: "2",
|
|
103
|
+
// label: "flow editor",
|
|
104
|
+
// type: "flow"
|
|
105
|
+
// },
|
|
106
|
+
// {
|
|
107
|
+
// id: "3",
|
|
108
|
+
// label: "Database manager",
|
|
109
|
+
// type: "database"
|
|
110
|
+
// }
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
keepMount($resizing);
|
|
114
|
+
onMount($applications, () => {
|
|
115
|
+
if (isServer$3) return;
|
|
116
|
+
const currentApplication = $currentApplication.get();
|
|
117
|
+
if (currentApplication) {
|
|
118
|
+
setVar("global", "currentEditingApplication", currentApplication);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const isServer$2 = typeof window === "undefined";
|
|
123
|
+
|
|
124
|
+
const currentLoadedApplication = isServer$2 ? [] : JSON.parse(window["__INITIAL_CURRENT_APPLICATION_STATE__"] ?? null);
|
|
125
|
+
|
|
126
|
+
const fillComponentChildren = (components, component) => {
|
|
127
|
+
const componentMap = new Map(components.map((comp) => [comp.uuid, comp]));
|
|
128
|
+
const stack = [component];
|
|
129
|
+
while (stack.length > 0) {
|
|
130
|
+
const currentComponent = stack.pop();
|
|
131
|
+
if (!currentComponent.childrens) currentComponent.childrens = [];
|
|
132
|
+
if (currentComponent.childrenIds) {
|
|
133
|
+
currentComponent.childrens = currentComponent.childrenIds.map((childId) => componentMap.get(childId)).filter(Boolean);
|
|
134
|
+
stack.push(...currentComponent.childrens);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return component;
|
|
138
|
+
};
|
|
139
|
+
const fillApplicationComponents = (components) => components.map((component) => fillComponentChildren(components, component));
|
|
140
|
+
const extractChildresIds = (components) => components.map((component) => fillComponentChildren(components, component));
|
|
141
|
+
const extractAllChildrenIds = (components, component) => {
|
|
142
|
+
const componentMap = new Map(components.map((comp) => [comp.uuid, comp]));
|
|
143
|
+
const result = [];
|
|
144
|
+
const stack = [component];
|
|
145
|
+
while (stack.length > 0) {
|
|
146
|
+
const current = stack.pop();
|
|
147
|
+
if (current?.childrenIds) {
|
|
148
|
+
result.push(...current.childrenIds);
|
|
149
|
+
stack.push(...current.childrenIds.map((childId) => componentMap.get(childId)).filter(Boolean));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
class EventDispatcher {
|
|
156
|
+
constructor() {
|
|
157
|
+
this.subjects = {};
|
|
158
|
+
this.subscriptions = {};
|
|
159
|
+
this.globalEventSubject = new Subject();
|
|
160
|
+
this.allEvents$ = this.globalEventSubject.asObservable().pipe(share());
|
|
161
|
+
}
|
|
162
|
+
static getInstance() {
|
|
163
|
+
if (!EventDispatcher.instance) {
|
|
164
|
+
EventDispatcher.instance = new EventDispatcher();
|
|
165
|
+
}
|
|
166
|
+
return EventDispatcher.instance;
|
|
167
|
+
}
|
|
168
|
+
getSubject(event) {
|
|
169
|
+
if (!this.subjects[event]) {
|
|
170
|
+
this.subjects[event] = new Subject();
|
|
171
|
+
}
|
|
172
|
+
return this.subjects[event];
|
|
173
|
+
}
|
|
174
|
+
on(event, listener) {
|
|
175
|
+
if (!this.subscriptions[event]) {
|
|
176
|
+
this.subscriptions[event] = /* @__PURE__ */ new Map();
|
|
177
|
+
}
|
|
178
|
+
const subscription = this.getSubject(event).subscribe((data) => listener(data));
|
|
179
|
+
this.subscriptions[event].set(listener, subscription);
|
|
180
|
+
return subscription;
|
|
181
|
+
}
|
|
182
|
+
onAny(listener) {
|
|
183
|
+
return this.allEvents$.subscribe(({ eventName, data }) => listener(eventName, data));
|
|
184
|
+
}
|
|
185
|
+
off(event, listener) {
|
|
186
|
+
if (!this.subscriptions[event]) return;
|
|
187
|
+
const subscription = this.subscriptions[event].get(listener);
|
|
188
|
+
if (subscription) {
|
|
189
|
+
subscription.unsubscribe();
|
|
190
|
+
this.subscriptions[event].delete(listener);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
emit(event, data) {
|
|
194
|
+
this.getSubject(event).next(data);
|
|
195
|
+
this.globalEventSubject.next({ eventName: event, data });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const eventDispatcher = EventDispatcher.getInstance();
|
|
199
|
+
|
|
200
|
+
const isServer$1 = typeof window === "undefined";
|
|
201
|
+
const initialStates = isServer$1 ? [] : JSON.parse(window["__INITIAL_COMPONENT_STATE__"] ?? "[]");
|
|
202
|
+
const initialState$1 = isServer$1 ? {} : {};
|
|
203
|
+
if (currentLoadedApplication) {
|
|
204
|
+
initialState$1[currentLoadedApplication.uuid] = initialStates;
|
|
205
|
+
}
|
|
206
|
+
const $components = deepMap(initialState$1);
|
|
207
|
+
const $currentComponentId = persistentAtom(
|
|
208
|
+
"currentComponentId",
|
|
209
|
+
null,
|
|
210
|
+
{
|
|
211
|
+
encode: JSON.stringify,
|
|
212
|
+
decode: JSON.parse
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
const $hoveredComponentId = atom(null);
|
|
216
|
+
const $hoveredComponent = atom(null);
|
|
217
|
+
const $draggingComponentInfo = atom(null);
|
|
218
|
+
const $applicationComponents = ($application_id) => computed(
|
|
219
|
+
[$components],
|
|
220
|
+
(componentsStore) => {
|
|
221
|
+
const applicationComponents = Array.from(componentsStore[$application_id] ?? [])?.map((component) => ({
|
|
222
|
+
...component
|
|
223
|
+
})) ?? [];
|
|
224
|
+
return applicationComponents;
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
computed(
|
|
228
|
+
[$components],
|
|
229
|
+
(componentsStore) => Object.values(componentsStore).flat().filter((component) => !component.parent)
|
|
230
|
+
);
|
|
231
|
+
const $componentWithChildren = ($application_id) => computed(
|
|
232
|
+
[$applicationComponents($application_id)],
|
|
233
|
+
(components) => fillApplicationComponents(components)
|
|
234
|
+
);
|
|
235
|
+
const $selectedComponent = ($application_id) => computed(
|
|
236
|
+
[$applicationComponents($application_id), $currentComponentId],
|
|
237
|
+
(components, currentComponentId) => components.find((component) => component.uuid === currentComponentId) || null
|
|
238
|
+
);
|
|
239
|
+
const $componentsByUUIDs = ($application_id, uuids) => computed(
|
|
240
|
+
[$applicationComponents($application_id)],
|
|
241
|
+
(components) => components.filter((component) => uuids.includes(component.uuid))
|
|
242
|
+
);
|
|
243
|
+
const $runtimeStyles = deepMap({});
|
|
244
|
+
const setcomponentRuntimeStyleAttribute = (componentId, attribute, value) => {
|
|
245
|
+
$runtimeStyles.setKey(componentId, {
|
|
246
|
+
...$runtimeStyles.get()[componentId],
|
|
247
|
+
[attribute]: value
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
$runtimeStyles.subscribe((styles) => {
|
|
251
|
+
});
|
|
252
|
+
const $runtimeStylescomponentStyleByID = ($componentId) => computed(
|
|
253
|
+
[$runtimeStyles],
|
|
254
|
+
(styles) => {
|
|
255
|
+
const componentStyles = styles[$componentId] || {};
|
|
256
|
+
return componentStyles;
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
const clearComponentRuntimeStyleAttributes = () => {
|
|
260
|
+
$runtimeStyles.set({});
|
|
261
|
+
};
|
|
262
|
+
const $runtimeValues = deepMap({});
|
|
263
|
+
const setComponentRuntimeValue = (componentId, key, value) => {
|
|
264
|
+
if (!componentId) {
|
|
265
|
+
console.error("Cannot set runtime value: componentId is undefined");
|
|
266
|
+
return;
|
|
267
|
+
} else {
|
|
268
|
+
console.log("setComponentRuntimeValue", componentId, key, value);
|
|
269
|
+
}
|
|
270
|
+
$runtimeValues.setKey(componentId, {
|
|
271
|
+
...$runtimeValues.get()[componentId],
|
|
272
|
+
[key]: value
|
|
273
|
+
});
|
|
274
|
+
console.log($runtimeValues.get()[componentId]);
|
|
275
|
+
eventDispatcher.emit("component:value:change", {
|
|
276
|
+
componentId,
|
|
277
|
+
key,
|
|
278
|
+
value
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
const setComponentRuntimeValues = (componentId, values) => {
|
|
282
|
+
$runtimeValues.setKey(componentId, {
|
|
283
|
+
...$runtimeValues.get()[componentId],
|
|
284
|
+
...values
|
|
285
|
+
});
|
|
286
|
+
eventDispatcher.emit("component:values:change", {
|
|
287
|
+
componentId,
|
|
288
|
+
values
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
const $componentRuntimeValuesById = (componentId) => computed(
|
|
292
|
+
[$runtimeValues],
|
|
293
|
+
(values) => {
|
|
294
|
+
return values[componentId] || {};
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
const $componentRuntimeValueByKey = (componentId, key) => computed(
|
|
298
|
+
[$runtimeValues],
|
|
299
|
+
(values) => {
|
|
300
|
+
const componentValues = values[componentId] || {};
|
|
301
|
+
return componentValues[key];
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
const clearComponentRuntimeValues = (componentId) => {
|
|
305
|
+
$runtimeValues.setKey(componentId, {});
|
|
306
|
+
eventDispatcher.emit("component:values:clear", {
|
|
307
|
+
componentId
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
const clearComponentRuntimeValue = (componentId, key) => {
|
|
311
|
+
const currentValues = { ...$runtimeValues.get()[componentId] };
|
|
312
|
+
if (currentValues && key in currentValues) {
|
|
313
|
+
delete currentValues[key];
|
|
314
|
+
$runtimeValues.setKey(componentId, currentValues);
|
|
315
|
+
eventDispatcher.emit("component:value:remove", {
|
|
316
|
+
componentId,
|
|
317
|
+
key
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const clearAllRuntimeValues = () => {
|
|
322
|
+
$runtimeValues.set({});
|
|
323
|
+
eventDispatcher.emit("component:values:clear:all");
|
|
324
|
+
};
|
|
325
|
+
$runtimeValues.subscribe((values) => {
|
|
326
|
+
});
|
|
327
|
+
const getAllChildrenRecursive = ($application_id, componentId) => computed(
|
|
328
|
+
[$applicationComponents($application_id)],
|
|
329
|
+
(components) => {
|
|
330
|
+
const componentMap = /* @__PURE__ */ new Map();
|
|
331
|
+
components.forEach((component) => componentMap.set(component.uuid, component));
|
|
332
|
+
const collectDescendants = (component) => {
|
|
333
|
+
if (!component.childrenIds || component.childrenIds.length === 0) {
|
|
334
|
+
return [];
|
|
335
|
+
}
|
|
336
|
+
const children = [];
|
|
337
|
+
for (const childId of component.childrenIds) {
|
|
338
|
+
const childComponent = componentMap.get(childId);
|
|
339
|
+
if (childComponent) {
|
|
340
|
+
children.push(childComponent);
|
|
341
|
+
children.push(...collectDescendants(childComponent));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return children;
|
|
345
|
+
};
|
|
346
|
+
if (componentId) {
|
|
347
|
+
const parentComponent = componentMap.get(componentId);
|
|
348
|
+
if (!parentComponent) return [];
|
|
349
|
+
return [parentComponent, ...collectDescendants(parentComponent)];
|
|
350
|
+
}
|
|
351
|
+
const rootComponents = components.filter((component) => !component.parent);
|
|
352
|
+
const result = [];
|
|
353
|
+
for (const rootComponent of rootComponents) {
|
|
354
|
+
result.push(rootComponent);
|
|
355
|
+
result.push(...collectDescendants(rootComponent));
|
|
356
|
+
}
|
|
357
|
+
return result;
|
|
358
|
+
}
|
|
359
|
+
);
|
|
360
|
+
const getDirectChildren = ($application_id, componentId) => computed(
|
|
361
|
+
[$applicationComponents($application_id)],
|
|
362
|
+
(components) => {
|
|
363
|
+
const parentComponent = components.find((component) => component.uuid === componentId);
|
|
364
|
+
if (!parentComponent || !parentComponent.childrenIds) {
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
return components.filter(
|
|
368
|
+
(component) => parentComponent.childrenIds.includes(component.uuid)
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
);
|
|
372
|
+
const $componentById = ($application_id, componentId) => computed(
|
|
373
|
+
[$applicationComponents($application_id)],
|
|
374
|
+
(components) => components.find((component) => component.uuid === componentId) || null
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
class Editor {
|
|
378
|
+
constructor() {
|
|
379
|
+
this.components = [];
|
|
380
|
+
this.functions = [];
|
|
381
|
+
this.currentEditingApplication = {};
|
|
382
|
+
this.currentComponent = null;
|
|
383
|
+
this.selectedComponents = [];
|
|
384
|
+
this.currentPlatform = {};
|
|
385
|
+
this.isPreviewMode = false;
|
|
386
|
+
this.isEditorMode = false;
|
|
387
|
+
this.Vars = {};
|
|
388
|
+
this.currentSelection = [];
|
|
389
|
+
this.Tabs = [];
|
|
390
|
+
this.handleResize = () => {
|
|
391
|
+
if (!this.isEditorMode) {
|
|
392
|
+
this.updatePlatform();
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
this.Console = {
|
|
396
|
+
log: (log) => {
|
|
397
|
+
this.log(log);
|
|
398
|
+
},
|
|
399
|
+
error: (log) => {
|
|
400
|
+
this.log(log);
|
|
401
|
+
},
|
|
402
|
+
warn: (log) => {
|
|
403
|
+
this.log(log);
|
|
404
|
+
},
|
|
405
|
+
info: (log) => {
|
|
406
|
+
this.log(log);
|
|
407
|
+
},
|
|
408
|
+
debug: (log) => {
|
|
409
|
+
this.log(log);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
if (!isServer$2) {
|
|
413
|
+
window.addEventListener("resize", this.handleResize);
|
|
414
|
+
}
|
|
415
|
+
eventDispatcher.on("Vars:currentPlatform", (data) => {
|
|
416
|
+
this.currentPlatform = { ...this.ExecuteInstance.Vars.currentPlatform };
|
|
417
|
+
});
|
|
418
|
+
$editorState.subscribe(() => {
|
|
419
|
+
this.Tabs = $editorState.get().tabs;
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Lazy getter for ExecuteInstance to avoid circular dependency.
|
|
424
|
+
* Uses dynamic import to load after module initialization.
|
|
425
|
+
*/
|
|
426
|
+
get ExecuteInstance() {
|
|
427
|
+
return globalThis.__NURALY_EXECUTE_INSTANCE__;
|
|
428
|
+
}
|
|
429
|
+
get isDarkMode() {
|
|
430
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
431
|
+
}
|
|
432
|
+
updatePlatform() {
|
|
433
|
+
if (isServer$2) return;
|
|
434
|
+
const width = window.innerWidth;
|
|
435
|
+
let currentPlatform = {};
|
|
436
|
+
if (width <= 500) {
|
|
437
|
+
currentPlatform = createPlatform("mobile", "430px", "767px", true);
|
|
438
|
+
} else if (width <= 1024) {
|
|
439
|
+
currentPlatform = createPlatform("tablet", "1024px", "768px", true);
|
|
440
|
+
} else {
|
|
441
|
+
currentPlatform = createPlatform("desktop", "1366px", void 0, false);
|
|
442
|
+
}
|
|
443
|
+
if (currentPlatform.platform !== this.currentPlatform.platform) {
|
|
444
|
+
this.currentPlatform = { ...currentPlatform };
|
|
445
|
+
this.ExecuteInstance.VarsProxy.currentPlatform = { ...this.currentPlatform };
|
|
446
|
+
eventDispatcher.emit("component:refresh");
|
|
447
|
+
}
|
|
448
|
+
return currentPlatform;
|
|
449
|
+
}
|
|
450
|
+
static createPlatform(platform, width, height, isMobile = false) {
|
|
451
|
+
return { platform, width, height, isMobile };
|
|
452
|
+
}
|
|
453
|
+
setEditorMode(isEditorMode) {
|
|
454
|
+
this.isEditorMode = isEditorMode;
|
|
455
|
+
if (this.isEditorMode) {
|
|
456
|
+
this.updatePlatform();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
getEditorMode() {
|
|
460
|
+
return this.isEditorMode;
|
|
461
|
+
}
|
|
462
|
+
getComponentStyle(component, attribute) {
|
|
463
|
+
if (this.currentPlatform.platform !== "desktop") {
|
|
464
|
+
const breakpointStyle = component?.breakpoints?.[this.currentPlatform.width]?.style;
|
|
465
|
+
return { ...component?.style, ...breakpointStyle }[attribute];
|
|
466
|
+
} else {
|
|
467
|
+
return component?.style?.[attribute];
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
getComponentStyles(component) {
|
|
471
|
+
if (this.currentPlatform.platform !== "desktop") {
|
|
472
|
+
const breakpointStyle = component?.breakpoints?.[this.currentPlatform.width]?.style;
|
|
473
|
+
return { ...component?.style, ...breakpointStyle };
|
|
474
|
+
} else {
|
|
475
|
+
return component?.style ?? {};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Get component style value for a specific attribute considering selected state and platform
|
|
480
|
+
* @param component - The component object
|
|
481
|
+
* @param attribute - The style attribute name
|
|
482
|
+
* @returns The style value for the attribute
|
|
483
|
+
*/
|
|
484
|
+
getComponentStyleForState(component, attribute) {
|
|
485
|
+
const selectedState = this.ExecuteInstance.Vars.selected_component_style_state;
|
|
486
|
+
let baseStyle = component?.style ?? {};
|
|
487
|
+
if (this.currentPlatform.platform !== "desktop") {
|
|
488
|
+
const breakpointStyle = component?.breakpoints?.[this.currentPlatform.width]?.style;
|
|
489
|
+
baseStyle = { ...baseStyle, ...breakpointStyle };
|
|
490
|
+
}
|
|
491
|
+
if (selectedState && selectedState !== "default") {
|
|
492
|
+
const pseudoStateStyle = baseStyle[selectedState];
|
|
493
|
+
if (pseudoStateStyle && typeof pseudoStateStyle === "object" && attribute in pseudoStateStyle) {
|
|
494
|
+
return pseudoStateStyle[attribute];
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const pseudoStates = [":hover", ":focus", ":active", ":disabled"];
|
|
498
|
+
if (pseudoStates.includes(attribute)) {
|
|
499
|
+
return baseStyle[attribute];
|
|
500
|
+
}
|
|
501
|
+
return baseStyle[attribute];
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Get all component styles considering selected state and platform
|
|
505
|
+
* @param component - The component object
|
|
506
|
+
* @returns Merged style object with pseudo-state styles applied if selected
|
|
507
|
+
*/
|
|
508
|
+
getComponentStylesForState(component) {
|
|
509
|
+
const selectedState = this.ExecuteInstance.Vars.selected_component_style_state;
|
|
510
|
+
let baseStyle = component?.style ?? {};
|
|
511
|
+
if (this.currentPlatform.platform !== "desktop") {
|
|
512
|
+
const breakpointStyle = component?.breakpoints?.[this.currentPlatform.width]?.style;
|
|
513
|
+
baseStyle = { ...baseStyle, ...breakpointStyle };
|
|
514
|
+
}
|
|
515
|
+
if (selectedState && selectedState !== "default") {
|
|
516
|
+
const pseudoStateStyle = baseStyle[selectedState];
|
|
517
|
+
if (pseudoStateStyle && typeof pseudoStateStyle === "object") {
|
|
518
|
+
const pseudoStates = [":hover", ":focus", ":active", ":disabled"];
|
|
519
|
+
const regularStyles = Object.keys(baseStyle).filter((key) => !pseudoStates.includes(key)).reduce((obj, key) => {
|
|
520
|
+
obj[key] = baseStyle[key];
|
|
521
|
+
return obj;
|
|
522
|
+
}, {});
|
|
523
|
+
return { ...regularStyles, ...pseudoStateStyle };
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return baseStyle;
|
|
527
|
+
}
|
|
528
|
+
getCurrentPlatform() {
|
|
529
|
+
return this.currentPlatform;
|
|
530
|
+
}
|
|
531
|
+
getComponentBreakpointStyle(component, attribute) {
|
|
532
|
+
return component?.breakpoints?.[this.currentPlatform.width]?.style?.[attribute];
|
|
533
|
+
}
|
|
534
|
+
getComponentBreakpointInput(component, attributeName) {
|
|
535
|
+
const baseInput = component?.input?.[attributeName];
|
|
536
|
+
const breakpointInput = component?.breakpoints?.[this.currentPlatform.width]?.input?.[attributeName];
|
|
537
|
+
if (baseInput?.type === "handler") {
|
|
538
|
+
return baseInput;
|
|
539
|
+
}
|
|
540
|
+
return { ...baseInput, ...breakpointInput };
|
|
541
|
+
}
|
|
542
|
+
getComponentBreakpointInputs(component) {
|
|
543
|
+
const baseInput = component?.input;
|
|
544
|
+
const breakpointInput = component?.breakpoints?.[this.currentPlatform.width]?.input;
|
|
545
|
+
if (baseInput?.type === "handler") {
|
|
546
|
+
return baseInput;
|
|
547
|
+
}
|
|
548
|
+
return { ...baseInput, ...breakpointInput };
|
|
549
|
+
}
|
|
550
|
+
log(log) {
|
|
551
|
+
eventDispatcher.emit("kernel:log", log);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const EditorInstance = new Editor();
|
|
555
|
+
const createPlatform = (platform, width, height, isMobile = false) => {
|
|
556
|
+
return { platform, width, height, isMobile };
|
|
557
|
+
};
|
|
558
|
+
const getInitPlatform = () => {
|
|
559
|
+
if (isServer$2) return;
|
|
560
|
+
const width = window.innerWidth;
|
|
561
|
+
let currentPlatform = {};
|
|
562
|
+
if (width <= 500) {
|
|
563
|
+
currentPlatform = createPlatform("mobile", "430px", "932px", true);
|
|
564
|
+
} else if (width <= 1024) {
|
|
565
|
+
currentPlatform = createPlatform("tablet", "1024px", "768px", true);
|
|
566
|
+
} else {
|
|
567
|
+
currentPlatform = createPlatform("desktop", "1366px", void 0, false);
|
|
568
|
+
}
|
|
569
|
+
return currentPlatform;
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
class RuntimeHelpers {
|
|
573
|
+
/**
|
|
574
|
+
* Capitalizes the first letter of a string
|
|
575
|
+
* @param string - The string to capitalize
|
|
576
|
+
* @returns The string with first letter capitalized
|
|
577
|
+
*/
|
|
578
|
+
static CapitalizeFirstLetter(string) {
|
|
579
|
+
if (!string) return "";
|
|
580
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Gets the first element of an array
|
|
584
|
+
* @param array - The array to get the first element from
|
|
585
|
+
* @returns The first element or null if array is empty
|
|
586
|
+
*/
|
|
587
|
+
static first(array) {
|
|
588
|
+
return array?.[0] ?? null;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Extracts the unit from a CSS value string
|
|
592
|
+
* @param str - CSS value string (e.g., "100px", "50%")
|
|
593
|
+
* @returns The unit portion (e.g., "px", "%") or empty string
|
|
594
|
+
*/
|
|
595
|
+
static extractUnit(str) {
|
|
596
|
+
return str?.match(/[a-zA-Z%]+/g)?.[0] || "";
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Creates an RxJS Observable from a nanostore
|
|
600
|
+
* @param store - The nanostore to observe
|
|
601
|
+
* @returns Observable that emits on store changes
|
|
602
|
+
*/
|
|
603
|
+
static createStoreObservable(store) {
|
|
604
|
+
return new Observable((subscriber) => {
|
|
605
|
+
const unsubscribe = store.subscribe((data) => subscriber.next(data));
|
|
606
|
+
return () => unsubscribe();
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Checks if a value is a Promise
|
|
611
|
+
* @param value - The value to check
|
|
612
|
+
* @returns True if the value is a Promise
|
|
613
|
+
*/
|
|
614
|
+
static isPromise(value) {
|
|
615
|
+
return Boolean(value && typeof value.then === "function");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
const FORBIDDEN_GLOBALS = /* @__PURE__ */ new Set([
|
|
620
|
+
"eval",
|
|
621
|
+
"Function",
|
|
622
|
+
"window",
|
|
623
|
+
"global",
|
|
624
|
+
"globalThis",
|
|
625
|
+
"process",
|
|
626
|
+
"require",
|
|
627
|
+
"__dirname",
|
|
628
|
+
"__filename",
|
|
629
|
+
"module",
|
|
630
|
+
"exports",
|
|
631
|
+
"self",
|
|
632
|
+
"top",
|
|
633
|
+
"parent",
|
|
634
|
+
"frames",
|
|
635
|
+
"localStorage",
|
|
636
|
+
"sessionStorage",
|
|
637
|
+
"indexedDB",
|
|
638
|
+
"XMLHttpRequest",
|
|
639
|
+
"WebSocket",
|
|
640
|
+
"Worker",
|
|
641
|
+
"SharedWorker",
|
|
642
|
+
"ServiceWorker",
|
|
643
|
+
"import",
|
|
644
|
+
// Dynamic imports
|
|
645
|
+
"importScripts"
|
|
646
|
+
]);
|
|
647
|
+
const FORBIDDEN_PROPERTIES = /* @__PURE__ */ new Set([
|
|
648
|
+
"__proto__",
|
|
649
|
+
"prototype",
|
|
650
|
+
"constructor"
|
|
651
|
+
]);
|
|
652
|
+
let ALLOWED_GLOBALS_CACHE = null;
|
|
653
|
+
function getAllowedGlobals() {
|
|
654
|
+
if (!ALLOWED_GLOBALS_CACHE) {
|
|
655
|
+
ALLOWED_GLOBALS_CACHE = new Set(HANDLER_PARAMETERS);
|
|
656
|
+
}
|
|
657
|
+
return ALLOWED_GLOBALS_CACHE;
|
|
658
|
+
}
|
|
659
|
+
const FORBIDDEN_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
660
|
+
"eval",
|
|
661
|
+
"Function",
|
|
662
|
+
"setTimeout",
|
|
663
|
+
// When used with string argument
|
|
664
|
+
"setInterval",
|
|
665
|
+
// When used with string argument
|
|
666
|
+
"setImmediate"
|
|
667
|
+
]);
|
|
668
|
+
const VALIDATION_ERROR_MESSAGES = {
|
|
669
|
+
eval: "Use of 'eval()' is forbidden for security reasons. Use InvokeFunction() to execute server-side functions instead.",
|
|
670
|
+
Function: "Dynamic function creation via 'Function()' constructor is not allowed. Define handler logic directly.",
|
|
671
|
+
setTimeout_string: "Calling 'setTimeout()' with string argument is forbidden (acts as eval). Use a function instead.",
|
|
672
|
+
setInterval_string: "Calling 'setInterval()' with string argument is forbidden (acts as eval). Use a function instead.",
|
|
673
|
+
window: "Access to 'window' object is forbidden. Use provided runtime API instead.",
|
|
674
|
+
global: "Access to 'global' object is forbidden. Use provided runtime API instead.",
|
|
675
|
+
globalThis: "Access to 'globalThis' object is forbidden. Use provided runtime API instead.",
|
|
676
|
+
process: "Access to 'process' object is forbidden in handlers.",
|
|
677
|
+
require: "Use of 'require()' is not allowed. All dependencies must be provided through runtime API.",
|
|
678
|
+
__proto__: "Prototype manipulation via '__proto__' is forbidden for security reasons.",
|
|
679
|
+
prototype: "Direct prototype access is forbidden to prevent prototype pollution.",
|
|
680
|
+
constructor: "Access to 'constructor' property is forbidden to prevent prototype pollution.",
|
|
681
|
+
localStorage: "Direct localStorage access is forbidden. Use GetVar()/SetVar() for state management.",
|
|
682
|
+
sessionStorage: "Direct sessionStorage access is forbidden. Use GetVar()/SetVar() for state management.",
|
|
683
|
+
indexedDB: "Direct indexedDB access is forbidden. Use Database API provided in runtime context.",
|
|
684
|
+
unknownGlobal: (name) => {
|
|
685
|
+
const allowedGlobals = getAllowedGlobals();
|
|
686
|
+
return `'${name}' is not available in handler context. Available globals: ${Array.from(allowedGlobals).slice(0, 10).join(", ")}... (${allowedGlobals.size} total)`;
|
|
687
|
+
},
|
|
688
|
+
syntaxError: (message) => `Syntax error in handler code: ${message}`
|
|
689
|
+
};
|
|
690
|
+
function getErrorMessage(type, identifier) {
|
|
691
|
+
if (type === "unknownGlobal" && identifier) {
|
|
692
|
+
return VALIDATION_ERROR_MESSAGES.unknownGlobal(identifier);
|
|
693
|
+
}
|
|
694
|
+
if (type === "syntaxError" && identifier) {
|
|
695
|
+
return VALIDATION_ERROR_MESSAGES.syntaxError(identifier);
|
|
696
|
+
}
|
|
697
|
+
return VALIDATION_ERROR_MESSAGES[type] || `Security violation: ${type}`;
|
|
698
|
+
}
|
|
699
|
+
function isForbiddenGlobal(name) {
|
|
700
|
+
return FORBIDDEN_GLOBALS.has(name);
|
|
701
|
+
}
|
|
702
|
+
function isForbiddenProperty(name) {
|
|
703
|
+
return FORBIDDEN_PROPERTIES.has(name);
|
|
704
|
+
}
|
|
705
|
+
function isAllowedGlobal(name) {
|
|
706
|
+
return getAllowedGlobals().has(name);
|
|
707
|
+
}
|
|
708
|
+
function isForbiddenFunction(name) {
|
|
709
|
+
return FORBIDDEN_FUNCTIONS.has(name);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function validateHandlerCode(code) {
|
|
713
|
+
if (!code || code.trim() === "") {
|
|
714
|
+
return { valid: true, errors: [] };
|
|
715
|
+
}
|
|
716
|
+
const context = {
|
|
717
|
+
errors: [],
|
|
718
|
+
declaredVariables: /* @__PURE__ */ new Set(),
|
|
719
|
+
scopeStack: [/* @__PURE__ */ new Set()]
|
|
720
|
+
};
|
|
721
|
+
try {
|
|
722
|
+
const wrappedCode = `(function() { ${code} })`;
|
|
723
|
+
const ast = acorn.parse(wrappedCode, {
|
|
724
|
+
ecmaVersion: "latest",
|
|
725
|
+
sourceType: "script",
|
|
726
|
+
locations: true
|
|
727
|
+
});
|
|
728
|
+
walkAST(ast, context);
|
|
729
|
+
} catch (error) {
|
|
730
|
+
context.errors.push({
|
|
731
|
+
type: "syntax",
|
|
732
|
+
message: getErrorMessage("syntaxError", error.message),
|
|
733
|
+
line: error.loc?.line,
|
|
734
|
+
column: error.loc?.column,
|
|
735
|
+
code: extractErrorContext(code, error.loc?.line)
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return {
|
|
739
|
+
valid: context.errors.length === 0,
|
|
740
|
+
errors: context.errors
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function walkAST(ast, context) {
|
|
744
|
+
walk.ancestor(ast, {
|
|
745
|
+
// Check identifier usage
|
|
746
|
+
Identifier(node, ancestors) {
|
|
747
|
+
checkIdentifier(node, context);
|
|
748
|
+
},
|
|
749
|
+
// Check member expressions (e.g., obj.prop, obj['prop'])
|
|
750
|
+
MemberExpression(node) {
|
|
751
|
+
checkMemberExpression(node, context);
|
|
752
|
+
},
|
|
753
|
+
// Check function calls
|
|
754
|
+
CallExpression(node) {
|
|
755
|
+
checkCallExpression(node, context);
|
|
756
|
+
},
|
|
757
|
+
// Check new expressions (e.g., new Function())
|
|
758
|
+
NewExpression(node) {
|
|
759
|
+
checkNewExpression(node, context);
|
|
760
|
+
},
|
|
761
|
+
// Check dynamic imports
|
|
762
|
+
ImportExpression(node) {
|
|
763
|
+
context.errors.push({
|
|
764
|
+
type: "forbidden_pattern",
|
|
765
|
+
message: "Dynamic 'import()' is not allowed in handlers.",
|
|
766
|
+
line: node.loc?.start.line,
|
|
767
|
+
column: node.loc?.start.column
|
|
768
|
+
});
|
|
769
|
+
},
|
|
770
|
+
// Track variable declarations to avoid false positives
|
|
771
|
+
VariableDeclaration(node, ancestors) {
|
|
772
|
+
node.declarations.forEach((decl) => {
|
|
773
|
+
if (decl.id.type === "Identifier") {
|
|
774
|
+
getCurrentScope(context).add(decl.id.name);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
},
|
|
778
|
+
// Track function parameters
|
|
779
|
+
FunctionDeclaration(node, ancestors) {
|
|
780
|
+
const fnScope = /* @__PURE__ */ new Set();
|
|
781
|
+
if (node.id) {
|
|
782
|
+
fnScope.add(node.id.name);
|
|
783
|
+
}
|
|
784
|
+
node.params.forEach((param) => {
|
|
785
|
+
if (param.type === "Identifier") {
|
|
786
|
+
fnScope.add(param.name);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
context.declaredVariables = /* @__PURE__ */ new Set([...context.declaredVariables, ...fnScope]);
|
|
790
|
+
},
|
|
791
|
+
FunctionExpression(node, ancestors) {
|
|
792
|
+
const fnScope = /* @__PURE__ */ new Set();
|
|
793
|
+
if (node.id) {
|
|
794
|
+
fnScope.add(node.id.name);
|
|
795
|
+
}
|
|
796
|
+
node.params.forEach((param) => {
|
|
797
|
+
if (param.type === "Identifier") {
|
|
798
|
+
fnScope.add(param.name);
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
context.declaredVariables = /* @__PURE__ */ new Set([...context.declaredVariables, ...fnScope]);
|
|
802
|
+
},
|
|
803
|
+
ArrowFunctionExpression(node, ancestors) {
|
|
804
|
+
const fnScope = /* @__PURE__ */ new Set();
|
|
805
|
+
node.params.forEach((param) => {
|
|
806
|
+
if (param.type === "Identifier") {
|
|
807
|
+
fnScope.add(param.name);
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
context.declaredVariables = /* @__PURE__ */ new Set([...context.declaredVariables, ...fnScope]);
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
function checkIdentifier(node, context, ancestors) {
|
|
815
|
+
const name = node.name;
|
|
816
|
+
if (isInDeclaredVariables(name, context)) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (isForbiddenGlobal(name)) {
|
|
820
|
+
context.errors.push({
|
|
821
|
+
type: "forbidden_global",
|
|
822
|
+
message: getErrorMessage(name),
|
|
823
|
+
line: node.loc?.start.line,
|
|
824
|
+
column: node.loc?.start.column,
|
|
825
|
+
identifier: name
|
|
826
|
+
});
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const standardBuiltins = /* @__PURE__ */ new Set([
|
|
830
|
+
"undefined",
|
|
831
|
+
"null",
|
|
832
|
+
"true",
|
|
833
|
+
"false",
|
|
834
|
+
"NaN",
|
|
835
|
+
"Infinity",
|
|
836
|
+
"Object",
|
|
837
|
+
"Array",
|
|
838
|
+
"String",
|
|
839
|
+
"Number",
|
|
840
|
+
"Boolean",
|
|
841
|
+
"Date",
|
|
842
|
+
"Math",
|
|
843
|
+
"JSON",
|
|
844
|
+
"RegExp",
|
|
845
|
+
"Error",
|
|
846
|
+
"Promise",
|
|
847
|
+
"Map",
|
|
848
|
+
"Set",
|
|
849
|
+
"WeakMap",
|
|
850
|
+
"WeakSet",
|
|
851
|
+
"parseInt",
|
|
852
|
+
"parseFloat",
|
|
853
|
+
"isNaN",
|
|
854
|
+
"isFinite",
|
|
855
|
+
"encodeURI",
|
|
856
|
+
"decodeURI",
|
|
857
|
+
"encodeURIComponent",
|
|
858
|
+
"decodeURIComponent"
|
|
859
|
+
]);
|
|
860
|
+
if (standardBuiltins.has(name)) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (isAllowedGlobal(name)) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function checkMemberExpression(node, context) {
|
|
868
|
+
if (node.property) {
|
|
869
|
+
const propName = node.property.name || node.property.value;
|
|
870
|
+
if (typeof propName === "string" && isForbiddenProperty(propName)) {
|
|
871
|
+
context.errors.push({
|
|
872
|
+
type: "forbidden_property",
|
|
873
|
+
message: getErrorMessage(propName),
|
|
874
|
+
line: node.loc?.start.line,
|
|
875
|
+
column: node.loc?.start.column,
|
|
876
|
+
identifier: propName
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (node.computed && node.property.type === "Literal") {
|
|
881
|
+
const propValue = node.property.value;
|
|
882
|
+
if (typeof propValue === "string" && isForbiddenProperty(propValue)) {
|
|
883
|
+
context.errors.push({
|
|
884
|
+
type: "forbidden_property",
|
|
885
|
+
message: getErrorMessage(propValue),
|
|
886
|
+
line: node.loc?.start.line,
|
|
887
|
+
column: node.loc?.start.column,
|
|
888
|
+
identifier: propValue
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
function checkCallExpression(node, context) {
|
|
894
|
+
const calleeName = getCalleeName(node.callee);
|
|
895
|
+
if (!calleeName) return;
|
|
896
|
+
if (calleeName === "eval") {
|
|
897
|
+
context.errors.push({
|
|
898
|
+
type: "forbidden_function",
|
|
899
|
+
message: getErrorMessage("eval"),
|
|
900
|
+
line: node.loc?.start.line,
|
|
901
|
+
column: node.loc?.start.column,
|
|
902
|
+
identifier: "eval"
|
|
903
|
+
});
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (calleeName === "setTimeout" || calleeName === "setInterval") {
|
|
907
|
+
if (node.arguments.length > 0 && node.arguments[0].type === "Literal") {
|
|
908
|
+
context.errors.push({
|
|
909
|
+
type: "forbidden_function",
|
|
910
|
+
message: getErrorMessage(`${calleeName}_string`),
|
|
911
|
+
line: node.loc?.start.line,
|
|
912
|
+
column: node.loc?.start.column,
|
|
913
|
+
identifier: calleeName
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function checkNewExpression(node, context) {
|
|
919
|
+
const calleeName = getCalleeName(node.callee);
|
|
920
|
+
if (calleeName === "Function") {
|
|
921
|
+
context.errors.push({
|
|
922
|
+
type: "forbidden_function",
|
|
923
|
+
message: getErrorMessage("Function"),
|
|
924
|
+
line: node.loc?.start.line,
|
|
925
|
+
column: node.loc?.start.column,
|
|
926
|
+
identifier: "Function"
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
function getCalleeName(callee) {
|
|
931
|
+
if (callee.type === "Identifier") {
|
|
932
|
+
return callee.name;
|
|
933
|
+
}
|
|
934
|
+
if (callee.type === "MemberExpression" && callee.property.type === "Identifier") {
|
|
935
|
+
return callee.property.name;
|
|
936
|
+
}
|
|
937
|
+
return null;
|
|
938
|
+
}
|
|
939
|
+
function getCurrentScope(context, ancestors) {
|
|
940
|
+
return context.scopeStack[context.scopeStack.length - 1];
|
|
941
|
+
}
|
|
942
|
+
function isInDeclaredVariables(name, context) {
|
|
943
|
+
return context.declaredVariables.has(name) || context.scopeStack.some((scope) => scope.has(name));
|
|
944
|
+
}
|
|
945
|
+
function extractErrorContext(code, line) {
|
|
946
|
+
if (!line) return void 0;
|
|
947
|
+
const lines = code.split("\n");
|
|
948
|
+
const errorLine = lines[line - 1];
|
|
949
|
+
return errorLine?.trim();
|
|
950
|
+
}
|
|
951
|
+
function validateStringHandlers(handlers, prefix, allErrors) {
|
|
952
|
+
if (!handlers) return;
|
|
953
|
+
Object.entries(handlers).forEach(([name, code]) => {
|
|
954
|
+
if (typeof code === "string") {
|
|
955
|
+
const result = validateHandlerCode(code);
|
|
956
|
+
if (!result.valid) {
|
|
957
|
+
result.errors.forEach((error) => {
|
|
958
|
+
allErrors.push({
|
|
959
|
+
...error,
|
|
960
|
+
code: `${prefix}.${name}: ${error.code || code.split("\n")[0]}`
|
|
961
|
+
});
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
function validateHandlerTypeProperties(properties, prefix, allErrors) {
|
|
968
|
+
if (!properties) return;
|
|
969
|
+
Object.entries(properties).forEach(([name, value]) => {
|
|
970
|
+
if (value && typeof value === "object" && value.type === "handler" && typeof value.value === "string") {
|
|
971
|
+
const result = validateHandlerCode(value.value);
|
|
972
|
+
if (!result.valid) {
|
|
973
|
+
result.errors.forEach((error) => {
|
|
974
|
+
allErrors.push({
|
|
975
|
+
...error,
|
|
976
|
+
code: `${prefix}.${name}: ${error.code || value.value.split("\n")[0]}`
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
function validateComponentHandlers(component) {
|
|
984
|
+
const allErrors = [];
|
|
985
|
+
validateStringHandlers(component.event, "event", allErrors);
|
|
986
|
+
validateHandlerTypeProperties(component.input, "input", allErrors);
|
|
987
|
+
validateHandlerTypeProperties(component.style, "style", allErrors);
|
|
988
|
+
validateStringHandlers(component.inputHandlers, "inputHandlers", allErrors);
|
|
989
|
+
validateStringHandlers(component.styleHandlers, "styleHandlers", allErrors);
|
|
990
|
+
return {
|
|
991
|
+
valid: allErrors.length === 0,
|
|
992
|
+
errors: allErrors
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
const handlerFunctionCache = {};
|
|
997
|
+
const HANDLER_PARAMETERS = [
|
|
998
|
+
"Database",
|
|
999
|
+
"eventHandler",
|
|
1000
|
+
"Components",
|
|
1001
|
+
"Editor",
|
|
1002
|
+
"Event",
|
|
1003
|
+
"Item",
|
|
1004
|
+
"Current",
|
|
1005
|
+
"currentPlatform",
|
|
1006
|
+
"Values",
|
|
1007
|
+
"Apps",
|
|
1008
|
+
"Vars",
|
|
1009
|
+
"SetVar",
|
|
1010
|
+
"GetContextVar",
|
|
1011
|
+
"UpdateApplication",
|
|
1012
|
+
"GetVar",
|
|
1013
|
+
"GetComponent",
|
|
1014
|
+
"GetComponents",
|
|
1015
|
+
"AddComponent",
|
|
1016
|
+
"SetContextVar",
|
|
1017
|
+
"AddPage",
|
|
1018
|
+
"TraitCompoentFromSchema",
|
|
1019
|
+
"NavigateToUrl",
|
|
1020
|
+
"NavigateToHash",
|
|
1021
|
+
"NavigateToPage",
|
|
1022
|
+
"UpdatePage",
|
|
1023
|
+
"context",
|
|
1024
|
+
"applications",
|
|
1025
|
+
"updateInput",
|
|
1026
|
+
"updateInputHandlers",
|
|
1027
|
+
"deletePage",
|
|
1028
|
+
"CopyComponentToClipboard",
|
|
1029
|
+
"PasteComponentFromClipboard",
|
|
1030
|
+
"DeleteComponentAction",
|
|
1031
|
+
"updateName",
|
|
1032
|
+
"updateEvent",
|
|
1033
|
+
"updateStyleHandlers",
|
|
1034
|
+
"EventData",
|
|
1035
|
+
"updateStyle",
|
|
1036
|
+
"openEditorTab",
|
|
1037
|
+
"setCurrentEditorTab",
|
|
1038
|
+
"InvokeFunction",
|
|
1039
|
+
"Utils",
|
|
1040
|
+
"console",
|
|
1041
|
+
"UploadFile",
|
|
1042
|
+
"BrowseFiles",
|
|
1043
|
+
"Instance",
|
|
1044
|
+
"ShowToast",
|
|
1045
|
+
"ShowSuccessToast",
|
|
1046
|
+
"ShowErrorToast",
|
|
1047
|
+
"ShowWarningToast",
|
|
1048
|
+
"ShowInfoToast",
|
|
1049
|
+
"HideToast",
|
|
1050
|
+
"ClearAllToasts"
|
|
1051
|
+
];
|
|
1052
|
+
function compileHandlerFunction(code) {
|
|
1053
|
+
if (!handlerFunctionCache[code]) {
|
|
1054
|
+
const validationResult = validateHandlerCode(code);
|
|
1055
|
+
if (!validationResult.valid) {
|
|
1056
|
+
throw new Error(`Handler validation failed: ${validationResult.errors[0]?.message || "Unknown error"}`);
|
|
1057
|
+
}
|
|
1058
|
+
handlerFunctionCache[code] = new Function(
|
|
1059
|
+
...HANDLER_PARAMETERS,
|
|
1060
|
+
`return (function() { ${code} }).apply(this);`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
return handlerFunctionCache[code];
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
const observe = (o, f) => new Proxy(o, {
|
|
1067
|
+
set: (target, prop, value) => {
|
|
1068
|
+
let result = Reflect.set(target, prop, value);
|
|
1069
|
+
if (typeof prop === "string") {
|
|
1070
|
+
f(target, prop, value);
|
|
1071
|
+
}
|
|
1072
|
+
return result;
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
function setupRuntimeContext(context, component, EventData = {}) {
|
|
1076
|
+
context.Current = component;
|
|
1077
|
+
if (!component.children && component.childrenIds && Array.isArray(component.childrenIds)) {
|
|
1078
|
+
component.children = [];
|
|
1079
|
+
}
|
|
1080
|
+
if (component.uniqueUUID) {
|
|
1081
|
+
context.attachValuesProperty(component);
|
|
1082
|
+
let parentComponent = component.parent;
|
|
1083
|
+
while (parentComponent) {
|
|
1084
|
+
if (parentComponent.uniqueUUID) {
|
|
1085
|
+
context.attachValuesProperty(parentComponent);
|
|
1086
|
+
}
|
|
1087
|
+
parentComponent = parentComponent.parent;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
context.Event = EventData.event;
|
|
1091
|
+
context.Current.style = context.Current.style ?? {};
|
|
1092
|
+
if (!context.styleProxyCache.has(context.Current.style)) {
|
|
1093
|
+
const newProxy = observe(context.Current.style, (target, prop, value) => {
|
|
1094
|
+
context.setComponentRuntimeStyleAttribute(
|
|
1095
|
+
context.Current.uniqueUUID,
|
|
1096
|
+
prop,
|
|
1097
|
+
value
|
|
1098
|
+
);
|
|
1099
|
+
});
|
|
1100
|
+
context.Current.style = newProxy;
|
|
1101
|
+
context.styleProxyCache.set(context.Current.style, newProxy);
|
|
1102
|
+
} else {
|
|
1103
|
+
context.Current.style = context.styleProxyCache.get(context.Current.style);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
function extractRuntimeContext(context) {
|
|
1107
|
+
return {
|
|
1108
|
+
context: context.context,
|
|
1109
|
+
applications: context.applications,
|
|
1110
|
+
Apps: context.Apps,
|
|
1111
|
+
Values: context.Values,
|
|
1112
|
+
PropertiesProxy: context.PropertiesProxy,
|
|
1113
|
+
VarsProxy: context.VarsProxy,
|
|
1114
|
+
Current: context.Current,
|
|
1115
|
+
currentPlatform: context.currentPlatform,
|
|
1116
|
+
Event: context.Event
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function createVariableFunctions(runtimeContext) {
|
|
1121
|
+
const { context } = runtimeContext;
|
|
1122
|
+
return {
|
|
1123
|
+
/**
|
|
1124
|
+
* Sets a global variable accessible across all applications.
|
|
1125
|
+
*
|
|
1126
|
+
* @description
|
|
1127
|
+
* Stores a value in the global scope that persists for the session
|
|
1128
|
+
* and is accessible from any application or component.
|
|
1129
|
+
*
|
|
1130
|
+
* **Use Cases:**
|
|
1131
|
+
* - User authentication state
|
|
1132
|
+
* - Application-wide theme/settings
|
|
1133
|
+
* - Language/locale preferences
|
|
1134
|
+
* - Shared data between applications
|
|
1135
|
+
* - Feature flags
|
|
1136
|
+
*
|
|
1137
|
+
* **Storage:**
|
|
1138
|
+
* Stored in `$context.get().global[symbol]`
|
|
1139
|
+
*
|
|
1140
|
+
* **Reactivity:**
|
|
1141
|
+
* Changes trigger store updates and component re-renders that depend on the variable.
|
|
1142
|
+
*
|
|
1143
|
+
* @param {string} symbol - Variable name/key
|
|
1144
|
+
* @param {any} value - Value to store (any JSON-serializable value)
|
|
1145
|
+
*
|
|
1146
|
+
* @returns {void}
|
|
1147
|
+
*
|
|
1148
|
+
* @example Basic Usage
|
|
1149
|
+
* ```javascript
|
|
1150
|
+
* // Set primitive values
|
|
1151
|
+
* SetVar('username', 'John Doe');
|
|
1152
|
+
* SetVar('count', 42);
|
|
1153
|
+
* SetVar('isLoggedIn', true);
|
|
1154
|
+
*
|
|
1155
|
+
* // Set objects
|
|
1156
|
+
* SetVar('user', {
|
|
1157
|
+
* id: 123,
|
|
1158
|
+
* name: 'John Doe',
|
|
1159
|
+
* email: 'john@example.com'
|
|
1160
|
+
* });
|
|
1161
|
+
*
|
|
1162
|
+
* // Set arrays
|
|
1163
|
+
* SetVar('items', ['apple', 'banana', 'cherry']);
|
|
1164
|
+
* ```
|
|
1165
|
+
*
|
|
1166
|
+
* @example Updating Existing Variable
|
|
1167
|
+
* ```javascript
|
|
1168
|
+
* // Get current value, modify, set back
|
|
1169
|
+
* const count = GetVar('count') || 0;
|
|
1170
|
+
* SetVar('count', count + 1);
|
|
1171
|
+
*
|
|
1172
|
+
* // Update object property
|
|
1173
|
+
* const settings = GetVar('settings') || {};
|
|
1174
|
+
* SetVar('settings', { ...settings, darkMode: true });
|
|
1175
|
+
*
|
|
1176
|
+
* // Add to array
|
|
1177
|
+
* const items = GetVar('items') || [];
|
|
1178
|
+
* SetVar('items', [...items, newItem]);
|
|
1179
|
+
* ```
|
|
1180
|
+
*
|
|
1181
|
+
* @example Authentication Pattern
|
|
1182
|
+
* ```javascript
|
|
1183
|
+
* // On login
|
|
1184
|
+
* SetVar('isLoggedIn', true);
|
|
1185
|
+
* SetVar('currentUser', { id: 123, name: 'John' });
|
|
1186
|
+
* SetVar('authToken', 'jwt-token-here');
|
|
1187
|
+
*
|
|
1188
|
+
* // On logout
|
|
1189
|
+
* SetVar('isLoggedIn', false);
|
|
1190
|
+
* SetVar('currentUser', null);
|
|
1191
|
+
* SetVar('authToken', null);
|
|
1192
|
+
* ```
|
|
1193
|
+
*/
|
|
1194
|
+
SetVar: (symbol, value) => {
|
|
1195
|
+
setVar("global", symbol, value);
|
|
1196
|
+
},
|
|
1197
|
+
/**
|
|
1198
|
+
* Gets a global variable value.
|
|
1199
|
+
*
|
|
1200
|
+
* @description
|
|
1201
|
+
* Retrieves a value from the global scope. Returns undefined if
|
|
1202
|
+
* the variable doesn't exist.
|
|
1203
|
+
*
|
|
1204
|
+
* **Use Cases:**
|
|
1205
|
+
* - Check authentication status
|
|
1206
|
+
* - Get user preferences
|
|
1207
|
+
* - Access shared application state
|
|
1208
|
+
* - Retrieve cached data
|
|
1209
|
+
*
|
|
1210
|
+
* **Storage:**
|
|
1211
|
+
* Reads from `$context.get().global[symbol].value`
|
|
1212
|
+
*
|
|
1213
|
+
* @param {string} symbol - Variable name/key to retrieve
|
|
1214
|
+
*
|
|
1215
|
+
* @returns {any} The variable value, or undefined if not found
|
|
1216
|
+
*
|
|
1217
|
+
* @example Basic Usage
|
|
1218
|
+
* ```javascript
|
|
1219
|
+
* const username = GetVar('username');
|
|
1220
|
+
* const count = GetVar('count');
|
|
1221
|
+
* const user = GetVar('user');
|
|
1222
|
+
*
|
|
1223
|
+
* console.log(username); // "John Doe" or undefined
|
|
1224
|
+
* ```
|
|
1225
|
+
*
|
|
1226
|
+
* @example With Default Values
|
|
1227
|
+
* ```javascript
|
|
1228
|
+
* // Provide default if variable doesn't exist
|
|
1229
|
+
* const count = GetVar('count') || 0;
|
|
1230
|
+
* const theme = GetVar('theme') || 'light';
|
|
1231
|
+
* const settings = GetVar('settings') || { darkMode: false };
|
|
1232
|
+
* ```
|
|
1233
|
+
*
|
|
1234
|
+
* @example Conditional Logic
|
|
1235
|
+
* ```javascript
|
|
1236
|
+
* // Check if variable exists
|
|
1237
|
+
* const isLoggedIn = GetVar('isLoggedIn');
|
|
1238
|
+
* if (isLoggedIn) {
|
|
1239
|
+
* NavigateToPage('Dashboard');
|
|
1240
|
+
* } else {
|
|
1241
|
+
* NavigateToPage('Login');
|
|
1242
|
+
* }
|
|
1243
|
+
*
|
|
1244
|
+
* // Access nested properties safely
|
|
1245
|
+
* const user = GetVar('user');
|
|
1246
|
+
* const userName = user?.name || 'Guest';
|
|
1247
|
+
* ```
|
|
1248
|
+
*
|
|
1249
|
+
* @example Display Pattern
|
|
1250
|
+
* ```javascript
|
|
1251
|
+
* // Use in component display
|
|
1252
|
+
* return `Welcome, ${GetVar('username') || 'Guest'}!`;
|
|
1253
|
+
*
|
|
1254
|
+
* // Computed value
|
|
1255
|
+
* const firstName = GetVar('firstName');
|
|
1256
|
+
* const lastName = GetVar('lastName');
|
|
1257
|
+
* return `${firstName} ${lastName}`;
|
|
1258
|
+
* ```
|
|
1259
|
+
*/
|
|
1260
|
+
GetVar: (symbol) => {
|
|
1261
|
+
if (context && context["global"] && context["global"][symbol] && "value" in context["global"][symbol]) {
|
|
1262
|
+
return context["global"][symbol].value;
|
|
1263
|
+
}
|
|
1264
|
+
},
|
|
1265
|
+
/**
|
|
1266
|
+
* Gets a context-scoped (application-specific) variable.
|
|
1267
|
+
*
|
|
1268
|
+
* @description
|
|
1269
|
+
* Retrieves a value from an application's context scope. Context variables
|
|
1270
|
+
* are isolated per application and don't affect other applications.
|
|
1271
|
+
*
|
|
1272
|
+
* **Use Cases:**
|
|
1273
|
+
* - Application-specific state
|
|
1274
|
+
* - Page navigation state within an app
|
|
1275
|
+
* - App configuration data
|
|
1276
|
+
* - Isolated feature state
|
|
1277
|
+
*
|
|
1278
|
+
* **Storage:**
|
|
1279
|
+
* Reads from `$context.get()[appId][symbol].value`
|
|
1280
|
+
*
|
|
1281
|
+
* **Scope Resolution:**
|
|
1282
|
+
* - If `customContentId` provided, uses that as the scope
|
|
1283
|
+
* - Otherwise, uses `component.application_id` as the scope
|
|
1284
|
+
*
|
|
1285
|
+
* @param {string} symbol - Variable name/key to retrieve
|
|
1286
|
+
* @param {string | null} customContentId - Optional custom context ID (app ID)
|
|
1287
|
+
* @param {any} component - Component object to get application_id from
|
|
1288
|
+
*
|
|
1289
|
+
* @returns {any} The variable value, or null if not found
|
|
1290
|
+
*
|
|
1291
|
+
* @example Basic Usage
|
|
1292
|
+
* ```javascript
|
|
1293
|
+
* // Get variable from current app context
|
|
1294
|
+
* const currentPage = GetContextVar('currentPage', null, Current);
|
|
1295
|
+
* const appSettings = GetContextVar('settings', null, Current);
|
|
1296
|
+
*
|
|
1297
|
+
* console.log(currentPage); // "dashboard" or null
|
|
1298
|
+
* ```
|
|
1299
|
+
*
|
|
1300
|
+
* @example Custom Context ID
|
|
1301
|
+
* ```javascript
|
|
1302
|
+
* // Get variable from specific app
|
|
1303
|
+
* const otherAppData = GetContextVar('userData', 'app-123', Current);
|
|
1304
|
+
*
|
|
1305
|
+
* // Cross-app communication
|
|
1306
|
+
* const sharedState = GetContextVar('sharedData', 'main-app-id', Current);
|
|
1307
|
+
* ```
|
|
1308
|
+
*
|
|
1309
|
+
* @example With Default Values
|
|
1310
|
+
* ```javascript
|
|
1311
|
+
* const currentPage = GetContextVar('currentPage', null, Current) || 'home';
|
|
1312
|
+
* const appConfig = GetContextVar('config', null, Current) || { initialized: false };
|
|
1313
|
+
* ```
|
|
1314
|
+
*
|
|
1315
|
+
* @example Application Navigation
|
|
1316
|
+
* ```javascript
|
|
1317
|
+
* // Store and retrieve current page in app context
|
|
1318
|
+
* SetContextVar('currentPage', 'profile', Current);
|
|
1319
|
+
*
|
|
1320
|
+
* // Later, in another component of same app:
|
|
1321
|
+
* const page = GetContextVar('currentPage', null, Current);
|
|
1322
|
+
* if (page === 'profile') {
|
|
1323
|
+
* // Show profile-specific UI
|
|
1324
|
+
* }
|
|
1325
|
+
* ```
|
|
1326
|
+
*/
|
|
1327
|
+
GetContextVar: (symbol, customContentId, component) => {
|
|
1328
|
+
const contentId = customContentId || component?.application_id;
|
|
1329
|
+
if (context && context[contentId] && context[contentId]?.[symbol] && "value" in context[contentId]?.[symbol]) {
|
|
1330
|
+
return context[contentId]?.[symbol]?.value;
|
|
1331
|
+
}
|
|
1332
|
+
return null;
|
|
1333
|
+
},
|
|
1334
|
+
/**
|
|
1335
|
+
* Sets a context-scoped (application-specific) variable.
|
|
1336
|
+
*
|
|
1337
|
+
* @description
|
|
1338
|
+
* Stores a value in an application's context scope. The value is isolated
|
|
1339
|
+
* to this application and won't affect other applications.
|
|
1340
|
+
*
|
|
1341
|
+
* **Use Cases:**
|
|
1342
|
+
* - Store app-specific state
|
|
1343
|
+
* - Track navigation within an app
|
|
1344
|
+
* - App configuration
|
|
1345
|
+
* - Isolated feature data
|
|
1346
|
+
*
|
|
1347
|
+
* **Storage:**
|
|
1348
|
+
* Stored in `$context.get()[appId][symbol]`
|
|
1349
|
+
*
|
|
1350
|
+
* **Scope:**
|
|
1351
|
+
* Uses `component.application_id` to determine the scope
|
|
1352
|
+
*
|
|
1353
|
+
* **Reactivity:**
|
|
1354
|
+
* Changes trigger store updates and re-renders of components in that app
|
|
1355
|
+
* that depend on the variable.
|
|
1356
|
+
*
|
|
1357
|
+
* @param {string} symbol - Variable name/key
|
|
1358
|
+
* @param {any} value - Value to store (any JSON-serializable value)
|
|
1359
|
+
* @param {any} component - Component object to get application_id from
|
|
1360
|
+
*
|
|
1361
|
+
* @returns {void}
|
|
1362
|
+
*
|
|
1363
|
+
* @example Basic Usage
|
|
1364
|
+
* ```javascript
|
|
1365
|
+
* // Set context variable in current app
|
|
1366
|
+
* SetContextVar('currentPage', 'dashboard', Current);
|
|
1367
|
+
* SetContextVar('userData', { id: 123, name: 'John' }, Current);
|
|
1368
|
+
* SetContextVar('appSettings', { theme: 'dark', layout: 'grid' }, Current);
|
|
1369
|
+
* ```
|
|
1370
|
+
*
|
|
1371
|
+
* @example Page Navigation State
|
|
1372
|
+
* ```javascript
|
|
1373
|
+
* // Store navigation history in app context
|
|
1374
|
+
* const history = GetContextVar('pageHistory', null, Current) || [];
|
|
1375
|
+
* SetContextVar('pageHistory', [...history, 'profile'], Current);
|
|
1376
|
+
*
|
|
1377
|
+
* // Track current page
|
|
1378
|
+
* SetContextVar('currentPage', 'profile', Current);
|
|
1379
|
+
* SetContextVar('previousPage', GetContextVar('currentPage', null, Current), Current);
|
|
1380
|
+
* ```
|
|
1381
|
+
*
|
|
1382
|
+
* @example App Configuration
|
|
1383
|
+
* ```javascript
|
|
1384
|
+
* // Initialize app config
|
|
1385
|
+
* SetContextVar('config', {
|
|
1386
|
+
* apiEndpoint: '/api/v1',
|
|
1387
|
+
* maxItems: 50,
|
|
1388
|
+
* enableFeatureX: true
|
|
1389
|
+
* }, Current);
|
|
1390
|
+
*
|
|
1391
|
+
* // Update config
|
|
1392
|
+
* const config = GetContextVar('config', null, Current);
|
|
1393
|
+
* SetContextVar('config', { ...config, maxItems: 100 }, Current);
|
|
1394
|
+
* ```
|
|
1395
|
+
*
|
|
1396
|
+
* @example Isolated State Between Apps
|
|
1397
|
+
* ```javascript
|
|
1398
|
+
* // App A sets its own state
|
|
1399
|
+
* SetContextVar('currentUser', { id: 1, name: 'Alice' }, appAComponent);
|
|
1400
|
+
*
|
|
1401
|
+
* // App B sets its own state (doesn't affect App A)
|
|
1402
|
+
* SetContextVar('currentUser', { id: 2, name: 'Bob' }, appBComponent);
|
|
1403
|
+
*
|
|
1404
|
+
* // Each app has its own isolated state
|
|
1405
|
+
* ```
|
|
1406
|
+
*/
|
|
1407
|
+
SetContextVar: (symbol, value, component) => {
|
|
1408
|
+
setVar(component.application_id, symbol, value);
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
var ComponentType = /* @__PURE__ */ ((ComponentType2) => {
|
|
1414
|
+
ComponentType2["TextLabel"] = "text_label";
|
|
1415
|
+
ComponentType2["Tabs"] = "tabs";
|
|
1416
|
+
ComponentType2["TextInput"] = "text_input";
|
|
1417
|
+
ComponentType2["Menu"] = "menu";
|
|
1418
|
+
ComponentType2["Button"] = "button_input";
|
|
1419
|
+
ComponentType2["Collection"] = "Collection";
|
|
1420
|
+
ComponentType2["Container"] = "vertical-container-block";
|
|
1421
|
+
ComponentType2["ColorPicker"] = "color_picker";
|
|
1422
|
+
ComponentType2["NumberInput"] = "number_input";
|
|
1423
|
+
ComponentType2["IconButton"] = "icon_button";
|
|
1424
|
+
ComponentType2["Select"] = "select";
|
|
1425
|
+
ComponentType2["ShadowBox"] = "shadow_box";
|
|
1426
|
+
ComponentType2["BorderRadius"] = "border_radius";
|
|
1427
|
+
ComponentType2["BoxModel"] = "box_model";
|
|
1428
|
+
ComponentType2["Event"] = "event";
|
|
1429
|
+
ComponentType2["Table"] = "Table";
|
|
1430
|
+
ComponentType2["Checkbox"] = "checkbox";
|
|
1431
|
+
ComponentType2["DatePicker"] = "Datepicker";
|
|
1432
|
+
ComponentType2["Icon"] = "Icon";
|
|
1433
|
+
ComponentType2["Image"] = "Image";
|
|
1434
|
+
ComponentType2["MicroApp"] = "MicroApp";
|
|
1435
|
+
ComponentType2["RadioButton"] = "RadioButton";
|
|
1436
|
+
ComponentType2["IconPicker"] = "IconPicker";
|
|
1437
|
+
ComponentType2["RefComponent"] = "RefComponent";
|
|
1438
|
+
ComponentType2["Code"] = "code-block";
|
|
1439
|
+
ComponentType2["RichText"] = "rich-text";
|
|
1440
|
+
ComponentType2["EmbedURL"] = "embed-url";
|
|
1441
|
+
ComponentType2["Link"] = "link";
|
|
1442
|
+
ComponentType2["Document"] = "document";
|
|
1443
|
+
ComponentType2["Video"] = "video";
|
|
1444
|
+
ComponentType2["FileUpload"] = "file-upload";
|
|
1445
|
+
ComponentType2["RichTextEditor"] = "rich-text-editor";
|
|
1446
|
+
ComponentType2["UsersDropdown"] = "UsersDropdown";
|
|
1447
|
+
ComponentType2["InsertDropdown"] = "InsertDropdown";
|
|
1448
|
+
ComponentType2["Collapse"] = "Collapse";
|
|
1449
|
+
ComponentType2["Handlers"] = "Handlers";
|
|
1450
|
+
ComponentType2["AI"] = "AI";
|
|
1451
|
+
ComponentType2["Divider"] = "Divider";
|
|
1452
|
+
ComponentType2["ExportImport"] = "ExportImport";
|
|
1453
|
+
ComponentType2["InvokeFunction"] = "InvokeFunction";
|
|
1454
|
+
ComponentType2["Dropdown"] = "dropdown";
|
|
1455
|
+
ComponentType2["Textarea"] = "Textarea";
|
|
1456
|
+
ComponentType2["Badge"] = "Badge";
|
|
1457
|
+
ComponentType2["Card"] = "Card";
|
|
1458
|
+
ComponentType2["Tag"] = "Tag";
|
|
1459
|
+
ComponentType2["Slider"] = "Slider";
|
|
1460
|
+
ComponentType2["Alert"] = "Alert";
|
|
1461
|
+
ComponentType2["Modal"] = "Modal";
|
|
1462
|
+
ComponentType2["Toast"] = "Toast";
|
|
1463
|
+
ComponentType2["Panel"] = "Panel";
|
|
1464
|
+
return ComponentType2;
|
|
1465
|
+
})(ComponentType || {});
|
|
1466
|
+
|
|
1467
|
+
const FRONT_API_URLS = {
|
|
1468
|
+
COMPONENTS: "/api/components",
|
|
1469
|
+
FUNCTIONS: "/api/v1/functions",
|
|
1470
|
+
APPLICATIONS: "/api/applications",
|
|
1471
|
+
PAGES: "/api/pages",
|
|
1472
|
+
REFRESH_COMPONENTS: "/api/components/application/{application_id}",
|
|
1473
|
+
REFRESH_PAGES: "/api/pages/application"
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
function formatValidationErrors$1(errors) {
|
|
1477
|
+
if (errors.length === 0) return "";
|
|
1478
|
+
if (errors.length === 1) {
|
|
1479
|
+
return `Security violation: ${errors[0].message}`;
|
|
1480
|
+
}
|
|
1481
|
+
return `Found ${errors.length} security violations:
|
|
1482
|
+
${errors.map(
|
|
1483
|
+
(e, i) => `${i + 1}. ${e.code || "Handler"}: ${e.message}`
|
|
1484
|
+
).join("\n")}`;
|
|
1485
|
+
}
|
|
1486
|
+
const validateAndEmitErrors = (component) => {
|
|
1487
|
+
const validationResult = validateComponentHandlers(component);
|
|
1488
|
+
if (!validationResult.valid) {
|
|
1489
|
+
const errorMessage = formatValidationErrors$1(validationResult.errors);
|
|
1490
|
+
eventDispatcher.emit("kernel:log", {
|
|
1491
|
+
type: "error",
|
|
1492
|
+
message: "Handler Validation Failed",
|
|
1493
|
+
details: errorMessage,
|
|
1494
|
+
errors: validationResult.errors
|
|
1495
|
+
});
|
|
1496
|
+
eventDispatcher.emit("component:validation-error", {
|
|
1497
|
+
componentId: component.uuid,
|
|
1498
|
+
errors: validationResult.errors,
|
|
1499
|
+
message: errorMessage
|
|
1500
|
+
});
|
|
1501
|
+
console.error("Handler validation failed:", validationResult.errors);
|
|
1502
|
+
return Promise.reject({
|
|
1503
|
+
type: "validation_error",
|
|
1504
|
+
message: errorMessage,
|
|
1505
|
+
errors: validationResult.errors
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
return null;
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
const addComponentHandler = ({ component }, currentApplicatinId) => {
|
|
1512
|
+
const validationError = validateAndEmitErrors(component);
|
|
1513
|
+
if (validationError instanceof Promise) return validationError;
|
|
1514
|
+
delete component.parent;
|
|
1515
|
+
delete component.children;
|
|
1516
|
+
delete component.childrens;
|
|
1517
|
+
fetch(FRONT_API_URLS.COMPONENTS, {
|
|
1518
|
+
method: "POST",
|
|
1519
|
+
headers: {
|
|
1520
|
+
"Content-Type": "application/json"
|
|
1521
|
+
},
|
|
1522
|
+
body: JSON.stringify({ component: { ...component, application_id: currentApplicatinId } })
|
|
1523
|
+
}).then((res) => res.json()).catch((err) => {
|
|
1524
|
+
eventDispatcher.emit("component:save-error", {
|
|
1525
|
+
componentId: component.uuid,
|
|
1526
|
+
error: err.message || "Failed to save component"
|
|
1527
|
+
});
|
|
1528
|
+
console.error(err);
|
|
1529
|
+
});
|
|
1530
|
+
};
|
|
1531
|
+
|
|
1532
|
+
const isServer = typeof window === "undefined";
|
|
1533
|
+
const initialAppState = isServer ? [] : JSON.parse(window["__INITIAL_CURRENT_APPLICATION_STATE__"] ?? null);
|
|
1534
|
+
const initialState = {};
|
|
1535
|
+
if (initialAppState && !isServer) {
|
|
1536
|
+
initialState[initialAppState.uuid] = JSON.parse(
|
|
1537
|
+
window["__INITIAL_PAGE_STATE__"] ?? []
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
const $pages = atom(initialState);
|
|
1541
|
+
const $microAppCurrentPage = deepMap({});
|
|
1542
|
+
const $currentPageId = ($application_id) => persistentAtom(`page_id_${$application_id}`, null, {
|
|
1543
|
+
encode: JSON.stringify,
|
|
1544
|
+
decode: JSON.parse
|
|
1545
|
+
});
|
|
1546
|
+
const $currentPageViewPort = persistentAtom(
|
|
1547
|
+
"current_page_view_port",
|
|
1548
|
+
"",
|
|
1549
|
+
{
|
|
1550
|
+
encode: JSON.stringify,
|
|
1551
|
+
decode: JSON.parse
|
|
1552
|
+
}
|
|
1553
|
+
);
|
|
1554
|
+
const $pageZoom = atom("99");
|
|
1555
|
+
const $pageSize = persistentAtom(
|
|
1556
|
+
"page_info",
|
|
1557
|
+
{},
|
|
1558
|
+
{
|
|
1559
|
+
encode: JSON.stringify,
|
|
1560
|
+
decode: JSON.parse
|
|
1561
|
+
}
|
|
1562
|
+
);
|
|
1563
|
+
const $showBorder = persistentAtom("show_border", false, {
|
|
1564
|
+
encode: JSON.stringify,
|
|
1565
|
+
decode: JSON.parse
|
|
1566
|
+
});
|
|
1567
|
+
const $contextMenuEvent = atom();
|
|
1568
|
+
const $applicationPages = ($application_id) => computed([$pages], (pagesStore) => {
|
|
1569
|
+
return pagesStore[$application_id] || [];
|
|
1570
|
+
});
|
|
1571
|
+
const $currentPage = ($application_id, currentPageId) => computed([$applicationPages($application_id)], (pages) => {
|
|
1572
|
+
if (!Array.isArray(pages)) {
|
|
1573
|
+
return void 0;
|
|
1574
|
+
}
|
|
1575
|
+
const currentPage = pages.find((page) => {
|
|
1576
|
+
return page.uuid === currentPageId;
|
|
1577
|
+
});
|
|
1578
|
+
if (!currentPage && pages.length > 0) {
|
|
1579
|
+
return pages[0];
|
|
1580
|
+
}
|
|
1581
|
+
return currentPage;
|
|
1582
|
+
});
|
|
1583
|
+
const refreshPageStoreVar = () => {
|
|
1584
|
+
const pagesStore = $pages.get();
|
|
1585
|
+
Object.keys(pagesStore).forEach((key) => {
|
|
1586
|
+
setVar(key, `${key}.appPages`, pagesStore[key]);
|
|
1587
|
+
ExecuteInstance.VarsProxy[`${key}.appPages`] = pagesStore[key];
|
|
1588
|
+
});
|
|
1589
|
+
};
|
|
1590
|
+
onMount($pages, () => {
|
|
1591
|
+
refreshPageStoreVar();
|
|
1592
|
+
});
|
|
1593
|
+
onNotify($pages, () => {
|
|
1594
|
+
refreshPageStoreVar();
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
function addPageToApplicationAction(page, application_id) {
|
|
1598
|
+
$pages.set({
|
|
1599
|
+
...$pages.get(),
|
|
1600
|
+
[application_id]: [page, ...$pages.get()[application_id] || []]
|
|
1601
|
+
});
|
|
1602
|
+
const pages = $pages.get()[application_id];
|
|
1603
|
+
setVar(application_id, `${application_id}.appPages`, pages);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
function updatePageAction(page, application_id) {
|
|
1607
|
+
$pages.set({
|
|
1608
|
+
...$pages.get(),
|
|
1609
|
+
[application_id]: [...$pages.get()[application_id].map((oldPage) => {
|
|
1610
|
+
if (oldPage.uuid == page.uuid) {
|
|
1611
|
+
return page;
|
|
1612
|
+
}
|
|
1613
|
+
return oldPage;
|
|
1614
|
+
}) || []]
|
|
1615
|
+
});
|
|
1616
|
+
const pages = $pages.get()[application_id];
|
|
1617
|
+
setVar(application_id, `${application_id}.appPages`, pages);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
const addPageHandler = (page, resolve, reject) => {
|
|
1621
|
+
fetch(`/api/pages`, {
|
|
1622
|
+
method: "POST",
|
|
1623
|
+
headers: {
|
|
1624
|
+
"Content-Type": "application/json"
|
|
1625
|
+
},
|
|
1626
|
+
body: JSON.stringify({ page: { ...page, application_id: $currentApplication.get().uuid } })
|
|
1627
|
+
}).then((res) => res.json()).then(
|
|
1628
|
+
(page2) => {
|
|
1629
|
+
if (resolve) {
|
|
1630
|
+
resolve(page2);
|
|
1631
|
+
}
|
|
1632
|
+
addPageToApplicationAction(page2, $currentApplication.get().uuid);
|
|
1633
|
+
}
|
|
1634
|
+
).catch((error) => {
|
|
1635
|
+
if (reject) {
|
|
1636
|
+
reject(error);
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
};
|
|
1640
|
+
let lastPageUpdateTime = 0;
|
|
1641
|
+
const PAGE_UPDATE_DEBOUNCE_MS = 100;
|
|
1642
|
+
const updatePageHandler = (page, callback) => {
|
|
1643
|
+
fetch("/api/pages/" + page.uuid, {
|
|
1644
|
+
method: "PUT",
|
|
1645
|
+
headers: {
|
|
1646
|
+
"Content-Type": "application/json"
|
|
1647
|
+
},
|
|
1648
|
+
body: JSON.stringify({ page })
|
|
1649
|
+
}).then((res) => res.json()).then((res) => {
|
|
1650
|
+
updatePageAction(res, $currentApplication.get().uuid);
|
|
1651
|
+
const now = Date.now();
|
|
1652
|
+
if (now - lastPageUpdateTime > PAGE_UPDATE_DEBOUNCE_MS) {
|
|
1653
|
+
lastPageUpdateTime = now;
|
|
1654
|
+
eventDispatcher.emit("Vars:currentPage");
|
|
1655
|
+
}
|
|
1656
|
+
if (callback) {
|
|
1657
|
+
callback(res);
|
|
1658
|
+
}
|
|
1659
|
+
});
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
function addComponentToCurrentPageAction(componentId) {
|
|
1663
|
+
const currentApp = $currentApplication.get();
|
|
1664
|
+
const currentAppId = currentApp.uuid;
|
|
1665
|
+
const currentPageId = ExecuteInstance.Vars.currentPage;
|
|
1666
|
+
const currentPages = $pages.get();
|
|
1667
|
+
const currentPage = currentPages[currentAppId].find((page) => page.uuid === currentPageId);
|
|
1668
|
+
if (currentPage) {
|
|
1669
|
+
const { component_ids = [] } = currentPage;
|
|
1670
|
+
component_ids.push(componentId);
|
|
1671
|
+
const updatedPage = { ...currentPage, component_ids };
|
|
1672
|
+
const updatedPages = {
|
|
1673
|
+
...currentPages,
|
|
1674
|
+
[currentAppId]: currentPages[currentAppId].map(
|
|
1675
|
+
(page) => page.uuid === currentPageId ? updatedPage : page
|
|
1676
|
+
)
|
|
1677
|
+
};
|
|
1678
|
+
$pages.set(updatedPages);
|
|
1679
|
+
updatePageHandler(updatedPage, (page) => {
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
const updateComponentHandler = (component, application_id) => {
|
|
1685
|
+
const validationError = validateAndEmitErrors(component);
|
|
1686
|
+
if (validationError instanceof Promise) return validationError;
|
|
1687
|
+
const ucomponent = { ...component };
|
|
1688
|
+
delete ucomponent.parent;
|
|
1689
|
+
delete ucomponent.children;
|
|
1690
|
+
delete ucomponent.childrens;
|
|
1691
|
+
fetch(`${FRONT_API_URLS.COMPONENTS}/${ucomponent.uuid}`, {
|
|
1692
|
+
method: "PUT",
|
|
1693
|
+
headers: {
|
|
1694
|
+
"Content-Type": "application/json"
|
|
1695
|
+
},
|
|
1696
|
+
body: JSON.stringify({
|
|
1697
|
+
component: { ...ucomponent, application_id }
|
|
1698
|
+
})
|
|
1699
|
+
}).then((res) => res.json()).catch((err) => {
|
|
1700
|
+
eventDispatcher.emit("component:save-error", {
|
|
1701
|
+
componentId: component.uuid,
|
|
1702
|
+
error: err.message || "Failed to save component"
|
|
1703
|
+
});
|
|
1704
|
+
console.error(err);
|
|
1705
|
+
});
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
const addComponentAction = (component, pageUUID, currentApplicationId, updateParent = true) => {
|
|
1709
|
+
const currentComponentId = ExecuteInstance.Vars.selectedComponents?.[0]?.uuid;
|
|
1710
|
+
const componentsStore = $components.get();
|
|
1711
|
+
const components = componentsStore[currentApplicationId] || [];
|
|
1712
|
+
const currentComponent = components.find((comp) => comp.uuid === currentComponentId);
|
|
1713
|
+
const componentId = component.uuid ?? v4();
|
|
1714
|
+
const newComponent = {
|
|
1715
|
+
...component,
|
|
1716
|
+
uuid: componentId,
|
|
1717
|
+
pageId: pageUUID,
|
|
1718
|
+
application_id: currentApplicationId,
|
|
1719
|
+
childrenIds: component.childrenIds ?? []
|
|
1720
|
+
// Initialize childrenIds if necessary
|
|
1721
|
+
};
|
|
1722
|
+
if (!currentComponentId || currentComponent?.component_type !== ComponentType.Container && currentComponent?.component_type !== ComponentType.Collection && currentComponent?.component_type !== ComponentType.Link) {
|
|
1723
|
+
newComponent.root = true;
|
|
1724
|
+
}
|
|
1725
|
+
if (currentComponentId) {
|
|
1726
|
+
if (currentComponent?.component_type === ComponentType.Container || currentComponent?.component_type === ComponentType.Dropdown || currentComponent?.component_type === ComponentType.Link || currentComponent?.component_type === ComponentType.Collection) {
|
|
1727
|
+
if (updateParent) {
|
|
1728
|
+
const parentComponent = components.find((comp) => comp.uuid === currentComponentId);
|
|
1729
|
+
if (parentComponent) {
|
|
1730
|
+
if (!parentComponent.childrenIds) {
|
|
1731
|
+
parentComponent.childrenIds = [];
|
|
1732
|
+
}
|
|
1733
|
+
parentComponent.childrenIds.push(componentId);
|
|
1734
|
+
componentsStore[currentApplicationId] = components.map(
|
|
1735
|
+
(comp) => comp.uuid === currentComponentId ? parentComponent : comp
|
|
1736
|
+
);
|
|
1737
|
+
setTimeout(() => {
|
|
1738
|
+
updateComponentHandler(parentComponent, currentApplicationId);
|
|
1739
|
+
}, 0);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
} else {
|
|
1743
|
+
addComponentToCurrentPageAction(componentId);
|
|
1744
|
+
}
|
|
1745
|
+
} else {
|
|
1746
|
+
addComponentToCurrentPageAction(componentId);
|
|
1747
|
+
}
|
|
1748
|
+
componentsStore[currentApplicationId] = [...components, newComponent];
|
|
1749
|
+
$components.set(componentsStore);
|
|
1750
|
+
setTimeout(() => {
|
|
1751
|
+
addComponentHandler({ component: newComponent }, currentApplicationId);
|
|
1752
|
+
}, 10);
|
|
1753
|
+
eventDispatcher.emit("component:refresh");
|
|
1754
|
+
};
|
|
1755
|
+
|
|
1756
|
+
const deleteComponentActionHandler = async (uuid) => {
|
|
1757
|
+
try {
|
|
1758
|
+
const response = await fetch(`${FRONT_API_URLS.COMPONENTS}/${uuid}`, {
|
|
1759
|
+
method: "DELETE",
|
|
1760
|
+
headers: {
|
|
1761
|
+
"Content-Type": "application/json"
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
if (!response.ok) {
|
|
1765
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
1766
|
+
}
|
|
1767
|
+
} catch (err) {
|
|
1768
|
+
console.error(err);
|
|
1769
|
+
throw err;
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
|
|
1773
|
+
function removeComponentToCurrentPageAction(removedComponentId) {
|
|
1774
|
+
const currentApp = $currentApplication.get();
|
|
1775
|
+
const currentAppId = currentApp.uuid;
|
|
1776
|
+
const currentPageId = ExecuteInstance.Vars.currentPage;
|
|
1777
|
+
const currentPages = $pages.get();
|
|
1778
|
+
const currentPage = currentPages[currentAppId].find((page) => page.uuid === currentPageId);
|
|
1779
|
+
if (currentPage) {
|
|
1780
|
+
const { component_ids = [] } = currentPage;
|
|
1781
|
+
const updatedComponentIds = component_ids.filter(
|
|
1782
|
+
(componentId) => componentId !== removedComponentId
|
|
1783
|
+
);
|
|
1784
|
+
const updatedPage = { ...currentPage, component_ids: updatedComponentIds };
|
|
1785
|
+
const updatedPages = {
|
|
1786
|
+
...currentPages,
|
|
1787
|
+
[currentAppId]: currentPages[currentAppId].map(
|
|
1788
|
+
(page) => page.uuid === currentPageId ? updatedPage : page
|
|
1789
|
+
)
|
|
1790
|
+
};
|
|
1791
|
+
$pages.set(updatedPages);
|
|
1792
|
+
updatePageHandler(updatedPage);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
async function deleteComponentAction(componentId, application_id) {
|
|
1797
|
+
const components = $components.get()[application_id];
|
|
1798
|
+
const componentToDelete = components.find(
|
|
1799
|
+
(component) => component.uuid === componentId
|
|
1800
|
+
);
|
|
1801
|
+
if (componentToDelete) {
|
|
1802
|
+
if (componentToDelete.root) {
|
|
1803
|
+
removeComponentToCurrentPageAction(componentId);
|
|
1804
|
+
} else {
|
|
1805
|
+
components.forEach((component) => {
|
|
1806
|
+
if (component.childrenIds) {
|
|
1807
|
+
const originalChildrenIds = [...component.childrenIds];
|
|
1808
|
+
component.childrenIds = component.childrenIds.filter(
|
|
1809
|
+
(childId) => childId !== componentId
|
|
1810
|
+
);
|
|
1811
|
+
if (originalChildrenIds.length !== component.childrenIds.length) {
|
|
1812
|
+
updateComponentHandler(component, application_id);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
$components.set({
|
|
1817
|
+
...$components.get(),
|
|
1818
|
+
[application_id]: components
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
$components.set({
|
|
1822
|
+
...$components.get(),
|
|
1823
|
+
[application_id]: components.filter(
|
|
1824
|
+
(component) => component.uuid !== componentId
|
|
1825
|
+
)
|
|
1826
|
+
});
|
|
1827
|
+
await deleteComponentActionHandler(componentId);
|
|
1828
|
+
eventDispatcher.emit("component:deleted");
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
function moveDraggedComponent(dropInComponentId, draggedComponentId, position = "inside") {
|
|
1833
|
+
const appUUID = $currentApplication.get().uuid;
|
|
1834
|
+
const components = $componentWithChildren(appUUID).get();
|
|
1835
|
+
let draggedComponent;
|
|
1836
|
+
let parentOfDragged;
|
|
1837
|
+
let oldIndexInParent = -1;
|
|
1838
|
+
function findDraggedRecursively(comp) {
|
|
1839
|
+
if (comp.uuid === draggedComponentId) {
|
|
1840
|
+
draggedComponent = { ...comp };
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
if (comp.childrenIds) {
|
|
1844
|
+
for (const childId of comp.childrenIds) {
|
|
1845
|
+
const child = components.find((c) => c.uuid === childId);
|
|
1846
|
+
if (child) {
|
|
1847
|
+
findDraggedRecursively(child);
|
|
1848
|
+
if (draggedComponent) return;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
parentOfDragged = components.find((c) => c.childrenIds?.includes(draggedComponentId));
|
|
1854
|
+
for (const rootComp of components) {
|
|
1855
|
+
findDraggedRecursively(rootComp);
|
|
1856
|
+
if (draggedComponent) break;
|
|
1857
|
+
}
|
|
1858
|
+
if (!draggedComponent || draggedComponent.uuid === dropInComponentId) {
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
if (!components.some((c) => c.uuid === draggedComponentId)) {
|
|
1862
|
+
components.push({ ...draggedComponent });
|
|
1863
|
+
}
|
|
1864
|
+
const currentPageId = ExecuteInstance.Vars.currentPage;
|
|
1865
|
+
const pagesForApp = $pages.get()[appUUID];
|
|
1866
|
+
const pageIndex = pagesForApp.findIndex((page2) => page2.uuid === currentPageId);
|
|
1867
|
+
if (pageIndex < 0) return;
|
|
1868
|
+
const page = pagesForApp[pageIndex];
|
|
1869
|
+
if (parentOfDragged) {
|
|
1870
|
+
oldIndexInParent = parentOfDragged.childrenIds?.indexOf(draggedComponentId) ?? -1;
|
|
1871
|
+
parentOfDragged.childrenIds = parentOfDragged.childrenIds?.filter((id) => id !== draggedComponentId);
|
|
1872
|
+
updateComponentHandler(parentOfDragged, appUUID);
|
|
1873
|
+
} else {
|
|
1874
|
+
oldIndexInParent = page.component_ids.indexOf(draggedComponentId);
|
|
1875
|
+
page.component_ids = page.component_ids.filter((id) => id !== draggedComponentId);
|
|
1876
|
+
if ("root" in draggedComponent) {
|
|
1877
|
+
draggedComponent.root = false;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const dropInComponent = components.find((c) => c.uuid === dropInComponentId);
|
|
1881
|
+
if (!dropInComponent) {
|
|
1882
|
+
const insertionIndex = oldIndexInParent >= 0 && oldIndexInParent <= page.component_ids.length ? oldIndexInParent : page.component_ids.length;
|
|
1883
|
+
page.component_ids.splice(insertionIndex, 0, draggedComponentId);
|
|
1884
|
+
draggedComponent.root = true;
|
|
1885
|
+
} else {
|
|
1886
|
+
const dropInIsContainer = Array.isArray(dropInComponent.childrenIds);
|
|
1887
|
+
if (position === "inside" && dropInIsContainer) {
|
|
1888
|
+
dropInComponent.childrenIds = dropInComponent.childrenIds || [];
|
|
1889
|
+
const insertionIndex = oldIndexInParent >= 0 && oldIndexInParent <= dropInComponent.childrenIds.length ? oldIndexInParent : dropInComponent.childrenIds.length;
|
|
1890
|
+
dropInComponent.childrenIds.splice(insertionIndex, 0, draggedComponentId);
|
|
1891
|
+
updateComponentHandler(dropInComponent, appUUID);
|
|
1892
|
+
} else {
|
|
1893
|
+
const parentOfDropIn = components.find((c) => c.childrenIds?.includes(dropInComponentId));
|
|
1894
|
+
if (parentOfDropIn) {
|
|
1895
|
+
const indexOfDropIn = parentOfDropIn.childrenIds?.indexOf(dropInComponentId);
|
|
1896
|
+
if (indexOfDropIn != null && indexOfDropIn >= 0) {
|
|
1897
|
+
let insertIndex = indexOfDropIn;
|
|
1898
|
+
if (position === "after") insertIndex += 1;
|
|
1899
|
+
else if (position === "before") insertIndex = Math.max(0, insertIndex);
|
|
1900
|
+
parentOfDropIn.childrenIds?.splice(insertIndex, 0, draggedComponentId);
|
|
1901
|
+
} else {
|
|
1902
|
+
parentOfDropIn.childrenIds?.push(draggedComponentId);
|
|
1903
|
+
}
|
|
1904
|
+
updateComponentHandler(parentOfDropIn, appUUID);
|
|
1905
|
+
} else {
|
|
1906
|
+
draggedComponent.root = true;
|
|
1907
|
+
const dropInIndex = page.component_ids.indexOf(dropInComponentId);
|
|
1908
|
+
if (dropInIndex >= 0) {
|
|
1909
|
+
let insertIndex = dropInIndex;
|
|
1910
|
+
if (position === "after") insertIndex += 1;
|
|
1911
|
+
else if (position === "before") insertIndex = Math.max(0, insertIndex);
|
|
1912
|
+
page.component_ids.splice(insertIndex, 0, draggedComponentId);
|
|
1913
|
+
} else {
|
|
1914
|
+
const insertionIndex = oldIndexInParent >= 0 && oldIndexInParent <= page.component_ids.length ? oldIndexInParent : page.component_ids.length;
|
|
1915
|
+
page.component_ids.splice(insertionIndex, 0, draggedComponentId);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
updateComponentHandler(draggedComponent, appUUID);
|
|
1921
|
+
$components.setKey(appUUID, components);
|
|
1922
|
+
updatePageAction(page, appUUID);
|
|
1923
|
+
updatePageHandler(page);
|
|
1924
|
+
eventDispatcher.emit("component:refresh");
|
|
1925
|
+
console.log(`Moved ${draggedComponent.uuid} to ${position} ${dropInComponentId}`, draggedComponent);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
function setCurrentComponentIdAction(componentId) {
|
|
1929
|
+
$currentComponentId.set(componentId);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
function setDraggingComponentInfo(draggingComponentInfo) {
|
|
1933
|
+
if (draggingComponentInfo) {
|
|
1934
|
+
$draggingComponentInfo.set({
|
|
1935
|
+
...draggingComponentInfo
|
|
1936
|
+
});
|
|
1937
|
+
} else {
|
|
1938
|
+
$draggingComponentInfo.set(null);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
function setHoveredComponentAction(component) {
|
|
1943
|
+
$hoveredComponent.set(component);
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
function updateComponentName(application_id, componentId, updatedName, save = true) {
|
|
1947
|
+
const componentsStore = $components.get();
|
|
1948
|
+
const applicationComponents = componentsStore[application_id] || [];
|
|
1949
|
+
const componentIndex = applicationComponents.findIndex(
|
|
1950
|
+
(component) => component.uuid === componentId
|
|
1951
|
+
);
|
|
1952
|
+
if (componentIndex !== -1) {
|
|
1953
|
+
const componentToUpdate = applicationComponents[componentIndex];
|
|
1954
|
+
const currentName = componentToUpdate.name || "";
|
|
1955
|
+
if (!deepEqual(currentName, updatedName)) {
|
|
1956
|
+
componentToUpdate.name = updatedName;
|
|
1957
|
+
$components.setKey(`${application_id}[${componentIndex}]`, componentToUpdate);
|
|
1958
|
+
if (save) {
|
|
1959
|
+
setTimeout(() => {
|
|
1960
|
+
updateComponentHandler(componentToUpdate, application_id);
|
|
1961
|
+
}, 0);
|
|
1962
|
+
}
|
|
1963
|
+
const pagesStore = $pages.get();
|
|
1964
|
+
Object.keys(pagesStore).forEach((key) => {
|
|
1965
|
+
setVar(key, `${key}.appPages`, pagesStore[key]);
|
|
1966
|
+
ExecuteInstance.VarsProxy[`${key}.appPages`] = [...pagesStore[key]];
|
|
1967
|
+
});
|
|
1968
|
+
eventDispatcher.emit("component:updated");
|
|
1969
|
+
refreshPageStoreVar();
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
function formatValidationErrors(errors) {
|
|
1975
|
+
if (errors.length === 0) return "";
|
|
1976
|
+
if (errors.length === 1) {
|
|
1977
|
+
return `Security violation: ${errors[0].message}`;
|
|
1978
|
+
}
|
|
1979
|
+
return `Found ${errors.length} security violations:
|
|
1980
|
+
${errors.map(
|
|
1981
|
+
(e, i) => `${i + 1}. ${e.code || "Handler"}: ${e.message}`
|
|
1982
|
+
).join("\n")}`;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
function updateComponentAttributes(application_id, componentId, updateType, updatedAttributes, save = true) {
|
|
1986
|
+
const currentPlatform = ExecuteInstance.Vars.currentPlatform ?? {
|
|
1987
|
+
platform: "desktop",
|
|
1988
|
+
isMobile: false
|
|
1989
|
+
};
|
|
1990
|
+
const componentsStore = $components.get();
|
|
1991
|
+
const applicationComponents = componentsStore[application_id] || [];
|
|
1992
|
+
const componentIndex = applicationComponents.findIndex(
|
|
1993
|
+
(component) => component.uuid === componentId
|
|
1994
|
+
);
|
|
1995
|
+
if (componentIndex !== -1) {
|
|
1996
|
+
const componentToUpdate = applicationComponents[componentIndex];
|
|
1997
|
+
let currentAttributes = {};
|
|
1998
|
+
let desktopAttributes = {};
|
|
1999
|
+
if (updateType === "style" || updateType === "input") {
|
|
2000
|
+
desktopAttributes = componentToUpdate[updateType] || {};
|
|
2001
|
+
if (currentPlatform.platform !== "desktop") {
|
|
2002
|
+
componentToUpdate.breakpoints = componentToUpdate.breakpoints || {};
|
|
2003
|
+
componentToUpdate.breakpoints[currentPlatform.width] = componentToUpdate.breakpoints[currentPlatform.width] || {};
|
|
2004
|
+
componentToUpdate.breakpoints[currentPlatform.width][updateType] = componentToUpdate.breakpoints[currentPlatform.width][updateType] ?? {};
|
|
2005
|
+
currentAttributes = componentToUpdate.breakpoints[currentPlatform.width][updateType];
|
|
2006
|
+
} else {
|
|
2007
|
+
currentAttributes = componentToUpdate[updateType] || {};
|
|
2008
|
+
}
|
|
2009
|
+
} else {
|
|
2010
|
+
currentAttributes = componentToUpdate[updateType] || {};
|
|
2011
|
+
}
|
|
2012
|
+
let needsUpdate = false;
|
|
2013
|
+
for (const key of Object.keys(updatedAttributes)) {
|
|
2014
|
+
if (!deepEqual(currentAttributes[key], updatedAttributes[key])) {
|
|
2015
|
+
needsUpdate = true;
|
|
2016
|
+
break;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
if (needsUpdate) {
|
|
2020
|
+
const hasOriginalUpdateType = updateType in componentToUpdate;
|
|
2021
|
+
const hasOriginalBreakpoints = "breakpoints" in componentToUpdate;
|
|
2022
|
+
const originalState = {
|
|
2023
|
+
[updateType]: hasOriginalUpdateType ? structuredClone(componentToUpdate[updateType]) : void 0,
|
|
2024
|
+
breakpoints: hasOriginalBreakpoints ? structuredClone(componentToUpdate.breakpoints) : void 0,
|
|
2025
|
+
hasUpdateType: hasOriginalUpdateType,
|
|
2026
|
+
hasBreakpoints: hasOriginalBreakpoints
|
|
2027
|
+
};
|
|
2028
|
+
if ((updateType === "style" || updateType === "input" && updatedAttributes.type !== "handler") && currentPlatform.platform !== "desktop") {
|
|
2029
|
+
componentToUpdate.breakpoints = componentToUpdate.breakpoints || {};
|
|
2030
|
+
componentToUpdate.breakpoints[currentPlatform.width] = componentToUpdate.breakpoints[currentPlatform.width] || {};
|
|
2031
|
+
for (const [key, value] of Object.entries(updatedAttributes)) {
|
|
2032
|
+
if (deepEqual(value, desktopAttributes[key])) {
|
|
2033
|
+
delete componentToUpdate.breakpoints[currentPlatform.width][updateType][key];
|
|
2034
|
+
} else {
|
|
2035
|
+
if (value.type === "handler") {
|
|
2036
|
+
componentToUpdate[updateType][key] = value;
|
|
2037
|
+
} else {
|
|
2038
|
+
componentToUpdate.breakpoints[currentPlatform.width][updateType] = componentToUpdate.breakpoints[currentPlatform.width][updateType] || {};
|
|
2039
|
+
componentToUpdate.breakpoints[currentPlatform.width][updateType][key] = value;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
const breakpointAttributes = componentToUpdate.breakpoints[currentPlatform.width];
|
|
2044
|
+
if (Object.keys(breakpointAttributes).every((type) => Object.keys(breakpointAttributes[type]).length === 0)) {
|
|
2045
|
+
delete componentToUpdate.breakpoints[currentPlatform.width];
|
|
2046
|
+
}
|
|
2047
|
+
if (Object.keys(componentToUpdate.breakpoints).length === 0) {
|
|
2048
|
+
delete componentToUpdate.breakpoints;
|
|
2049
|
+
}
|
|
2050
|
+
} else {
|
|
2051
|
+
componentToUpdate[updateType] = {
|
|
2052
|
+
...currentAttributes,
|
|
2053
|
+
...updatedAttributes
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
const validationResult = validateComponentHandlers(componentToUpdate);
|
|
2057
|
+
if (!validationResult.valid) {
|
|
2058
|
+
if (originalState.hasUpdateType) {
|
|
2059
|
+
componentToUpdate[updateType] = originalState[updateType];
|
|
2060
|
+
} else {
|
|
2061
|
+
delete componentToUpdate[updateType];
|
|
2062
|
+
}
|
|
2063
|
+
if (originalState.hasBreakpoints) {
|
|
2064
|
+
componentToUpdate.breakpoints = originalState.breakpoints;
|
|
2065
|
+
} else {
|
|
2066
|
+
delete componentToUpdate.breakpoints;
|
|
2067
|
+
}
|
|
2068
|
+
const errorMessage = formatValidationErrors(validationResult.errors);
|
|
2069
|
+
eventDispatcher.emit("component:validation-error", {
|
|
2070
|
+
componentId: componentToUpdate.uuid,
|
|
2071
|
+
errors: validationResult.errors,
|
|
2072
|
+
message: errorMessage
|
|
2073
|
+
});
|
|
2074
|
+
eventDispatcher.emit("kernel:log", {
|
|
2075
|
+
type: "error",
|
|
2076
|
+
message: "Handler Validation Failed",
|
|
2077
|
+
details: errorMessage,
|
|
2078
|
+
errors: validationResult.errors
|
|
2079
|
+
});
|
|
2080
|
+
console.error("Handler validation failed:", validationResult.errors);
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
$components.setKey(`${application_id}[${componentIndex}]`, componentToUpdate);
|
|
2084
|
+
if (save) {
|
|
2085
|
+
setTimeout(() => {
|
|
2086
|
+
updateComponentHandler(componentToUpdate, application_id);
|
|
2087
|
+
}, 0);
|
|
2088
|
+
}
|
|
2089
|
+
const selectedComponents = ExecuteInstance.VarsProxy.selectedComponents;
|
|
2090
|
+
const index = selectedComponents.findIndex((c) => c.uuid === componentToUpdate.uuid);
|
|
2091
|
+
if (index !== -1) {
|
|
2092
|
+
ExecuteInstance.VarsProxy.selectedComponents[index] = componentToUpdate;
|
|
2093
|
+
}
|
|
2094
|
+
eventDispatcher.emit("component:updated");
|
|
2095
|
+
eventDispatcher.emit(`component-updated:${String(componentId)}`);
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
function copyCpmponentToClipboard(component) {
|
|
2101
|
+
delete component.parent;
|
|
2102
|
+
delete component.children;
|
|
2103
|
+
delete component.childrens;
|
|
2104
|
+
const application_id = component.application_id;
|
|
2105
|
+
const currentApplicationComponents = $applicationComponents(application_id).get();
|
|
2106
|
+
const currentComponent = currentApplicationComponents.find((c) => c.uuid === component.uuid);
|
|
2107
|
+
const componentChildrenIDs = extractAllChildrenIds(currentApplicationComponents, currentComponent);
|
|
2108
|
+
const childrenComponents = componentChildrenIDs.map((childId) => currentApplicationComponents.find((c) => c.uuid === childId));
|
|
2109
|
+
delete currentComponent.parent;
|
|
2110
|
+
delete currentComponent.children;
|
|
2111
|
+
delete currentComponent.childrens;
|
|
2112
|
+
const schema = generateNuralyClipboardStructure(currentComponent, childrenComponents);
|
|
2113
|
+
navigator.clipboard.writeText(JSON.stringify(schema, null, 2)).then(() => {
|
|
2114
|
+
}).catch((err) => {
|
|
2115
|
+
console.error("Error while copying:", err);
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
function pasteComponentFromClipboard() {
|
|
2119
|
+
navigator.clipboard.readText().then((clipboardText) => {
|
|
2120
|
+
traitCompoentFromSchema(clipboardText);
|
|
2121
|
+
}).catch((err) => {
|
|
2122
|
+
console.error("Error while reading the text:", err);
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
function traitCompoentFromSchema(clipboardText) {
|
|
2126
|
+
try {
|
|
2127
|
+
const schema = JSON.parse(clipboardText);
|
|
2128
|
+
if (schema.version !== "1.0") {
|
|
2129
|
+
console.error("Schema version not supported");
|
|
2130
|
+
return;
|
|
2131
|
+
} else {
|
|
2132
|
+
const newSchema = transformSchemaWithNewUUIDs(schema);
|
|
2133
|
+
const [rootComponents, childrens] = findRootAndChildren(newSchema);
|
|
2134
|
+
const application_id = $currentApplication.get()?.uuid;
|
|
2135
|
+
const currentPage = ExecuteInstance.Vars.currentPage;
|
|
2136
|
+
childrens.forEach(
|
|
2137
|
+
(component) => {
|
|
2138
|
+
delete component.root;
|
|
2139
|
+
addComponentAction(component, currentPage, application_id, false);
|
|
2140
|
+
}
|
|
2141
|
+
);
|
|
2142
|
+
rootComponents.forEach((component) => {
|
|
2143
|
+
delete component.root;
|
|
2144
|
+
addComponentAction(component, currentPage, application_id);
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
} catch (err) {
|
|
2148
|
+
console.error("Error while reading the text:", err);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
function generateNuralyClipboardStructure(component, childrenComponents) {
|
|
2152
|
+
const NuralySchema = {
|
|
2153
|
+
version: "1.0",
|
|
2154
|
+
components: [
|
|
2155
|
+
component,
|
|
2156
|
+
...childrenComponents
|
|
2157
|
+
]
|
|
2158
|
+
};
|
|
2159
|
+
return NuralySchema;
|
|
2160
|
+
}
|
|
2161
|
+
function transformSchemaWithNewUUIDs(schema) {
|
|
2162
|
+
const uuidMap = /* @__PURE__ */ new Map();
|
|
2163
|
+
function generateUUID() {
|
|
2164
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
2165
|
+
const r = Math.random() * 16 | 0, v = c === "x" ? r : r & 3 | 8;
|
|
2166
|
+
return v.toString(16);
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
schema.components.forEach((component) => {
|
|
2170
|
+
const newUUID = generateUUID();
|
|
2171
|
+
uuidMap.set(component.uuid, newUUID);
|
|
2172
|
+
component.uuid = newUUID;
|
|
2173
|
+
});
|
|
2174
|
+
schema.components.forEach((component) => {
|
|
2175
|
+
component.childrenIds = component.childrenIds.map((oldUUID) => uuidMap.get(oldUUID) || oldUUID);
|
|
2176
|
+
component.name += `_${Math.random().toString(36).substring(2, 6)}`;
|
|
2177
|
+
});
|
|
2178
|
+
return schema;
|
|
2179
|
+
}
|
|
2180
|
+
function findRootAndChildren(data) {
|
|
2181
|
+
const allComponents = data.components;
|
|
2182
|
+
const childIds = new Set(allComponents.flatMap((comp) => comp.childrenIds));
|
|
2183
|
+
const rootComponents = allComponents.filter((comp) => !childIds.has(comp.uuid));
|
|
2184
|
+
const otherComponents = allComponents.filter((comp) => childIds.has(comp.uuid));
|
|
2185
|
+
return [rootComponents, otherComponents];
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
const GenerateName = (componentType) => {
|
|
2189
|
+
const randomNumber = Math.floor(Math.random() * 1e4);
|
|
2190
|
+
return `${componentType}_${randomNumber}`;
|
|
2191
|
+
};
|
|
2192
|
+
|
|
2193
|
+
function createComponentFunctions(runtimeContext) {
|
|
2194
|
+
const { applications } = runtimeContext;
|
|
2195
|
+
return {
|
|
2196
|
+
/**
|
|
2197
|
+
* Gets a component by UUID
|
|
2198
|
+
*/
|
|
2199
|
+
GetComponent: (componentUuid, application_id) => {
|
|
2200
|
+
return EditorInstance.components.find((c) => c.uuid === componentUuid);
|
|
2201
|
+
},
|
|
2202
|
+
/**
|
|
2203
|
+
* Gets multiple components by their IDs
|
|
2204
|
+
*/
|
|
2205
|
+
GetComponents: (componentIds) => {
|
|
2206
|
+
return Object.values(applications).flat().filter((c) => componentIds.includes(c.uuid));
|
|
2207
|
+
},
|
|
2208
|
+
/**
|
|
2209
|
+
* Adds a new component to the page
|
|
2210
|
+
*/
|
|
2211
|
+
AddComponent: ({ application_id, pageId, componentType, additionalData }) => {
|
|
2212
|
+
const generatedName = GenerateName(componentType);
|
|
2213
|
+
addComponentAction({ name: generatedName, component_type: componentType, ...additionalData }, pageId, application_id);
|
|
2214
|
+
},
|
|
2215
|
+
/**
|
|
2216
|
+
* Deletes a component with confirmation
|
|
2217
|
+
*/
|
|
2218
|
+
DeleteComponentAction: (component) => {
|
|
2219
|
+
const userInput = confirm("Are you sure you want to delete this component?");
|
|
2220
|
+
if (userInput) {
|
|
2221
|
+
deleteComponentAction(component.uuid, component.application_id);
|
|
2222
|
+
}
|
|
2223
|
+
},
|
|
2224
|
+
/**
|
|
2225
|
+
* Copies component to clipboard
|
|
2226
|
+
*/
|
|
2227
|
+
CopyComponentToClipboard: (component) => {
|
|
2228
|
+
copyCpmponentToClipboard(component);
|
|
2229
|
+
},
|
|
2230
|
+
/**
|
|
2231
|
+
* Pastes component from clipboard
|
|
2232
|
+
*/
|
|
2233
|
+
PasteComponentFromClipboard: () => {
|
|
2234
|
+
pasteComponentFromClipboard();
|
|
2235
|
+
}
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
function createComponentPropertyFunctions() {
|
|
2240
|
+
return {
|
|
2241
|
+
/**
|
|
2242
|
+
* Updates component name
|
|
2243
|
+
*/
|
|
2244
|
+
updateName: (component, componentName) => {
|
|
2245
|
+
updateComponentName(component.application_id, component.uuid, componentName);
|
|
2246
|
+
},
|
|
2247
|
+
/**
|
|
2248
|
+
* Updates component input property
|
|
2249
|
+
*/
|
|
2250
|
+
updateInput: (component, inputName, handlerType, handlerValue) => {
|
|
2251
|
+
const eventData = { [inputName]: { type: handlerType, value: handlerValue } };
|
|
2252
|
+
updateComponentAttributes(component.application_id, component.uuid, "input", eventData);
|
|
2253
|
+
},
|
|
2254
|
+
/**
|
|
2255
|
+
* Updates component input handlers
|
|
2256
|
+
*/
|
|
2257
|
+
updateInputHandlers: (component, inputName, value) => {
|
|
2258
|
+
const eventData = { [inputName]: value };
|
|
2259
|
+
updateComponentAttributes(component.application_id, component.uuid, "inputHandlers", eventData);
|
|
2260
|
+
},
|
|
2261
|
+
/**
|
|
2262
|
+
* Updates component event handler
|
|
2263
|
+
*/
|
|
2264
|
+
updateEvent: (component, symbol, value) => {
|
|
2265
|
+
const eventData = { [symbol]: value };
|
|
2266
|
+
updateComponentAttributes(component.application_id, component.uuid, "event", eventData);
|
|
2267
|
+
},
|
|
2268
|
+
/**
|
|
2269
|
+
* Updates component style, supporting pseudo-states
|
|
2270
|
+
*/
|
|
2271
|
+
updateStyle: (component, symbol, value) => {
|
|
2272
|
+
const selectedState = ExecuteInstance.Vars.selected_component_style_state;
|
|
2273
|
+
let eventData;
|
|
2274
|
+
if (selectedState && selectedState !== "default") {
|
|
2275
|
+
const existingPseudoStateStyles = component.style?.[selectedState] || {};
|
|
2276
|
+
eventData = {
|
|
2277
|
+
[selectedState]: {
|
|
2278
|
+
...existingPseudoStateStyles,
|
|
2279
|
+
[symbol]: value
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
} else {
|
|
2283
|
+
eventData = { [symbol]: value };
|
|
2284
|
+
}
|
|
2285
|
+
updateComponentAttributes(component.application_id, component.uuid, "style", eventData);
|
|
2286
|
+
},
|
|
2287
|
+
/**
|
|
2288
|
+
* Updates component style handlers
|
|
2289
|
+
*/
|
|
2290
|
+
updateStyleHandlers: (component, symbol, value) => {
|
|
2291
|
+
updateComponentAttributes(component.application_id, component.uuid, "styleHandlers", { [symbol]: value });
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
const refreshPagesActionHandler = async (uuid) => {
|
|
2297
|
+
try {
|
|
2298
|
+
const response = await fetch(`${FRONT_API_URLS.REFRESH_PAGES}/${uuid}`, {
|
|
2299
|
+
method: "GET",
|
|
2300
|
+
headers: {
|
|
2301
|
+
"Content-Type": "application/json"
|
|
2302
|
+
}
|
|
2303
|
+
});
|
|
2304
|
+
if (!response.ok) {
|
|
2305
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
2306
|
+
}
|
|
2307
|
+
const pages = await response.json();
|
|
2308
|
+
$pages.set(
|
|
2309
|
+
{ ...$pages.get(), [uuid]: pages }
|
|
2310
|
+
);
|
|
2311
|
+
refreshPageStoreVar();
|
|
2312
|
+
} catch (err) {
|
|
2313
|
+
console.error(err);
|
|
2314
|
+
throw err;
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
|
|
2318
|
+
const deletePageHandler = async (page, callback) => {
|
|
2319
|
+
try {
|
|
2320
|
+
const response = await fetch(`/api/pages/${page.uuid}`, {
|
|
2321
|
+
method: "DELETE",
|
|
2322
|
+
headers: {
|
|
2323
|
+
"Content-Type": "application/json"
|
|
2324
|
+
},
|
|
2325
|
+
body: JSON.stringify({ page })
|
|
2326
|
+
});
|
|
2327
|
+
const res = await response.json();
|
|
2328
|
+
refreshPagesActionHandler(page.application_id);
|
|
2329
|
+
if (callback) {
|
|
2330
|
+
callback(res);
|
|
2331
|
+
}
|
|
2332
|
+
} catch (error) {
|
|
2333
|
+
console.error("Error deleting page:", error);
|
|
2334
|
+
}
|
|
2335
|
+
};
|
|
2336
|
+
|
|
2337
|
+
function deletePageAction(page) {
|
|
2338
|
+
deletePageHandler(page);
|
|
2339
|
+
$applicationPages(page.application_id).get();
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
function createPageFunctions() {
|
|
2343
|
+
return {
|
|
2344
|
+
/**
|
|
2345
|
+
* Adds a new page
|
|
2346
|
+
*/
|
|
2347
|
+
AddPage: (page) => {
|
|
2348
|
+
return new Promise((resolve) => {
|
|
2349
|
+
addPageHandler(page, (page2) => {
|
|
2350
|
+
resolve(page2);
|
|
2351
|
+
});
|
|
2352
|
+
});
|
|
2353
|
+
},
|
|
2354
|
+
/**
|
|
2355
|
+
* Updates an existing page
|
|
2356
|
+
*/
|
|
2357
|
+
UpdatePage: (page) => {
|
|
2358
|
+
return new Promise((resolve) => {
|
|
2359
|
+
updatePageHandler(page, (page2) => {
|
|
2360
|
+
resolve(page2);
|
|
2361
|
+
});
|
|
2362
|
+
});
|
|
2363
|
+
},
|
|
2364
|
+
/**
|
|
2365
|
+
* Deletes a page with confirmation
|
|
2366
|
+
*/
|
|
2367
|
+
deletePage: (page) => {
|
|
2368
|
+
const userInput = confirm("Are you sure you want to delete this page?");
|
|
2369
|
+
if (userInput) {
|
|
2370
|
+
deletePageAction(page);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
function addTempApplication(uuid, components) {
|
|
2377
|
+
$components.set({
|
|
2378
|
+
...$components.get(),
|
|
2379
|
+
[uuid]: components
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
const API_BASE = typeof window === "undefined" ? `http://${process.env.NURALY_SERVICES_HOST || "gateway"}` : "";
|
|
2384
|
+
const APIS_URL = {
|
|
2385
|
+
getApplication: (id) => `${API_BASE}/api/applications/${id}`,
|
|
2386
|
+
getApplicationComponents: (id) => `${API_BASE}/api/components/application/${id}`,
|
|
2387
|
+
fetchAllApplications: () => `${API_BASE}/api/applications`,
|
|
2388
|
+
getApplicationPages: (uuid) => `${API_BASE}/api/pages/application/${uuid}`,
|
|
2389
|
+
getPageComponents: (uuid) => `${API_BASE}/api/pages/${uuid}/components`,
|
|
2390
|
+
getApplicationPermission: (application_id, resource_id) => `${API_BASE}/api/permissions/${application_id}/${resource_id}`
|
|
2391
|
+
};
|
|
2392
|
+
|
|
2393
|
+
const $toasts = deepMap({
|
|
2394
|
+
toasts: []
|
|
2395
|
+
});
|
|
2396
|
+
|
|
2397
|
+
function showToast(options) {
|
|
2398
|
+
const id = `toast-${v4()}`;
|
|
2399
|
+
const toast = {
|
|
2400
|
+
id,
|
|
2401
|
+
type: "info",
|
|
2402
|
+
duration: 3e3,
|
|
2403
|
+
closable: true,
|
|
2404
|
+
...options
|
|
2405
|
+
};
|
|
2406
|
+
const current = $toasts.get();
|
|
2407
|
+
$toasts.setKey("toasts", [...current.toasts, toast]);
|
|
2408
|
+
eventDispatcher.emit("toast:show", toast);
|
|
2409
|
+
if (toast.duration && toast.duration > 0) {
|
|
2410
|
+
setTimeout(() => hideToast(id), toast.duration);
|
|
2411
|
+
}
|
|
2412
|
+
return id;
|
|
2413
|
+
}
|
|
2414
|
+
function hideToast(id) {
|
|
2415
|
+
const current = $toasts.get();
|
|
2416
|
+
$toasts.setKey("toasts", current.toasts.filter((t) => t.id !== id));
|
|
2417
|
+
eventDispatcher.emit("toast:hide", { id });
|
|
2418
|
+
}
|
|
2419
|
+
function clearAllToasts() {
|
|
2420
|
+
$toasts.setKey("toasts", []);
|
|
2421
|
+
eventDispatcher.emit("toast:clear");
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
function setApplication(apps) {
|
|
2425
|
+
$applications.set(apps);
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
function closeCreateApplicationModalAction() {
|
|
2429
|
+
$showCreateApplicationModal.set(false);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
function setPermissionMessage(message) {
|
|
2433
|
+
$permissionsState.set({
|
|
2434
|
+
...$permissionsState.get(),
|
|
2435
|
+
message
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
function loadOrRefreshApplications() {
|
|
2440
|
+
fetch("/api/applications", {
|
|
2441
|
+
method: "GET"
|
|
2442
|
+
}).then((res) => res.json()).then((res) => {
|
|
2443
|
+
setApplication(res);
|
|
2444
|
+
closeCreateApplicationModalAction();
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
function createApplicationAction(application) {
|
|
2448
|
+
fetch("/api/applications", {
|
|
2449
|
+
method: "POST",
|
|
2450
|
+
headers: {
|
|
2451
|
+
"Content-Type": "application/json"
|
|
2452
|
+
},
|
|
2453
|
+
body: JSON.stringify(application)
|
|
2454
|
+
}).then((res) => res.json()).then((res) => {
|
|
2455
|
+
loadOrRefreshApplications();
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2458
|
+
function deleteApplicationAction(application_id) {
|
|
2459
|
+
fetch("/api/applications/" + application_id, {
|
|
2460
|
+
method: "DELETE",
|
|
2461
|
+
headers: {
|
|
2462
|
+
"Content-Type": "application/json"
|
|
2463
|
+
}
|
|
2464
|
+
}).then((res) => res.json()).then((res) => {
|
|
2465
|
+
loadOrRefreshApplications();
|
|
2466
|
+
});
|
|
2467
|
+
}
|
|
2468
|
+
function updateApplicationActionHandler(application) {
|
|
2469
|
+
const { uuid } = application;
|
|
2470
|
+
delete application.uuid;
|
|
2471
|
+
fetch("/api/applications/" + uuid, {
|
|
2472
|
+
method: "PUT",
|
|
2473
|
+
headers: {
|
|
2474
|
+
"Content-Type": "application/json"
|
|
2475
|
+
},
|
|
2476
|
+
body: JSON.stringify(application)
|
|
2477
|
+
}).then((res) => res.json()).then((res) => {
|
|
2478
|
+
loadOrRefreshApplications();
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
function addPermission({ resource_id, resource_type, user_id, permission_type }) {
|
|
2482
|
+
fetch("/api/permissions", {
|
|
2483
|
+
method: "POST",
|
|
2484
|
+
headers: {
|
|
2485
|
+
"Content-Type": "application/json"
|
|
2486
|
+
},
|
|
2487
|
+
body: JSON.stringify({
|
|
2488
|
+
resource_id,
|
|
2489
|
+
resource_type,
|
|
2490
|
+
permission_type,
|
|
2491
|
+
user_id
|
|
2492
|
+
})
|
|
2493
|
+
}).then((res) => res.json()).then((res) => {
|
|
2494
|
+
setPermissionMessage(res.message);
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
function updateApplication(attribute) {
|
|
2499
|
+
$currentApplication.set({
|
|
2500
|
+
...$currentApplication.get(),
|
|
2501
|
+
...attribute
|
|
2502
|
+
});
|
|
2503
|
+
updateApplicationActionHandler($currentApplication.get());
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
function createApplicationFunctions() {
|
|
2507
|
+
return {
|
|
2508
|
+
/**
|
|
2509
|
+
* Updates an application
|
|
2510
|
+
*/
|
|
2511
|
+
UpdateApplication: (application) => {
|
|
2512
|
+
updateApplication(application);
|
|
2513
|
+
}
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
function createNavigationFunctions() {
|
|
2518
|
+
return {
|
|
2519
|
+
/**
|
|
2520
|
+
* Navigates to a URL
|
|
2521
|
+
*/
|
|
2522
|
+
NavigateToUrl: (url) => {
|
|
2523
|
+
window.location.href = url;
|
|
2524
|
+
ExecuteInstance.Event?.preventDefault?.();
|
|
2525
|
+
ExecuteInstance.Event?.stopPropagation?.();
|
|
2526
|
+
},
|
|
2527
|
+
/**
|
|
2528
|
+
* Navigates to a hash anchor and scrolls to it
|
|
2529
|
+
*/
|
|
2530
|
+
NavigateToHash: (hash) => {
|
|
2531
|
+
window.location.hash = hash;
|
|
2532
|
+
if (hash) {
|
|
2533
|
+
const element = document.querySelector(hash);
|
|
2534
|
+
if (element) {
|
|
2535
|
+
element.scrollIntoView({ behavior: "smooth" });
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
ExecuteInstance.Event?.preventDefault?.();
|
|
2539
|
+
ExecuteInstance.Event?.stopPropagation?.();
|
|
2540
|
+
},
|
|
2541
|
+
/**
|
|
2542
|
+
* Navigates to a page by name within the current application
|
|
2543
|
+
*/
|
|
2544
|
+
NavigateToPage: (pageName) => {
|
|
2545
|
+
ExecuteInstance.Event?.preventDefault?.();
|
|
2546
|
+
ExecuteInstance.Event?.stopPropagation?.();
|
|
2547
|
+
const currentEditingApplication = ExecuteInstance.GetVar("currentEditingApplication");
|
|
2548
|
+
const appPages = ExecuteInstance.GetContextVar(
|
|
2549
|
+
currentEditingApplication?.uuid + ".appPages",
|
|
2550
|
+
currentEditingApplication?.uuid
|
|
2551
|
+
);
|
|
2552
|
+
const targetPage = appPages?.find((pageItem) => pageItem.name === pageName);
|
|
2553
|
+
if (targetPage) {
|
|
2554
|
+
ExecuteInstance.VarsProxy.currentPage = targetPage.uuid;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
function createStorageFunctions() {
|
|
2561
|
+
return {
|
|
2562
|
+
/**
|
|
2563
|
+
* Uploads one or more files to storage
|
|
2564
|
+
*
|
|
2565
|
+
* @param files - Single file or array of files to upload
|
|
2566
|
+
* @param folderPath - Destination folder path
|
|
2567
|
+
* @returns Upload result(s)
|
|
2568
|
+
*/
|
|
2569
|
+
UploadFile: async (files, folderPath = "my-folder") => {
|
|
2570
|
+
const fileArray = Array.isArray(files) ? files : [files];
|
|
2571
|
+
const results = [];
|
|
2572
|
+
for (const file of fileArray) {
|
|
2573
|
+
const formData = new FormData();
|
|
2574
|
+
formData.append("file", file);
|
|
2575
|
+
formData.append("fileName", file.name);
|
|
2576
|
+
formData.append("contentType", file.type || "");
|
|
2577
|
+
try {
|
|
2578
|
+
const response = await fetch(`/api/v1/storage/files/${folderPath}`, {
|
|
2579
|
+
method: "POST",
|
|
2580
|
+
body: formData
|
|
2581
|
+
});
|
|
2582
|
+
if (!response.ok) {
|
|
2583
|
+
throw new Error(`Upload failed with status ${response.status}`);
|
|
2584
|
+
}
|
|
2585
|
+
const result = await response.json();
|
|
2586
|
+
EditorInstance.Console.log({ message: "Upload success", data: result });
|
|
2587
|
+
results.push(result);
|
|
2588
|
+
} catch (err) {
|
|
2589
|
+
EditorInstance.Console.error({ message: "Upload failed", error: err });
|
|
2590
|
+
throw err;
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
return results.length === 1 ? results[0] : results;
|
|
2594
|
+
},
|
|
2595
|
+
/**
|
|
2596
|
+
* Browses files in a folder with pagination support
|
|
2597
|
+
*
|
|
2598
|
+
* @param folderPath - Folder path to browse
|
|
2599
|
+
* @param options - Browse options (continuation token, limit)
|
|
2600
|
+
* @returns List of files and continuation token
|
|
2601
|
+
*/
|
|
2602
|
+
BrowseFiles: async (folderPath = "my-folder", options = {}) => {
|
|
2603
|
+
try {
|
|
2604
|
+
const { continuation = null, limit = 100 } = options;
|
|
2605
|
+
let url = `/api/v1/storage/browse/${folderPath}`;
|
|
2606
|
+
const params = new URLSearchParams();
|
|
2607
|
+
if (continuation) params.append("continuation", continuation);
|
|
2608
|
+
if (limit) params.append("limit", limit.toString());
|
|
2609
|
+
if (params.toString()) {
|
|
2610
|
+
url += `?${params.toString()}`;
|
|
2611
|
+
}
|
|
2612
|
+
const response = await fetch(url, {
|
|
2613
|
+
method: "GET",
|
|
2614
|
+
headers: {
|
|
2615
|
+
"accept": "*/*"
|
|
2616
|
+
}
|
|
2617
|
+
});
|
|
2618
|
+
if (!response.ok) {
|
|
2619
|
+
throw new Error(`Browse failed with status ${response.status}`);
|
|
2620
|
+
}
|
|
2621
|
+
const result = await response.json();
|
|
2622
|
+
EditorInstance.Console.log({ message: "Browse success", data: result });
|
|
2623
|
+
return result;
|
|
2624
|
+
} catch (err) {
|
|
2625
|
+
EditorInstance.Console.error({ message: "Browse failed", error: err });
|
|
2626
|
+
throw err;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
const invokeFunctionHandler = (functionId, data) => {
|
|
2633
|
+
return fetch(`${FRONT_API_URLS.FUNCTIONS}/invoke/${functionId}`, {
|
|
2634
|
+
method: "POST",
|
|
2635
|
+
headers: {
|
|
2636
|
+
"Content-Type": "application/json"
|
|
2637
|
+
},
|
|
2638
|
+
body: JSON.stringify({
|
|
2639
|
+
data
|
|
2640
|
+
})
|
|
2641
|
+
});
|
|
2642
|
+
};
|
|
2643
|
+
|
|
2644
|
+
const loadFunctionsHandler = async () => {
|
|
2645
|
+
return await fetch(`${FRONT_API_URLS.FUNCTIONS}`, {
|
|
2646
|
+
method: "GET",
|
|
2647
|
+
headers: {
|
|
2648
|
+
"Content-Type": "application/json"
|
|
2649
|
+
}
|
|
2650
|
+
}).then((res) => res.json());
|
|
2651
|
+
};
|
|
2652
|
+
|
|
2653
|
+
function createFunctionInvocationFunctions() {
|
|
2654
|
+
return {
|
|
2655
|
+
/**
|
|
2656
|
+
* Invokes a studio function by name
|
|
2657
|
+
*
|
|
2658
|
+
* @param name - Function name to invoke
|
|
2659
|
+
* @param payload - Data to pass to the function
|
|
2660
|
+
* @returns Function execution result
|
|
2661
|
+
*/
|
|
2662
|
+
InvokeFunction: async (name, payload = {}) => {
|
|
2663
|
+
if (!ExecuteInstance.Vars.studio_functions) {
|
|
2664
|
+
const functions = await loadFunctionsHandler();
|
|
2665
|
+
ExecuteInstance.VarsProxy.studio_functions = [...functions];
|
|
2666
|
+
}
|
|
2667
|
+
const targetFunction = (ExecuteInstance.Vars.studio_functions ?? []).find((_function) => _function.label === name);
|
|
2668
|
+
try {
|
|
2669
|
+
const result = await invokeFunctionHandler(targetFunction.id, payload);
|
|
2670
|
+
const contentType = result.headers?.get("Content-Type") || "";
|
|
2671
|
+
if (contentType.includes("application/json")) {
|
|
2672
|
+
const jsonData = await result.json();
|
|
2673
|
+
return jsonData;
|
|
2674
|
+
} else {
|
|
2675
|
+
const textData = await result.text();
|
|
2676
|
+
return textData;
|
|
2677
|
+
}
|
|
2678
|
+
} catch (error) {
|
|
2679
|
+
console.error("Error in InvokeFunctionHandler:", error);
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
function openEditorTab(tab) {
|
|
2686
|
+
const isTabOpen = $editorState.get().tabs.find((t) => t.id === tab.id);
|
|
2687
|
+
if (!isTabOpen) {
|
|
2688
|
+
$editorState.set({
|
|
2689
|
+
...$editorState.get(),
|
|
2690
|
+
tabs: [...$editorState.get().tabs, tab]
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
function setCurrentEditorTab(tab) {
|
|
2696
|
+
$editorState.set({
|
|
2697
|
+
...$editorState.get(),
|
|
2698
|
+
currentTab: tab
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
var ViewMode = /* @__PURE__ */ ((ViewMode2) => {
|
|
2703
|
+
ViewMode2["Edit"] = "edit";
|
|
2704
|
+
ViewMode2["Preview"] = "preview";
|
|
2705
|
+
return ViewMode2;
|
|
2706
|
+
})(ViewMode || {});
|
|
2707
|
+
const $environment = atom(
|
|
2708
|
+
{
|
|
2709
|
+
mode: "edit" /* Edit */
|
|
2710
|
+
}
|
|
2711
|
+
);
|
|
2712
|
+
keepMount($environment);
|
|
2713
|
+
|
|
2714
|
+
function createEditorFunctions() {
|
|
2715
|
+
return {
|
|
2716
|
+
/**
|
|
2717
|
+
* Opens an editor tab
|
|
2718
|
+
*/
|
|
2719
|
+
openEditorTab,
|
|
2720
|
+
/**
|
|
2721
|
+
* Sets the current active editor tab
|
|
2722
|
+
*/
|
|
2723
|
+
setCurrentEditorTab,
|
|
2724
|
+
/**
|
|
2725
|
+
* Creates components from schema text
|
|
2726
|
+
*/
|
|
2727
|
+
TraitCompoentFromSchema: (text) => {
|
|
2728
|
+
traitCompoentFromSchema(text);
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
function createToastFunctions() {
|
|
2734
|
+
return {
|
|
2735
|
+
/**
|
|
2736
|
+
* Shows a toast notification
|
|
2737
|
+
* @param message - The message to display
|
|
2738
|
+
* @param type - Toast type: 'success', 'error', 'warning', 'info' (default: 'info')
|
|
2739
|
+
* @param options - Additional options (duration, closable)
|
|
2740
|
+
* @returns Toast ID for programmatic control
|
|
2741
|
+
*
|
|
2742
|
+
* @example
|
|
2743
|
+
* ShowToast('File saved successfully!', 'success');
|
|
2744
|
+
* ShowToast('Error occurred', 'error', { duration: 5000 });
|
|
2745
|
+
* ShowToast('Processing...', 'info', { duration: 0 }); // No auto-hide
|
|
2746
|
+
*/
|
|
2747
|
+
ShowToast: (message, type = "info", options) => {
|
|
2748
|
+
return showToast({
|
|
2749
|
+
message,
|
|
2750
|
+
type,
|
|
2751
|
+
...options
|
|
2752
|
+
});
|
|
2753
|
+
},
|
|
2754
|
+
/**
|
|
2755
|
+
* Shows a success toast (convenience function)
|
|
2756
|
+
* @param message - Success message
|
|
2757
|
+
* @param duration - Display duration in milliseconds (default: 3000)
|
|
2758
|
+
* @returns Toast ID
|
|
2759
|
+
*
|
|
2760
|
+
* @example
|
|
2761
|
+
* ShowSuccessToast('Operation completed!');
|
|
2762
|
+
*/
|
|
2763
|
+
ShowSuccessToast: (message, duration = 3e3) => {
|
|
2764
|
+
return showToast({ message, type: "success", duration });
|
|
2765
|
+
},
|
|
2766
|
+
/**
|
|
2767
|
+
* Shows an error toast (convenience function)
|
|
2768
|
+
* @param message - Error message
|
|
2769
|
+
* @param duration - Display duration in milliseconds (default: 5000)
|
|
2770
|
+
* @returns Toast ID
|
|
2771
|
+
*
|
|
2772
|
+
* @example
|
|
2773
|
+
* ShowErrorToast('Failed to save file');
|
|
2774
|
+
*/
|
|
2775
|
+
ShowErrorToast: (message, duration = 5e3) => {
|
|
2776
|
+
return showToast({ message, type: "error", duration });
|
|
2777
|
+
},
|
|
2778
|
+
/**
|
|
2779
|
+
* Shows a warning toast (convenience function)
|
|
2780
|
+
* @param message - Warning message
|
|
2781
|
+
* @param duration - Display duration in milliseconds (default: 4000)
|
|
2782
|
+
* @returns Toast ID
|
|
2783
|
+
*
|
|
2784
|
+
* @example
|
|
2785
|
+
* ShowWarningToast('This action cannot be undone');
|
|
2786
|
+
*/
|
|
2787
|
+
ShowWarningToast: (message, duration = 4e3) => {
|
|
2788
|
+
return showToast({ message, type: "warning", duration });
|
|
2789
|
+
},
|
|
2790
|
+
/**
|
|
2791
|
+
* Shows an info toast (convenience function)
|
|
2792
|
+
* @param message - Info message
|
|
2793
|
+
* @param duration - Display duration in milliseconds (default: 3000)
|
|
2794
|
+
* @returns Toast ID
|
|
2795
|
+
*
|
|
2796
|
+
* @example
|
|
2797
|
+
* ShowInfoToast('Loading data...');
|
|
2798
|
+
*/
|
|
2799
|
+
ShowInfoToast: (message, duration = 3e3) => {
|
|
2800
|
+
return showToast({ message, type: "info", duration });
|
|
2801
|
+
},
|
|
2802
|
+
/**
|
|
2803
|
+
* Hides a specific toast by ID
|
|
2804
|
+
* @param id - Toast ID returned from ShowToast
|
|
2805
|
+
*
|
|
2806
|
+
* @example
|
|
2807
|
+
* const toastId = ShowToast('Processing...', 'info', { duration: 0 });
|
|
2808
|
+
* // ... later
|
|
2809
|
+
* HideToast(toastId);
|
|
2810
|
+
*/
|
|
2811
|
+
HideToast: (id) => {
|
|
2812
|
+
hideToast(id);
|
|
2813
|
+
},
|
|
2814
|
+
/**
|
|
2815
|
+
* Clears all active toasts
|
|
2816
|
+
*
|
|
2817
|
+
* @example
|
|
2818
|
+
* ClearAllToasts();
|
|
2819
|
+
*/
|
|
2820
|
+
ClearAllToasts: () => {
|
|
2821
|
+
clearAllToasts();
|
|
2822
|
+
}
|
|
2823
|
+
};
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
function createGlobalHandlerFunctions(runtimeContext) {
|
|
2827
|
+
return {
|
|
2828
|
+
...createVariableFunctions(runtimeContext),
|
|
2829
|
+
...createComponentFunctions(runtimeContext),
|
|
2830
|
+
...createComponentPropertyFunctions(),
|
|
2831
|
+
...createPageFunctions(),
|
|
2832
|
+
...createApplicationFunctions(),
|
|
2833
|
+
...createNavigationFunctions(),
|
|
2834
|
+
...createStorageFunctions(),
|
|
2835
|
+
...createFunctionInvocationFunctions(),
|
|
2836
|
+
...createEditorFunctions(),
|
|
2837
|
+
...createToastFunctions()
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
function getContextFromComponent(component) {
|
|
2842
|
+
return component?.__microAppContext?.runtimeContext || ExecuteInstance;
|
|
2843
|
+
}
|
|
2844
|
+
function executeHandler(component, code, EventData = {}, item = {}) {
|
|
2845
|
+
const context = getContextFromComponent(component);
|
|
2846
|
+
setupRuntimeContext(context, component, EventData);
|
|
2847
|
+
if (isServer$2) {
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
const runtimeContext = extractRuntimeContext(context);
|
|
2851
|
+
const globalFunctions = createGlobalHandlerFunctions(runtimeContext);
|
|
2852
|
+
let compiledFunction;
|
|
2853
|
+
try {
|
|
2854
|
+
compiledFunction = compileHandlerFunction(code);
|
|
2855
|
+
} catch (error) {
|
|
2856
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown compilation error";
|
|
2857
|
+
if (globalFunctions.ShowErrorToast) {
|
|
2858
|
+
globalFunctions.ShowErrorToast(errorMessage, 5e3);
|
|
2859
|
+
}
|
|
2860
|
+
throw error;
|
|
2861
|
+
}
|
|
2862
|
+
const customConsole = {
|
|
2863
|
+
log: EditorInstance.Console.log,
|
|
2864
|
+
warn: EditorInstance.Console.warn,
|
|
2865
|
+
error: EditorInstance.Console.error,
|
|
2866
|
+
info: EditorInstance.Console.info,
|
|
2867
|
+
debug: EditorInstance.Console.debug
|
|
2868
|
+
};
|
|
2869
|
+
return compiledFunction(
|
|
2870
|
+
Database,
|
|
2871
|
+
eventDispatcher,
|
|
2872
|
+
runtimeContext.PropertiesProxy,
|
|
2873
|
+
EditorInstance,
|
|
2874
|
+
runtimeContext.Event,
|
|
2875
|
+
JSON.parse(JSON.stringify(item ?? {})),
|
|
2876
|
+
runtimeContext.Current,
|
|
2877
|
+
runtimeContext.currentPlatform,
|
|
2878
|
+
runtimeContext.Values,
|
|
2879
|
+
runtimeContext.Apps,
|
|
2880
|
+
runtimeContext.VarsProxy,
|
|
2881
|
+
globalFunctions.SetVar,
|
|
2882
|
+
globalFunctions.GetContextVar,
|
|
2883
|
+
globalFunctions.UpdateApplication,
|
|
2884
|
+
globalFunctions.GetVar,
|
|
2885
|
+
globalFunctions.GetComponent,
|
|
2886
|
+
globalFunctions.GetComponents,
|
|
2887
|
+
globalFunctions.AddComponent,
|
|
2888
|
+
globalFunctions.SetContextVar,
|
|
2889
|
+
globalFunctions.AddPage,
|
|
2890
|
+
globalFunctions.TraitCompoentFromSchema,
|
|
2891
|
+
globalFunctions.NavigateToUrl,
|
|
2892
|
+
globalFunctions.NavigateToHash,
|
|
2893
|
+
globalFunctions.NavigateToPage,
|
|
2894
|
+
globalFunctions.UpdatePage,
|
|
2895
|
+
runtimeContext.context,
|
|
2896
|
+
runtimeContext.applications,
|
|
2897
|
+
globalFunctions.updateInput,
|
|
2898
|
+
globalFunctions.updateInputHandlers,
|
|
2899
|
+
globalFunctions.deletePage,
|
|
2900
|
+
globalFunctions.CopyComponentToClipboard,
|
|
2901
|
+
globalFunctions.PasteComponentFromClipboard,
|
|
2902
|
+
globalFunctions.DeleteComponentAction,
|
|
2903
|
+
globalFunctions.updateName,
|
|
2904
|
+
globalFunctions.updateEvent,
|
|
2905
|
+
globalFunctions.updateStyleHandlers,
|
|
2906
|
+
EventData,
|
|
2907
|
+
globalFunctions.updateStyle,
|
|
2908
|
+
globalFunctions.openEditorTab,
|
|
2909
|
+
globalFunctions.setCurrentEditorTab,
|
|
2910
|
+
globalFunctions.InvokeFunction,
|
|
2911
|
+
RuntimeHelpers,
|
|
2912
|
+
// Passed as "Utils" parameter for handler code
|
|
2913
|
+
customConsole,
|
|
2914
|
+
globalFunctions.UploadFile,
|
|
2915
|
+
globalFunctions.BrowseFiles,
|
|
2916
|
+
component.Instance || {},
|
|
2917
|
+
// Component instance state (used by micro-apps)
|
|
2918
|
+
globalFunctions.ShowToast,
|
|
2919
|
+
globalFunctions.ShowSuccessToast,
|
|
2920
|
+
globalFunctions.ShowErrorToast,
|
|
2921
|
+
globalFunctions.ShowWarningToast,
|
|
2922
|
+
globalFunctions.ShowInfoToast,
|
|
2923
|
+
globalFunctions.HideToast,
|
|
2924
|
+
globalFunctions.ClearAllToasts
|
|
2925
|
+
);
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2928
|
+
class RuntimeContextHelpers {
|
|
2929
|
+
/**
|
|
2930
|
+
* Create a reactive proxy for an object with configurable event dispatching.
|
|
2931
|
+
*
|
|
2932
|
+
* This proxy tracks property access and changes, maintains listeners,
|
|
2933
|
+
* and emits events when properties are modified.
|
|
2934
|
+
*
|
|
2935
|
+
* @param target - Object to wrap with proxy
|
|
2936
|
+
* @param config - Configuration for proxy behavior
|
|
2937
|
+
* @returns Reactive proxy for the target object
|
|
2938
|
+
*
|
|
2939
|
+
* @example
|
|
2940
|
+
* ```typescript
|
|
2941
|
+
* const proxy = RuntimeContextHelpers.createReactiveProxy(myObject, {
|
|
2942
|
+
* eventPrefix: 'microapp:123',
|
|
2943
|
+
* scope: 'Vars',
|
|
2944
|
+
* listeners: this.listeners,
|
|
2945
|
+
* current: this.Current,
|
|
2946
|
+
* onPropertyChange: (prop, value, listeners) => {
|
|
2947
|
+
* listeners.forEach(name => {
|
|
2948
|
+
* eventDispatcher.emit(`${eventPrefix}:changed:${name}`, { prop, value });
|
|
2949
|
+
* });
|
|
2950
|
+
* }
|
|
2951
|
+
* });
|
|
2952
|
+
* ```
|
|
2953
|
+
*/
|
|
2954
|
+
static createReactiveProxy(target, config) {
|
|
2955
|
+
const { eventPrefix, scope, listeners, current, onPropertyChange, debug = false } = config;
|
|
2956
|
+
if (typeof target !== "object" || target === null) {
|
|
2957
|
+
return target;
|
|
2958
|
+
}
|
|
2959
|
+
return new Proxy(target, {
|
|
2960
|
+
get(proxyTarget, prop, receiver) {
|
|
2961
|
+
if (debug) {
|
|
2962
|
+
const prefix = eventPrefix ? `[${eventPrefix}]` : "[Global]";
|
|
2963
|
+
console.log(`${prefix} Accessing property '${String(prop)}'`);
|
|
2964
|
+
}
|
|
2965
|
+
const value = Reflect.get(proxyTarget, prop, receiver);
|
|
2966
|
+
if (!listeners[String(prop)]) {
|
|
2967
|
+
listeners[String(prop)] = /* @__PURE__ */ new Set();
|
|
2968
|
+
}
|
|
2969
|
+
if (current.name) {
|
|
2970
|
+
listeners[String(prop)].add(current.name);
|
|
2971
|
+
}
|
|
2972
|
+
if (typeof value === "object" && value !== null) {
|
|
2973
|
+
return RuntimeContextHelpers.createNestedProxy(value, {
|
|
2974
|
+
...config,
|
|
2975
|
+
parentProp: String(prop)
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
return value;
|
|
2979
|
+
},
|
|
2980
|
+
set(proxyTarget, prop, value, receiver) {
|
|
2981
|
+
const oldValue = proxyTarget[prop];
|
|
2982
|
+
let valuesEqual = false;
|
|
2983
|
+
try {
|
|
2984
|
+
valuesEqual = deepEqual(oldValue, value);
|
|
2985
|
+
} catch (e) {
|
|
2986
|
+
valuesEqual = false;
|
|
2987
|
+
}
|
|
2988
|
+
if (valuesEqual) {
|
|
2989
|
+
return true;
|
|
2990
|
+
}
|
|
2991
|
+
const result = Reflect.set(proxyTarget, prop, value, receiver);
|
|
2992
|
+
if (debug) {
|
|
2993
|
+
const prefix = eventPrefix ? `[${eventPrefix}]` : "[Global]";
|
|
2994
|
+
console.log(`${prefix} Setting property '${String(prop)}' to '${value}'`);
|
|
2995
|
+
}
|
|
2996
|
+
const propListeners = listeners[String(prop)] || /* @__PURE__ */ new Set();
|
|
2997
|
+
onPropertyChange(String(prop), value, propListeners);
|
|
2998
|
+
if (scope) {
|
|
2999
|
+
const eventName = eventPrefix ? `${eventPrefix}:${scope}:${String(prop)}` : `${scope}:${String(prop)}`;
|
|
3000
|
+
if (debug || scope === "Vars" && String(prop) === "selectedComponents") {
|
|
3001
|
+
console.log(`[RuntimeContextHelpers] Emitting event: ${eventName}`, { value, ctx: current });
|
|
3002
|
+
}
|
|
3003
|
+
eventDispatcher.emit(eventName, {
|
|
3004
|
+
value,
|
|
3005
|
+
ctx: current
|
|
3006
|
+
// IMPORTANT: Include ctx for scope events (e.g., Vars:selectedComponents)
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
return result;
|
|
3010
|
+
}
|
|
3011
|
+
});
|
|
3012
|
+
}
|
|
3013
|
+
/**
|
|
3014
|
+
* Create a nested proxy for object properties.
|
|
3015
|
+
*
|
|
3016
|
+
* Nested proxies maintain the same reactive behavior as the parent proxy
|
|
3017
|
+
* but track changes to nested properties separately.
|
|
3018
|
+
*
|
|
3019
|
+
* @param target - Nested object to wrap
|
|
3020
|
+
* @param config - Configuration including parent property name
|
|
3021
|
+
* @returns Reactive proxy for nested object
|
|
3022
|
+
*/
|
|
3023
|
+
static createNestedProxy(target, config) {
|
|
3024
|
+
const { eventPrefix, scope, listeners, current, parentProp, debug = false } = config;
|
|
3025
|
+
return new Proxy(target, {
|
|
3026
|
+
set(proxyTarget, prop, value, receiver) {
|
|
3027
|
+
const oldValue = proxyTarget[prop];
|
|
3028
|
+
const result = Reflect.set(proxyTarget, prop, value, receiver);
|
|
3029
|
+
if (debug) {
|
|
3030
|
+
const prefix = eventPrefix ? `[${eventPrefix}]` : "[Global]";
|
|
3031
|
+
console.log(
|
|
3032
|
+
`${prefix} Updated nested property '${String(prop)}' from '${oldValue}' to '${value}'`
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
let valuesEqual = false;
|
|
3036
|
+
try {
|
|
3037
|
+
valuesEqual = deepEqual(oldValue, value);
|
|
3038
|
+
} catch (e) {
|
|
3039
|
+
valuesEqual = false;
|
|
3040
|
+
}
|
|
3041
|
+
if (!valuesEqual) {
|
|
3042
|
+
const parentListeners = listeners[parentProp] || /* @__PURE__ */ new Set();
|
|
3043
|
+
parentListeners.forEach((componentName) => {
|
|
3044
|
+
const eventName = eventPrefix ? `${eventPrefix}:component-property-changed:${componentName}` : `component-property-changed:${componentName}`;
|
|
3045
|
+
eventDispatcher.emit(eventName, {
|
|
3046
|
+
prop: parentProp,
|
|
3047
|
+
value,
|
|
3048
|
+
ctx: current
|
|
3049
|
+
});
|
|
3050
|
+
});
|
|
3051
|
+
if (scope) {
|
|
3052
|
+
const eventName = eventPrefix ? `${eventPrefix}:${scope}:${parentProp}.${String(prop)}` : `${scope}:${parentProp}.${String(prop)}`;
|
|
3053
|
+
eventDispatcher.emit(eventName, {
|
|
3054
|
+
prop,
|
|
3055
|
+
value,
|
|
3056
|
+
oldValue,
|
|
3057
|
+
parent: parentProp
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
return result;
|
|
3062
|
+
},
|
|
3063
|
+
deleteProperty(proxyTarget, prop) {
|
|
3064
|
+
if (debug) {
|
|
3065
|
+
const prefix = eventPrefix ? `[${eventPrefix}]` : "[Global]";
|
|
3066
|
+
console.log(`${prefix} Deleting nested property '${String(prop)}'`);
|
|
3067
|
+
}
|
|
3068
|
+
const result = Reflect.deleteProperty(proxyTarget, prop);
|
|
3069
|
+
if (result) {
|
|
3070
|
+
const parentListeners = listeners[parentProp] || /* @__PURE__ */ new Set();
|
|
3071
|
+
parentListeners.forEach((componentName) => {
|
|
3072
|
+
const eventName = eventPrefix ? `${eventPrefix}:component-property-changed:${componentName}` : `component-property-changed:${componentName}`;
|
|
3073
|
+
eventDispatcher.emit(eventName, {
|
|
3074
|
+
prop: parentProp,
|
|
3075
|
+
ctx: current
|
|
3076
|
+
});
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
return result;
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
/**
|
|
3084
|
+
* Create a values proxy for component Instance property.
|
|
3085
|
+
*
|
|
3086
|
+
* This proxy provides reactive access to component runtime values,
|
|
3087
|
+
* reading from and writing to a configurable backend store.
|
|
3088
|
+
*
|
|
3089
|
+
* @param component - Component to create values proxy for
|
|
3090
|
+
* @param backend - Backend store interface
|
|
3091
|
+
* @param onValueChange - Callback when value changes
|
|
3092
|
+
* @param cache - Optional WeakMap cache for proxy reuse
|
|
3093
|
+
* @returns Reactive proxy for component values
|
|
3094
|
+
*
|
|
3095
|
+
* @example
|
|
3096
|
+
* ```typescript
|
|
3097
|
+
* // For global RuntimeContext
|
|
3098
|
+
* const proxy = RuntimeContextHelpers.createValuesProxy(component, {
|
|
3099
|
+
* get: (id, prop) => $runtimeValues.get()[id]?.[prop],
|
|
3100
|
+
* set: (id, prop, value) => setComponentRuntimeValue(id, prop, value),
|
|
3101
|
+
* has: (id, prop) => prop in ($runtimeValues.get()[id] || {})
|
|
3102
|
+
* }, (id, prop, value) => {
|
|
3103
|
+
* eventDispatcher.emit(`component:value:set:${id}`, { prop, value });
|
|
3104
|
+
* });
|
|
3105
|
+
*
|
|
3106
|
+
* // For MicroAppRuntimeContext
|
|
3107
|
+
* const proxy = RuntimeContextHelpers.createValuesProxy(component, {
|
|
3108
|
+
* get: (id, prop) => storeContext.getRuntimeValue(id, prop),
|
|
3109
|
+
* set: (id, prop, value) => storeContext.setRuntimeValue(id, prop, value),
|
|
3110
|
+
* has: (id, prop) => storeContext.getRuntimeValue(id, prop) !== undefined
|
|
3111
|
+
* }, (id, prop, value) => {
|
|
3112
|
+
* eventDispatcher.emit(`${eventNamespace}:component-instance-changed:${id}`, { prop, value });
|
|
3113
|
+
* });
|
|
3114
|
+
* ```
|
|
3115
|
+
*/
|
|
3116
|
+
static createValuesProxy(component, backend, onValueChange, cache) {
|
|
3117
|
+
if (cache?.has(component)) {
|
|
3118
|
+
return cache.get(component);
|
|
3119
|
+
}
|
|
3120
|
+
const componentId = component.uuid || component.uniqueUUID;
|
|
3121
|
+
if (!componentId) {
|
|
3122
|
+
console.error("Cannot create values proxy: component UUID is undefined", component);
|
|
3123
|
+
return {};
|
|
3124
|
+
}
|
|
3125
|
+
const valuesProxy = new Proxy({}, {
|
|
3126
|
+
get: (target, prop) => {
|
|
3127
|
+
return backend.get(componentId, prop);
|
|
3128
|
+
},
|
|
3129
|
+
set: (target, prop, value) => {
|
|
3130
|
+
const oldValue = backend.get(componentId, prop);
|
|
3131
|
+
backend.set(componentId, prop, value);
|
|
3132
|
+
if (!deepEqual(oldValue, value)) {
|
|
3133
|
+
onValueChange(componentId, prop, value, oldValue);
|
|
3134
|
+
}
|
|
3135
|
+
return true;
|
|
3136
|
+
},
|
|
3137
|
+
has: (target, prop) => {
|
|
3138
|
+
return backend.has(componentId, prop);
|
|
3139
|
+
},
|
|
3140
|
+
deleteProperty: (target, prop) => {
|
|
3141
|
+
if (backend.delete) {
|
|
3142
|
+
backend.delete(componentId, prop);
|
|
3143
|
+
onValueChange(componentId, prop, void 0);
|
|
3144
|
+
}
|
|
3145
|
+
return true;
|
|
3146
|
+
},
|
|
3147
|
+
ownKeys: (target) => {
|
|
3148
|
+
if (backend.keys) {
|
|
3149
|
+
return backend.keys(componentId);
|
|
3150
|
+
}
|
|
3151
|
+
return [];
|
|
3152
|
+
},
|
|
3153
|
+
getOwnPropertyDescriptor: (target, prop) => {
|
|
3154
|
+
if (backend.has(componentId, prop)) {
|
|
3155
|
+
return {
|
|
3156
|
+
enumerable: true,
|
|
3157
|
+
configurable: true
|
|
3158
|
+
};
|
|
3159
|
+
}
|
|
3160
|
+
return void 0;
|
|
3161
|
+
}
|
|
3162
|
+
});
|
|
3163
|
+
if (cache) {
|
|
3164
|
+
cache.set(component, valuesProxy);
|
|
3165
|
+
}
|
|
3166
|
+
return valuesProxy;
|
|
3167
|
+
}
|
|
3168
|
+
/**
|
|
3169
|
+
* Register component hierarchy (parent-child relationships).
|
|
3170
|
+
*
|
|
3171
|
+
* This shared logic resolves component childrenIds into actual component
|
|
3172
|
+
* references and sets up bidirectional parent-child relationships.
|
|
3173
|
+
*
|
|
3174
|
+
* @param components - Array of components to process
|
|
3175
|
+
* @param getComponentByUUID - Function to retrieve component by UUID
|
|
3176
|
+
* @param debug - Optional debug logging
|
|
3177
|
+
*
|
|
3178
|
+
* @example
|
|
3179
|
+
* ```typescript
|
|
3180
|
+
* RuntimeContextHelpers.registerComponentHierarchy(
|
|
3181
|
+
* components,
|
|
3182
|
+
* (uuid) => this.applications[appUUID][uuid],
|
|
3183
|
+
* DEBUG
|
|
3184
|
+
* );
|
|
3185
|
+
* ```
|
|
3186
|
+
*/
|
|
3187
|
+
static registerComponentHierarchy(components, getComponentByUUID, debug = false) {
|
|
3188
|
+
components.forEach((component) => {
|
|
3189
|
+
if (!component.children) {
|
|
3190
|
+
component.children = [];
|
|
3191
|
+
}
|
|
3192
|
+
if (component.childrenIds && Array.isArray(component.childrenIds) && component.childrenIds.length > 0) {
|
|
3193
|
+
component.children = component.childrenIds.map((childId) => {
|
|
3194
|
+
const child = getComponentByUUID(childId);
|
|
3195
|
+
if (!child && debug) {
|
|
3196
|
+
console.warn(
|
|
3197
|
+
`Warning: Child component with UUID "${childId}" not found for parent "${component.name}" (UUID: ${component.uuid})`
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
return child;
|
|
3201
|
+
}).filter(Boolean);
|
|
3202
|
+
component.children.forEach((child) => {
|
|
3203
|
+
child.parent = component;
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
});
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
const DEBUG = false;
|
|
3211
|
+
class RuntimeContext {
|
|
3212
|
+
/**
|
|
3213
|
+
* Private constructor to enforce singleton pattern.
|
|
3214
|
+
* Initializes the executor system and sets up event listeners.
|
|
3215
|
+
*/
|
|
3216
|
+
constructor() {
|
|
3217
|
+
/** Global context registry */
|
|
3218
|
+
this.context = {};
|
|
3219
|
+
/** Applications registry by ID */
|
|
3220
|
+
this.applications = {};
|
|
3221
|
+
/** Applications registry by name */
|
|
3222
|
+
this.Apps = {};
|
|
3223
|
+
/** Component values registry */
|
|
3224
|
+
this.Values = {};
|
|
3225
|
+
/** Component properties registry */
|
|
3226
|
+
this.Properties = {};
|
|
3227
|
+
/** Variables registry */
|
|
3228
|
+
this.Vars = {};
|
|
3229
|
+
/** Reactive proxy for component properties */
|
|
3230
|
+
this.PropertiesProxy = {};
|
|
3231
|
+
/** Reactive proxy for variables */
|
|
3232
|
+
this.VarsProxy = {};
|
|
3233
|
+
/** Currently active component context */
|
|
3234
|
+
this.Current = {};
|
|
3235
|
+
/** Property change listeners map */
|
|
3236
|
+
this.listeners = {};
|
|
3237
|
+
/** Cache for style proxies to avoid recreation */
|
|
3238
|
+
this.styleProxyCache = /* @__PURE__ */ new WeakMap();
|
|
3239
|
+
/** Cache for values proxies to avoid recreation */
|
|
3240
|
+
this.valuesProxyCache = /* @__PURE__ */ new WeakMap();
|
|
3241
|
+
if (isServer$2) {
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
this.PropertiesProxy = this.createProxy(this.Properties);
|
|
3245
|
+
this.VarsProxy = this.createProxy(this.Vars, "Vars");
|
|
3246
|
+
this.registerContext();
|
|
3247
|
+
$applications.subscribe(() => this.registerApplications());
|
|
3248
|
+
$components.subscribe(() => this.registerApplications());
|
|
3249
|
+
eventDispatcher.on("component:refresh", () => this.registerApplications());
|
|
3250
|
+
eventDispatcher.on("component:updated", () => this.registerApplications());
|
|
3251
|
+
}
|
|
3252
|
+
/**
|
|
3253
|
+
* Updates the editor context with selected components.
|
|
3254
|
+
* Filters the current application's components based on selection state.
|
|
3255
|
+
*/
|
|
3256
|
+
updateEditorContext() {
|
|
3257
|
+
const selectedComponensIds = this.Vars.selectedComponents || [];
|
|
3258
|
+
const currentEditingApplicationUUID = getVar("global", "currentEditingApplication")?.value?.uuid;
|
|
3259
|
+
EditorInstance.Vars = EditorInstance.Vars ?? {};
|
|
3260
|
+
EditorInstance.selectedComponents = this.createProxy(Object.values(this.applications[currentEditingApplicationUUID] || {}).filter((c) => selectedComponensIds.includes(c.uuid)));
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Creates a reactive proxy for the target object.
|
|
3264
|
+
* Tracks property access and changes, triggers events on property updates.
|
|
3265
|
+
*
|
|
3266
|
+
* Uses RuntimeContextHelpers to eliminate code duplication with MicroAppRuntimeContext.
|
|
3267
|
+
*
|
|
3268
|
+
* @param target - Object to be proxied
|
|
3269
|
+
* @param scope - Optional scope name for event namespacing
|
|
3270
|
+
* @returns Reactive proxy for the target object
|
|
3271
|
+
*/
|
|
3272
|
+
createProxy(target, scope) {
|
|
3273
|
+
return RuntimeContextHelpers.createReactiveProxy(target, {
|
|
3274
|
+
eventPrefix: "",
|
|
3275
|
+
// Empty prefix for global context (no scoping)
|
|
3276
|
+
scope,
|
|
3277
|
+
listeners: this.listeners,
|
|
3278
|
+
current: this.Current,
|
|
3279
|
+
onPropertyChange: (prop, value, listeners) => {
|
|
3280
|
+
listeners.forEach((componentName) => {
|
|
3281
|
+
eventDispatcher.emit(`component-property-changed:${componentName}`, {
|
|
3282
|
+
prop,
|
|
3283
|
+
value,
|
|
3284
|
+
// IMPORTANT: Include value in event data
|
|
3285
|
+
ctx: this.Current
|
|
3286
|
+
});
|
|
3287
|
+
});
|
|
3288
|
+
if (scope === "Vars") {
|
|
3289
|
+
eventDispatcher.emit("global:variable:changed", {
|
|
3290
|
+
varName: prop,
|
|
3291
|
+
name: prop,
|
|
3292
|
+
value,
|
|
3293
|
+
oldValue: void 0
|
|
3294
|
+
// Global context doesn't track oldValue
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
},
|
|
3298
|
+
debug: DEBUG
|
|
3299
|
+
});
|
|
3300
|
+
}
|
|
3301
|
+
/**
|
|
3302
|
+
* Attaches a values property to the component that is backed by $runtimeValues.
|
|
3303
|
+
* Creates a reactive proxy that interacts with the global runtime values store.
|
|
3304
|
+
*
|
|
3305
|
+
* Uses RuntimeContextHelpers to eliminate code duplication with MicroAppRuntimeContext.
|
|
3306
|
+
*
|
|
3307
|
+
* @param component - The component to attach the values property to
|
|
3308
|
+
*/
|
|
3309
|
+
attachValuesProperty(component) {
|
|
3310
|
+
const componentId = component.uniqueUUID;
|
|
3311
|
+
if (!componentId) {
|
|
3312
|
+
console.error("Cannot attach values property: component uniqueUUID is undefined");
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3315
|
+
const valuesProxy = RuntimeContextHelpers.createValuesProxy(
|
|
3316
|
+
component,
|
|
3317
|
+
{
|
|
3318
|
+
// Backend: Global runtime values store
|
|
3319
|
+
get: (id, prop) => {
|
|
3320
|
+
const runtimeValues = $runtimeValues.get();
|
|
3321
|
+
return runtimeValues[id]?.[prop];
|
|
3322
|
+
},
|
|
3323
|
+
set: (id, prop, value) => {
|
|
3324
|
+
setComponentRuntimeValue(id, prop, value);
|
|
3325
|
+
},
|
|
3326
|
+
has: (id, prop) => {
|
|
3327
|
+
const runtimeValues = $runtimeValues.get();
|
|
3328
|
+
return prop in (runtimeValues[id] || {});
|
|
3329
|
+
},
|
|
3330
|
+
delete: (id, prop) => {
|
|
3331
|
+
const runtimeValues = $runtimeValues.get();
|
|
3332
|
+
const componentValues = { ...runtimeValues[id] || {} };
|
|
3333
|
+
if (prop in componentValues) {
|
|
3334
|
+
delete componentValues[prop];
|
|
3335
|
+
setComponentRuntimeValues(id, componentValues);
|
|
3336
|
+
eventDispatcher.emit("component:value:remove", { componentId: id, key: prop });
|
|
3337
|
+
}
|
|
3338
|
+
},
|
|
3339
|
+
keys: (id) => {
|
|
3340
|
+
const runtimeValues = $runtimeValues.get();
|
|
3341
|
+
return Object.keys(runtimeValues[id] || {});
|
|
3342
|
+
}
|
|
3343
|
+
},
|
|
3344
|
+
(id, prop, value) => {
|
|
3345
|
+
eventDispatcher.emit(`component:value:set:${id}`, { prop, value });
|
|
3346
|
+
},
|
|
3347
|
+
this.valuesProxyCache
|
|
3348
|
+
);
|
|
3349
|
+
component.Instance = valuesProxy;
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* Creates a proxy for style objects that tracks changes to style properties.
|
|
3353
|
+
* Uses a cache to avoid recreating proxies for the same target objects.
|
|
3354
|
+
*
|
|
3355
|
+
* @param target - The style object to watch
|
|
3356
|
+
* @param callback - Function to call when a style property changes
|
|
3357
|
+
* @returns A proxy that watches for style property changes
|
|
3358
|
+
*/
|
|
3359
|
+
watchStyleChanges(target, callback) {
|
|
3360
|
+
if (typeof target !== "object" || target === null) {
|
|
3361
|
+
return target;
|
|
3362
|
+
}
|
|
3363
|
+
if (this.styleProxyCache.has(target)) {
|
|
3364
|
+
return this.styleProxyCache.get(target);
|
|
3365
|
+
}
|
|
3366
|
+
const proxy = new Proxy(target, {
|
|
3367
|
+
set(obj, prop, value) {
|
|
3368
|
+
if (obj[prop] !== value) {
|
|
3369
|
+
console.log(`Style property changed: ${prop} = ${value}`);
|
|
3370
|
+
callback(prop, value);
|
|
3371
|
+
}
|
|
3372
|
+
obj[prop] = value;
|
|
3373
|
+
return true;
|
|
3374
|
+
}
|
|
3375
|
+
});
|
|
3376
|
+
this.styleProxyCache.set(target, proxy);
|
|
3377
|
+
return proxy;
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* Get component by UUID.
|
|
3381
|
+
* Searches through all applications to find a component by its UUID.
|
|
3382
|
+
*
|
|
3383
|
+
* @param uuid - Component UUID to find
|
|
3384
|
+
* @returns Component element or undefined if not found
|
|
3385
|
+
*/
|
|
3386
|
+
getComponentByUUID(uuid) {
|
|
3387
|
+
for (const appId in this.applications) {
|
|
3388
|
+
const appComponents = this.applications[appId];
|
|
3389
|
+
for (const componentName in appComponents) {
|
|
3390
|
+
const component = appComponents[componentName];
|
|
3391
|
+
if (component.uuid === uuid) {
|
|
3392
|
+
return component;
|
|
3393
|
+
}
|
|
3394
|
+
const found = this.findComponentInChildren(component, uuid);
|
|
3395
|
+
if (found) return found;
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
return void 0;
|
|
3399
|
+
}
|
|
3400
|
+
/**
|
|
3401
|
+
* Recursively search for component in children.
|
|
3402
|
+
*
|
|
3403
|
+
* @param parent - Parent component to search in
|
|
3404
|
+
* @param uuid - UUID to find
|
|
3405
|
+
* @returns Component or undefined
|
|
3406
|
+
*/
|
|
3407
|
+
findComponentInChildren(parent, uuid) {
|
|
3408
|
+
if (!parent.children || parent.children.length === 0) {
|
|
3409
|
+
return void 0;
|
|
3410
|
+
}
|
|
3411
|
+
for (const child of parent.children) {
|
|
3412
|
+
if (child.uuid === uuid) {
|
|
3413
|
+
return child;
|
|
3414
|
+
}
|
|
3415
|
+
const found = this.findComponentInChildren(child, uuid);
|
|
3416
|
+
if (found) return found;
|
|
3417
|
+
}
|
|
3418
|
+
return void 0;
|
|
3419
|
+
}
|
|
3420
|
+
/**
|
|
3421
|
+
* Get component by name.
|
|
3422
|
+
*
|
|
3423
|
+
* @param name - Component name
|
|
3424
|
+
* @param appId - Optional application ID (uses first available app if not provided)
|
|
3425
|
+
* @returns Component element or undefined if not found
|
|
3426
|
+
*/
|
|
3427
|
+
getComponent(name, appId) {
|
|
3428
|
+
if (appId) {
|
|
3429
|
+
return this.applications[appId]?.[name];
|
|
3430
|
+
}
|
|
3431
|
+
for (const applicationId in this.applications) {
|
|
3432
|
+
const component = this.applications[applicationId][name];
|
|
3433
|
+
if (component) return component;
|
|
3434
|
+
}
|
|
3435
|
+
return void 0;
|
|
3436
|
+
}
|
|
3437
|
+
/**
|
|
3438
|
+
* Set variable value.
|
|
3439
|
+
* Updates the variable in the reactive proxy, triggering change events.
|
|
3440
|
+
*
|
|
3441
|
+
* @param name - Variable name
|
|
3442
|
+
* @param value - Value to set
|
|
3443
|
+
*/
|
|
3444
|
+
setVar(name, value) {
|
|
3445
|
+
this.VarsProxy[name] = value;
|
|
3446
|
+
}
|
|
3447
|
+
/**
|
|
3448
|
+
* Set component runtime style attribute.
|
|
3449
|
+
* Updates the component's runtime styles and triggers re-render.
|
|
3450
|
+
*
|
|
3451
|
+
* @param componentId - Component unique UUID
|
|
3452
|
+
* @param attribute - Style attribute name (e.g., 'backgroundColor')
|
|
3453
|
+
* @param value - Style value
|
|
3454
|
+
*/
|
|
3455
|
+
setComponentRuntimeStyleAttribute(componentId, attribute, value) {
|
|
3456
|
+
setcomponentRuntimeStyleAttribute(componentId, attribute, value);
|
|
3457
|
+
}
|
|
3458
|
+
/**
|
|
3459
|
+
* Gets the singleton instance of the RuntimeContext class.
|
|
3460
|
+
* Creates it if it doesn't exist yet.
|
|
3461
|
+
*
|
|
3462
|
+
* @returns The singleton RuntimeContext instance
|
|
3463
|
+
*/
|
|
3464
|
+
static getInstance() {
|
|
3465
|
+
if (!RuntimeContext.instance) {
|
|
3466
|
+
RuntimeContext.instance = new RuntimeContext();
|
|
3467
|
+
}
|
|
3468
|
+
return RuntimeContext.instance;
|
|
3469
|
+
}
|
|
3470
|
+
/**
|
|
3471
|
+
* Registers the global context.
|
|
3472
|
+
* Sets up a listener for context changes and updates the internal context.
|
|
3473
|
+
*/
|
|
3474
|
+
registerContext() {
|
|
3475
|
+
$context.listen((context) => {
|
|
3476
|
+
Object.assign(this.context, context);
|
|
3477
|
+
});
|
|
3478
|
+
}
|
|
3479
|
+
/**
|
|
3480
|
+
* Registers all applications and their components.
|
|
3481
|
+
* Builds the component hierarchy, initializes runtime values,
|
|
3482
|
+
* and sets up component relationships.
|
|
3483
|
+
*/
|
|
3484
|
+
registerApplications() {
|
|
3485
|
+
const components = $components.get();
|
|
3486
|
+
const componentsList = Object.values(components).flat();
|
|
3487
|
+
const runtimeValues = $runtimeValues.get();
|
|
3488
|
+
const loadedApplications = $applications.get();
|
|
3489
|
+
const loadedApplicationObj = {};
|
|
3490
|
+
loadedApplications.forEach((app) => {
|
|
3491
|
+
loadedApplicationObj[app.uuid] = app.name;
|
|
3492
|
+
});
|
|
3493
|
+
componentsList.forEach((component) => {
|
|
3494
|
+
const application_id = component.application_id || component.application_id;
|
|
3495
|
+
if (!this.context[application_id]) {
|
|
3496
|
+
this.context[application_id] = {};
|
|
3497
|
+
}
|
|
3498
|
+
if (!this.context[application_id][component.uuid]) {
|
|
3499
|
+
this.context[application_id][component.uuid] = { ...component };
|
|
3500
|
+
}
|
|
3501
|
+
if (!this.applications[application_id]) {
|
|
3502
|
+
this.applications[application_id] = {};
|
|
3503
|
+
}
|
|
3504
|
+
if (!this.Apps[loadedApplicationObj[application_id]]) {
|
|
3505
|
+
this.Apps[loadedApplicationObj[application_id]] = {};
|
|
3506
|
+
}
|
|
3507
|
+
component.children = [];
|
|
3508
|
+
this.Apps[loadedApplicationObj[application_id]][component.name] = component;
|
|
3509
|
+
this.applications[application_id][component.name] = component;
|
|
3510
|
+
if (component.uniqueUUID) {
|
|
3511
|
+
const existingValues = runtimeValues[component.uniqueUUID] || {};
|
|
3512
|
+
const initialValues = component.Instance || {};
|
|
3513
|
+
if (Object.keys(initialValues).length > 0) {
|
|
3514
|
+
const mergedValues = { ...existingValues, ...initialValues };
|
|
3515
|
+
if (JSON.stringify(existingValues) !== JSON.stringify(mergedValues)) {
|
|
3516
|
+
setComponentRuntimeValues(component.uniqueUUID, mergedValues);
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
this.attachValuesProperty(component);
|
|
3520
|
+
}
|
|
3521
|
+
});
|
|
3522
|
+
componentsList.forEach((component) => {
|
|
3523
|
+
if (component.childrenIds && Array.isArray(component.childrenIds) && component.childrenIds.length > 0) {
|
|
3524
|
+
component.childrenIds.forEach((childId) => {
|
|
3525
|
+
const childComponent = componentsList.find((c) => c.uuid === childId);
|
|
3526
|
+
if (childComponent) {
|
|
3527
|
+
component.children.push(childComponent);
|
|
3528
|
+
childComponent.parent = component;
|
|
3529
|
+
}
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
});
|
|
3533
|
+
EditorInstance.components = componentsList;
|
|
3534
|
+
this.PropertiesProxy = componentsList;
|
|
3535
|
+
this.updateEditorContext();
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
const RuntimeInstance = RuntimeContext.getInstance();
|
|
3539
|
+
RuntimeInstance.setcomponentRuntimeStyleAttribute = setcomponentRuntimeStyleAttribute;
|
|
3540
|
+
if (!isServer$2) {
|
|
3541
|
+
globalThis.__NURALY_EXECUTE_INSTANCE__ = RuntimeInstance;
|
|
3542
|
+
}
|
|
3543
|
+
const ExecuteInstance = RuntimeInstance;
|
|
3544
|
+
|
|
3545
|
+
const $debug = atom(
|
|
3546
|
+
{
|
|
3547
|
+
error: {
|
|
3548
|
+
components: {}
|
|
3549
|
+
// functions : {},
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
);
|
|
3553
|
+
keepMount($debug);
|
|
3554
|
+
|
|
3555
|
+
const $providers = atom([]);
|
|
3556
|
+
persistentAtom("$activeTables", {}, {
|
|
3557
|
+
encode: JSON.stringify,
|
|
3558
|
+
decode: JSON.parse
|
|
3559
|
+
});
|
|
3560
|
+
|
|
3561
|
+
function setContextMenuEvent(e) {
|
|
3562
|
+
$contextMenuEvent.set(e);
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
function setResizing(isResizing) {
|
|
3566
|
+
$resizing.set(isResizing);
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
function addGeneratedComponents(structureComponent) {
|
|
3570
|
+
structureComponent.forEach((component) => {
|
|
3571
|
+
addComponentAction(
|
|
3572
|
+
component,
|
|
3573
|
+
getVar("global", "currentPage").value,
|
|
3574
|
+
getVar("global", "currentEditingApplication").value.uuid
|
|
3575
|
+
);
|
|
3576
|
+
});
|
|
3577
|
+
setTimeout(() => {
|
|
3578
|
+
eventDispatcher.emit("component:refresh");
|
|
3579
|
+
}, 1e3);
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
function addlogDebug({
|
|
3583
|
+
errors
|
|
3584
|
+
}) {
|
|
3585
|
+
const debug = $debug.get();
|
|
3586
|
+
$debug.set({
|
|
3587
|
+
error: {
|
|
3588
|
+
components: {
|
|
3589
|
+
...debug.error?.components || {},
|
|
3590
|
+
[errors.component.uuid]: errors.component
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
});
|
|
3594
|
+
}
|
|
3595
|
+
function resetComponentDebug() {
|
|
3596
|
+
$debug.get();
|
|
3597
|
+
$debug.set({
|
|
3598
|
+
error: {
|
|
3599
|
+
components: {}
|
|
3600
|
+
}
|
|
3601
|
+
});
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3604
|
+
const setupChangeDetection = () => {
|
|
3605
|
+
eventDispatcher.onAny((eventName, { ctx } = {}) => {
|
|
3606
|
+
if (eventName.startsWith("ccomponent-property-changed")) {
|
|
3607
|
+
const chdilrensComponent = getAllChildrenRecursive(ctx.application_id, ctx.uuid).get();
|
|
3608
|
+
chdilrensComponent.forEach((component) => {
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
});
|
|
3612
|
+
};
|
|
3613
|
+
|
|
3614
|
+
const selectTemplate = (props, isViewMode) => html`<select-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></select-block>`;
|
|
3615
|
+
const iconButtonTemplate = (props, isViewMode) => html`<icon-button-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></icon-button-block>`;
|
|
3616
|
+
const colorPickerTemplate = (props, isViewMode) => html`<color-picker-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></color-picker-block>`;
|
|
3617
|
+
const numberInputTemplate = (props, isViewMode) => html`<number-input-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></number-input-block>`;
|
|
3618
|
+
const shadowBoxTemplate = (props, isViewMode) => html`<attribute-box-shadow-value .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></attribute-box-shadow-value>`;
|
|
3619
|
+
const borderRadiusTemplate = (props, isViewMode) => html`<attribute-border-value .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></attribute-border-value>`;
|
|
3620
|
+
const boxModelTemplate = (props, isViewMode) => html`<box-model-display .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></box-model-display>`;
|
|
3621
|
+
const eventTemplate = (props, isViewMode) => html`<parameter-event-handler .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></parameter-event-handler>`;
|
|
3622
|
+
const tableTemplate = (props, isViewMode) => html`<table-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></table-block>`;
|
|
3623
|
+
const textInputTemplate = (props, isViewMode) => html`<text-input-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></text-input-block>`;
|
|
3624
|
+
const textLabelTemplate = (props, isViewMode) => html`<text-label-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></text-label-block>`;
|
|
3625
|
+
const buttonTemplate = (props, isViewMode) => html`<button-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></button-block>`;
|
|
3626
|
+
const tabsTemplate = (props, isViewMode) => html`<tabs-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></tabs-block>`;
|
|
3627
|
+
const menuTemplate = (props, isViewMode) => html`<menu-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></menu-block>`;
|
|
3628
|
+
const verticalContainerTemplate = (props, isViewMode) => html`<vertical-container-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></vertical-container-block>`;
|
|
3629
|
+
const collectionViewerTemplate = (props, isViewMode) => html`<collection-viewer .isViewMode=${isViewMode} .parentcomponent=${props.parent} .component=${props.component}></collection-viewer>`;
|
|
3630
|
+
const checkboxTemplate = (props, isViewMode) => html`<checkbox-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></checkbox-block>`;
|
|
3631
|
+
const datePickerTemplate = (props, isViewMode) => html`<date-picker-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></date-picker-block>`;
|
|
3632
|
+
const iconTemplate = (props, isViewMode) => html`<icon-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></icon-block>`;
|
|
3633
|
+
const imageTemplate = (props, isViewMode) => html`<image-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></image-block>`;
|
|
3634
|
+
const radioButtonTemplate = (props, isViewMode) => html`<radio-button-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></radio-button-block>`;
|
|
3635
|
+
const aiTemplate = (props, isViewMode) => html`<ai-chat-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></ai-chat-block>`;
|
|
3636
|
+
const iconPickerTemplate = (props, isViewMode) => html`<icon-picker-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></icon-picker-block>`;
|
|
3637
|
+
const usersDropdownTemplate = (props, isViewMode) => html`<users-dropdown-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></users-dropdown-block>`;
|
|
3638
|
+
const insertDropdownTemplate = (props, isViewMode) => html`<insert-dropdown-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></insert-dropdown-block>`;
|
|
3639
|
+
const microAppTemplate = (props, isViewMode) => html`<micro-app-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></micro-app-block>`;
|
|
3640
|
+
const collapseTemplate = (props, isViewMode) => html`<collapse-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></collapse-block>`;
|
|
3641
|
+
const dividerTemplate = (props, isViewMode) => html`<divider-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></divider-block>`;
|
|
3642
|
+
const handlersTemplate = (props, isViewMode) => html`<handler-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></handler-block>`;
|
|
3643
|
+
const dropDownTemplate = (props, isViewMode) => html`<dropdown-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></dropdown-block>`;
|
|
3644
|
+
const refComponentTemplate = (props, isViewMode) => html`<ref-component-container-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></ref-component-container-block>`;
|
|
3645
|
+
const codeTemplate = (props, isViewMode) => html`<code-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></code-block>`;
|
|
3646
|
+
const richTextTemplate = (props, isViewMode) => html`<rich-text-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></rich-text-block>`;
|
|
3647
|
+
const embedURLTemplate = (props, isViewMode) => html`<embed-url-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></embed-url-block>`;
|
|
3648
|
+
const linkTemplate = (props, isViewMode) => html`<link-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></link-block>`;
|
|
3649
|
+
const fileUploadTemplate = (props, isViewMode) => html`<file-upload-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></file-upload-block>`;
|
|
3650
|
+
const videoTemplate = (props, isViewMode) => html`<video-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></video-block>`;
|
|
3651
|
+
const documentTemplate = (props, isViewMode) => html`<document-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></document-block>`;
|
|
3652
|
+
const textareaTemplate = (props, isViewMode) => html`<textarea-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></textarea-block>`;
|
|
3653
|
+
const badgeTemplate = (props, isViewMode) => html`<badge-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></badge-block>`;
|
|
3654
|
+
const cardTemplate = (props, isViewMode) => html`<card-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></card-block>`;
|
|
3655
|
+
const tagTemplate = (props, isViewMode) => html`<tag-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></tag-block>`;
|
|
3656
|
+
const sliderTemplate = (props, isViewMode) => html`<slider-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></slider-block>`;
|
|
3657
|
+
const panelTemplate = (props, isViewMode) => html`<panel-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></panel-block>`;
|
|
3658
|
+
const invokeFunctionTemplate = (props, isViewMode) => html`
|
|
3659
|
+
<invoke-function-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></invoke-function-block>
|
|
3660
|
+
`;
|
|
3661
|
+
const importExportTemplate = (props, isViewMode) => html`
|
|
3662
|
+
<export-import-block .isViewMode=${isViewMode} .parentcomponent=${props.parent} .item=${props.item} .component=${props.component}></export-import-block>
|
|
3663
|
+
`;
|
|
3664
|
+
function renderComponentElement(component, commonProps, isViewMode) {
|
|
3665
|
+
const template = getComponentTemplate(component, commonProps, isViewMode);
|
|
3666
|
+
return html`${template}`;
|
|
3667
|
+
}
|
|
3668
|
+
function getComponentTemplate(component, commonProps, isViewMode) {
|
|
3669
|
+
switch (component?.component_type) {
|
|
3670
|
+
case ComponentType.Event:
|
|
3671
|
+
return eventTemplate(commonProps, isViewMode);
|
|
3672
|
+
case ComponentType.BorderRadius:
|
|
3673
|
+
return borderRadiusTemplate(commonProps, isViewMode);
|
|
3674
|
+
case ComponentType.BoxModel:
|
|
3675
|
+
return boxModelTemplate(commonProps, isViewMode);
|
|
3676
|
+
case ComponentType.ShadowBox:
|
|
3677
|
+
return shadowBoxTemplate(commonProps, isViewMode);
|
|
3678
|
+
case ComponentType.Select:
|
|
3679
|
+
return selectTemplate(commonProps, isViewMode);
|
|
3680
|
+
case ComponentType.IconButton:
|
|
3681
|
+
return iconButtonTemplate(commonProps, isViewMode);
|
|
3682
|
+
case ComponentType.ColorPicker:
|
|
3683
|
+
return colorPickerTemplate(commonProps, isViewMode);
|
|
3684
|
+
case ComponentType.NumberInput:
|
|
3685
|
+
return numberInputTemplate(commonProps, isViewMode);
|
|
3686
|
+
case ComponentType.TextInput:
|
|
3687
|
+
return textInputTemplate(commonProps, isViewMode);
|
|
3688
|
+
case ComponentType.TextLabel:
|
|
3689
|
+
return textLabelTemplate(commonProps, isViewMode);
|
|
3690
|
+
case ComponentType.Button:
|
|
3691
|
+
return buttonTemplate(commonProps, isViewMode);
|
|
3692
|
+
case ComponentType.Tabs:
|
|
3693
|
+
return tabsTemplate(commonProps, isViewMode);
|
|
3694
|
+
case ComponentType.Menu:
|
|
3695
|
+
return menuTemplate(commonProps, isViewMode);
|
|
3696
|
+
case ComponentType.Table:
|
|
3697
|
+
return tableTemplate(commonProps, isViewMode);
|
|
3698
|
+
case ComponentType.Container:
|
|
3699
|
+
return verticalContainerTemplate(commonProps, isViewMode);
|
|
3700
|
+
case ComponentType.Collection:
|
|
3701
|
+
return collectionViewerTemplate(commonProps, isViewMode);
|
|
3702
|
+
case ComponentType.Checkbox:
|
|
3703
|
+
return checkboxTemplate(commonProps, isViewMode);
|
|
3704
|
+
case ComponentType.DatePicker:
|
|
3705
|
+
return datePickerTemplate(commonProps, isViewMode);
|
|
3706
|
+
case ComponentType.Divider:
|
|
3707
|
+
return dividerTemplate(commonProps, isViewMode);
|
|
3708
|
+
case ComponentType.Icon:
|
|
3709
|
+
return iconTemplate(commonProps, isViewMode);
|
|
3710
|
+
case ComponentType.Image:
|
|
3711
|
+
return imageTemplate(commonProps, isViewMode);
|
|
3712
|
+
case ComponentType.RadioButton:
|
|
3713
|
+
return radioButtonTemplate(commonProps, isViewMode);
|
|
3714
|
+
case ComponentType.AI:
|
|
3715
|
+
return aiTemplate(commonProps, isViewMode);
|
|
3716
|
+
case ComponentType.IconPicker:
|
|
3717
|
+
return iconPickerTemplate(commonProps, isViewMode);
|
|
3718
|
+
case ComponentType.MicroApp:
|
|
3719
|
+
return microAppTemplate(commonProps, isViewMode);
|
|
3720
|
+
case ComponentType.UsersDropdown:
|
|
3721
|
+
return usersDropdownTemplate(commonProps, isViewMode);
|
|
3722
|
+
case ComponentType.InsertDropdown:
|
|
3723
|
+
return insertDropdownTemplate(commonProps, isViewMode);
|
|
3724
|
+
case ComponentType.Collapse:
|
|
3725
|
+
return collapseTemplate(commonProps, isViewMode);
|
|
3726
|
+
case ComponentType.Handlers:
|
|
3727
|
+
return handlersTemplate(commonProps, isViewMode);
|
|
3728
|
+
case ComponentType.ExportImport:
|
|
3729
|
+
return importExportTemplate(commonProps, isViewMode);
|
|
3730
|
+
case ComponentType.InvokeFunction:
|
|
3731
|
+
return invokeFunctionTemplate(commonProps, isViewMode);
|
|
3732
|
+
case ComponentType.Dropdown:
|
|
3733
|
+
return dropDownTemplate(commonProps, isViewMode);
|
|
3734
|
+
case ComponentType.RefComponent:
|
|
3735
|
+
return refComponentTemplate(commonProps, isViewMode);
|
|
3736
|
+
case ComponentType.Code:
|
|
3737
|
+
return codeTemplate(commonProps, isViewMode);
|
|
3738
|
+
case ComponentType.RichText:
|
|
3739
|
+
return richTextTemplate(commonProps, isViewMode);
|
|
3740
|
+
case ComponentType.EmbedURL:
|
|
3741
|
+
return embedURLTemplate(commonProps, isViewMode);
|
|
3742
|
+
case ComponentType.Link:
|
|
3743
|
+
return linkTemplate(commonProps, isViewMode);
|
|
3744
|
+
case ComponentType.FileUpload:
|
|
3745
|
+
return fileUploadTemplate(commonProps, isViewMode);
|
|
3746
|
+
case ComponentType.Video:
|
|
3747
|
+
return videoTemplate(commonProps, isViewMode);
|
|
3748
|
+
case ComponentType.Document:
|
|
3749
|
+
return documentTemplate(commonProps, isViewMode);
|
|
3750
|
+
case ComponentType.Textarea:
|
|
3751
|
+
return textareaTemplate(commonProps, isViewMode);
|
|
3752
|
+
case ComponentType.Badge:
|
|
3753
|
+
return badgeTemplate(commonProps, isViewMode);
|
|
3754
|
+
case ComponentType.Card:
|
|
3755
|
+
return cardTemplate(commonProps, isViewMode);
|
|
3756
|
+
case ComponentType.Tag:
|
|
3757
|
+
return tagTemplate(commonProps, isViewMode);
|
|
3758
|
+
case ComponentType.Slider:
|
|
3759
|
+
return sliderTemplate(commonProps, isViewMode);
|
|
3760
|
+
case ComponentType.Panel:
|
|
3761
|
+
return panelTemplate(commonProps, isViewMode);
|
|
3762
|
+
default:
|
|
3763
|
+
return html``;
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
function renderComponent(components, item, isViewMode, parent) {
|
|
3767
|
+
if (!components || !components.length) return html``;
|
|
3768
|
+
return html`
|
|
3769
|
+
${components.map((component) => {
|
|
3770
|
+
const commonProps = { item: { ...item }, component, parent: { ...parent } };
|
|
3771
|
+
return renderComponentElement(component, commonProps, isViewMode);
|
|
3772
|
+
})}
|
|
3773
|
+
`;
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3776
|
+
const LOG_LEVELS = {
|
|
3777
|
+
ERROR: 0,
|
|
3778
|
+
WARN: 1,
|
|
3779
|
+
INFO: 2,
|
|
3780
|
+
DEBUG: 3,
|
|
3781
|
+
EXECUTION_TIME: 3
|
|
3782
|
+
};
|
|
3783
|
+
let logLevel = LOG_LEVELS.INFO;
|
|
3784
|
+
let loggingEnabled = false;
|
|
3785
|
+
let currentPrefix = "";
|
|
3786
|
+
function setLogLevel(level) {
|
|
3787
|
+
logLevel = level;
|
|
3788
|
+
}
|
|
3789
|
+
function enableLogging(enabled) {
|
|
3790
|
+
loggingEnabled = enabled;
|
|
3791
|
+
}
|
|
3792
|
+
function enableBenchmarking(enabled) {
|
|
3793
|
+
}
|
|
3794
|
+
function logMessage(level, message, ...args) {
|
|
3795
|
+
if (!loggingEnabled || level > logLevel) return;
|
|
3796
|
+
const styles = {
|
|
3797
|
+
[LOG_LEVELS.ERROR]: "background: #FF6347; color: white; padding: 2px; border-radius: 3px;",
|
|
3798
|
+
// Tomato
|
|
3799
|
+
[LOG_LEVELS.WARN]: "background: #FFD700; color: black; padding: 2px; border-radius: 3px;",
|
|
3800
|
+
// Gold
|
|
3801
|
+
[LOG_LEVELS.INFO]: "background: #4682B4; color: white; padding: 2px; border-radius: 3px;",
|
|
3802
|
+
// SteelBlue
|
|
3803
|
+
[LOG_LEVELS.DEBUG]: "background: #D1D1D1; color: black; padding: 2px; border-radius: 3px;",
|
|
3804
|
+
// LightGray
|
|
3805
|
+
[LOG_LEVELS.EXECUTION_TIME]: "background: #90EE90; color: black; padding: 2px; border-radius: 3px;"
|
|
3806
|
+
// LightGreen
|
|
3807
|
+
};
|
|
3808
|
+
const prefixStyle = "background: #8A2BE2; color: white; padding: 2px; border-radius: 3px;";
|
|
3809
|
+
if (currentPrefix) {
|
|
3810
|
+
console.log(`%c${currentPrefix} %c${message}`, prefixStyle, styles[level], ...args);
|
|
3811
|
+
currentPrefix = "";
|
|
3812
|
+
} else {
|
|
3813
|
+
console.log(`%c${message}`, styles[level], ...args);
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
const log = {
|
|
3817
|
+
error: (message, ...args) => logMessage(LOG_LEVELS.ERROR, message, ...args),
|
|
3818
|
+
warn: (message, ...args) => logMessage(LOG_LEVELS.WARN, message, ...args),
|
|
3819
|
+
info: (message, ...args) => logMessage(LOG_LEVELS.INFO, message, ...args),
|
|
3820
|
+
debug: (message, ...args) => logMessage(LOG_LEVELS.DEBUG, message, ...args),
|
|
3821
|
+
executionTime: (message, ...args) => logMessage(LOG_LEVELS.EXECUTION_TIME, message, ...args),
|
|
3822
|
+
prefix: (prefix) => {
|
|
3823
|
+
currentPrefix = prefix;
|
|
3824
|
+
return log;
|
|
3825
|
+
}
|
|
3826
|
+
};
|
|
3827
|
+
|
|
3828
|
+
function getNestedAttribute(obj, path) {
|
|
3829
|
+
return path.split(".").reduce((acc, key) => {
|
|
3830
|
+
return acc && acc[key] !== void 0 ? acc[key] : void 0;
|
|
3831
|
+
}, obj);
|
|
3832
|
+
}
|
|
3833
|
+
function hasOnlyEmptyObjects(error) {
|
|
3834
|
+
if (!error || Object.keys(error).length === 0) {
|
|
3835
|
+
return true;
|
|
3836
|
+
}
|
|
3837
|
+
return Object.values(error).every(
|
|
3838
|
+
(value) => typeof value === "object" && value !== null && Object.keys(value).length === 0
|
|
3839
|
+
);
|
|
3840
|
+
}
|
|
3841
|
+
|
|
3842
|
+
const NO_EVENT_LISTENER = "";
|
|
3843
|
+
const EMPTY_STRING = "";
|
|
3844
|
+
|
|
3845
|
+
setupChangeDetection();
|
|
3846
|
+
|
|
3847
|
+
export { $components as $, APIS_URL as A, $runtimeStyles as B, $runtimeValues as C, $componentRuntimeValuesById as D, ExecuteInstance as E, FRONT_API_URLS as F, $componentRuntimeValueByKey as G, $componentsByUUIDs as H, $runtimeStylescomponentStyleByID as I, getAllChildrenRecursive as J, getDirectChildren as K, $componentById as L, setComponentRuntimeValue as M, setComponentRuntimeValues as N, setcomponentRuntimeStyleAttribute as O, clearComponentRuntimeValues as P, clearComponentRuntimeValue as Q, RuntimeInstance as R, clearAllRuntimeValues as S, clearComponentRuntimeStyleAttributes as T, fillComponentChildren as U, fillApplicationComponents as V, extractChildresIds as W, extractAllChildrenIds as X, $applications as Y, $resizing as Z, $currentPage as _, $hoveredComponentId as a, isForbiddenProperty as a$, $contextMenuEvent as a0, $microAppCurrentPage as a1, $applicationPages as a2, refreshPageStoreVar as a3, $context as a4, ViewMode as a5, $toasts as a6, $debug as a7, $providers as a8, executeHandler as a9, addComponentHandler as aA, deleteComponentActionHandler as aB, validateAndEmitErrors as aC, updatePageHandler as aD, deletePageHandler as aE, refreshPagesActionHandler as aF, loadOrRefreshApplications as aG, createApplicationAction as aH, deleteApplicationAction as aI, addPermission as aJ, invokeFunctionHandler as aK, loadFunctionsHandler as aL, renderComponent as aM, log as aN, setLogLevel as aO, enableLogging as aP, enableBenchmarking as aQ, LOG_LEVELS as aR, eventDispatcher as aS, copyCpmponentToClipboard as aT, pasteComponentFromClipboard as aU, traitCompoentFromSchema as aV, generateNuralyClipboardStructure as aW, RuntimeContextHelpers as aX, validateHandlerCode as aY, validateComponentHandlers as aZ, isForbiddenGlobal as a_, getContextFromComponent as aa, compileHandlerFunction as ab, addComponentAction as ac, addComponentToCurrentPageAction as ad, deleteComponentAction as ae, moveDraggedComponent as af, setCurrentComponentIdAction as ag, setDraggingComponentInfo as ah, setHoveredComponentAction as ai, updateComponentName as aj, updateComponentAttributes as ak, deletePageAction as al, setContextMenuEvent as am, setResizing as an, updatePageAction as ao, addPageToApplicationAction as ap, addTempApplication as aq, setApplication as ar, setPermissionMessage as as, updateApplication as at, closeCreateApplicationModalAction as au, openEditorTab as av, setCurrentEditorTab as aw, addGeneratedComponents as ax, addlogDebug as ay, resetComponentDebug as az, $showShareApplicationModal as b, isAllowedGlobal as b0, isForbiddenFunction as b1, getErrorMessage as b2, FORBIDDEN_GLOBALS as b3, FORBIDDEN_PROPERTIES as b4, FORBIDDEN_FUNCTIONS as b5, VALIDATION_ERROR_MESSAGES as b6, formatValidationErrors as b7, getNestedAttribute as b8, hasOnlyEmptyObjects as b9, GenerateName as ba, NO_EVENT_LISTENER as bb, EMPTY_STRING as bc, isServer$2 as bd, getInitPlatform as be, ComponentType as bf, getVar as bg, setVar as bh, hideToast as bi, $applicationPermission as c, $permissionsState as d, $currentApplication as e, updateApplicationActionHandler as f, $showCreateApplicationModal as g, $editorState as h, $environment as i, addPageHandler as j, $currentPageId as k, $currentPageViewPort as l, $showBorder as m, $pageSize as n, $pages as o, $pageZoom as p, EditorInstance as q, removeComponentToCurrentPageAction as r, RuntimeHelpers as s, $applicationComponents as t, updateComponentHandler as u, $selectedComponent as v, $currentComponentId as w, $hoveredComponent as x, $draggingComponentInfo as y, $componentWithChildren as z };
|