@atomm-developer/generator-workbench 0.1.0 → 0.1.2
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/README.md +31 -3
- package/dist/index.d.ts +39 -6
- package/dist/index.es.js +1136 -309
- package/dist/index.umd.js +1 -1
- package/package.json +3 -2
package/dist/index.es.js
CHANGED
|
@@ -21,6 +21,22 @@ function createAuthController(args) {
|
|
|
21
21
|
}
|
|
22
22
|
function createExportController(args) {
|
|
23
23
|
const { sdk, runtime, config, element } = args;
|
|
24
|
+
async function ensureLoggedIn() {
|
|
25
|
+
if (sdk.auth.getStatus().isLogin) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await sdk.auth.login();
|
|
29
|
+
if (!sdk.auth.getStatus().isLogin) {
|
|
30
|
+
throw new Error("[generator-workbench] login is required before export");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function consumeBilling() {
|
|
34
|
+
var _a;
|
|
35
|
+
if (!((_a = sdk.billing) == null ? void 0 : _a.consume)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await sdk.billing.consume();
|
|
39
|
+
}
|
|
24
40
|
return {
|
|
25
41
|
async exportSvg() {
|
|
26
42
|
var _a;
|
|
@@ -29,6 +45,8 @@ function createExportController(args) {
|
|
|
29
45
|
runtime,
|
|
30
46
|
element
|
|
31
47
|
}));
|
|
48
|
+
await ensureLoggedIn();
|
|
49
|
+
await consumeBilling();
|
|
32
50
|
return sdk.export.download({ format: "svg" });
|
|
33
51
|
},
|
|
34
52
|
async openInStudio() {
|
|
@@ -38,6 +56,8 @@ function createExportController(args) {
|
|
|
38
56
|
runtime,
|
|
39
57
|
element
|
|
40
58
|
}));
|
|
59
|
+
await ensureLoggedIn();
|
|
60
|
+
await consumeBilling();
|
|
41
61
|
return sdk.export.openInStudio({ format: "svg" });
|
|
42
62
|
}
|
|
43
63
|
};
|
|
@@ -86,12 +106,35 @@ function assert(condition, message) {
|
|
|
86
106
|
throw new Error(message);
|
|
87
107
|
}
|
|
88
108
|
}
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
function collectPanelFieldGroups(panelSchema, allowedFieldPaths) {
|
|
110
|
+
const allowedPathSet = (allowedFieldPaths == null ? void 0 : allowedFieldPaths.length) ? new Set(allowedFieldPaths) : null;
|
|
111
|
+
return panelSchema.groups.map((group) => {
|
|
112
|
+
var _a;
|
|
113
|
+
const fields = group.fields.map((field) => {
|
|
114
|
+
var _a2, _b, _c;
|
|
115
|
+
const path = (_b = (_a2 = field.bind) == null ? void 0 : _a2.path) == null ? void 0 : _b.trim();
|
|
116
|
+
if (!path) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (allowedPathSet && !allowedPathSet.has(path)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
id: field.id,
|
|
124
|
+
label: ((_c = field.label) == null ? void 0 : _c.trim()) || field.id || path,
|
|
125
|
+
path
|
|
126
|
+
};
|
|
127
|
+
}).filter((field) => Boolean(field));
|
|
128
|
+
return {
|
|
129
|
+
id: group.id,
|
|
130
|
+
title: ((_a = group.title) == null ? void 0 : _a.trim()) || group.id,
|
|
131
|
+
fields
|
|
132
|
+
};
|
|
133
|
+
}).filter((group) => group.fields.length > 0);
|
|
134
|
+
}
|
|
135
|
+
function collectPanelFieldPaths(panelSchema, allowedFieldPaths) {
|
|
136
|
+
return collectPanelFieldGroups(panelSchema, allowedFieldPaths).flatMap(
|
|
137
|
+
(group) => group.fields.map((field) => field.path)
|
|
95
138
|
);
|
|
96
139
|
}
|
|
97
140
|
function resolveGeneratorId(panelSchema, state) {
|
|
@@ -109,6 +152,27 @@ function resolveGeneratorId(panelSchema, state) {
|
|
|
109
152
|
}
|
|
110
153
|
function createTemplateController(args) {
|
|
111
154
|
const { sdk, runtime, config } = args;
|
|
155
|
+
function prepareTemplateExport() {
|
|
156
|
+
var _a;
|
|
157
|
+
const state = runtime.getState();
|
|
158
|
+
const panelSchema = runtime.getPanelSchema();
|
|
159
|
+
const configuredFieldPaths = (_a = config.getTemplateFieldPaths) == null ? void 0 : _a.call(config, panelSchema);
|
|
160
|
+
const fieldGroups = collectPanelFieldGroups(panelSchema, configuredFieldPaths);
|
|
161
|
+
const defaultSelectedFieldPaths = fieldGroups.flatMap(
|
|
162
|
+
(group) => group.fields.map((field) => field.path)
|
|
163
|
+
);
|
|
164
|
+
assert(
|
|
165
|
+
defaultSelectedFieldPaths.length > 0,
|
|
166
|
+
"[generator-workbench] exportTemplate requires at least one panel field path"
|
|
167
|
+
);
|
|
168
|
+
return {
|
|
169
|
+
generatorId: resolveGeneratorId(panelSchema, state),
|
|
170
|
+
state,
|
|
171
|
+
panelSchema,
|
|
172
|
+
fieldGroups,
|
|
173
|
+
selectedFieldPaths: defaultSelectedFieldPaths
|
|
174
|
+
};
|
|
175
|
+
}
|
|
112
176
|
return {
|
|
113
177
|
async importTemplate(file) {
|
|
114
178
|
const text = await file.text();
|
|
@@ -124,21 +188,21 @@ function createTemplateController(args) {
|
|
|
124
188
|
panelFilter: capturedPanelFilter
|
|
125
189
|
};
|
|
126
190
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
const
|
|
191
|
+
prepareTemplateExport,
|
|
192
|
+
async exportTemplate(selectedFieldPaths) {
|
|
193
|
+
var _a;
|
|
194
|
+
const prepared = prepareTemplateExport();
|
|
195
|
+
const finalSelectedFieldPaths = (selectedFieldPaths == null ? void 0 : selectedFieldPaths.length) ? collectPanelFieldPaths(prepared.panelSchema, selectedFieldPaths) : prepared.selectedFieldPaths;
|
|
132
196
|
assert(
|
|
133
|
-
|
|
197
|
+
finalSelectedFieldPaths.length > 0,
|
|
134
198
|
"[generator-workbench] exportTemplate requires at least one panel field path"
|
|
135
199
|
);
|
|
136
200
|
const template = sdk.template.build({
|
|
137
|
-
generatorId:
|
|
138
|
-
state,
|
|
139
|
-
panelSchema,
|
|
140
|
-
selectedFieldPaths,
|
|
141
|
-
templateMeta: (
|
|
201
|
+
generatorId: prepared.generatorId,
|
|
202
|
+
state: prepared.state,
|
|
203
|
+
panelSchema: prepared.panelSchema,
|
|
204
|
+
selectedFieldPaths: finalSelectedFieldPaths,
|
|
205
|
+
templateMeta: (_a = config.getTemplateMeta) == null ? void 0 : _a.call(config)
|
|
142
206
|
});
|
|
143
207
|
sdk.template.download(template);
|
|
144
208
|
return { template };
|
|
@@ -151,6 +215,8 @@ function createInitialWorkbenchState() {
|
|
|
151
215
|
isLogin: false,
|
|
152
216
|
userInfo: null
|
|
153
217
|
},
|
|
218
|
+
creditsBalance: 0,
|
|
219
|
+
billingUsage: null,
|
|
154
220
|
busy: {
|
|
155
221
|
login: false,
|
|
156
222
|
importTemplate: false,
|
|
@@ -173,6 +239,26 @@ function dispatchWorkbenchEvent(target, name, detail) {
|
|
|
173
239
|
})
|
|
174
240
|
);
|
|
175
241
|
}
|
|
242
|
+
function ensureBrowserProcessEnv() {
|
|
243
|
+
const browserGlobal = globalThis;
|
|
244
|
+
if (!browserGlobal.process) {
|
|
245
|
+
browserGlobal.process = {
|
|
246
|
+
env: {
|
|
247
|
+
NODE_ENV: "production"
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (!browserGlobal.process.env) {
|
|
253
|
+
browserGlobal.process.env = {
|
|
254
|
+
NODE_ENV: "production"
|
|
255
|
+
};
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (!browserGlobal.process.env.NODE_ENV) {
|
|
259
|
+
browserGlobal.process.env.NODE_ENV = "production";
|
|
260
|
+
}
|
|
261
|
+
}
|
|
176
262
|
function queryRequired(root, selector) {
|
|
177
263
|
const node = root.querySelector(selector);
|
|
178
264
|
if (!node) {
|
|
@@ -185,267 +271,853 @@ function queryRequired(root, selector) {
|
|
|
185
271
|
function collectWorkbenchRefs(root) {
|
|
186
272
|
return {
|
|
187
273
|
root,
|
|
188
|
-
topbar: queryRequired(root, ".topbar"),
|
|
189
274
|
workspace: queryRequired(root, '[data-role="workspace"]'),
|
|
190
|
-
logoArea:
|
|
191
|
-
importTemplateBtn: queryRequired(root, '[data-role="import-template"]'),
|
|
192
|
-
exportTemplateBtn: queryRequired(root, '[data-role="export-template"]'),
|
|
193
|
-
loginBtn: queryRequired(root, '[data-role="login"]'),
|
|
194
|
-
avatarButton: queryRequired(root, '[data-role="avatar-button"]'),
|
|
195
|
-
avatarImage: queryRequired(root, '[data-role="avatar-image"]'),
|
|
196
|
-
avatarMenu: queryRequired(root, '[data-role="avatar-menu"]'),
|
|
197
|
-
logoutBtn: queryRequired(root, '[data-role="logout"]'),
|
|
198
|
-
panelSidebar: queryRequired(root, '[data-role="panel-sidebar"]'),
|
|
199
|
-
panelHost: queryRequired(root, '[data-role="panel-host"]'),
|
|
200
|
-
panelActions: queryRequired(root, '[data-role="panel-actions"]'),
|
|
275
|
+
logoArea: root.querySelector('[data-role="logo-area"]'),
|
|
201
276
|
canvasHost: queryRequired(root, '[data-role="canvas-host"]'),
|
|
202
|
-
|
|
203
|
-
fabMenu: queryRequired(root, '[data-role="fab-menu"]'),
|
|
204
|
-
exportSvgBtn: queryRequired(root, '[data-role="export-svg"]'),
|
|
205
|
-
openInStudioBtn: queryRequired(root, '[data-role="open-in-studio"]'),
|
|
277
|
+
panelHost: queryRequired(root, '[data-role="panel-host"]'),
|
|
206
278
|
templateFileInput: queryRequired(root, '[data-role="template-file-input"]')
|
|
207
279
|
};
|
|
208
280
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
225
|
-
}
|
|
281
|
+
const ATOMM_UI_CDN_CSS_URL = "https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.min.css";
|
|
282
|
+
const CREDIT_ICON_DATA_URI = "data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3ccircle%20cx='12'%20cy='12'%20r='9'%20fill='url(%23paint0_linear_503_69253)'/%3e%3cg%20filter='url(%23filter0_d_503_69253)'%3e%3crect%20x='7.75781'%20y='12'%20width='6'%20height='6'%20rx='1'%20transform='rotate(-45%207.75781%2012)'%20fill='url(%23paint1_linear_503_69253)'/%3e%3c/g%3e%3cdefs%3e%3cfilter%20id='filter0_d_503_69253'%20x='2.17188'%20y='4.17188'%20width='19.6572'%20height='19.6562'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeColorMatrix%20in='SourceAlpha'%20type='matrix'%20values='0%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%20127%200'%20result='hardAlpha'/%3e%3cfeOffset%20dy='2'/%3e%3cfeGaussianBlur%20stdDeviation='3'/%3e%3cfeComposite%20in2='hardAlpha'%20operator='out'/%3e%3cfeColorMatrix%20type='matrix'%20values='0%200%200%200%201%200%200%200%200%200.206957%200%200%200%200%200.0670085%200%200%200%201%200'/%3e%3cfeBlend%20mode='normal'%20in2='BackgroundImageFix'%20result='effect1_dropShadow_503_69253'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='effect1_dropShadow_503_69253'%20result='shape'/%3e%3c/filter%3e%3clinearGradient%20id='paint0_linear_503_69253'%20x1='12'%20y1='3'%20x2='12'%20y2='21'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='%23FFA346'/%3e%3cstop%20offset='1'%20stop-color='%23FF7C23'/%3e%3c/linearGradient%3e%3clinearGradient%20id='paint1_linear_503_69253'%20x1='13.2327'%20y1='12.5252'%20x2='8.63652'%20y2='18.5356'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='white'/%3e%3cstop%20offset='1'%20stop-color='%23FFD3B5'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e";
|
|
283
|
+
const EXPORT_ICON_DATA_URI = "data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%201088%201024'%20xmlns%3D'http%3A//www.w3.org/2000/svg'%3E%3Cpath%20d%3D'M416%20128v85.312h-128A42.688%2042.688%200%200%200%20245.312%20256v512c0%2023.552%2019.136%2042.688%2042.688%2042.688h512a42.688%2042.688%200%200%200%2042.688-42.688V597.312H928V768a128%20128%200%200%201-128%20128h-512a128%20128%200%200%201-128-128V256a128%20128%200%200%201%20128-128h128z'%20fill%3D'%23ffffff'/%3E%3Cpath%20d%3D'M723.52%20520.832L924.352%20320l-200.832-200.832-60.352%2060.352%2097.856%2097.792h-67.712A298.688%20298.688%200%200%200%20394.688%20576v85.312H480V576a213.312%20213.312%200%200%201%20213.312-213.312h67.712l-97.856%2097.792%2060.352%2060.352z'%20fill%3D'%23ffffff'/%3E%3C/svg%3E";
|
|
284
|
+
const WORKBENCH_SHELL_STYLES = `
|
|
285
|
+
:host {
|
|
286
|
+
display: block;
|
|
287
|
+
height: 100%;
|
|
288
|
+
color: #111827;
|
|
289
|
+
font-family: Inter, "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
290
|
+
--bg-soft: #f3f4f6;
|
|
291
|
+
--border-default: #e5e7eb;
|
|
292
|
+
--text-primary: #111827;
|
|
293
|
+
--text-secondary: #4b5563;
|
|
294
|
+
--text-muted: #9ca3af;
|
|
295
|
+
}
|
|
226
296
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
297
|
+
* {
|
|
298
|
+
box-sizing: border-box;
|
|
299
|
+
}
|
|
230
300
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
flex-direction: column;
|
|
235
|
-
background: #f5f7fb;
|
|
236
|
-
}
|
|
301
|
+
[data-workbench-vue-root] {
|
|
302
|
+
height: 100%;
|
|
303
|
+
}
|
|
237
304
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
305
|
+
.shell {
|
|
306
|
+
height: 100%;
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-direction: column;
|
|
309
|
+
background:
|
|
310
|
+
radial-gradient(rgba(17, 24, 39, 0.06) 1px, transparent 1px),
|
|
311
|
+
linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(249, 250, 251, 0.96));
|
|
312
|
+
background-size: 20px 20px, auto;
|
|
313
|
+
}
|
|
248
314
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
315
|
+
.topbar,
|
|
316
|
+
.app-topbar {
|
|
317
|
+
height: 64px;
|
|
318
|
+
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: space-between;
|
|
321
|
+
gap: 12px;
|
|
322
|
+
padding: 0 24px;
|
|
323
|
+
background: rgba(255, 255, 255, 0.92);
|
|
324
|
+
border-bottom: 1px solid var(--border-default);
|
|
325
|
+
backdrop-filter: blur(12px);
|
|
326
|
+
position: relative;
|
|
327
|
+
z-index: 20;
|
|
328
|
+
}
|
|
252
329
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
330
|
+
.logo-area,
|
|
331
|
+
.app-topbar-main {
|
|
332
|
+
display: flex;
|
|
333
|
+
align-items: center;
|
|
334
|
+
gap: 18px;
|
|
335
|
+
min-width: 0;
|
|
336
|
+
flex: 1;
|
|
337
|
+
}
|
|
258
338
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
339
|
+
.app-topbar-nav {
|
|
340
|
+
display: flex;
|
|
341
|
+
align-items: center;
|
|
342
|
+
gap: 10px;
|
|
343
|
+
flex-wrap: wrap;
|
|
344
|
+
}
|
|
265
345
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
346
|
+
.workspace {
|
|
347
|
+
flex: 1;
|
|
348
|
+
min-height: 0;
|
|
349
|
+
display: grid;
|
|
350
|
+
grid-template-columns: minmax(0, 1fr) 320px;
|
|
351
|
+
}
|
|
269
352
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
353
|
+
.workspace.panel-left {
|
|
354
|
+
grid-template-columns: 320px minmax(0, 1fr);
|
|
355
|
+
}
|
|
273
356
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
357
|
+
.workspace.panel-right .canvas-host {
|
|
358
|
+
grid-column: 1;
|
|
359
|
+
}
|
|
277
360
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
361
|
+
.workspace.panel-right .panel-sidebar {
|
|
362
|
+
grid-column: 2;
|
|
363
|
+
}
|
|
281
364
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
365
|
+
.workspace.panel-left .panel-sidebar {
|
|
366
|
+
grid-column: 1;
|
|
367
|
+
}
|
|
285
368
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
flex-direction: column;
|
|
290
|
-
background: #fff;
|
|
291
|
-
}
|
|
369
|
+
.workspace.panel-left .canvas-host {
|
|
370
|
+
grid-column: 2;
|
|
371
|
+
}
|
|
292
372
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
373
|
+
.panel-sidebar {
|
|
374
|
+
min-height: 0;
|
|
375
|
+
display: flex;
|
|
376
|
+
flex-direction: column;
|
|
377
|
+
background: #ffffff;
|
|
378
|
+
}
|
|
298
379
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
place-items: center;
|
|
305
|
-
}
|
|
380
|
+
.panel-host {
|
|
381
|
+
flex: 1;
|
|
382
|
+
min-height: 0;
|
|
383
|
+
overflow: auto;
|
|
384
|
+
}
|
|
306
385
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
color: #fff;
|
|
314
|
-
font: inherit;
|
|
315
|
-
}
|
|
386
|
+
.canvas-host {
|
|
387
|
+
position: relative;
|
|
388
|
+
min-height: 480px;
|
|
389
|
+
display: grid;
|
|
390
|
+
place-items: center;
|
|
391
|
+
}
|
|
316
392
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
393
|
+
.brand-logo {
|
|
394
|
+
height: 32px;
|
|
395
|
+
width: 92px;
|
|
396
|
+
display: block;
|
|
397
|
+
cursor: pointer;
|
|
398
|
+
flex: 0 0 auto;
|
|
399
|
+
}
|
|
321
400
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
401
|
+
.app-topbar-auth {
|
|
402
|
+
display: flex;
|
|
403
|
+
align-items: center;
|
|
404
|
+
justify-content: flex-end;
|
|
405
|
+
gap: 12px;
|
|
406
|
+
flex: 0 0 auto;
|
|
407
|
+
}
|
|
326
408
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
409
|
+
.topbar-credits-badge {
|
|
410
|
+
display: inline-flex;
|
|
411
|
+
align-items: center;
|
|
412
|
+
gap: 4px;
|
|
413
|
+
padding: 0;
|
|
414
|
+
color: #2d3541;
|
|
415
|
+
font-size: 14px;
|
|
416
|
+
font-weight: 500;
|
|
417
|
+
line-height: 1;
|
|
418
|
+
white-space: nowrap;
|
|
419
|
+
cursor: default;
|
|
420
|
+
}
|
|
332
421
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
gap: 8px;
|
|
337
|
-
background: transparent;
|
|
338
|
-
color: #111827;
|
|
339
|
-
padding: 0;
|
|
340
|
-
}
|
|
422
|
+
.topbar-credits-value {
|
|
423
|
+
font-variant-numeric: tabular-nums;
|
|
424
|
+
}
|
|
341
425
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
426
|
+
.credits-token-icon {
|
|
427
|
+
width: 20px;
|
|
428
|
+
height: 20px;
|
|
429
|
+
flex: 0 0 16px;
|
|
430
|
+
user-select: none;
|
|
431
|
+
-webkit-user-drag: none;
|
|
432
|
+
}
|
|
349
433
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
padding: 8px;
|
|
356
|
-
display: none;
|
|
357
|
-
background: #fff;
|
|
358
|
-
border: 1px solid #e5e7eb;
|
|
359
|
-
border-radius: 12px;
|
|
360
|
-
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);
|
|
361
|
-
}
|
|
434
|
+
.credits-token-icon--sm {
|
|
435
|
+
width: 16px;
|
|
436
|
+
height: 16px;
|
|
437
|
+
flex-basis: 16px;
|
|
438
|
+
}
|
|
362
439
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
440
|
+
.auth-avatar-trigger {
|
|
441
|
+
display: inline-flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
gap: 6px;
|
|
444
|
+
padding: 4px 8px 4px 4px;
|
|
445
|
+
border-radius: 999px;
|
|
446
|
+
cursor: pointer;
|
|
447
|
+
transition: background 150ms ease;
|
|
448
|
+
}
|
|
367
449
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
450
|
+
.auth-avatar-trigger:hover {
|
|
451
|
+
background: var(--bg-soft);
|
|
452
|
+
}
|
|
372
453
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
454
|
+
.auth-avatar {
|
|
455
|
+
width: 40px;
|
|
456
|
+
height: 40px;
|
|
457
|
+
border-radius: 50%;
|
|
458
|
+
display: grid;
|
|
459
|
+
place-items: center;
|
|
460
|
+
overflow: hidden;
|
|
461
|
+
flex: 0 0 auto;
|
|
462
|
+
background: #f3f4f6;
|
|
463
|
+
color: var(--text-secondary);
|
|
464
|
+
font-size: 14px;
|
|
465
|
+
font-weight: 600;
|
|
466
|
+
}
|
|
377
467
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
468
|
+
.auth-avatar--lg {
|
|
469
|
+
width: 40px;
|
|
470
|
+
height: 40px;
|
|
471
|
+
font-size: 14px;
|
|
472
|
+
}
|
|
381
473
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
474
|
+
.auth-avatar img {
|
|
475
|
+
width: 100%;
|
|
476
|
+
height: 100%;
|
|
477
|
+
object-fit: cover;
|
|
478
|
+
display: block;
|
|
479
|
+
}
|
|
385
480
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
gap: 8px;
|
|
391
|
-
width: 100%;
|
|
392
|
-
}
|
|
481
|
+
.auth-popover-body {
|
|
482
|
+
min-width: 200px;
|
|
483
|
+
padding: 4px 0;
|
|
484
|
+
}
|
|
393
485
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
border-radius: 12px;
|
|
401
|
-
box-shadow: 0 16px 40px rgba(15, 23, 42, 0.12);
|
|
402
|
-
}
|
|
486
|
+
.auth-popover-header {
|
|
487
|
+
display: flex;
|
|
488
|
+
align-items: center;
|
|
489
|
+
gap: 12px;
|
|
490
|
+
padding: 12px 16px;
|
|
491
|
+
}
|
|
403
492
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
493
|
+
.auth-popover-user-text {
|
|
494
|
+
min-width: 0;
|
|
495
|
+
flex: 1;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.auth-popover-name {
|
|
499
|
+
display: block;
|
|
500
|
+
font-size: 14px;
|
|
501
|
+
font-weight: 600;
|
|
502
|
+
color: var(--text-primary);
|
|
503
|
+
overflow: hidden;
|
|
504
|
+
text-overflow: ellipsis;
|
|
505
|
+
white-space: nowrap;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.auth-popover-sub {
|
|
509
|
+
display: block;
|
|
510
|
+
margin-top: 2px;
|
|
511
|
+
font-size: 12px;
|
|
512
|
+
color: var(--text-secondary);
|
|
513
|
+
overflow: hidden;
|
|
514
|
+
text-overflow: ellipsis;
|
|
515
|
+
white-space: nowrap;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.auth-popover-divider {
|
|
519
|
+
height: 1px;
|
|
520
|
+
background: var(--border-default);
|
|
521
|
+
margin: 4px 0;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.auth-popover-action {
|
|
525
|
+
display: flex;
|
|
526
|
+
align-items: center;
|
|
527
|
+
gap: 8px;
|
|
528
|
+
padding: 8px 16px;
|
|
529
|
+
font-size: 13px;
|
|
530
|
+
color: var(--text-secondary);
|
|
531
|
+
cursor: pointer;
|
|
532
|
+
transition: all 150ms ease;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.auth-popover-action:hover {
|
|
536
|
+
background: var(--bg-soft);
|
|
537
|
+
color: var(--text-primary);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.auth-hover-card {
|
|
541
|
+
position: relative;
|
|
542
|
+
display: inline-flex;
|
|
543
|
+
align-items: center;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.auth-hover-panel {
|
|
547
|
+
position: absolute;
|
|
548
|
+
top: calc(100% + 8px);
|
|
549
|
+
right: 0;
|
|
550
|
+
z-index: 40;
|
|
551
|
+
min-width: 200px;
|
|
552
|
+
background: #fff;
|
|
553
|
+
border: 1px solid var(--border-default);
|
|
554
|
+
border-radius: 12px;
|
|
555
|
+
box-shadow: 0 8px 28px rgba(17, 24, 39, 0.12);
|
|
556
|
+
opacity: 0;
|
|
557
|
+
transform: translateY(4px);
|
|
558
|
+
pointer-events: none;
|
|
559
|
+
transition: opacity 150ms ease, transform 150ms ease;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.auth-hover-card:hover .auth-hover-panel,
|
|
563
|
+
.auth-hover-card:focus-within .auth-hover-panel {
|
|
564
|
+
opacity: 1;
|
|
565
|
+
transform: translateY(0);
|
|
566
|
+
pointer-events: auto;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.panel-actions,
|
|
570
|
+
#sidebar-footer {
|
|
571
|
+
flex-shrink: 0;
|
|
572
|
+
padding: 14px 24px;
|
|
573
|
+
border-top: 1px solid var(--border-default);
|
|
574
|
+
background: #ffffff;
|
|
575
|
+
display: flex;
|
|
576
|
+
align-items: center;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.sidebar-footer-export {
|
|
580
|
+
width: 100%;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.sidebar-footer-export .sidebar-export-trigger-btn,
|
|
584
|
+
.sidebar-footer-export .sidebar-export-trigger-btn-wrap,
|
|
585
|
+
.sidebar-export-trigger-btn-wrap {
|
|
586
|
+
width: 100%;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
.sidebar-export-dropdown-menu {
|
|
590
|
+
width: 268px;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.sidebar-export-trigger-btn img {
|
|
594
|
+
margin-right: 4px;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.export-credits-hint {
|
|
598
|
+
display: inline-flex;
|
|
599
|
+
align-items: center;
|
|
600
|
+
justify-content: center;
|
|
601
|
+
gap: 2px;
|
|
602
|
+
padding: 0;
|
|
603
|
+
font-size: 12px;
|
|
604
|
+
font-weight: 600;
|
|
605
|
+
line-height: 1;
|
|
606
|
+
color: #ff7c23;
|
|
607
|
+
margin-left: 10px;
|
|
608
|
+
white-space: nowrap;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.export-credits-hint-value {
|
|
612
|
+
color: white;
|
|
613
|
+
font-size: 13px;
|
|
614
|
+
font-weight: 700;
|
|
615
|
+
font-variant-numeric: tabular-nums;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.export-overlay-menu,
|
|
619
|
+
.fab-menu-content {
|
|
620
|
+
padding: 4px;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.export-overlay-item {
|
|
624
|
+
display: flex;
|
|
625
|
+
align-items: center;
|
|
626
|
+
gap: 8px;
|
|
627
|
+
padding: 8px 12px;
|
|
628
|
+
border-radius: 6px;
|
|
629
|
+
font-size: 14px;
|
|
630
|
+
color: var(--text-primary);
|
|
631
|
+
cursor: pointer;
|
|
632
|
+
transition: background 120ms ease;
|
|
633
|
+
user-select: none;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.export-overlay-item:hover {
|
|
637
|
+
background: var(--bg-soft);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.export-overlay-item-icon {
|
|
641
|
+
width: 16px;
|
|
642
|
+
height: 16px;
|
|
643
|
+
border-radius: 4px;
|
|
644
|
+
background: #cbd5e1;
|
|
645
|
+
display: inline-block;
|
|
646
|
+
flex: 0 0 auto;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.export-overlay-item-icon--svg {
|
|
650
|
+
background: linear-gradient(180deg, #94a3b8, #64748b);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.export-overlay-item-icon--studio {
|
|
654
|
+
background: linear-gradient(180deg, #cbd5e1, #94a3b8);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.workspace.panel-right .panel-sidebar {
|
|
658
|
+
border-left: 1px solid var(--border-default);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.workspace.panel-left .panel-sidebar {
|
|
662
|
+
border-right: 1px solid var(--border-default);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.template-export-modal {
|
|
666
|
+
display: grid;
|
|
667
|
+
gap: 16px;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
.template-export-groups {
|
|
673
|
+
display: grid;
|
|
674
|
+
gap: 12px;
|
|
675
|
+
max-height: 360px;
|
|
676
|
+
overflow: auto;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.template-export-group {
|
|
680
|
+
display: grid;
|
|
681
|
+
gap: 10px;
|
|
682
|
+
padding: 14px 16px;
|
|
683
|
+
border: 1px solid var(--border-default);
|
|
684
|
+
border-radius: 12px;
|
|
685
|
+
background: #ffffff;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.template-export-group-title {
|
|
689
|
+
font-size: 13px;
|
|
690
|
+
font-weight: 700;
|
|
691
|
+
color: var(--text-primary);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.template-export-field-list {
|
|
695
|
+
display: grid;
|
|
696
|
+
gap: 10px;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.template-export-field {
|
|
700
|
+
display: grid;
|
|
701
|
+
gap: 4px;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.template-export-field-path {
|
|
705
|
+
padding-left: 28px;
|
|
706
|
+
font-size: 12px;
|
|
707
|
+
color: var(--text-muted);
|
|
708
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.template-export-footer {
|
|
712
|
+
display: flex;
|
|
713
|
+
justify-content: flex-end;
|
|
714
|
+
gap: 12px;
|
|
715
|
+
padding: 8px 24px;
|
|
716
|
+
}
|
|
717
|
+
`;
|
|
718
|
+
const WORKBENCH_VUE_TEMPLATE = `
|
|
408
719
|
<div class="shell">
|
|
409
|
-
<header class="topbar">
|
|
410
|
-
<div class="logo-area" data-role="logo-area"
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
<
|
|
420
|
-
|
|
720
|
+
<header v-if="state.shellMode !== 'template'" class="topbar app-topbar">
|
|
721
|
+
<div class="logo-area app-topbar-main" data-role="logo-area">
|
|
722
|
+
<img
|
|
723
|
+
:src="state.logoSrc"
|
|
724
|
+
:alt="state.logoText || 'Atomm'"
|
|
725
|
+
class="brand-logo"
|
|
726
|
+
data-role="brand-logo"
|
|
727
|
+
draggable="false"
|
|
728
|
+
/>
|
|
729
|
+
<div class="app-topbar-nav">
|
|
730
|
+
<xt-button
|
|
731
|
+
v-show="state.templateEnabled"
|
|
732
|
+
type="secondary"
|
|
733
|
+
size="small"
|
|
734
|
+
data-role="import-template"
|
|
735
|
+
@click="callbacks.onImportTemplate()"
|
|
736
|
+
>导入模板</xt-button>
|
|
737
|
+
<xt-button
|
|
738
|
+
v-show="state.templateEnabled"
|
|
739
|
+
type="secondary"
|
|
740
|
+
size="small"
|
|
741
|
+
data-role="export-template"
|
|
742
|
+
@click="callbacks.onExportTemplate()"
|
|
743
|
+
>生成模板</xt-button>
|
|
744
|
+
</div>
|
|
745
|
+
</div>
|
|
746
|
+
<div class="app-topbar-auth">
|
|
747
|
+
<div
|
|
748
|
+
v-if="state.isLogin"
|
|
749
|
+
class="topbar-credits-badge"
|
|
750
|
+
data-role="topbar-credits"
|
|
751
|
+
title="Remaining credits"
|
|
752
|
+
>
|
|
753
|
+
<img src="${CREDIT_ICON_DATA_URI}" alt="" class="credits-token-icon" draggable="false" />
|
|
754
|
+
<span class="topbar-credits-value" data-role="topbar-credits-value">{{ state.creditsBalance }}</span>
|
|
755
|
+
</div>
|
|
756
|
+
|
|
757
|
+
<div
|
|
758
|
+
v-if="state.isLogin && state.avatarMenuTrigger === 'hover'"
|
|
759
|
+
class="auth-hover-card"
|
|
760
|
+
>
|
|
761
|
+
<div class="auth-avatar-trigger" data-role="avatar-button" tabindex="0">
|
|
762
|
+
<div class="auth-avatar">
|
|
763
|
+
<img
|
|
764
|
+
v-if="state.avatarSrc"
|
|
765
|
+
:src="state.avatarSrc"
|
|
766
|
+
alt="Avatar"
|
|
767
|
+
data-role="avatar-image"
|
|
768
|
+
/>
|
|
769
|
+
<span v-else data-role="avatar-image">{{ state.avatarText }}</span>
|
|
770
|
+
</div>
|
|
771
|
+
</div>
|
|
772
|
+
<div class="auth-hover-panel">
|
|
773
|
+
<div class="auth-popover-body" data-role="avatar-menu">
|
|
774
|
+
<div class="auth-popover-header">
|
|
775
|
+
<div class="auth-avatar auth-avatar--lg">
|
|
776
|
+
<img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />
|
|
777
|
+
<span v-else>{{ state.avatarText }}</span>
|
|
778
|
+
</div>
|
|
779
|
+
<div class="auth-popover-user-text">
|
|
780
|
+
<span class="auth-popover-name">{{ state.authDisplayName }}</span>
|
|
781
|
+
<span class="auth-popover-sub">{{ state.authSubline }}</span>
|
|
782
|
+
</div>
|
|
783
|
+
</div>
|
|
784
|
+
<div class="auth-popover-divider"></div>
|
|
785
|
+
<div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">
|
|
786
|
+
Logout
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
421
789
|
</div>
|
|
422
790
|
</div>
|
|
791
|
+
|
|
792
|
+
<xt-dropdown-menu
|
|
793
|
+
v-else-if="state.isLogin"
|
|
794
|
+
trigger="click"
|
|
795
|
+
:portal-disabled="true"
|
|
796
|
+
placement="bottomRight"
|
|
797
|
+
>
|
|
798
|
+
<template #trigger>
|
|
799
|
+
<div class="auth-avatar-trigger" data-role="avatar-button">
|
|
800
|
+
<div class="auth-avatar">
|
|
801
|
+
<img
|
|
802
|
+
v-if="state.avatarSrc"
|
|
803
|
+
:src="state.avatarSrc"
|
|
804
|
+
alt="Avatar"
|
|
805
|
+
data-role="avatar-image"
|
|
806
|
+
/>
|
|
807
|
+
<span v-else data-role="avatar-image">{{ state.avatarText }}</span>
|
|
808
|
+
</div>
|
|
809
|
+
</div>
|
|
810
|
+
</template>
|
|
811
|
+
<template #overlay>
|
|
812
|
+
<div class="auth-popover-body" data-role="avatar-menu">
|
|
813
|
+
<div class="auth-popover-header">
|
|
814
|
+
<div class="auth-avatar auth-avatar--lg">
|
|
815
|
+
<img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />
|
|
816
|
+
<span v-else>{{ state.avatarText }}</span>
|
|
817
|
+
</div>
|
|
818
|
+
<div class="auth-popover-user-text">
|
|
819
|
+
<span class="auth-popover-name">{{ state.authDisplayName }}</span>
|
|
820
|
+
<span class="auth-popover-sub">{{ state.authSubline }}</span>
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
<div class="auth-popover-divider"></div>
|
|
824
|
+
<div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">
|
|
825
|
+
Logout
|
|
826
|
+
</div>
|
|
827
|
+
</div>
|
|
828
|
+
</template>
|
|
829
|
+
</xt-dropdown-menu>
|
|
830
|
+
|
|
831
|
+
<xt-button
|
|
832
|
+
size="small"
|
|
833
|
+
type="secondary"
|
|
834
|
+
data-role="login"
|
|
835
|
+
:loading="state.loginLoading"
|
|
836
|
+
v-if="!state.isLogin"
|
|
837
|
+
@click="callbacks.onLogin()"
|
|
838
|
+
>Login</xt-button>
|
|
423
839
|
</div>
|
|
424
840
|
</header>
|
|
425
|
-
|
|
841
|
+
|
|
842
|
+
<div
|
|
843
|
+
class="workspace"
|
|
844
|
+
:class="state.panelTarget === 'left' ? 'panel-left' : 'panel-right'"
|
|
845
|
+
data-role="workspace"
|
|
846
|
+
>
|
|
426
847
|
<main class="canvas-host" data-role="canvas-host"></main>
|
|
427
848
|
<aside class="panel-sidebar" data-role="panel-sidebar">
|
|
428
849
|
<div class="panel-host" data-role="panel-host"></div>
|
|
429
|
-
<div class="panel-actions" data-role="panel-actions">
|
|
430
|
-
<
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
850
|
+
<div id="sidebar-footer" class="sidebar-footer-export panel-actions" data-role="panel-actions">
|
|
851
|
+
<xt-dropdown-menu
|
|
852
|
+
trigger="click"
|
|
853
|
+
:portal-disabled="true"
|
|
854
|
+
placement="topLeft"
|
|
855
|
+
domTriggerClass="sidebar-export-trigger-btn-wrap"
|
|
856
|
+
:show-trigger-icon="false"
|
|
857
|
+
domContentClass="sidebar-export-dropdown-menu"
|
|
858
|
+
>
|
|
859
|
+
<template #trigger>
|
|
860
|
+
<xt-button class="sidebar-export-trigger-btn" block data-role="fab-trigger">
|
|
861
|
+
<template #icon>
|
|
862
|
+
<img
|
|
863
|
+
src="${EXPORT_ICON_DATA_URI}"
|
|
864
|
+
alt=""
|
|
865
|
+
width="16"
|
|
866
|
+
height="16"
|
|
867
|
+
draggable="false"
|
|
868
|
+
/>
|
|
869
|
+
</template>
|
|
870
|
+
Export SVG
|
|
871
|
+
<template #append-icon>
|
|
872
|
+
<div v-if="state.isLogin" class="export-credits-hint">
|
|
873
|
+
<img src="${CREDIT_ICON_DATA_URI}" alt="" class="credits-token-icon credits-token-icon--sm" draggable="false" />
|
|
874
|
+
<span class="export-credits-hint-value" data-role="export-credits-value">{{ state.exportCreditsCost }}</span>
|
|
875
|
+
</div>
|
|
876
|
+
</template>
|
|
877
|
+
</xt-button>
|
|
878
|
+
</template>
|
|
879
|
+
<template #overlay>
|
|
880
|
+
<div class="export-overlay-menu fab-menu-content" data-role="fab-menu">
|
|
881
|
+
<div
|
|
882
|
+
v-show="state.exportEnabled"
|
|
883
|
+
class="export-overlay-item"
|
|
884
|
+
data-role="export-svg"
|
|
885
|
+
@click="callbacks.onExportSvg()"
|
|
886
|
+
>
|
|
887
|
+
<span class="export-overlay-item-icon export-overlay-item-icon--svg"></span>
|
|
888
|
+
Export SVG
|
|
889
|
+
</div>
|
|
890
|
+
<div
|
|
891
|
+
v-show="state.studioEnabled"
|
|
892
|
+
class="export-overlay-item"
|
|
893
|
+
data-role="open-in-studio"
|
|
894
|
+
@click="callbacks.onOpenInStudio()"
|
|
895
|
+
>
|
|
896
|
+
<span class="export-overlay-item-icon export-overlay-item-icon--studio"></span>
|
|
897
|
+
Open in Studio
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
</template>
|
|
901
|
+
</xt-dropdown-menu>
|
|
437
902
|
</div>
|
|
438
903
|
</aside>
|
|
439
904
|
</div>
|
|
440
|
-
|
|
905
|
+
|
|
906
|
+
<input
|
|
907
|
+
data-role="template-file-input"
|
|
908
|
+
type="file"
|
|
909
|
+
accept="application/json"
|
|
910
|
+
style="display:none"
|
|
911
|
+
@change="callbacks.onFileChange($event)"
|
|
912
|
+
/>
|
|
913
|
+
|
|
914
|
+
<xt-modal
|
|
915
|
+
:model-value="state.templateDialogOpen"
|
|
916
|
+
title="发布模板"
|
|
917
|
+
:show-footer="false"
|
|
918
|
+
:portal-disabled="true"
|
|
919
|
+
@update:model-value="callbacks.onToggleTemplateDialog($event)"
|
|
920
|
+
>
|
|
921
|
+
<div
|
|
922
|
+
v-if="state.templateDialogOpen"
|
|
923
|
+
class="template-export-modal"
|
|
924
|
+
data-role="template-export-modal"
|
|
925
|
+
>
|
|
926
|
+
|
|
927
|
+
<div class="template-export-groups">
|
|
928
|
+
<div
|
|
929
|
+
v-for="group in state.templateFieldGroups"
|
|
930
|
+
:key="group.id"
|
|
931
|
+
class="template-export-group"
|
|
932
|
+
>
|
|
933
|
+
<div class="template-export-group-title">{{ group.title }}</div>
|
|
934
|
+
<div class="template-export-field-list">
|
|
935
|
+
<div
|
|
936
|
+
v-for="field in group.fields"
|
|
937
|
+
:key="field.path"
|
|
938
|
+
class="template-export-field"
|
|
939
|
+
data-role="template-export-field"
|
|
940
|
+
>
|
|
941
|
+
<xt-checkbox
|
|
942
|
+
:model-value="state.templateSelectedFieldPaths.includes(field.path)"
|
|
943
|
+
:disabled="state.templateExportLoading"
|
|
944
|
+
@update:model-value="callbacks.onToggleTemplateField(field.path, $event)"
|
|
945
|
+
>{{ field.label }}</xt-checkbox>
|
|
946
|
+
<div class="template-export-field-path">{{ field.path }}</div>
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
</div>
|
|
950
|
+
</div>
|
|
951
|
+
|
|
952
|
+
<div class="template-export-footer">
|
|
953
|
+
<xt-button
|
|
954
|
+
type="secondary"
|
|
955
|
+
:disabled="state.templateExportLoading"
|
|
956
|
+
@click="callbacks.onCloseTemplateDialog()"
|
|
957
|
+
>取消</xt-button>
|
|
958
|
+
<xt-button
|
|
959
|
+
type="primary"
|
|
960
|
+
data-role="template-export-confirm"
|
|
961
|
+
:loading="state.templateExportLoading"
|
|
962
|
+
:disabled="state.templateSelectedFieldPaths.length === 0"
|
|
963
|
+
@click="callbacks.onConfirmTemplateExport()"
|
|
964
|
+
>发布模板</xt-button>
|
|
965
|
+
</div>
|
|
966
|
+
</div>
|
|
967
|
+
</xt-modal>
|
|
441
968
|
</div>
|
|
442
969
|
`;
|
|
443
|
-
function
|
|
444
|
-
|
|
445
|
-
|
|
970
|
+
function requireVue() {
|
|
971
|
+
const Vue = globalThis.Vue;
|
|
972
|
+
if (!Vue || typeof Vue.createApp !== "function") {
|
|
973
|
+
throw new Error(
|
|
974
|
+
'[generator-workbench] Vue 3 is required. Load it via CDN: <script src="https://unpkg.com/vue@3/dist/vue.global.js"><\/script>'
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
return Vue;
|
|
978
|
+
}
|
|
979
|
+
function injectStyles(root, cdnCssUrl) {
|
|
980
|
+
const link = document.createElement("link");
|
|
981
|
+
link.rel = "stylesheet";
|
|
982
|
+
link.href = cdnCssUrl || ATOMM_UI_CDN_CSS_URL;
|
|
983
|
+
root.appendChild(link);
|
|
984
|
+
const style = document.createElement("style");
|
|
985
|
+
style.textContent = WORKBENCH_SHELL_STYLES;
|
|
986
|
+
root.appendChild(style);
|
|
987
|
+
}
|
|
988
|
+
function stateFromConfig(vue, config) {
|
|
989
|
+
return vue.reactive({
|
|
990
|
+
shellMode: config.mode || "full",
|
|
991
|
+
logoText: config.logoText || config.title,
|
|
992
|
+
logoSrc: config.logoUrl || "https://storage-us.atomm.com/resource/xart/static/agent/imgs/atomm-logo.svg",
|
|
993
|
+
panelTarget: config.panelTarget || "right",
|
|
994
|
+
avatarMenuTrigger: config.avatarMenuTrigger || "hover",
|
|
995
|
+
templateEnabled: config.templateEnabled !== false,
|
|
996
|
+
exportEnabled: config.exportEnabled !== false,
|
|
997
|
+
studioEnabled: config.studioEnabled !== false,
|
|
998
|
+
isLogin: false,
|
|
999
|
+
avatarSrc: "",
|
|
1000
|
+
avatarText: "U",
|
|
1001
|
+
authDisplayName: "",
|
|
1002
|
+
authSubline: "",
|
|
1003
|
+
creditsBalance: 0,
|
|
1004
|
+
exportCreditsCost: 1,
|
|
1005
|
+
loginLoading: false,
|
|
1006
|
+
templateDialogOpen: false,
|
|
1007
|
+
templateExportLoading: false,
|
|
1008
|
+
templateSelectedFieldPaths: [],
|
|
1009
|
+
templateFieldGroups: []
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
function createNoopCallbacks() {
|
|
1013
|
+
return {
|
|
1014
|
+
onLogin: () => {
|
|
1015
|
+
},
|
|
1016
|
+
onLogout: () => {
|
|
1017
|
+
},
|
|
1018
|
+
onImportTemplate: () => {
|
|
1019
|
+
},
|
|
1020
|
+
onExportTemplate: () => {
|
|
1021
|
+
},
|
|
1022
|
+
onCloseTemplateDialog: () => {
|
|
1023
|
+
},
|
|
1024
|
+
onToggleTemplateDialog: () => {
|
|
1025
|
+
},
|
|
1026
|
+
onToggleTemplateField: () => {
|
|
1027
|
+
},
|
|
1028
|
+
onConfirmTemplateExport: () => {
|
|
1029
|
+
},
|
|
1030
|
+
onExportSvg: () => {
|
|
1031
|
+
},
|
|
1032
|
+
onOpenInStudio: () => {
|
|
1033
|
+
},
|
|
1034
|
+
onFileChange: () => {
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
function registerFallbackComponents(app) {
|
|
1039
|
+
app.component("xt-button", {
|
|
1040
|
+
inheritAttrs: true,
|
|
1041
|
+
template: '<button v-bind="$attrs"><slot name="icon" /><slot /><slot name="append-icon" /></button>'
|
|
1042
|
+
});
|
|
1043
|
+
app.component("xt-avatar", {
|
|
1044
|
+
inheritAttrs: true,
|
|
1045
|
+
template: '<span v-bind="$attrs"><slot /></span>'
|
|
1046
|
+
});
|
|
1047
|
+
app.component("xt-dropdown-menu", {
|
|
1048
|
+
inheritAttrs: true,
|
|
1049
|
+
template: '<div v-bind="$attrs"><slot name="trigger" /><slot name="overlay" /><slot /></div>'
|
|
1050
|
+
});
|
|
1051
|
+
app.component("xt-hover-card", {
|
|
1052
|
+
inheritAttrs: true,
|
|
1053
|
+
template: '<div v-bind="$attrs"><slot name="trigger" /><slot name="content" /></div>'
|
|
1054
|
+
});
|
|
1055
|
+
app.component("xt-modal", {
|
|
1056
|
+
inheritAttrs: false,
|
|
1057
|
+
props: {
|
|
1058
|
+
modelValue: { type: Boolean, default: false },
|
|
1059
|
+
title: { type: String, default: "" }
|
|
1060
|
+
},
|
|
1061
|
+
emits: ["update:modelValue"],
|
|
1062
|
+
template: `
|
|
1063
|
+
<div v-if="modelValue" v-bind="$attrs">
|
|
1064
|
+
<div>{{ title }}</div>
|
|
1065
|
+
<slot />
|
|
1066
|
+
</div>
|
|
1067
|
+
`
|
|
1068
|
+
});
|
|
1069
|
+
app.component("xt-checkbox", {
|
|
1070
|
+
inheritAttrs: false,
|
|
1071
|
+
props: {
|
|
1072
|
+
modelValue: { type: Boolean, default: false },
|
|
1073
|
+
label: { type: String, default: "" },
|
|
1074
|
+
disabled: { type: Boolean, default: false }
|
|
1075
|
+
},
|
|
1076
|
+
emits: ["update:modelValue", "change"],
|
|
1077
|
+
template: `
|
|
1078
|
+
<label v-bind="$attrs">
|
|
1079
|
+
<input
|
|
1080
|
+
type="checkbox"
|
|
1081
|
+
:checked="modelValue"
|
|
1082
|
+
:disabled="disabled"
|
|
1083
|
+
@change="$emit('update:modelValue', $event.target.checked)"
|
|
1084
|
+
/>
|
|
1085
|
+
<span><slot>{{ label }}</slot></span>
|
|
1086
|
+
</label>
|
|
1087
|
+
`
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
function renderWorkbenchShell(root, config) {
|
|
1091
|
+
const vue = requireVue();
|
|
1092
|
+
ensureBrowserProcessEnv();
|
|
1093
|
+
injectStyles(root, config.atommUiCssUrl);
|
|
1094
|
+
const state = stateFromConfig(vue, config);
|
|
1095
|
+
const callbacks = createNoopCallbacks();
|
|
1096
|
+
const container = document.createElement("div");
|
|
1097
|
+
container.setAttribute("data-workbench-vue-root", "");
|
|
1098
|
+
root.appendChild(container);
|
|
1099
|
+
const AtommUI = globalThis.AtommUI;
|
|
1100
|
+
const app = vue.createApp({
|
|
1101
|
+
setup() {
|
|
1102
|
+
return { state, callbacks };
|
|
1103
|
+
},
|
|
1104
|
+
template: WORKBENCH_VUE_TEMPLATE
|
|
1105
|
+
});
|
|
1106
|
+
if (AtommUI) {
|
|
1107
|
+
app.use(AtommUI);
|
|
1108
|
+
} else {
|
|
1109
|
+
registerFallbackComponents(app);
|
|
1110
|
+
}
|
|
1111
|
+
app.mount(container);
|
|
1112
|
+
const refs = collectWorkbenchRefs(root);
|
|
1113
|
+
return { state, callbacks, app, refs };
|
|
1114
|
+
}
|
|
1115
|
+
function unmountWorkbenchShell(context) {
|
|
1116
|
+
context.app.unmount();
|
|
446
1117
|
}
|
|
447
1118
|
const DEFAULT_CONFIG = {
|
|
448
1119
|
title: "",
|
|
1120
|
+
mode: "full",
|
|
449
1121
|
templateEnabled: true,
|
|
450
1122
|
exportEnabled: true,
|
|
451
1123
|
studioEnabled: true,
|
|
@@ -453,6 +1125,7 @@ const DEFAULT_CONFIG = {
|
|
|
453
1125
|
panelTarget: "right",
|
|
454
1126
|
avatarMenuTrigger: "hover"
|
|
455
1127
|
};
|
|
1128
|
+
const TOKEN_STORAGE_KEY_PREFIX = "__atomm_sdk_token__";
|
|
456
1129
|
function normalizeWorkbenchConfig(config) {
|
|
457
1130
|
return {
|
|
458
1131
|
...DEFAULT_CONFIG,
|
|
@@ -465,14 +1138,16 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
465
1138
|
__publicField(this, "_sdk", null);
|
|
466
1139
|
__publicField(this, "_runtime", null);
|
|
467
1140
|
__publicField(this, "_config", { ...DEFAULT_CONFIG });
|
|
468
|
-
__publicField(this, "_refs", null);
|
|
469
1141
|
__publicField(this, "_mounted", false);
|
|
470
1142
|
__publicField(this, "_state", createInitialWorkbenchState());
|
|
471
1143
|
__publicField(this, "_cleanupAuth");
|
|
1144
|
+
__publicField(this, "_cleanupCredits");
|
|
1145
|
+
__publicField(this, "_cleanupBilling");
|
|
472
1146
|
__publicField(this, "_authController");
|
|
473
1147
|
__publicField(this, "_templateController");
|
|
474
1148
|
__publicField(this, "_exportController");
|
|
475
1149
|
__publicField(this, "_runtimeController");
|
|
1150
|
+
__publicField(this, "_shellContext");
|
|
476
1151
|
this.attachShadow({ mode: "open" });
|
|
477
1152
|
}
|
|
478
1153
|
get sdk() {
|
|
@@ -520,11 +1195,13 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
520
1195
|
}
|
|
521
1196
|
this.render();
|
|
522
1197
|
this.bindControllers();
|
|
523
|
-
this.
|
|
1198
|
+
this.bindShellCallbacks();
|
|
524
1199
|
this.bindAuthState();
|
|
525
|
-
await
|
|
1200
|
+
await this.syncBillingState();
|
|
1201
|
+
const refs = this.requireRefs();
|
|
1202
|
+
await ((_a = this._runtimeController) == null ? void 0 : _a.mountCanvas(refs.canvasHost));
|
|
526
1203
|
await ((_b = this._runtimeController) == null ? void 0 : _b.mountPanel(
|
|
527
|
-
|
|
1204
|
+
refs.panelHost,
|
|
528
1205
|
this._state.activePanelFilter
|
|
529
1206
|
));
|
|
530
1207
|
this._mounted = true;
|
|
@@ -534,10 +1211,18 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
534
1211
|
});
|
|
535
1212
|
}
|
|
536
1213
|
async unmount() {
|
|
537
|
-
var _a, _b;
|
|
1214
|
+
var _a, _b, _c, _d;
|
|
538
1215
|
(_a = this._cleanupAuth) == null ? void 0 : _a.call(this);
|
|
539
1216
|
this._cleanupAuth = void 0;
|
|
540
|
-
|
|
1217
|
+
(_b = this._cleanupCredits) == null ? void 0 : _b.call(this);
|
|
1218
|
+
this._cleanupCredits = void 0;
|
|
1219
|
+
(_c = this._cleanupBilling) == null ? void 0 : _c.call(this);
|
|
1220
|
+
this._cleanupBilling = void 0;
|
|
1221
|
+
await ((_d = this._runtimeController) == null ? void 0 : _d.unmountAll());
|
|
1222
|
+
if (this._shellContext) {
|
|
1223
|
+
unmountWorkbenchShell(this._shellContext);
|
|
1224
|
+
this._shellContext = void 0;
|
|
1225
|
+
}
|
|
541
1226
|
this._mounted = false;
|
|
542
1227
|
}
|
|
543
1228
|
refreshLayout() {
|
|
@@ -546,9 +1231,10 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
546
1231
|
try {
|
|
547
1232
|
const result = await this.requireTemplateController().importTemplate(file);
|
|
548
1233
|
this._state.activePanelFilter = result.panelFilter;
|
|
549
|
-
|
|
1234
|
+
const refs = this.requireRefs();
|
|
1235
|
+
if (this._runtimeController) {
|
|
550
1236
|
await this._runtimeController.remountPanel(
|
|
551
|
-
|
|
1237
|
+
refs.panelHost,
|
|
552
1238
|
result.panelFilter
|
|
553
1239
|
);
|
|
554
1240
|
}
|
|
@@ -558,11 +1244,28 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
558
1244
|
}
|
|
559
1245
|
}
|
|
560
1246
|
async exportTemplate() {
|
|
1247
|
+
return this.exportTemplateWithFields();
|
|
1248
|
+
}
|
|
1249
|
+
async exportTemplateWithFields(selectedFieldPaths) {
|
|
561
1250
|
try {
|
|
562
|
-
|
|
1251
|
+
this._state.busy.exportTemplate = true;
|
|
1252
|
+
if (this._shellContext) {
|
|
1253
|
+
this._shellContext.state.templateExportLoading = true;
|
|
1254
|
+
}
|
|
1255
|
+
const result = await this.requireTemplateController().exportTemplate(
|
|
1256
|
+
selectedFieldPaths
|
|
1257
|
+
);
|
|
563
1258
|
dispatchWorkbenchEvent(this, "template-exported", result);
|
|
1259
|
+
if (selectedFieldPaths) {
|
|
1260
|
+
this.closeTemplateExportDialog();
|
|
1261
|
+
}
|
|
564
1262
|
} catch (error) {
|
|
565
1263
|
this.handleError("template", error);
|
|
1264
|
+
} finally {
|
|
1265
|
+
this._state.busy.exportTemplate = false;
|
|
1266
|
+
if (this._shellContext) {
|
|
1267
|
+
this._shellContext.state.templateExportLoading = false;
|
|
1268
|
+
}
|
|
566
1269
|
}
|
|
567
1270
|
}
|
|
568
1271
|
async exportSvg() {
|
|
@@ -581,11 +1284,37 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
581
1284
|
this.handleError("export", error);
|
|
582
1285
|
}
|
|
583
1286
|
}
|
|
1287
|
+
async setAuthToken(token) {
|
|
1288
|
+
var _a, _b;
|
|
1289
|
+
const normalizedToken = token.trim();
|
|
1290
|
+
if (!normalizedToken) {
|
|
1291
|
+
throw new Error("[generator-workbench] token is required");
|
|
1292
|
+
}
|
|
1293
|
+
if (!this._sdk) {
|
|
1294
|
+
throw new Error("[generator-workbench] sdk is required before setAuthToken()");
|
|
1295
|
+
}
|
|
1296
|
+
const appKey = (_b = (_a = this._sdk).getAppKey) == null ? void 0 : _b.call(_a);
|
|
1297
|
+
if (!appKey) {
|
|
1298
|
+
throw new Error("[generator-workbench] sdk.getAppKey() is required for setAuthToken()");
|
|
1299
|
+
}
|
|
1300
|
+
if (typeof this._sdk.auth.syncToken !== "function") {
|
|
1301
|
+
throw new Error("[generator-workbench] sdk.auth.syncToken() is required for setAuthToken()");
|
|
1302
|
+
}
|
|
1303
|
+
try {
|
|
1304
|
+
localStorage.setItem(`${TOKEN_STORAGE_KEY_PREFIX}${appKey}`, normalizedToken);
|
|
1305
|
+
} catch {
|
|
1306
|
+
}
|
|
1307
|
+
await this._sdk.auth.syncToken(normalizedToken);
|
|
1308
|
+
}
|
|
584
1309
|
render() {
|
|
585
1310
|
if (!this.shadowRoot) return;
|
|
586
|
-
|
|
587
|
-
|
|
1311
|
+
if (this._shellContext) {
|
|
1312
|
+
unmountWorkbenchShell(this._shellContext);
|
|
1313
|
+
this.shadowRoot.innerHTML = "";
|
|
1314
|
+
}
|
|
1315
|
+
this._shellContext = renderWorkbenchShell(this.shadowRoot, this._config);
|
|
588
1316
|
this.syncAuthUI();
|
|
1317
|
+
this.syncBillingUI();
|
|
589
1318
|
}
|
|
590
1319
|
bindControllers() {
|
|
591
1320
|
if (!this._sdk || !this._runtime) return;
|
|
@@ -605,47 +1334,86 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
605
1334
|
runtime: this._runtime
|
|
606
1335
|
});
|
|
607
1336
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
1337
|
+
bindShellCallbacks() {
|
|
1338
|
+
if (!this._shellContext) return;
|
|
1339
|
+
const { callbacks } = this._shellContext;
|
|
1340
|
+
callbacks.onLogin = () => {
|
|
611
1341
|
void this.handleLogin();
|
|
612
|
-
}
|
|
613
|
-
|
|
1342
|
+
};
|
|
1343
|
+
callbacks.onLogout = () => {
|
|
614
1344
|
void this.handleLogout();
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}
|
|
622
|
-
|
|
1345
|
+
};
|
|
1346
|
+
callbacks.onImportTemplate = () => {
|
|
1347
|
+
this.requireRefs().templateFileInput.click();
|
|
1348
|
+
};
|
|
1349
|
+
callbacks.onExportTemplate = () => {
|
|
1350
|
+
this.openTemplateExportDialog();
|
|
1351
|
+
};
|
|
1352
|
+
callbacks.onCloseTemplateDialog = () => {
|
|
1353
|
+
this.closeTemplateExportDialog();
|
|
1354
|
+
};
|
|
1355
|
+
callbacks.onToggleTemplateDialog = (open) => {
|
|
1356
|
+
if (!open) {
|
|
1357
|
+
this.closeTemplateExportDialog();
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
callbacks.onToggleTemplateField = (path, checked) => {
|
|
1361
|
+
this.toggleTemplateExportField(path, checked);
|
|
1362
|
+
};
|
|
1363
|
+
callbacks.onConfirmTemplateExport = () => {
|
|
623
1364
|
var _a;
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
refs.fabTrigger.addEventListener("click", () => {
|
|
630
|
-
this.toggleFabMenu();
|
|
631
|
-
});
|
|
632
|
-
refs.exportSvgBtn.addEventListener("click", () => {
|
|
1365
|
+
void this.exportTemplateWithFields(
|
|
1366
|
+
((_a = this._shellContext) == null ? void 0 : _a.state.templateSelectedFieldPaths) || []
|
|
1367
|
+
);
|
|
1368
|
+
};
|
|
1369
|
+
callbacks.onExportSvg = () => {
|
|
633
1370
|
void this.exportSvg();
|
|
634
|
-
}
|
|
635
|
-
|
|
1371
|
+
};
|
|
1372
|
+
callbacks.onOpenInStudio = () => {
|
|
636
1373
|
void this.openInStudio();
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
1374
|
+
};
|
|
1375
|
+
callbacks.onFileChange = (event) => {
|
|
1376
|
+
var _a;
|
|
1377
|
+
const input = event.target;
|
|
1378
|
+
const file = (_a = input.files) == null ? void 0 : _a[0];
|
|
1379
|
+
if (!file) return;
|
|
1380
|
+
void this.importTemplate(file);
|
|
1381
|
+
input.value = "";
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
openTemplateExportDialog() {
|
|
1385
|
+
try {
|
|
1386
|
+
if (!this._shellContext) return;
|
|
1387
|
+
const prepared = this.requireTemplateController().prepareTemplateExport();
|
|
1388
|
+
this._shellContext.state.templateFieldGroups = prepared.fieldGroups.map(
|
|
1389
|
+
(group) => ({
|
|
1390
|
+
...group,
|
|
1391
|
+
fields: group.fields.map((field) => ({ ...field }))
|
|
1392
|
+
})
|
|
1393
|
+
);
|
|
1394
|
+
this._shellContext.state.templateSelectedFieldPaths = [
|
|
1395
|
+
...prepared.selectedFieldPaths
|
|
1396
|
+
];
|
|
1397
|
+
this._shellContext.state.templateDialogOpen = true;
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
this.handleError("template", error);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
closeTemplateExportDialog() {
|
|
1403
|
+
if (!this._shellContext) return;
|
|
1404
|
+
this._shellContext.state.templateDialogOpen = false;
|
|
1405
|
+
this._shellContext.state.templateFieldGroups = [];
|
|
1406
|
+
this._shellContext.state.templateSelectedFieldPaths = [];
|
|
1407
|
+
}
|
|
1408
|
+
toggleTemplateExportField(path, checked) {
|
|
1409
|
+
if (!this._shellContext) return;
|
|
1410
|
+
const selected = new Set(this._shellContext.state.templateSelectedFieldPaths);
|
|
1411
|
+
if (checked) {
|
|
1412
|
+
selected.add(path);
|
|
1413
|
+
} else {
|
|
1414
|
+
selected.delete(path);
|
|
648
1415
|
}
|
|
1416
|
+
this._shellContext.state.templateSelectedFieldPaths = Array.from(selected);
|
|
649
1417
|
}
|
|
650
1418
|
bindAuthState() {
|
|
651
1419
|
var _a;
|
|
@@ -654,52 +1422,111 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
654
1422
|
this._cleanupAuth = controller.subscribe((status) => {
|
|
655
1423
|
this._state.authStatus = status;
|
|
656
1424
|
this.syncAuthUI();
|
|
1425
|
+
void this.syncBillingState(status);
|
|
657
1426
|
dispatchWorkbenchEvent(this, "auth-change", status);
|
|
658
1427
|
});
|
|
1428
|
+
this.bindBillingSubscriptions();
|
|
1429
|
+
}
|
|
1430
|
+
bindBillingSubscriptions() {
|
|
1431
|
+
var _a, _b, _c, _d;
|
|
1432
|
+
(_a = this._cleanupCredits) == null ? void 0 : _a.call(this);
|
|
1433
|
+
this._cleanupCredits = void 0;
|
|
1434
|
+
(_b = this._cleanupBilling) == null ? void 0 : _b.call(this);
|
|
1435
|
+
this._cleanupBilling = void 0;
|
|
1436
|
+
const creditsModule = (_c = this._sdk) == null ? void 0 : _c.credits;
|
|
1437
|
+
if (typeof (creditsModule == null ? void 0 : creditsModule.onChange) === "function") {
|
|
1438
|
+
this._cleanupCredits = creditsModule.onChange((balance) => {
|
|
1439
|
+
this._state.creditsBalance = Number(balance) || 0;
|
|
1440
|
+
this.syncBillingUI();
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
const billingModule = (_d = this._sdk) == null ? void 0 : _d.billing;
|
|
1444
|
+
if (typeof (billingModule == null ? void 0 : billingModule.onChange) === "function") {
|
|
1445
|
+
this._cleanupBilling = billingModule.onChange((usage) => {
|
|
1446
|
+
this.applyBillingUsage(usage);
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
659
1449
|
}
|
|
660
1450
|
syncAuthUI() {
|
|
661
|
-
|
|
662
|
-
|
|
1451
|
+
var _a, _b, _c, _d;
|
|
1452
|
+
if (!this._shellContext) return;
|
|
1453
|
+
const { state } = this._shellContext;
|
|
663
1454
|
const { isLogin, userInfo } = this._state.authStatus;
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
this.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
this.
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
this.
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1455
|
+
const displayName = ((_a = userInfo == null ? void 0 : userInfo.userName) == null ? void 0 : _a.trim()) || ((_b = userInfo == null ? void 0 : userInfo.email) == null ? void 0 : _b.trim()) || ((_c = userInfo == null ? void 0 : userInfo.phoneNumber) == null ? void 0 : _c.trim()) || "";
|
|
1456
|
+
const avatarText = displayName ? displayName.charAt(0).toUpperCase() : "U";
|
|
1457
|
+
const authSubline = ((_d = userInfo == null ? void 0 : userInfo.email) == null ? void 0 : _d.trim()) || ((userInfo == null ? void 0 : userInfo.phoneNumber) ? `${userInfo.phoneZone || ""}${userInfo.phoneNumber}` : "Connected to Generator SDK");
|
|
1458
|
+
state.isLogin = isLogin;
|
|
1459
|
+
state.avatarSrc = isLogin ? (userInfo == null ? void 0 : userInfo.headpic) || "" : "";
|
|
1460
|
+
state.avatarText = avatarText;
|
|
1461
|
+
state.authDisplayName = displayName;
|
|
1462
|
+
state.authSubline = isLogin ? authSubline : "";
|
|
1463
|
+
}
|
|
1464
|
+
syncBillingUI() {
|
|
1465
|
+
if (!this._shellContext) return;
|
|
1466
|
+
const { state } = this._shellContext;
|
|
1467
|
+
const usage = this._state.billingUsage;
|
|
1468
|
+
state.creditsBalance = this._state.creditsBalance;
|
|
1469
|
+
state.exportCreditsCost = (usage == null ? void 0 : usage.creditsPerUse) ?? (usage && "unitPrice" in usage ? Number(usage.unitPrice) || 1 : 1);
|
|
1470
|
+
}
|
|
1471
|
+
applyBillingUsage(usage) {
|
|
1472
|
+
this._state.billingUsage = usage || null;
|
|
1473
|
+
if (usage && typeof usage.creditsBalance === "number") {
|
|
1474
|
+
this._state.creditsBalance = usage.creditsBalance;
|
|
1475
|
+
}
|
|
1476
|
+
this.syncBillingUI();
|
|
1477
|
+
}
|
|
1478
|
+
resetBillingState() {
|
|
1479
|
+
this._state.creditsBalance = 0;
|
|
1480
|
+
this._state.billingUsage = null;
|
|
1481
|
+
this.syncBillingUI();
|
|
1482
|
+
}
|
|
1483
|
+
async syncBillingState(status = this._state.authStatus) {
|
|
1484
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1485
|
+
if (!status.isLogin || !this._sdk) {
|
|
1486
|
+
this.resetBillingState();
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
const cachedBalance = (_b = (_a = this._sdk.credits) == null ? void 0 : _a.getCachedBalance) == null ? void 0 : _b.call(_a);
|
|
1490
|
+
if (typeof cachedBalance === "number") {
|
|
1491
|
+
this._state.creditsBalance = cachedBalance;
|
|
1492
|
+
}
|
|
1493
|
+
const cachedUsage = (_d = (_c = this._sdk.billing) == null ? void 0 : _c.getCachedUsage) == null ? void 0 : _d.call(_c);
|
|
1494
|
+
if (cachedUsage) {
|
|
1495
|
+
this.applyBillingUsage(cachedUsage);
|
|
1496
|
+
} else {
|
|
1497
|
+
this.syncBillingUI();
|
|
1498
|
+
}
|
|
1499
|
+
try {
|
|
1500
|
+
const [creditsResult, usage] = await Promise.all([
|
|
1501
|
+
(_f = (_e = this._sdk.credits) == null ? void 0 : _e.getBalance) == null ? void 0 : _f.call(_e),
|
|
1502
|
+
(_h = (_g = this._sdk.billing) == null ? void 0 : _g.getUsage) == null ? void 0 : _h.call(_g)
|
|
1503
|
+
]);
|
|
1504
|
+
if (typeof (creditsResult == null ? void 0 : creditsResult.quota) === "number") {
|
|
1505
|
+
this._state.creditsBalance = creditsResult.quota;
|
|
1506
|
+
}
|
|
1507
|
+
if (usage) {
|
|
1508
|
+
this.applyBillingUsage(usage);
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
this.syncBillingUI();
|
|
1512
|
+
} catch (error) {
|
|
1513
|
+
this.handleError("auth", error);
|
|
1514
|
+
}
|
|
694
1515
|
}
|
|
695
1516
|
async handleLogin() {
|
|
696
1517
|
try {
|
|
697
1518
|
this._state.busy.login = true;
|
|
1519
|
+
if (this._shellContext) {
|
|
1520
|
+
this._shellContext.state.loginLoading = true;
|
|
1521
|
+
}
|
|
698
1522
|
await this.requireAuthController().login();
|
|
699
1523
|
} catch (error) {
|
|
700
1524
|
this.handleError("auth", error);
|
|
701
1525
|
} finally {
|
|
702
1526
|
this._state.busy.login = false;
|
|
1527
|
+
if (this._shellContext) {
|
|
1528
|
+
this._shellContext.state.loginLoading = false;
|
|
1529
|
+
}
|
|
703
1530
|
}
|
|
704
1531
|
}
|
|
705
1532
|
async handleLogout() {
|
|
@@ -719,10 +1546,10 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
719
1546
|
});
|
|
720
1547
|
}
|
|
721
1548
|
requireRefs() {
|
|
722
|
-
if (!this.
|
|
723
|
-
throw new Error("[generator-workbench]
|
|
1549
|
+
if (!this._shellContext) {
|
|
1550
|
+
throw new Error("[generator-workbench] shell context is not ready");
|
|
724
1551
|
}
|
|
725
|
-
return this.
|
|
1552
|
+
return this._shellContext.refs;
|
|
726
1553
|
}
|
|
727
1554
|
requireAuthController() {
|
|
728
1555
|
if (!this._authController) {
|