@mevdragon/vidfarm-devcli 0.2.7 → 0.2.9
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/.env.example +9 -0
- package/GETTING_STARTED.developers.md +1 -30
- package/README.md +22 -5
- package/SKILL.developer.md +464 -12
- package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +475 -0
- package/auto-create-templates/extractor-system-prompt.md +113 -0
- package/auto-create-templates/production-graph.schema.json +276 -0
- package/auto-create-templates/runbook.md +140 -0
- package/auto-create-templates/template-plan.schema.json +230 -0
- package/auto-create-templates/template-planner-prompt.md +75 -0
- package/dist/src/account-pages-legacy.js +9064 -0
- package/dist/src/account-pages.js +41 -620
- package/dist/src/app.js +7173 -494
- package/dist/src/cli.js +525 -29
- package/dist/src/config.js +14 -7
- package/dist/src/context.js +51 -35
- package/dist/src/db.js +1049 -55
- package/dist/src/dev-app-legacy.js +693 -0
- package/dist/src/dev-app.js +4 -904
- package/dist/src/domain.js +1 -1
- package/dist/src/editor-chat-history.js +72 -0
- package/dist/src/editor-chat.js +202 -0
- package/dist/src/frontend/flockposter-cache-store.js +116 -0
- package/dist/src/frontend/homepage-client.js +114 -0
- package/dist/src/frontend/homepage-shared.js +3 -0
- package/dist/src/frontend/homepage-store.js +27 -0
- package/dist/src/frontend/homepage-view.js +147 -0
- package/dist/src/frontend/page-runtime-client.js +100 -0
- package/dist/src/frontend/page-runtime-store.js +8 -0
- package/dist/src/frontend/template-editor-chat.js +2261 -0
- package/dist/src/homepage.js +695 -339
- package/dist/src/lib/template-paths.js +10 -4
- package/dist/src/lib/template-style-options.js +95 -15
- package/dist/src/page-runtime.js +1 -0
- package/dist/src/page-shell.js +941 -0
- package/dist/src/primitive-context.js +163 -0
- package/dist/src/primitive-registry.js +340 -0
- package/dist/src/primitive-sdk.js +3 -0
- package/dist/src/primitives/remotion/html-image.js +28 -0
- package/dist/src/react-page-shell.js +34 -0
- package/dist/src/ready-post-schedule-component.js +1514 -0
- package/dist/src/registry.js +44 -18
- package/dist/src/runtime.js +6 -1
- package/dist/src/services/api-call-history.js +245 -0
- package/dist/src/services/auth.js +27 -9
- package/dist/src/services/billing.js +248 -9
- package/dist/src/services/chat-threads.js +88 -0
- package/dist/src/services/job-logs.js +10 -3
- package/dist/src/services/jobs.js +13 -2
- package/dist/src/services/providers.js +944 -55
- package/dist/src/services/rate-limits.js +236 -0
- package/dist/src/services/remotion.js +143 -16
- package/dist/src/services/storage.js +23 -8
- package/dist/src/services/template-certification.js +26 -3
- package/dist/src/services/template-loader.js +19 -1
- package/dist/src/services/template-sources.js +316 -7
- package/dist/src/template-editor-pages.js +2309 -0
- package/dist/src/template-editor-shell.js +1507 -0
- package/dist/src/worker.js +120 -22
- package/package.json +30 -6
- package/public/assets/homepage-app.js +54 -0
- package/public/assets/homepage-client-app.js +54 -0
- package/public/assets/page-runtime-client-app.js +68 -0
- package/dist/templates/template_0000/src/lib/images.js +0 -202
- package/dist/templates/template_0000/src/remotion/Root.js +0 -33
- package/dist/templates/template_0000/src/remotion/index.js +0 -3
- package/dist/templates/template_0000/src/sdk.js +0 -3
- package/dist/templates/template_0000/src/style-options.js +0 -51
- package/dist/templates/template_0000/src/template-dna.js +0 -9
- package/dist/templates/template_0000/src/template.js +0 -1441
- package/templates/template_0000/README.md +0 -77
- package/templates/template_0000/SKILL.md +0 -225
- package/templates/template_0000/assets/Abel-Regular.ttf +0 -0
- package/templates/template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
- package/templates/template_0000/assets/Montserrat[wght].ttf +0 -0
- package/templates/template_0000/assets/SourceCodePro[wght].ttf +0 -0
- package/templates/template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
- package/templates/template_0000/assets/Yesteryear-Regular.ttf +0 -0
- package/templates/template_0000/composition.json +0 -11
- package/templates/template_0000/package.json +0 -28
- package/templates/template_0000/research/preview/.gitkeep +0 -1
- package/templates/template_0000/research/source_notes.md +0 -7
- package/templates/template_0000/src/lib/images.js +0 -202
- package/templates/template_0000/src/lib/images.ts +0 -241
- package/templates/template_0000/src/remotion/Root.js +0 -33
- package/templates/template_0000/src/remotion/Root.tsx +0 -75
- package/templates/template_0000/src/remotion/index.js +0 -3
- package/templates/template_0000/src/remotion/index.tsx +0 -4
- package/templates/template_0000/src/sdk.js +0 -3
- package/templates/template_0000/src/sdk.ts +0 -122
- package/templates/template_0000/src/style-options.js +0 -51
- package/templates/template_0000/src/style-options.ts +0 -60
- package/templates/template_0000/src/template-dna.js +0 -9
- package/templates/template_0000/src/template-dna.ts +0 -15
- package/templates/template_0000/src/template.js +0 -1441
- package/templates/template_0000/src/template.ts +0 -2042
- package/templates/template_0000/template.config.json +0 -21
- package/templates/template_0000/tsconfig.json +0 -19
|
@@ -0,0 +1,2309 @@
|
|
|
1
|
+
import { escapeAttribute, escapeHtml, renderPageShell, withAccountQuery } from "./page-shell.js";
|
|
2
|
+
import { renderTemplateEditorChrome, TEMPLATE_EDITOR_SHELL_SCRIPT, TEMPLATE_EDITOR_SHELL_STYLES } from "./template-editor-shell.js";
|
|
3
|
+
export function renderTemplateEditorDocsPage(input) {
|
|
4
|
+
const backHref = withAccountQuery("/discover", input.account.userId);
|
|
5
|
+
const hasHistoryAccess = input.account.isLoggedIn;
|
|
6
|
+
const preview = input.template.previewUrl
|
|
7
|
+
? renderPreview(input.template.previewUrl, `${input.template.title} preview`)
|
|
8
|
+
: `<div class="editor-preview editor-preview-empty">No preview asset</div>`;
|
|
9
|
+
return renderPageShell({
|
|
10
|
+
title: `${input.template.title} editor`,
|
|
11
|
+
mainClass: "is-wide",
|
|
12
|
+
runtimeBoot: input.editorChat ? {
|
|
13
|
+
pageKind: "legacy",
|
|
14
|
+
title: `${input.template.title} editor`,
|
|
15
|
+
userId: input.account.userId ?? null,
|
|
16
|
+
editorChat: input.editorChat
|
|
17
|
+
} : undefined,
|
|
18
|
+
style: `
|
|
19
|
+
${TEMPLATE_EDITOR_SHELL_STYLES}
|
|
20
|
+
|
|
21
|
+
.editor-workbench,
|
|
22
|
+
.editor-main,
|
|
23
|
+
.editor-shell {
|
|
24
|
+
padding-bottom: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.editor-shell {
|
|
28
|
+
display: grid;
|
|
29
|
+
gap: 18px;
|
|
30
|
+
min-height: 0;
|
|
31
|
+
grid-template-rows: auto auto minmax(0, 1fr);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.editor-hero,
|
|
35
|
+
.editor-section {
|
|
36
|
+
border: 1px solid rgba(102, 82, 43, 0.14);
|
|
37
|
+
border-radius: 28px;
|
|
38
|
+
background: rgba(255, 251, 244, 0.78);
|
|
39
|
+
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.04);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.editor-panel {
|
|
43
|
+
border: 1px solid rgba(102, 82, 43, 0.14);
|
|
44
|
+
border-radius: 28px;
|
|
45
|
+
background: rgba(255, 251, 244, 0.78);
|
|
46
|
+
box-shadow: 0 14px 34px rgba(15, 23, 42, 0.04);
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.editor-panel > summary {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: space-between;
|
|
54
|
+
gap: 16px;
|
|
55
|
+
padding: 18px 22px;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
list-style: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.editor-panel > summary::-webkit-details-marker {
|
|
61
|
+
display: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.editor-panel-summary {
|
|
65
|
+
display: grid;
|
|
66
|
+
gap: 4px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.editor-panel-summary h2 {
|
|
70
|
+
margin: 0;
|
|
71
|
+
font-size: 1.55rem;
|
|
72
|
+
letter-spacing: -0.04em;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.editor-panel-summary p {
|
|
76
|
+
margin: 0;
|
|
77
|
+
color: #617087;
|
|
78
|
+
line-height: 1.6;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.editor-panel-toggle {
|
|
82
|
+
display: inline-flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 10px;
|
|
85
|
+
color: #445066;
|
|
86
|
+
font-size: 0.82rem;
|
|
87
|
+
font-weight: 700;
|
|
88
|
+
letter-spacing: 0.08em;
|
|
89
|
+
text-transform: uppercase;
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.editor-panel-toggle::before {
|
|
94
|
+
content: "";
|
|
95
|
+
width: 11px;
|
|
96
|
+
height: 11px;
|
|
97
|
+
border-right: 2px solid currentColor;
|
|
98
|
+
border-bottom: 2px solid currentColor;
|
|
99
|
+
transform: rotate(45deg) translateY(-2px);
|
|
100
|
+
transition: transform 180ms ease;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.editor-panel[open] .editor-panel-toggle::before {
|
|
104
|
+
transform: rotate(225deg) translateY(-1px);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.editor-panel-body {
|
|
108
|
+
padding: 0 22px 22px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.editor-panel-body > .editor-hero,
|
|
112
|
+
.editor-panel-body > .editor-section {
|
|
113
|
+
border: 0;
|
|
114
|
+
border-radius: 0;
|
|
115
|
+
background: transparent;
|
|
116
|
+
box-shadow: none;
|
|
117
|
+
padding: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.editor-hero {
|
|
121
|
+
display: grid;
|
|
122
|
+
grid-template-columns: minmax(280px, 420px) minmax(0, 1fr);
|
|
123
|
+
gap: 22px;
|
|
124
|
+
padding: 22px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.editor-preview {
|
|
128
|
+
width: 100%;
|
|
129
|
+
min-height: 320px;
|
|
130
|
+
max-height: 560px;
|
|
131
|
+
object-fit: contain;
|
|
132
|
+
border-radius: 24px;
|
|
133
|
+
border: 1px solid rgba(209, 219, 233, 0.96);
|
|
134
|
+
background: rgba(255, 255, 255, 0.92);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.editor-preview-empty {
|
|
138
|
+
display: grid;
|
|
139
|
+
place-items: center;
|
|
140
|
+
color: #74829c;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.editor-copy {
|
|
144
|
+
display: grid;
|
|
145
|
+
align-content: start;
|
|
146
|
+
gap: 18px;
|
|
147
|
+
min-width: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.editor-kicker {
|
|
151
|
+
color: #8d99ae;
|
|
152
|
+
font-size: 0.85rem;
|
|
153
|
+
text-transform: uppercase;
|
|
154
|
+
letter-spacing: 0.12em;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.editor-title {
|
|
158
|
+
margin: 0;
|
|
159
|
+
font-size: clamp(2rem, 3.6vw, 3.1rem);
|
|
160
|
+
line-height: 0.94;
|
|
161
|
+
letter-spacing: -0.06em;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.editor-copy p {
|
|
165
|
+
margin: 0;
|
|
166
|
+
color: #5f6c83;
|
|
167
|
+
font-size: 1rem;
|
|
168
|
+
line-height: 1.7;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.editor-pills,
|
|
172
|
+
.editor-route-list {
|
|
173
|
+
display: flex;
|
|
174
|
+
flex-wrap: wrap;
|
|
175
|
+
gap: 10px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.editor-toolbar {
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-wrap: wrap;
|
|
181
|
+
gap: 10px;
|
|
182
|
+
margin-top: 14px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.editor-copy-button {
|
|
186
|
+
appearance: none;
|
|
187
|
+
border: 1px solid rgba(102, 82, 43, 0.18);
|
|
188
|
+
background: rgba(255, 255, 255, 0.88);
|
|
189
|
+
color: #2f3c4f;
|
|
190
|
+
border-radius: 999px;
|
|
191
|
+
padding: 10px 14px;
|
|
192
|
+
font: inherit;
|
|
193
|
+
font-size: 0.88rem;
|
|
194
|
+
font-weight: 700;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.editor-copy-button:hover {
|
|
199
|
+
border-color: rgba(102, 82, 43, 0.3);
|
|
200
|
+
background: #fff;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.editor-pill,
|
|
204
|
+
.editor-route-method {
|
|
205
|
+
display: inline-flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
justify-content: center;
|
|
208
|
+
min-height: 42px;
|
|
209
|
+
padding: 0 16px;
|
|
210
|
+
border-radius: 999px;
|
|
211
|
+
border: 1px solid rgba(191, 164, 109, 0.34);
|
|
212
|
+
background: rgba(255, 255, 255, 0.9);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.editor-grid {
|
|
216
|
+
display: grid;
|
|
217
|
+
grid-template-columns: minmax(0, 1fr);
|
|
218
|
+
gap: 18px;
|
|
219
|
+
min-height: 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.editor-section {
|
|
223
|
+
display: grid;
|
|
224
|
+
align-content: start;
|
|
225
|
+
gap: 16px;
|
|
226
|
+
padding: 22px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.editor-section h2,
|
|
230
|
+
.editor-section h3 {
|
|
231
|
+
margin: 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.editor-section h2 {
|
|
235
|
+
font-size: 1.55rem;
|
|
236
|
+
letter-spacing: -0.04em;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.editor-section h3 {
|
|
240
|
+
font-size: 1rem;
|
|
241
|
+
color: #243041;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.editor-section-header {
|
|
245
|
+
display: grid;
|
|
246
|
+
gap: 6px;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.editor-section-header p,
|
|
250
|
+
.editor-note {
|
|
251
|
+
margin: 0;
|
|
252
|
+
color: #617087;
|
|
253
|
+
line-height: 1.7;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.editor-route-card {
|
|
257
|
+
display: grid;
|
|
258
|
+
gap: 10px;
|
|
259
|
+
padding: 16px;
|
|
260
|
+
border-radius: 20px;
|
|
261
|
+
border: 1px solid rgba(191, 164, 109, 0.22);
|
|
262
|
+
background: rgba(255, 255, 255, 0.72);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.editor-route-head {
|
|
266
|
+
display: flex;
|
|
267
|
+
flex-wrap: wrap;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 10px;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.editor-route-method {
|
|
273
|
+
min-height: 30px;
|
|
274
|
+
padding: 0 10px;
|
|
275
|
+
font-size: 0.77rem;
|
|
276
|
+
font-weight: 800;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.editor-route-method[data-method="POST"] {
|
|
280
|
+
color: #7a4b16;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.editor-route-method[data-method="GET"] {
|
|
284
|
+
color: #1e5c52;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.editor-route-path {
|
|
288
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
289
|
+
font-size: 0.82rem;
|
|
290
|
+
line-height: 1.5;
|
|
291
|
+
word-break: break-all;
|
|
292
|
+
color: #324156;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.editor-code-block {
|
|
296
|
+
margin: 0;
|
|
297
|
+
padding: 14px 16px;
|
|
298
|
+
border-radius: 18px;
|
|
299
|
+
background: rgba(37, 45, 61, 0.97);
|
|
300
|
+
color: #f7efe1;
|
|
301
|
+
overflow: auto;
|
|
302
|
+
font-size: 0.82rem;
|
|
303
|
+
line-height: 1.55;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.editor-quickstart-grid {
|
|
307
|
+
display: grid;
|
|
308
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
309
|
+
gap: 14px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.editor-quickstart-field {
|
|
313
|
+
display: grid;
|
|
314
|
+
gap: 8px;
|
|
315
|
+
min-width: 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.editor-quickstart-field-head {
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
justify-content: flex-start;
|
|
322
|
+
gap: 8px;
|
|
323
|
+
min-width: 0;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.editor-quickstart-field-head span {
|
|
327
|
+
color: #324156;
|
|
328
|
+
font-size: 0.82rem;
|
|
329
|
+
font-weight: 800;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.editor-quickstart-copy {
|
|
333
|
+
appearance: none;
|
|
334
|
+
box-sizing: border-box;
|
|
335
|
+
display: inline-flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
justify-content: center;
|
|
338
|
+
width: 36px;
|
|
339
|
+
min-width: 36px;
|
|
340
|
+
height: 36px;
|
|
341
|
+
min-height: 36px;
|
|
342
|
+
flex: 0 0 36px;
|
|
343
|
+
gap: 0;
|
|
344
|
+
padding: 0;
|
|
345
|
+
border-radius: 999px;
|
|
346
|
+
border: 1px solid rgba(171, 138, 68, 0.48);
|
|
347
|
+
background: #dbc17a;
|
|
348
|
+
color: #243041;
|
|
349
|
+
cursor: pointer;
|
|
350
|
+
line-height: 1;
|
|
351
|
+
box-shadow:
|
|
352
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.58),
|
|
353
|
+
0 6px 14px rgba(102, 82, 43, 0.12);
|
|
354
|
+
transition:
|
|
355
|
+
transform 120ms ease,
|
|
356
|
+
border-color 120ms ease,
|
|
357
|
+
background 120ms ease,
|
|
358
|
+
color 120ms ease;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.editor-quickstart-copy:hover {
|
|
362
|
+
border-color: rgba(102, 82, 43, 0.44);
|
|
363
|
+
background: #e4cb84;
|
|
364
|
+
color: #243041;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.editor-quickstart-copy:active {
|
|
368
|
+
transform: scale(0.94);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.editor-quickstart-copy::after {
|
|
372
|
+
content: "✓";
|
|
373
|
+
display: none;
|
|
374
|
+
color: currentColor;
|
|
375
|
+
font-size: 1rem;
|
|
376
|
+
font-weight: 900;
|
|
377
|
+
line-height: 1;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.editor-quickstart-copy[data-copying="true"] {
|
|
381
|
+
border-color: rgba(102, 82, 43, 0.5);
|
|
382
|
+
background: #ead89d;
|
|
383
|
+
color: #243041;
|
|
384
|
+
transform: scale(0.96);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.editor-quickstart-copy[data-copied="true"] {
|
|
388
|
+
border-color: rgba(30, 92, 82, 0.42);
|
|
389
|
+
background: #b9e1cf;
|
|
390
|
+
color: #1e5c52;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.editor-quickstart-copy[data-copy-error="true"] {
|
|
394
|
+
border-color: rgba(155, 45, 45, 0.42);
|
|
395
|
+
background: #f0c5bd;
|
|
396
|
+
color: #8d2f24;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.editor-quickstart-copy[data-copy-error="true"]::after {
|
|
400
|
+
content: "!";
|
|
401
|
+
display: block;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.editor-quickstart-copy[data-copied="true"]::after {
|
|
405
|
+
display: block;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.editor-quickstart-copy[data-copy-error="true"] svg,
|
|
409
|
+
.editor-quickstart-copy[data-copied="true"] svg {
|
|
410
|
+
display: none;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.editor-quickstart-copy svg {
|
|
414
|
+
display: block;
|
|
415
|
+
width: 17px;
|
|
416
|
+
height: 17px;
|
|
417
|
+
stroke: currentColor;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.editor-quickstart-textarea {
|
|
421
|
+
width: 100%;
|
|
422
|
+
min-height: 190px;
|
|
423
|
+
resize: vertical;
|
|
424
|
+
border: 1px solid rgba(191, 164, 109, 0.24);
|
|
425
|
+
border-radius: 18px;
|
|
426
|
+
background: rgba(255, 255, 255, 0.72);
|
|
427
|
+
color: #324156;
|
|
428
|
+
padding: 14px 15px;
|
|
429
|
+
font: 0.82rem/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
430
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.76);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.editor-quickstart-textarea:focus {
|
|
434
|
+
outline: 2px solid rgba(219, 193, 122, 0.38);
|
|
435
|
+
outline-offset: 2px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.editor-quickstart-samples {
|
|
439
|
+
display: grid;
|
|
440
|
+
gap: 8px;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.editor-quickstart-samples > h3 {
|
|
444
|
+
margin: 2px 0 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.editor-sample-prompt-row {
|
|
448
|
+
display: flex;
|
|
449
|
+
gap: 10px;
|
|
450
|
+
overflow-x: auto;
|
|
451
|
+
overflow-y: hidden;
|
|
452
|
+
padding: 2px 0 8px;
|
|
453
|
+
scrollbar-width: thin;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.editor-sample-prompt {
|
|
457
|
+
flex: 0 0 min(360px, 86vw);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.editor-sample-prompt .editor-quickstart-textarea {
|
|
461
|
+
min-height: 150px;
|
|
462
|
+
resize: none;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.editor-history-toolbar {
|
|
466
|
+
display: flex;
|
|
467
|
+
flex-wrap: wrap;
|
|
468
|
+
align-items: center;
|
|
469
|
+
justify-content: space-between;
|
|
470
|
+
gap: 12px;
|
|
471
|
+
margin-bottom: 18px;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.editor-history-toolbar p {
|
|
475
|
+
margin: 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.editor-history-chip-row {
|
|
479
|
+
display: flex;
|
|
480
|
+
flex-wrap: wrap;
|
|
481
|
+
gap: 8px;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.editor-history-toolbar-actions,
|
|
485
|
+
.editor-history-group-actions {
|
|
486
|
+
display: flex;
|
|
487
|
+
flex-wrap: wrap;
|
|
488
|
+
align-items: center;
|
|
489
|
+
gap: 8px;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.editor-history-toolbar-actions {
|
|
493
|
+
justify-content: flex-end;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.editor-history-button,
|
|
497
|
+
.editor-history-remove {
|
|
498
|
+
display: inline-flex;
|
|
499
|
+
align-items: center;
|
|
500
|
+
justify-content: center;
|
|
501
|
+
min-height: 32px;
|
|
502
|
+
padding: 0 12px;
|
|
503
|
+
border-radius: 999px;
|
|
504
|
+
border: 1px solid rgba(191, 164, 109, 0.34);
|
|
505
|
+
background: rgba(255, 255, 255, 0.92);
|
|
506
|
+
color: #324156;
|
|
507
|
+
font-size: 0.78rem;
|
|
508
|
+
font-weight: 700;
|
|
509
|
+
cursor: pointer;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.editor-history-remove {
|
|
513
|
+
color: #8d4a3b;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.editor-history-button.is-primary {
|
|
517
|
+
background: #dbc17a;
|
|
518
|
+
color: #243041;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.editor-history-refresh {
|
|
522
|
+
width: 30px;
|
|
523
|
+
min-height: 30px;
|
|
524
|
+
padding: 0;
|
|
525
|
+
border-radius: 999px;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.editor-history-refresh svg {
|
|
529
|
+
width: 15px;
|
|
530
|
+
height: 15px;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.editor-history-refresh[data-loading="true"] svg {
|
|
534
|
+
animation: editor-history-refresh-spin 0.8s linear infinite;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.editor-history-menu-wrap {
|
|
538
|
+
position: relative;
|
|
539
|
+
display: inline-flex;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.editor-history-menu-button {
|
|
543
|
+
width: 30px;
|
|
544
|
+
min-height: 30px;
|
|
545
|
+
padding: 0;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.editor-history-menu {
|
|
549
|
+
position: absolute;
|
|
550
|
+
right: 0;
|
|
551
|
+
top: calc(100% + 6px);
|
|
552
|
+
z-index: 20;
|
|
553
|
+
display: none;
|
|
554
|
+
min-width: 148px;
|
|
555
|
+
padding: 6px;
|
|
556
|
+
border: 1px solid rgba(191, 164, 109, 0.28);
|
|
557
|
+
border-radius: 10px;
|
|
558
|
+
background: rgba(255, 252, 247, 0.98);
|
|
559
|
+
box-shadow: 0 14px 34px rgba(37, 45, 61, 0.16);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.editor-history-menu-wrap[data-open="true"] .editor-history-menu {
|
|
563
|
+
display: grid;
|
|
564
|
+
gap: 2px;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.editor-history-menu button {
|
|
568
|
+
all: unset;
|
|
569
|
+
padding: 8px 9px;
|
|
570
|
+
border-radius: 7px;
|
|
571
|
+
color: #324156;
|
|
572
|
+
font-size: 0.78rem;
|
|
573
|
+
font-weight: 700;
|
|
574
|
+
cursor: pointer;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.editor-history-menu button:hover {
|
|
578
|
+
background: rgba(219, 193, 122, 0.16);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.editor-history-menu button[data-danger="true"] {
|
|
582
|
+
color: #8d4a3b;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.editor-history-group-previews {
|
|
586
|
+
display: flex;
|
|
587
|
+
flex-wrap: nowrap;
|
|
588
|
+
gap: 6px;
|
|
589
|
+
margin-top: 10px;
|
|
590
|
+
overflow: hidden;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.editor-history-group-previews.is-expanded {
|
|
594
|
+
max-width: min(100%, calc(100vw - 160px));
|
|
595
|
+
overflow-x: auto;
|
|
596
|
+
overflow-y: hidden;
|
|
597
|
+
padding-bottom: 5px;
|
|
598
|
+
scrollbar-width: thin;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.editor-history-group-preview {
|
|
602
|
+
position: relative;
|
|
603
|
+
width: 52px;
|
|
604
|
+
height: 52px;
|
|
605
|
+
padding: 0;
|
|
606
|
+
border-radius: 9px;
|
|
607
|
+
border: 1px solid rgba(191, 164, 109, 0.26);
|
|
608
|
+
background: rgba(255, 255, 255, 0.74);
|
|
609
|
+
overflow: hidden;
|
|
610
|
+
flex: 0 0 auto;
|
|
611
|
+
cursor: zoom-in;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.editor-history-group-preview img,
|
|
615
|
+
.editor-history-group-preview video {
|
|
616
|
+
width: 100%;
|
|
617
|
+
height: 100%;
|
|
618
|
+
object-fit: cover;
|
|
619
|
+
display: block;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.editor-history-group-preview-more {
|
|
623
|
+
display: inline-flex;
|
|
624
|
+
align-items: center;
|
|
625
|
+
justify-content: center;
|
|
626
|
+
padding: 0;
|
|
627
|
+
width: 52px;
|
|
628
|
+
height: 52px;
|
|
629
|
+
border-radius: 9px;
|
|
630
|
+
border: 1px dashed rgba(191, 164, 109, 0.32);
|
|
631
|
+
color: #617087;
|
|
632
|
+
font-size: 0.75rem;
|
|
633
|
+
font-weight: 800;
|
|
634
|
+
flex: 0 0 auto;
|
|
635
|
+
cursor: pointer;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
button.editor-history-group-preview-more:hover,
|
|
639
|
+
button.editor-history-group-preview-more:focus-visible {
|
|
640
|
+
border-style: solid;
|
|
641
|
+
color: #324156;
|
|
642
|
+
background: rgba(255, 255, 255, 0.9);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.editor-history-chip {
|
|
646
|
+
display: inline-flex;
|
|
647
|
+
align-items: center;
|
|
648
|
+
min-height: 30px;
|
|
649
|
+
padding: 0 10px;
|
|
650
|
+
border-radius: 999px;
|
|
651
|
+
border: 1px solid rgba(191, 164, 109, 0.34);
|
|
652
|
+
background: rgba(255, 255, 255, 0.9);
|
|
653
|
+
color: #3b465a;
|
|
654
|
+
font-size: 0.78rem;
|
|
655
|
+
font-weight: 700;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.editor-history-chip.is-empty {
|
|
659
|
+
color: #74829c;
|
|
660
|
+
border-style: dashed;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.editor-history-groups {
|
|
664
|
+
display: grid;
|
|
665
|
+
gap: 12px;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.editor-history-empty {
|
|
669
|
+
padding: 18px;
|
|
670
|
+
border-radius: 18px;
|
|
671
|
+
border: 1px dashed rgba(191, 164, 109, 0.34);
|
|
672
|
+
background: rgba(255, 255, 255, 0.56);
|
|
673
|
+
color: #617087;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.editor-history-group {
|
|
677
|
+
border: 1px solid rgba(191, 164, 109, 0.22);
|
|
678
|
+
border-radius: 20px;
|
|
679
|
+
background: rgba(255, 255, 255, 0.62);
|
|
680
|
+
overflow: hidden;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.editor-history-group > summary {
|
|
684
|
+
display: flex;
|
|
685
|
+
align-items: center;
|
|
686
|
+
justify-content: space-between;
|
|
687
|
+
gap: 12px;
|
|
688
|
+
padding: 14px 16px;
|
|
689
|
+
cursor: pointer;
|
|
690
|
+
list-style: none;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.editor-history-group > summary::-webkit-details-marker {
|
|
694
|
+
display: none;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.editor-history-group-main {
|
|
698
|
+
display: grid;
|
|
699
|
+
gap: 4px;
|
|
700
|
+
min-width: 0;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.editor-history-group-main h3 {
|
|
704
|
+
margin: 0;
|
|
705
|
+
font-size: 1rem;
|
|
706
|
+
color: #243041;
|
|
707
|
+
word-break: break-all;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.editor-history-group-main p {
|
|
711
|
+
margin: 0;
|
|
712
|
+
color: #74829c;
|
|
713
|
+
font-size: 0.82rem;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.editor-history-group-toggle {
|
|
717
|
+
color: #617087;
|
|
718
|
+
font-size: 0.8rem;
|
|
719
|
+
font-weight: 700;
|
|
720
|
+
letter-spacing: 0.08em;
|
|
721
|
+
text-transform: uppercase;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.editor-history-active {
|
|
725
|
+
display: inline-flex;
|
|
726
|
+
align-items: center;
|
|
727
|
+
min-height: 26px;
|
|
728
|
+
padding: 0 9px;
|
|
729
|
+
border-radius: 999px;
|
|
730
|
+
background: rgba(219, 193, 122, 0.2);
|
|
731
|
+
color: #7a4b16;
|
|
732
|
+
font-size: 0.74rem;
|
|
733
|
+
font-weight: 800;
|
|
734
|
+
letter-spacing: 0.08em;
|
|
735
|
+
text-transform: uppercase;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
@keyframes editor-history-refresh-spin {
|
|
739
|
+
to {
|
|
740
|
+
transform: rotate(360deg);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.editor-history-group-body {
|
|
745
|
+
display: grid;
|
|
746
|
+
gap: 10px;
|
|
747
|
+
padding: 0 16px 16px;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.editor-history-card {
|
|
751
|
+
display: grid;
|
|
752
|
+
gap: 8px;
|
|
753
|
+
padding: 10px;
|
|
754
|
+
border-radius: 12px;
|
|
755
|
+
border: 1px solid rgba(191, 164, 109, 0.18);
|
|
756
|
+
background: rgba(255, 251, 244, 0.92);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.editor-history-card-head {
|
|
760
|
+
display: flex;
|
|
761
|
+
flex-wrap: wrap;
|
|
762
|
+
justify-content: space-between;
|
|
763
|
+
gap: 10px;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.editor-history-card-main {
|
|
767
|
+
display: grid;
|
|
768
|
+
gap: 6px;
|
|
769
|
+
min-width: 0;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.editor-history-card-meta {
|
|
773
|
+
display: flex;
|
|
774
|
+
flex-wrap: wrap;
|
|
775
|
+
gap: 8px;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.editor-history-method,
|
|
779
|
+
.editor-history-status {
|
|
780
|
+
display: inline-flex;
|
|
781
|
+
align-items: center;
|
|
782
|
+
min-height: 28px;
|
|
783
|
+
padding: 0 10px;
|
|
784
|
+
border-radius: 999px;
|
|
785
|
+
border: 1px solid rgba(191, 164, 109, 0.3);
|
|
786
|
+
background: rgba(255, 255, 255, 0.92);
|
|
787
|
+
font-size: 0.78rem;
|
|
788
|
+
font-weight: 800;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.editor-history-method {
|
|
792
|
+
color: #7a4b16;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.editor-history-status.is-success {
|
|
796
|
+
color: #1e5c52;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.editor-history-status.is-error {
|
|
800
|
+
color: #9b2d2d;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.editor-history-card-path {
|
|
804
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
805
|
+
font-size: 0.8rem;
|
|
806
|
+
line-height: 1.55;
|
|
807
|
+
color: #324156;
|
|
808
|
+
word-break: break-all;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.editor-history-card-time {
|
|
812
|
+
color: #74829c;
|
|
813
|
+
font-size: 0.8rem;
|
|
814
|
+
white-space: nowrap;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.editor-history-card-previews {
|
|
818
|
+
display: flex;
|
|
819
|
+
flex-wrap: wrap;
|
|
820
|
+
gap: 8px;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.editor-history-card-preview {
|
|
824
|
+
position: relative;
|
|
825
|
+
width: 112px;
|
|
826
|
+
height: 112px;
|
|
827
|
+
display: inline-flex;
|
|
828
|
+
align-items: center;
|
|
829
|
+
justify-content: center;
|
|
830
|
+
overflow: hidden;
|
|
831
|
+
padding: 0;
|
|
832
|
+
border-radius: 18px;
|
|
833
|
+
border: 1px solid rgba(191, 164, 109, 0.34);
|
|
834
|
+
background: rgba(255, 255, 255, 0.94);
|
|
835
|
+
color: #324156;
|
|
836
|
+
text-decoration: none;
|
|
837
|
+
cursor: pointer;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.editor-history-video-play {
|
|
841
|
+
position: absolute;
|
|
842
|
+
left: 50%;
|
|
843
|
+
top: 50%;
|
|
844
|
+
width: 34px;
|
|
845
|
+
height: 34px;
|
|
846
|
+
transform: translate(-50%, -50%);
|
|
847
|
+
display: inline-flex;
|
|
848
|
+
align-items: center;
|
|
849
|
+
justify-content: center;
|
|
850
|
+
border-radius: 999px;
|
|
851
|
+
background: rgba(18, 24, 34, 0.72);
|
|
852
|
+
box-shadow: 0 8px 24px rgba(12, 18, 28, 0.22);
|
|
853
|
+
pointer-events: none;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.editor-history-group-preview .editor-history-video-play {
|
|
857
|
+
width: 24px;
|
|
858
|
+
height: 24px;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
.editor-history-video-play::before {
|
|
862
|
+
content: "";
|
|
863
|
+
display: block;
|
|
864
|
+
width: 0;
|
|
865
|
+
height: 0;
|
|
866
|
+
margin-left: 3px;
|
|
867
|
+
border-top: 7px solid transparent;
|
|
868
|
+
border-bottom: 7px solid transparent;
|
|
869
|
+
border-left: 11px solid #fff8ee;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.editor-history-group-preview .editor-history-video-play::before {
|
|
873
|
+
margin-left: 2px;
|
|
874
|
+
border-top-width: 5px;
|
|
875
|
+
border-bottom-width: 5px;
|
|
876
|
+
border-left-width: 8px;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
.editor-history-card-preview img,
|
|
880
|
+
.editor-history-card-preview video {
|
|
881
|
+
width: 100%;
|
|
882
|
+
height: 100%;
|
|
883
|
+
object-fit: cover;
|
|
884
|
+
display: block;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.editor-history-card-preview-label {
|
|
888
|
+
position: absolute;
|
|
889
|
+
left: 8px;
|
|
890
|
+
right: 8px;
|
|
891
|
+
bottom: 8px;
|
|
892
|
+
min-height: 22px;
|
|
893
|
+
display: inline-flex;
|
|
894
|
+
align-items: center;
|
|
895
|
+
justify-content: center;
|
|
896
|
+
padding: 0 8px;
|
|
897
|
+
border-radius: 999px;
|
|
898
|
+
background: rgba(24, 30, 42, 0.72);
|
|
899
|
+
color: #fff8ee;
|
|
900
|
+
font-size: 0.72rem;
|
|
901
|
+
font-weight: 700;
|
|
902
|
+
letter-spacing: 0.02em;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.editor-history-card-preview-fallback {
|
|
906
|
+
padding: 0 10px;
|
|
907
|
+
text-align: center;
|
|
908
|
+
font-size: 0.78rem;
|
|
909
|
+
font-weight: 700;
|
|
910
|
+
line-height: 1.4;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
.editor-history-card-grid {
|
|
914
|
+
display: grid;
|
|
915
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
916
|
+
gap: 12px;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.editor-history-card .vf-editor-chat-http-card {
|
|
920
|
+
background: rgba(248, 244, 235, 0.74);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.editor-history-card-foot {
|
|
924
|
+
display: flex;
|
|
925
|
+
justify-content: flex-end;
|
|
926
|
+
color: #7b879b;
|
|
927
|
+
font-size: 0.72rem;
|
|
928
|
+
line-height: 1.3;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.editor-history-sample {
|
|
932
|
+
display: grid;
|
|
933
|
+
gap: 8px;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.editor-history-sample h4 {
|
|
937
|
+
margin: 0;
|
|
938
|
+
font-size: 0.82rem;
|
|
939
|
+
color: #445066;
|
|
940
|
+
text-transform: uppercase;
|
|
941
|
+
letter-spacing: 0.08em;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.editor-history-sample pre {
|
|
945
|
+
margin: 0;
|
|
946
|
+
min-height: 90px;
|
|
947
|
+
max-height: 280px;
|
|
948
|
+
overflow: auto;
|
|
949
|
+
padding: 12px;
|
|
950
|
+
border-radius: 14px;
|
|
951
|
+
background: rgba(37, 45, 61, 0.96);
|
|
952
|
+
color: #f7efe1;
|
|
953
|
+
font-size: 0.78rem;
|
|
954
|
+
line-height: 1.5;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.editor-history-sample-note {
|
|
958
|
+
color: #74829c;
|
|
959
|
+
font-size: 0.78rem;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
.editor-modal-backdrop {
|
|
963
|
+
position: fixed;
|
|
964
|
+
inset: 0;
|
|
965
|
+
display: none;
|
|
966
|
+
align-items: center;
|
|
967
|
+
justify-content: center;
|
|
968
|
+
padding: 24px;
|
|
969
|
+
background: rgba(24, 30, 42, 0.52);
|
|
970
|
+
backdrop-filter: blur(10px);
|
|
971
|
+
z-index: 1200;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.editor-modal-backdrop[data-open="true"] {
|
|
975
|
+
display: flex;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.editor-modal {
|
|
979
|
+
width: min(100%, 460px);
|
|
980
|
+
display: grid;
|
|
981
|
+
gap: 16px;
|
|
982
|
+
padding: 22px;
|
|
983
|
+
border-radius: 26px;
|
|
984
|
+
border: 1px solid rgba(191, 164, 109, 0.28);
|
|
985
|
+
background: rgba(255, 251, 244, 0.98);
|
|
986
|
+
box-shadow: 0 24px 64px rgba(15, 23, 42, 0.22);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.editor-modal-head {
|
|
990
|
+
display: grid;
|
|
991
|
+
gap: 6px;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
.editor-modal-head h3 {
|
|
995
|
+
margin: 0;
|
|
996
|
+
font-size: 1.2rem;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.editor-modal-head p,
|
|
1000
|
+
.editor-modal-error,
|
|
1001
|
+
.editor-modal-label {
|
|
1002
|
+
margin: 0;
|
|
1003
|
+
color: #617087;
|
|
1004
|
+
line-height: 1.6;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.editor-modal-label {
|
|
1008
|
+
font-size: 0.82rem;
|
|
1009
|
+
font-weight: 700;
|
|
1010
|
+
letter-spacing: 0.08em;
|
|
1011
|
+
text-transform: uppercase;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
.editor-modal-input {
|
|
1015
|
+
width: 100%;
|
|
1016
|
+
min-height: 50px;
|
|
1017
|
+
padding: 0 14px;
|
|
1018
|
+
border-radius: 16px;
|
|
1019
|
+
border: 1px solid rgba(191, 164, 109, 0.34);
|
|
1020
|
+
background: rgba(255, 255, 255, 0.96);
|
|
1021
|
+
color: #243041;
|
|
1022
|
+
font: inherit;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
.editor-modal-input:focus {
|
|
1026
|
+
outline: 2px solid rgba(219, 193, 122, 0.7);
|
|
1027
|
+
outline-offset: 2px;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.editor-modal-error {
|
|
1031
|
+
min-height: 1.4em;
|
|
1032
|
+
color: #9b2d2d;
|
|
1033
|
+
font-size: 0.84rem;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.editor-modal-actions {
|
|
1037
|
+
display: flex;
|
|
1038
|
+
justify-content: flex-end;
|
|
1039
|
+
gap: 10px;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.editor-media-modal {
|
|
1043
|
+
width: min(100%, 980px);
|
|
1044
|
+
max-height: calc(100vh - 48px);
|
|
1045
|
+
display: grid;
|
|
1046
|
+
gap: 14px;
|
|
1047
|
+
padding: 18px;
|
|
1048
|
+
border-radius: 28px;
|
|
1049
|
+
border: 1px solid rgba(191, 164, 109, 0.28);
|
|
1050
|
+
background: rgba(255, 251, 244, 0.985);
|
|
1051
|
+
box-shadow: 0 28px 80px rgba(15, 23, 42, 0.28);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.editor-media-modal-head {
|
|
1055
|
+
display: flex;
|
|
1056
|
+
align-items: center;
|
|
1057
|
+
justify-content: space-between;
|
|
1058
|
+
gap: 12px;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.editor-media-modal-actions {
|
|
1062
|
+
display: inline-flex;
|
|
1063
|
+
align-items: center;
|
|
1064
|
+
gap: 10px;
|
|
1065
|
+
flex: 0 0 auto;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
.editor-media-modal-source {
|
|
1069
|
+
color: #617087;
|
|
1070
|
+
font-size: 0.82rem;
|
|
1071
|
+
font-weight: 700;
|
|
1072
|
+
text-decoration: underline;
|
|
1073
|
+
text-underline-offset: 0.14em;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
.editor-media-modal-title {
|
|
1077
|
+
margin: 0;
|
|
1078
|
+
color: #324156;
|
|
1079
|
+
font-size: 0.95rem;
|
|
1080
|
+
font-weight: 700;
|
|
1081
|
+
word-break: break-all;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.editor-media-modal-body {
|
|
1085
|
+
min-height: 0;
|
|
1086
|
+
display: grid;
|
|
1087
|
+
place-items: center;
|
|
1088
|
+
overflow: auto;
|
|
1089
|
+
border-radius: 20px;
|
|
1090
|
+
background: rgba(37, 45, 61, 0.96);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
.editor-media-modal-body img,
|
|
1094
|
+
.editor-media-modal-body video {
|
|
1095
|
+
max-width: 100%;
|
|
1096
|
+
max-height: calc(100vh - 180px);
|
|
1097
|
+
display: block;
|
|
1098
|
+
object-fit: contain;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
@media (max-width: 767px) {
|
|
1102
|
+
.editor-hero,
|
|
1103
|
+
.editor-grid {
|
|
1104
|
+
grid-template-columns: 1fr;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
.editor-history-card-grid {
|
|
1108
|
+
grid-template-columns: 1fr;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.editor-quickstart-grid {
|
|
1112
|
+
grid-template-columns: 1fr;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.editor-hero,
|
|
1116
|
+
.editor-section,
|
|
1117
|
+
.editor-panel {
|
|
1118
|
+
border-radius: 22px;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.editor-panel > summary {
|
|
1122
|
+
align-items: flex-start;
|
|
1123
|
+
padding: 16px;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
.editor-panel-toggle {
|
|
1127
|
+
font-size: 0;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
.editor-panel-toggle::before {
|
|
1131
|
+
width: 10px;
|
|
1132
|
+
height: 10px;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
.editor-panel-body {
|
|
1136
|
+
padding: 0 16px 16px;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
.editor-hero,
|
|
1140
|
+
.editor-section {
|
|
1141
|
+
padding: 16px;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.editor-preview {
|
|
1145
|
+
min-height: 0;
|
|
1146
|
+
max-height: none;
|
|
1147
|
+
aspect-ratio: 16 / 11;
|
|
1148
|
+
border-radius: 18px;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
.editor-title {
|
|
1152
|
+
font-size: clamp(2rem, 12vw, 2.85rem);
|
|
1153
|
+
line-height: 0.95;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
.editor-toolbar,
|
|
1157
|
+
.editor-history-toolbar-actions,
|
|
1158
|
+
.editor-history-group-actions {
|
|
1159
|
+
display: grid;
|
|
1160
|
+
grid-template-columns: 1fr;
|
|
1161
|
+
width: 100%;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
.editor-copy-button,
|
|
1165
|
+
.editor-history-button,
|
|
1166
|
+
.editor-history-remove {
|
|
1167
|
+
width: 100%;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.editor-pill,
|
|
1171
|
+
.editor-route-path,
|
|
1172
|
+
.editor-history-chip {
|
|
1173
|
+
max-width: 100%;
|
|
1174
|
+
overflow: hidden;
|
|
1175
|
+
text-overflow: ellipsis;
|
|
1176
|
+
white-space: nowrap;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
`,
|
|
1180
|
+
body: `
|
|
1181
|
+
<section class="editor-workbench">
|
|
1182
|
+
${renderTemplateEditorChrome({
|
|
1183
|
+
backHref,
|
|
1184
|
+
templateTitle: input.template.title,
|
|
1185
|
+
templateId: input.template.id,
|
|
1186
|
+
templateSlug: input.template.slugId
|
|
1187
|
+
})}
|
|
1188
|
+
<main class="editor-main">
|
|
1189
|
+
<section class="editor-shell page-content-start">
|
|
1190
|
+
<details class="editor-panel" open>
|
|
1191
|
+
<summary>
|
|
1192
|
+
<div class="editor-panel-summary">
|
|
1193
|
+
<h2>Character card</h2>
|
|
1194
|
+
<p>Preview the format, metadata, and editorial notes without losing space for the sections that follow.</p>
|
|
1195
|
+
</div>
|
|
1196
|
+
<span class="editor-panel-toggle" aria-hidden="true">Toggle</span>
|
|
1197
|
+
</summary>
|
|
1198
|
+
<div class="editor-panel-body">
|
|
1199
|
+
<section class="editor-hero">
|
|
1200
|
+
${preview}
|
|
1201
|
+
<div class="editor-copy">
|
|
1202
|
+
<div class="editor-kicker">Template Editor Docs</div>
|
|
1203
|
+
<h1 class="editor-title">${escapeHtml(input.template.title)}</h1>
|
|
1204
|
+
<div class="editor-pills">
|
|
1205
|
+
<span class="editor-pill">${escapeHtml(input.template.id)}</span>
|
|
1206
|
+
<span class="editor-pill">${escapeHtml(input.template.slugId)}</span>
|
|
1207
|
+
<span class="editor-pill">v${escapeHtml(input.template.version)}</span>
|
|
1208
|
+
</div>
|
|
1209
|
+
<p>${escapeHtml(input.template.viralDna || input.template.visualDna || "No editorial summary is available for this template yet.")}</p>
|
|
1210
|
+
${input.directorSkill?.trim()
|
|
1211
|
+
? `<div class="editor-toolbar">
|
|
1212
|
+
<button
|
|
1213
|
+
type="button"
|
|
1214
|
+
class="editor-copy-button"
|
|
1215
|
+
data-editor-copy-content="${escapeAttribute(input.directorSkill)}"
|
|
1216
|
+
data-editor-copy-label="Director SKILL.md"
|
|
1217
|
+
>Copy Director SKILL.md</button>
|
|
1218
|
+
</div>`
|
|
1219
|
+
: ""}
|
|
1220
|
+
</div>
|
|
1221
|
+
</section>
|
|
1222
|
+
</div>
|
|
1223
|
+
</details>
|
|
1224
|
+
<section class="editor-grid">
|
|
1225
|
+
<details class="editor-panel" open>
|
|
1226
|
+
<summary>
|
|
1227
|
+
<div class="editor-panel-summary">
|
|
1228
|
+
<h2>Quickstart</h2>
|
|
1229
|
+
<p>Use the template prompt scaffolds as readonly references before calling operations or continuing in Copilot.</p>
|
|
1230
|
+
</div>
|
|
1231
|
+
<span class="editor-panel-toggle" aria-hidden="true">Toggle</span>
|
|
1232
|
+
</summary>
|
|
1233
|
+
<div class="editor-panel-body">
|
|
1234
|
+
<section class="editor-section">
|
|
1235
|
+
<div class="editor-quickstart-grid">
|
|
1236
|
+
${renderQuickstartTextarea("Skeleton prompt", input.template.skeletonPrompt, 10)}
|
|
1237
|
+
${renderQuickstartTextarea("Proposal Generator", input.template.proposalGenerator, 10)}
|
|
1238
|
+
</div>
|
|
1239
|
+
<div class="editor-quickstart-samples">
|
|
1240
|
+
<h3>Sample prompts</h3>
|
|
1241
|
+
<div class="editor-sample-prompt-row" aria-label="Sample prompts">
|
|
1242
|
+
${input.template.samplePrompts.length
|
|
1243
|
+
? input.template.samplePrompts.map((sample, index) => `
|
|
1244
|
+
<div class="editor-sample-prompt">
|
|
1245
|
+
${renderQuickstartTextarea(`Sample ${index + 1}`, sample, 7)}
|
|
1246
|
+
</div>
|
|
1247
|
+
`).join("")
|
|
1248
|
+
: `<div class="editor-sample-prompt">${renderQuickstartTextarea("Sample 1", "No sample prompts are defined for this template yet.", 7)}</div>`}
|
|
1249
|
+
</div>
|
|
1250
|
+
</div>
|
|
1251
|
+
</section>
|
|
1252
|
+
</div>
|
|
1253
|
+
</details>
|
|
1254
|
+
<details class="editor-panel">
|
|
1255
|
+
<summary>
|
|
1256
|
+
<div class="editor-panel-summary">
|
|
1257
|
+
<h2>REST API docs</h2>
|
|
1258
|
+
<p>This editor combines template routes with platform primitive routes so asset generation, image edits, and template runs stay in one tracer-aware workflow.</p>
|
|
1259
|
+
</div>
|
|
1260
|
+
<span class="editor-panel-toggle" aria-hidden="true">Toggle</span>
|
|
1261
|
+
</summary>
|
|
1262
|
+
<div class="editor-panel-body">
|
|
1263
|
+
<section class="editor-section">
|
|
1264
|
+
<div class="editor-section-header">
|
|
1265
|
+
<p>Use tracer IDs to group a run across requests.</p>
|
|
1266
|
+
</div>
|
|
1267
|
+
<div class="editor-route-list">
|
|
1268
|
+
${input.docsRoutes.map((route) => `
|
|
1269
|
+
<article class="editor-route-card">
|
|
1270
|
+
<div class="editor-route-head">
|
|
1271
|
+
<span class="editor-route-method" data-method="${escapeAttribute(route.method)}">${escapeHtml(route.method)}</span>
|
|
1272
|
+
<div class="editor-route-path">${escapeHtml(route.path)}</div>
|
|
1273
|
+
</div>
|
|
1274
|
+
<div class="editor-note">${escapeHtml(route.summary)}</div>
|
|
1275
|
+
</article>
|
|
1276
|
+
`).join("")}
|
|
1277
|
+
</div>
|
|
1278
|
+
</section>
|
|
1279
|
+
</div>
|
|
1280
|
+
</details>
|
|
1281
|
+
<details class="editor-panel" open>
|
|
1282
|
+
<summary>
|
|
1283
|
+
<div class="editor-panel-summary">
|
|
1284
|
+
<h2>Tracer Logs</h2>
|
|
1285
|
+
<p>Recent POST calls are grouped by tracer so parallel workstreams stay readable. Newest requests appear first inside each tracer group.</p>
|
|
1286
|
+
</div>
|
|
1287
|
+
<span class="editor-panel-toggle" aria-hidden="true">Toggle</span>
|
|
1288
|
+
</summary>
|
|
1289
|
+
<div class="editor-panel-body">
|
|
1290
|
+
<section class="editor-section">
|
|
1291
|
+
<div class="editor-history-toolbar">
|
|
1292
|
+
<p class="editor-note">Tracer visibility lives here. Removing one only clears it from this page view; the underlying runs remain available in Job Runs.</p>
|
|
1293
|
+
<div class="editor-history-toolbar-actions">
|
|
1294
|
+
<button type="button" class="editor-history-button is-primary" data-editor-history-add>Add tracer</button>
|
|
1295
|
+
<div class="editor-history-chip-row" data-editor-history-tracers>
|
|
1296
|
+
${input.initialTracers.length
|
|
1297
|
+
? input.initialTracers.map((tracer) => `<span class="editor-history-chip">${escapeHtml(tracer)}</span>`).join("")
|
|
1298
|
+
: `<span class="editor-history-chip is-empty">No tracer selected yet</span>`}
|
|
1299
|
+
</div>
|
|
1300
|
+
</div>
|
|
1301
|
+
</div>
|
|
1302
|
+
<div class="editor-history-groups" data-editor-history-root>
|
|
1303
|
+
<div class="editor-history-empty">${hasHistoryAccess ? "Loading POST history…" : "Sign in to load tracer-scoped POST history."}</div>
|
|
1304
|
+
</div>
|
|
1305
|
+
</section>
|
|
1306
|
+
</div>
|
|
1307
|
+
</details>
|
|
1308
|
+
</section>
|
|
1309
|
+
</section>
|
|
1310
|
+
</main>
|
|
1311
|
+
</section>
|
|
1312
|
+
<div class="editor-modal-backdrop" data-editor-tracer-modal data-open="false" hidden>
|
|
1313
|
+
<div class="editor-modal" role="dialog" aria-modal="true" aria-labelledby="editor-tracer-modal-title">
|
|
1314
|
+
<div class="editor-modal-head">
|
|
1315
|
+
<h3 id="editor-tracer-modal-title">Add tracer</h3>
|
|
1316
|
+
<p>Type a tracer label to pin it into this page view. Existing labels stay untouched.</p>
|
|
1317
|
+
</div>
|
|
1318
|
+
<label class="editor-modal-label" for="editor-tracer-input">Tracer id</label>
|
|
1319
|
+
<input id="editor-tracer-input" class="editor-modal-input" type="text" autocomplete="off" spellcheck="false" placeholder="${escapeAttribute(`${input.template.slugId}-manual`)}" />
|
|
1320
|
+
<p class="editor-modal-error" data-editor-tracer-modal-error aria-live="polite"></p>
|
|
1321
|
+
<div class="editor-modal-actions">
|
|
1322
|
+
<button type="button" class="editor-history-button" data-editor-tracer-cancel>Cancel</button>
|
|
1323
|
+
<button type="button" class="editor-history-button is-primary" data-editor-tracer-submit>Add tracer</button>
|
|
1324
|
+
</div>
|
|
1325
|
+
</div>
|
|
1326
|
+
</div>
|
|
1327
|
+
<div class="editor-modal-backdrop" data-editor-media-modal data-open="false" hidden>
|
|
1328
|
+
<div class="editor-media-modal" role="dialog" aria-modal="true" aria-labelledby="editor-media-modal-title">
|
|
1329
|
+
<div class="editor-media-modal-head">
|
|
1330
|
+
<p id="editor-media-modal-title" class="editor-media-modal-title">Output preview</p>
|
|
1331
|
+
<div class="editor-media-modal-actions">
|
|
1332
|
+
<a class="editor-media-modal-source" data-editor-media-source href="#" target="_blank" rel="noreferrer">Open source</a>
|
|
1333
|
+
<button type="button" class="editor-history-button" data-editor-media-close>Close</button>
|
|
1334
|
+
</div>
|
|
1335
|
+
</div>
|
|
1336
|
+
<div class="editor-media-modal-body" data-editor-media-body></div>
|
|
1337
|
+
</div>
|
|
1338
|
+
</div>
|
|
1339
|
+
<div class="vf-editor-chat-http-modal-backdrop" data-editor-http-modal hidden>
|
|
1340
|
+
<div class="vf-editor-chat-http-modal" role="dialog" aria-modal="true" aria-labelledby="editor-http-modal-title">
|
|
1341
|
+
<div class="vf-editor-chat-http-modal-header">
|
|
1342
|
+
<div class="vf-editor-chat-http-modal-header-main" data-editor-http-modal-head>
|
|
1343
|
+
<span id="editor-http-modal-title" class="vf-editor-chat-http-modal-url">HTTP details</span>
|
|
1344
|
+
</div>
|
|
1345
|
+
<button type="button" class="vf-editor-chat-http-modal-close" data-editor-http-close aria-label="Close HTTP details">×</button>
|
|
1346
|
+
</div>
|
|
1347
|
+
<div class="vf-editor-chat-http-card-body is-modal" data-editor-http-modal-body></div>
|
|
1348
|
+
</div>
|
|
1349
|
+
</div>
|
|
1350
|
+
<script>
|
|
1351
|
+
${TEMPLATE_EDITOR_SHELL_SCRIPT}
|
|
1352
|
+
(() => {
|
|
1353
|
+
const historyRoot = document.querySelector("[data-editor-history-root]");
|
|
1354
|
+
const tracerChipRow = document.querySelector("[data-editor-history-tracers]");
|
|
1355
|
+
const addTracerButton = document.querySelector("[data-editor-history-add]");
|
|
1356
|
+
const modalBackdrop = document.querySelector("[data-editor-tracer-modal]");
|
|
1357
|
+
const modalInput = document.getElementById("editor-tracer-input");
|
|
1358
|
+
const modalError = document.querySelector("[data-editor-tracer-modal-error]");
|
|
1359
|
+
const modalSubmit = document.querySelector("[data-editor-tracer-submit]");
|
|
1360
|
+
const modalCancel = document.querySelector("[data-editor-tracer-cancel]");
|
|
1361
|
+
const mediaModalBackdrop = document.querySelector("[data-editor-media-modal]");
|
|
1362
|
+
const mediaModalBody = document.querySelector("[data-editor-media-body]");
|
|
1363
|
+
const mediaModalTitle = document.getElementById("editor-media-modal-title");
|
|
1364
|
+
const mediaModalClose = document.querySelector("[data-editor-media-close]");
|
|
1365
|
+
const mediaModalSource = document.querySelector("[data-editor-media-source]");
|
|
1366
|
+
const httpModalBackdrop = document.querySelector("[data-editor-http-modal]");
|
|
1367
|
+
const httpModalHead = document.querySelector("[data-editor-http-modal-head]");
|
|
1368
|
+
const httpModalBody = document.querySelector("[data-editor-http-modal-body]");
|
|
1369
|
+
const httpModalClose = document.querySelector("[data-editor-http-close]");
|
|
1370
|
+
if (!(historyRoot instanceof HTMLElement) || !(tracerChipRow instanceof HTMLElement)) {
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
const hasTracerModal = addTracerButton instanceof HTMLButtonElement
|
|
1375
|
+
&& modalBackdrop instanceof HTMLElement
|
|
1376
|
+
&& modalInput instanceof HTMLInputElement
|
|
1377
|
+
&& modalError instanceof HTMLElement
|
|
1378
|
+
&& modalSubmit instanceof HTMLButtonElement
|
|
1379
|
+
&& modalCancel instanceof HTMLButtonElement;
|
|
1380
|
+
const hasMediaModal = mediaModalBackdrop instanceof HTMLElement
|
|
1381
|
+
&& mediaModalBody instanceof HTMLElement
|
|
1382
|
+
&& mediaModalTitle instanceof HTMLElement
|
|
1383
|
+
&& mediaModalClose instanceof HTMLButtonElement
|
|
1384
|
+
&& mediaModalSource instanceof HTMLAnchorElement;
|
|
1385
|
+
const hasHttpModal = httpModalBackdrop instanceof HTMLElement
|
|
1386
|
+
&& httpModalHead instanceof HTMLElement
|
|
1387
|
+
&& httpModalBody instanceof HTMLElement
|
|
1388
|
+
&& httpModalClose instanceof HTMLButtonElement;
|
|
1389
|
+
|
|
1390
|
+
const boot = {
|
|
1391
|
+
historyEndpoint: ${JSON.stringify(input.historyEndpoint)},
|
|
1392
|
+
tracerEndpoint: ${JSON.stringify(input.tracerEndpoint)},
|
|
1393
|
+
fallbackHistoryEndpoint: ${JSON.stringify(withAccountQuery(`/job-runs/history?limit=250&template_id=${encodeURIComponent(input.template.id)}`, input.account.userId))},
|
|
1394
|
+
isLoggedIn: ${input.account.isLoggedIn ? "true" : "false"}
|
|
1395
|
+
};
|
|
1396
|
+
let lastHistoryEntries = [];
|
|
1397
|
+
let lastSelectedTracers = [];
|
|
1398
|
+
const expandedPreviewGroups = new Set();
|
|
1399
|
+
|
|
1400
|
+
function escapeHtml(value) {
|
|
1401
|
+
return String(value)
|
|
1402
|
+
.replace(/&/g, "&")
|
|
1403
|
+
.replace(/</g, "<")
|
|
1404
|
+
.replace(/>/g, ">")
|
|
1405
|
+
.replace(/"/g, """);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
function formatJson(value) {
|
|
1409
|
+
if (value == null) {
|
|
1410
|
+
return "null";
|
|
1411
|
+
}
|
|
1412
|
+
if (typeof value === "string") {
|
|
1413
|
+
return value;
|
|
1414
|
+
}
|
|
1415
|
+
try {
|
|
1416
|
+
return JSON.stringify(value, null, 2);
|
|
1417
|
+
} catch {
|
|
1418
|
+
return String(value);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
function setTextBlock(parent, label, value) {
|
|
1423
|
+
const block = document.createElement("div");
|
|
1424
|
+
block.className = "vf-editor-chat-http-block";
|
|
1425
|
+
const heading = document.createElement("div");
|
|
1426
|
+
heading.className = "vf-editor-chat-http-label";
|
|
1427
|
+
heading.textContent = label;
|
|
1428
|
+
const pre = document.createElement("pre");
|
|
1429
|
+
pre.className = "vf-editor-chat-http-pre";
|
|
1430
|
+
pre.textContent = typeof value === "string" ? value : formatJson(value);
|
|
1431
|
+
block.append(heading, pre);
|
|
1432
|
+
parent.append(block);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
function makeHttpPayload(entry) {
|
|
1436
|
+
return {
|
|
1437
|
+
method: entry.method,
|
|
1438
|
+
url: entry.path,
|
|
1439
|
+
status: Number(entry.status) || 0,
|
|
1440
|
+
statusText: "",
|
|
1441
|
+
request: {
|
|
1442
|
+
query: entry.request?.query || {},
|
|
1443
|
+
body: entry.request?.body ?? null,
|
|
1444
|
+
omitted: entry.request?.bodyOmittedReason || null
|
|
1445
|
+
},
|
|
1446
|
+
response: {
|
|
1447
|
+
status: entry.status,
|
|
1448
|
+
body: entry.response?.body ?? null,
|
|
1449
|
+
omitted: entry.response?.bodyOmittedReason || null
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function encodeHttpPayload(entry) {
|
|
1455
|
+
try {
|
|
1456
|
+
return encodeURIComponent(JSON.stringify(makeHttpPayload(entry)));
|
|
1457
|
+
} catch {
|
|
1458
|
+
return encodeURIComponent(JSON.stringify({
|
|
1459
|
+
method: entry.method,
|
|
1460
|
+
url: entry.path,
|
|
1461
|
+
status: Number(entry.status) || 0,
|
|
1462
|
+
statusText: "",
|
|
1463
|
+
request: { query: {}, body: null, omitted: "Request sample could not be encoded for display." },
|
|
1464
|
+
response: { status: entry.status, body: null, omitted: "Response sample could not be encoded for display." }
|
|
1465
|
+
}));
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
function renderHttpAction(entry) {
|
|
1470
|
+
const payload = encodeHttpPayload(entry);
|
|
1471
|
+
const status = Number(entry.status) || 0;
|
|
1472
|
+
const isError = status >= 400;
|
|
1473
|
+
const isSuccess = status >= 200 && status < 300;
|
|
1474
|
+
return '<div class="vf-editor-chat-http-card">' +
|
|
1475
|
+
'<button type="button" class="vf-editor-chat-http-card-header" data-editor-http-detail="' + escapeHtml(payload) + '" aria-label="Open HTTP details for ' + escapeHtml(entry.method) + ' ' + escapeHtml(entry.path) + '">' +
|
|
1476
|
+
'<span class="vf-editor-chat-http-pill">' + escapeHtml(entry.method) + '</span>' +
|
|
1477
|
+
'<span class="vf-editor-chat-http-url" title="' + escapeHtml(entry.path) + '">' + escapeHtml(entry.path) + '</span>' +
|
|
1478
|
+
'<span class="vf-editor-chat-http-status" data-error="' + (isError ? "true" : "false") + '" data-success="' + (isSuccess ? "true" : "false") + '">' + escapeHtml(status) + '</span>' +
|
|
1479
|
+
'<span class="vf-editor-chat-http-expand" aria-hidden="true">+</span>' +
|
|
1480
|
+
'</button>' +
|
|
1481
|
+
'</div>';
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function openHttpModal(payload) {
|
|
1485
|
+
if (!hasHttpModal) {
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
httpModalHead.innerHTML = "";
|
|
1489
|
+
const isError = payload.status >= 400;
|
|
1490
|
+
const isSuccess = payload.status >= 200 && payload.status < 300;
|
|
1491
|
+
const method = document.createElement("span");
|
|
1492
|
+
method.className = "vf-editor-chat-http-pill";
|
|
1493
|
+
method.textContent = payload.method || "HTTP";
|
|
1494
|
+
const url = document.createElement("span");
|
|
1495
|
+
url.className = "vf-editor-chat-http-modal-url";
|
|
1496
|
+
url.textContent = payload.url || "";
|
|
1497
|
+
const status = document.createElement("span");
|
|
1498
|
+
status.className = "vf-editor-chat-http-status";
|
|
1499
|
+
status.dataset.error = isError ? "true" : "false";
|
|
1500
|
+
status.dataset.success = isSuccess ? "true" : "false";
|
|
1501
|
+
status.textContent = String(payload.status || "");
|
|
1502
|
+
httpModalHead.append(method, url, status);
|
|
1503
|
+
httpModalBody.innerHTML = "";
|
|
1504
|
+
setTextBlock(httpModalBody, "URL", payload.url || "");
|
|
1505
|
+
if (payload.request?.omitted) {
|
|
1506
|
+
setTextBlock(httpModalBody, "Request note", payload.request.omitted);
|
|
1507
|
+
}
|
|
1508
|
+
setTextBlock(httpModalBody, "Request", {
|
|
1509
|
+
query: payload.request?.query || {},
|
|
1510
|
+
body: payload.request?.body ?? null
|
|
1511
|
+
});
|
|
1512
|
+
if (payload.response?.omitted) {
|
|
1513
|
+
setTextBlock(httpModalBody, "Response note", payload.response.omitted);
|
|
1514
|
+
}
|
|
1515
|
+
setTextBlock(httpModalBody, "Response", {
|
|
1516
|
+
status: payload.response?.status ?? payload.status,
|
|
1517
|
+
body: payload.response?.body ?? null
|
|
1518
|
+
});
|
|
1519
|
+
httpModalBackdrop.hidden = false;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
function closeHttpModal() {
|
|
1523
|
+
if (!hasHttpModal) {
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
httpModalBackdrop.hidden = true;
|
|
1527
|
+
httpModalBody.innerHTML = "";
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
function parseTracersFromUrl() {
|
|
1531
|
+
const params = new URLSearchParams(window.location.search);
|
|
1532
|
+
const values = [...params.getAll("tracers"), ...params.getAll("tracer")];
|
|
1533
|
+
const tracers = [];
|
|
1534
|
+
const seen = new Set();
|
|
1535
|
+
for (const rawValue of values) {
|
|
1536
|
+
const trimmed = String(rawValue || "").trim();
|
|
1537
|
+
if (!trimmed) {
|
|
1538
|
+
continue;
|
|
1539
|
+
}
|
|
1540
|
+
const inner = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1) : trimmed;
|
|
1541
|
+
for (const part of inner.split(",")) {
|
|
1542
|
+
const tracer = part.trim().replace(/^["']|["']$/g, "");
|
|
1543
|
+
if (!tracer || seen.has(tracer)) {
|
|
1544
|
+
continue;
|
|
1545
|
+
}
|
|
1546
|
+
seen.add(tracer);
|
|
1547
|
+
tracers.push(tracer);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return tracers;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
function makeTracerId() {
|
|
1554
|
+
const suffix = (globalThis.crypto && typeof globalThis.crypto.randomUUID === "function"
|
|
1555
|
+
? globalThis.crypto.randomUUID().replace(/-/g, "").slice(-8)
|
|
1556
|
+
: Math.random().toString(16).slice(2, 10).padEnd(8, "0").slice(0, 8));
|
|
1557
|
+
return ${JSON.stringify(input.template.slugId)}
|
|
1558
|
+
.replace(/_/g, "-")
|
|
1559
|
+
.replace(/[^a-zA-Z0-9-]/g, "-")
|
|
1560
|
+
.toLowerCase()
|
|
1561
|
+
.replace(/-+/g, "-")
|
|
1562
|
+
.replace(/^-|-$/g, "") + "-" + suffix;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
function syncTracerUrl(tracers) {
|
|
1566
|
+
const url = new URL(window.location.href);
|
|
1567
|
+
if (tracers.length) {
|
|
1568
|
+
url.searchParams.set("tracers", tracers.join(","));
|
|
1569
|
+
} else {
|
|
1570
|
+
url.searchParams.delete("tracers");
|
|
1571
|
+
}
|
|
1572
|
+
window.history.replaceState({}, "", url.toString());
|
|
1573
|
+
window.dispatchEvent(new CustomEvent("vidfarm:editor-tracers-changed", {
|
|
1574
|
+
detail: { tracers }
|
|
1575
|
+
}));
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
const tracerStore = window.__vidfarmEditorTracers || (() => {
|
|
1579
|
+
let listeners = [];
|
|
1580
|
+
const notify = () => {
|
|
1581
|
+
const nextTracers = parseTracersFromUrl();
|
|
1582
|
+
for (const listener of listeners) {
|
|
1583
|
+
listener(nextTracers);
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1586
|
+
return {
|
|
1587
|
+
get() {
|
|
1588
|
+
return parseTracersFromUrl();
|
|
1589
|
+
},
|
|
1590
|
+
set(tracers) {
|
|
1591
|
+
const normalized = [...new Set((Array.isArray(tracers) ? tracers : []).map((value) => String(value || "").trim()).filter(Boolean))];
|
|
1592
|
+
syncTracerUrl(normalized);
|
|
1593
|
+
notify();
|
|
1594
|
+
},
|
|
1595
|
+
add(tracer) {
|
|
1596
|
+
const nextTracer = String(tracer || "").trim() || makeTracerId();
|
|
1597
|
+
const current = this.get().filter((entry) => entry !== nextTracer);
|
|
1598
|
+
this.set([nextTracer, ...current]);
|
|
1599
|
+
return nextTracer;
|
|
1600
|
+
},
|
|
1601
|
+
remove(tracer) {
|
|
1602
|
+
const current = this.get().filter((entry) => entry !== tracer);
|
|
1603
|
+
this.set(current);
|
|
1604
|
+
},
|
|
1605
|
+
activate(tracer) {
|
|
1606
|
+
const current = this.get();
|
|
1607
|
+
if (!current.includes(tracer)) {
|
|
1608
|
+
this.add(tracer);
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
this.set([tracer, ...current.filter((entry) => entry !== tracer)]);
|
|
1612
|
+
},
|
|
1613
|
+
subscribe(listener) {
|
|
1614
|
+
listeners.push(listener);
|
|
1615
|
+
return () => {
|
|
1616
|
+
listeners = listeners.filter((entry) => entry !== listener);
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
})();
|
|
1621
|
+
window.__vidfarmEditorTracers = tracerStore;
|
|
1622
|
+
|
|
1623
|
+
function openTracerModal() {
|
|
1624
|
+
if (!hasTracerModal) {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
modalBackdrop.hidden = false;
|
|
1628
|
+
modalBackdrop.setAttribute("data-open", "true");
|
|
1629
|
+
modalError.textContent = "";
|
|
1630
|
+
modalInput.value = "";
|
|
1631
|
+
window.requestAnimationFrame(() => modalInput.focus());
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
function closeTracerModal() {
|
|
1635
|
+
if (!hasTracerModal) {
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
modalBackdrop.setAttribute("data-open", "false");
|
|
1639
|
+
modalBackdrop.hidden = true;
|
|
1640
|
+
modalError.textContent = "";
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function submitTracerModal() {
|
|
1644
|
+
if (!hasTracerModal) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
const tracer = modalInput.value.trim();
|
|
1648
|
+
if (!tracer) {
|
|
1649
|
+
modalError.textContent = "Enter a tracer id.";
|
|
1650
|
+
modalInput.focus();
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
tracerStore.add(tracer);
|
|
1654
|
+
closeTracerModal();
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
function renderTracerChips(tracers) {
|
|
1658
|
+
tracerChipRow.innerHTML = tracers.length
|
|
1659
|
+
? tracers.map((tracer) => '<span class="editor-history-chip">' + escapeHtml(tracer) + '</span>').join("")
|
|
1660
|
+
: '<span class="editor-history-chip is-empty">No tracer selected yet</span>';
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
function renderEmpty(message) {
|
|
1664
|
+
historyRoot.innerHTML = '<div class="editor-history-empty">' + escapeHtml(message) + '</div>';
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
function renderRefreshIcon() {
|
|
1668
|
+
return '<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
|
|
1669
|
+
'<path d="M21 12a9 9 0 0 1-15.1 6.6L3 16"></path>' +
|
|
1670
|
+
'<path d="M3 21v-5h5"></path>' +
|
|
1671
|
+
'<path d="M3 12a9 9 0 0 1 15.1-6.6L21 8"></path>' +
|
|
1672
|
+
'<path d="M21 3v5h-5"></path>' +
|
|
1673
|
+
'</svg>';
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
function getPreviewKind(url) {
|
|
1677
|
+
if (/\\.(png|jpe?g|gif|webp|avif|svg)(\\?|#|$)/i.test(url)) {
|
|
1678
|
+
return "image";
|
|
1679
|
+
}
|
|
1680
|
+
if (/\\.(mp4|webm|ogg|mov|m4v)(\\?|#|$)/i.test(url)) {
|
|
1681
|
+
return "video";
|
|
1682
|
+
}
|
|
1683
|
+
return "file";
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
function isPreviewableMediaUrl(url) {
|
|
1687
|
+
return getPreviewKind(url) !== "file";
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
function openMediaModal(url, kind, label) {
|
|
1691
|
+
if (!hasMediaModal) {
|
|
1692
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
mediaModalTitle.textContent = label;
|
|
1696
|
+
mediaModalSource.href = url;
|
|
1697
|
+
if (kind === "image") {
|
|
1698
|
+
mediaModalBody.innerHTML = '<img src="' + escapeHtml(url) + '" alt="' + escapeHtml(label) + '" />';
|
|
1699
|
+
} else if (kind === "video") {
|
|
1700
|
+
mediaModalBody.innerHTML = '<video src="' + escapeHtml(url) + '" controls autoplay playsinline preload="metadata"></video>';
|
|
1701
|
+
} else {
|
|
1702
|
+
mediaModalBody.innerHTML = '<a class="editor-history-button is-primary" href="' + escapeHtml(url) + '" target="_blank" rel="noreferrer">Open file</a>';
|
|
1703
|
+
}
|
|
1704
|
+
mediaModalBackdrop.hidden = false;
|
|
1705
|
+
mediaModalBackdrop.setAttribute("data-open", "true");
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
function closeMediaModal() {
|
|
1709
|
+
if (!hasMediaModal) {
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
mediaModalBackdrop.setAttribute("data-open", "false");
|
|
1713
|
+
mediaModalBackdrop.hidden = true;
|
|
1714
|
+
mediaModalSource.href = "#";
|
|
1715
|
+
mediaModalBody.innerHTML = "";
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
function renderPreviewLinks(urls) {
|
|
1719
|
+
if (!Array.isArray(urls) || !urls.length) {
|
|
1720
|
+
return "";
|
|
1721
|
+
}
|
|
1722
|
+
return '<div class="editor-history-card-previews">' + urls.map((url, index) => (
|
|
1723
|
+
(() => {
|
|
1724
|
+
const kind = getPreviewKind(url);
|
|
1725
|
+
const label = 'Output ' + (index + 1);
|
|
1726
|
+
if (kind === "image") {
|
|
1727
|
+
return '<button type="button" class="editor-history-card-preview" data-preview-url="' + escapeHtml(url) + '" data-preview-kind="' + kind + '" data-preview-label="' + escapeHtml(label) + '">' +
|
|
1728
|
+
'<img src="' + escapeHtml(url) + '" alt="' + escapeHtml(label) + '" loading="lazy" decoding="async" />' +
|
|
1729
|
+
'<span class="editor-history-card-preview-label">' + escapeHtml(label) + '</span>' +
|
|
1730
|
+
'</button>';
|
|
1731
|
+
}
|
|
1732
|
+
if (kind === "video") {
|
|
1733
|
+
return '<button type="button" class="editor-history-card-preview" data-preview-url="' + escapeHtml(url) + '" data-preview-kind="' + kind + '" data-preview-label="' + escapeHtml(label) + '">' +
|
|
1734
|
+
'<video src="' + escapeHtml(url) + '" muted playsinline preload="metadata" aria-hidden="true"></video>' +
|
|
1735
|
+
'<span class="editor-history-video-play" aria-hidden="true"></span>' +
|
|
1736
|
+
'<span class="editor-history-card-preview-label">' + escapeHtml(label) + '</span>' +
|
|
1737
|
+
'</button>';
|
|
1738
|
+
}
|
|
1739
|
+
return '<button type="button" class="editor-history-card-preview" data-preview-url="' + escapeHtml(url) + '" data-preview-kind="' + kind + '" data-preview-label="' + escapeHtml(label) + '">' +
|
|
1740
|
+
'<span class="editor-history-card-preview-fallback">' + escapeHtml(label) + '</span>' +
|
|
1741
|
+
'</button>';
|
|
1742
|
+
})()
|
|
1743
|
+
)).join("") + '</div>';
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
function collectGroupPreviewUrls(entries) {
|
|
1747
|
+
const seen = new Set();
|
|
1748
|
+
const urls = [];
|
|
1749
|
+
for (const entry of entries) {
|
|
1750
|
+
const candidates = entry.outputMediaUrls && entry.outputMediaUrls.length ? entry.outputMediaUrls : entry.mediaUrls;
|
|
1751
|
+
if (!Array.isArray(candidates)) {
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
for (const url of candidates) {
|
|
1755
|
+
if (!url || seen.has(url) || !isPreviewableMediaUrl(url)) {
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
seen.add(url);
|
|
1759
|
+
urls.push(url);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return urls;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
function renderGroupPreviewStrip(entries, groupKey) {
|
|
1766
|
+
const urls = collectGroupPreviewUrls(entries);
|
|
1767
|
+
if (!urls.length) {
|
|
1768
|
+
return "";
|
|
1769
|
+
}
|
|
1770
|
+
const isExpanded = expandedPreviewGroups.has(groupKey);
|
|
1771
|
+
const visibleUrls = isExpanded ? urls : urls.slice(0, 5);
|
|
1772
|
+
const visible = visibleUrls.map((url) => {
|
|
1773
|
+
const kind = getPreviewKind(url);
|
|
1774
|
+
if (kind === "video") {
|
|
1775
|
+
const label = 'Output preview';
|
|
1776
|
+
return '<button type="button" class="editor-history-group-preview" data-preview-url="' + escapeHtml(url) + '" data-preview-kind="video" data-preview-label="' + escapeHtml(label) + '" aria-label="Preview video output">' +
|
|
1777
|
+
'<video src="' + escapeHtml(url) + '" muted playsinline preload="metadata" aria-hidden="true"></video>' +
|
|
1778
|
+
'<span class="editor-history-video-play" aria-hidden="true"></span>' +
|
|
1779
|
+
'</button>';
|
|
1780
|
+
}
|
|
1781
|
+
if (kind === "image") {
|
|
1782
|
+
const label = 'Output preview';
|
|
1783
|
+
return '<button type="button" class="editor-history-group-preview" data-preview-url="' + escapeHtml(url) + '" data-preview-kind="image" data-preview-label="' + escapeHtml(label) + '" aria-label="Preview image output">' +
|
|
1784
|
+
'<img src="' + escapeHtml(url) + '" alt="" loading="lazy" decoding="async" />' +
|
|
1785
|
+
'</button>';
|
|
1786
|
+
}
|
|
1787
|
+
return "";
|
|
1788
|
+
}).join("");
|
|
1789
|
+
const more = !isExpanded && urls.length > visibleUrls.length
|
|
1790
|
+
? '<button type="button" class="editor-history-group-preview-more" data-editor-expand-media="' + escapeHtml(groupKey) + '" aria-label="Show all media previews">+' + escapeHtml(urls.length - visibleUrls.length) + '</button>'
|
|
1791
|
+
: "";
|
|
1792
|
+
return '<div class="editor-history-group-previews' + (isExpanded ? ' is-expanded' : '') + '" aria-label="Generated media previews">' + visible + more + '</div>';
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
function renderSample(title, payload, omittedReason) {
|
|
1796
|
+
return '<section class="editor-history-sample">' +
|
|
1797
|
+
'<h4>' + escapeHtml(title) + '</h4>' +
|
|
1798
|
+
(omittedReason ? '<div class="editor-history-sample-note">' + escapeHtml(omittedReason) + '</div>' : '') +
|
|
1799
|
+
'<pre>' + escapeHtml(formatJson(payload)) + '</pre>' +
|
|
1800
|
+
'</section>';
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
function renderEntry(entry) {
|
|
1804
|
+
return '<article class="editor-history-card">' +
|
|
1805
|
+
renderHttpAction(entry) +
|
|
1806
|
+
'<div class="editor-history-card-foot">' +
|
|
1807
|
+
'<span>' + escapeHtml(new Date(entry.createdAt).toLocaleString()) + '</span>' +
|
|
1808
|
+
'</div>' +
|
|
1809
|
+
renderPreviewLinks(entry.outputMediaUrls && entry.outputMediaUrls.length ? entry.outputMediaUrls : entry.mediaUrls) +
|
|
1810
|
+
'</article>';
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
function hasGeneratedTracerSuffix(tracer) {
|
|
1814
|
+
return /-[a-z0-9]{8}$/i.test(String(tracer || "").trim());
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
function doesTracerMatchSelection(entryTracer, selectedTracer) {
|
|
1818
|
+
const normalizedEntry = String(entryTracer || "").trim();
|
|
1819
|
+
const normalizedSelected = String(selectedTracer || "").trim();
|
|
1820
|
+
if (!normalizedEntry || !normalizedSelected) {
|
|
1821
|
+
return false;
|
|
1822
|
+
}
|
|
1823
|
+
if (normalizedEntry === normalizedSelected) {
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
return normalizedEntry.startsWith(normalizedSelected + "-") && hasGeneratedTracerSuffix(normalizedEntry);
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
async function copyText(value) {
|
|
1830
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
1831
|
+
try {
|
|
1832
|
+
await navigator.clipboard.writeText(value);
|
|
1833
|
+
return true;
|
|
1834
|
+
} catch {
|
|
1835
|
+
// Fall back to the textarea path when browser permissions block clipboard.writeText.
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
const field = document.createElement("textarea");
|
|
1839
|
+
field.value = value;
|
|
1840
|
+
field.setAttribute("readonly", "");
|
|
1841
|
+
field.style.position = "fixed";
|
|
1842
|
+
field.style.opacity = "0";
|
|
1843
|
+
document.body.appendChild(field);
|
|
1844
|
+
field.select();
|
|
1845
|
+
let copied = false;
|
|
1846
|
+
try {
|
|
1847
|
+
copied = document.execCommand("copy");
|
|
1848
|
+
} finally {
|
|
1849
|
+
field.remove();
|
|
1850
|
+
}
|
|
1851
|
+
return copied;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
const copyFeedbackTimers = new WeakMap();
|
|
1855
|
+
|
|
1856
|
+
function clearCopyFeedback(button) {
|
|
1857
|
+
const previousTimer = copyFeedbackTimers.get(button);
|
|
1858
|
+
if (previousTimer) {
|
|
1859
|
+
window.clearTimeout(previousTimer);
|
|
1860
|
+
}
|
|
1861
|
+
copyFeedbackTimers.delete(button);
|
|
1862
|
+
button.removeAttribute("data-copying");
|
|
1863
|
+
button.removeAttribute("data-copied");
|
|
1864
|
+
button.removeAttribute("data-copy-error");
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
function resetCopyFeedback(button, label) {
|
|
1868
|
+
button.removeAttribute("data-copying");
|
|
1869
|
+
button.removeAttribute("data-copied");
|
|
1870
|
+
button.removeAttribute("data-copy-error");
|
|
1871
|
+
button.setAttribute("aria-label", "Copy " + label);
|
|
1872
|
+
button.setAttribute("title", "Copy " + label);
|
|
1873
|
+
copyFeedbackTimers.delete(button);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
function showCopyingFeedback(button, label) {
|
|
1877
|
+
clearCopyFeedback(button);
|
|
1878
|
+
button.setAttribute("data-copying", "true");
|
|
1879
|
+
button.setAttribute("aria-label", "Copying " + label);
|
|
1880
|
+
button.setAttribute("title", "Copying");
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
function showCopyFeedback(button, label) {
|
|
1884
|
+
clearCopyFeedback(button);
|
|
1885
|
+
button.setAttribute("data-copied", "true");
|
|
1886
|
+
button.setAttribute("aria-label", "Copied " + label);
|
|
1887
|
+
button.setAttribute("title", "Copied");
|
|
1888
|
+
const timer = window.setTimeout(() => {
|
|
1889
|
+
resetCopyFeedback(button, label);
|
|
1890
|
+
}, 1400);
|
|
1891
|
+
copyFeedbackTimers.set(button, timer);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
function showCopyErrorFeedback(button, label) {
|
|
1895
|
+
clearCopyFeedback(button);
|
|
1896
|
+
button.setAttribute("data-copy-error", "true");
|
|
1897
|
+
button.setAttribute("aria-label", "Copy failed for " + label);
|
|
1898
|
+
button.setAttribute("title", "Copy failed");
|
|
1899
|
+
const timer = window.setTimeout(() => {
|
|
1900
|
+
resetCopyFeedback(button, label);
|
|
1901
|
+
}, 1800);
|
|
1902
|
+
copyFeedbackTimers.set(button, timer);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
function renderGroups(entries, tracers) {
|
|
1906
|
+
if (!tracers.length) {
|
|
1907
|
+
renderEmpty("Use Copilot to start or select a tracer, then its grouped POST history will appear here.");
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
const grouped = new Map();
|
|
1912
|
+
for (const entry of entries) {
|
|
1913
|
+
const key = tracers.find((tracer) => doesTracerMatchSelection(entry.tracer, tracer)) || entry.tracer || "No tracer";
|
|
1914
|
+
const existing = grouped.get(key) || [];
|
|
1915
|
+
existing.push(entry);
|
|
1916
|
+
grouped.set(key, existing);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
historyRoot.innerHTML = tracers.map((tracer, index) => {
|
|
1920
|
+
const groupEntries = grouped.get(tracer) || [];
|
|
1921
|
+
const activeRefresh = index === 0
|
|
1922
|
+
? '<button type="button" class="editor-history-button editor-history-refresh" data-editor-history-refresh="' + escapeHtml(tracer) + '" aria-label="Refresh tracer history" title="Refresh tracer history">' + renderRefreshIcon() + '</button>'
|
|
1923
|
+
: '';
|
|
1924
|
+
const menu = '<span class="editor-history-menu-wrap" data-editor-history-menu-wrap>' +
|
|
1925
|
+
'<button type="button" class="editor-history-button editor-history-menu-button" data-editor-history-menu-toggle="' + escapeHtml(tracer) + '" aria-label="Tracer actions" title="Tracer actions">...</button>' +
|
|
1926
|
+
'<span class="editor-history-menu" role="menu">' +
|
|
1927
|
+
'<button type="button" data-editor-history-copy="' + escapeHtml(tracer) + '">Copy Tracer</button>' +
|
|
1928
|
+
'<button type="button" data-editor-history-rename="' + escapeHtml(tracer) + '">Rename tracer</button>' +
|
|
1929
|
+
'<button type="button" data-editor-history-remove="' + escapeHtml(tracer) + '">Remove from view</button>' +
|
|
1930
|
+
'<button type="button" data-editor-history-archive="' + escapeHtml(tracer) + '" data-danger="true">Archive tracer</button>' +
|
|
1931
|
+
'</span>' +
|
|
1932
|
+
'</span>';
|
|
1933
|
+
const callsLabel = groupEntries.length
|
|
1934
|
+
? escapeHtml(groupEntries.length) + ' POST call' + (groupEntries.length === 1 ? '' : 's')
|
|
1935
|
+
: 'No POST calls yet';
|
|
1936
|
+
return (
|
|
1937
|
+
'<details class="editor-history-group"' + (index === 0 ? ' open' : '') + '>' +
|
|
1938
|
+
'<summary>' +
|
|
1939
|
+
'<div class="editor-history-group-main">' +
|
|
1940
|
+
'<h3>' + escapeHtml(tracer) + '</h3>' +
|
|
1941
|
+
'<p>' + callsLabel + '</p>' +
|
|
1942
|
+
renderGroupPreviewStrip(groupEntries, tracer) +
|
|
1943
|
+
'</div>' +
|
|
1944
|
+
'<div class="editor-history-group-actions">' +
|
|
1945
|
+
activeRefresh +
|
|
1946
|
+
menu +
|
|
1947
|
+
'<span class="editor-history-group-toggle">Toggle</span>' +
|
|
1948
|
+
'</div>' +
|
|
1949
|
+
'</summary>' +
|
|
1950
|
+
'<div class="editor-history-group-body">' +
|
|
1951
|
+
(groupEntries.length
|
|
1952
|
+
? groupEntries.map(renderEntry).join("")
|
|
1953
|
+
: '<div class="editor-history-empty">No POST history exists for this tracer yet.</div>') +
|
|
1954
|
+
'</div>' +
|
|
1955
|
+
'</details>'
|
|
1956
|
+
)}).join("");
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
async function fetchHistoryPayload(endpoint) {
|
|
1960
|
+
const response = await fetch(endpoint.toString(), { credentials: "same-origin" });
|
|
1961
|
+
let payload = null;
|
|
1962
|
+
try {
|
|
1963
|
+
payload = await response.json();
|
|
1964
|
+
} catch {
|
|
1965
|
+
payload = null;
|
|
1966
|
+
}
|
|
1967
|
+
if (!response.ok) {
|
|
1968
|
+
const message = payload && typeof payload.error === "string"
|
|
1969
|
+
? payload.error
|
|
1970
|
+
: "Unable to load POST history.";
|
|
1971
|
+
throw new Error(message + " (" + response.status + ")");
|
|
1972
|
+
}
|
|
1973
|
+
return payload || {};
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
async function loadFallbackHistory(selectedTracers) {
|
|
1977
|
+
if (!boot.fallbackHistoryEndpoint) {
|
|
1978
|
+
throw new Error("No fallback history endpoint is configured.");
|
|
1979
|
+
}
|
|
1980
|
+
const byId = new Map();
|
|
1981
|
+
for (const tracer of selectedTracers) {
|
|
1982
|
+
const endpoint = new URL(boot.fallbackHistoryEndpoint, window.location.origin);
|
|
1983
|
+
endpoint.searchParams.set("tracer", tracer);
|
|
1984
|
+
const payload = await fetchHistoryPayload(endpoint);
|
|
1985
|
+
for (const entry of Array.isArray(payload.entries) ? payload.entries : []) {
|
|
1986
|
+
byId.set(entry.id, entry);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
return { entries: [...byId.values()] };
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
async function loadHistory(options) {
|
|
1993
|
+
const showLoading = Boolean(options && options.showLoading);
|
|
1994
|
+
const triggerButton = options && options.triggerButton instanceof HTMLButtonElement ? options.triggerButton : null;
|
|
1995
|
+
const selectedTracers = tracerStore.get();
|
|
1996
|
+
renderTracerChips(selectedTracers);
|
|
1997
|
+
if (!selectedTracers.length) {
|
|
1998
|
+
renderEmpty("No tracer selected yet.");
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
if (!boot.isLoggedIn) {
|
|
2002
|
+
renderEmpty("Sign in to load tracer-scoped POST history.");
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
const endpoint = new URL(boot.historyEndpoint, window.location.origin);
|
|
2007
|
+
if (selectedTracers.length) {
|
|
2008
|
+
endpoint.searchParams.set("tracers", selectedTracers.join(","));
|
|
2009
|
+
} else {
|
|
2010
|
+
endpoint.searchParams.delete("tracers");
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
if (triggerButton) {
|
|
2014
|
+
triggerButton.disabled = true;
|
|
2015
|
+
triggerButton.setAttribute("data-loading", "true");
|
|
2016
|
+
} else if (showLoading) {
|
|
2017
|
+
historyRoot.innerHTML = '<div class="editor-history-empty">Loading POST history…</div>';
|
|
2018
|
+
}
|
|
2019
|
+
try {
|
|
2020
|
+
let payload;
|
|
2021
|
+
try {
|
|
2022
|
+
payload = await fetchHistoryPayload(endpoint);
|
|
2023
|
+
} catch (primaryError) {
|
|
2024
|
+
console.warn("Editor-scoped history failed; trying job-runs history fallback.", primaryError);
|
|
2025
|
+
payload = await loadFallbackHistory(selectedTracers);
|
|
2026
|
+
}
|
|
2027
|
+
const entries = Array.isArray(payload.entries) ? payload.entries : [];
|
|
2028
|
+
lastHistoryEntries = entries;
|
|
2029
|
+
lastSelectedTracers = selectedTracers;
|
|
2030
|
+
renderGroups(entries, selectedTracers);
|
|
2031
|
+
} catch (error) {
|
|
2032
|
+
console.error(error);
|
|
2033
|
+
renderEmpty("Unable to load tracer-scoped POST history" + (error instanceof Error && error.message ? ": " + error.message : "."));
|
|
2034
|
+
} finally {
|
|
2035
|
+
if (triggerButton) {
|
|
2036
|
+
triggerButton.disabled = false;
|
|
2037
|
+
triggerButton.setAttribute("data-loading", "false");
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
async function renameStoredTracer(fromTracer, toTracer) {
|
|
2043
|
+
const normalizedFrom = String(fromTracer || "").trim();
|
|
2044
|
+
const normalizedTo = String(toTracer || "").trim();
|
|
2045
|
+
if (!normalizedFrom || !normalizedTo || normalizedFrom === normalizedTo) {
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
const response = await fetch(boot.tracerEndpoint, {
|
|
2049
|
+
method: "PATCH",
|
|
2050
|
+
credentials: "same-origin",
|
|
2051
|
+
headers: { "content-type": "application/json" },
|
|
2052
|
+
body: JSON.stringify({
|
|
2053
|
+
from_tracer: normalizedFrom,
|
|
2054
|
+
to_tracer: normalizedTo
|
|
2055
|
+
})
|
|
2056
|
+
});
|
|
2057
|
+
if (!response.ok) {
|
|
2058
|
+
throw new Error("Unable to update tracer.");
|
|
2059
|
+
}
|
|
2060
|
+
const nextTracers = tracerStore.get().map((entry) => entry === normalizedFrom ? normalizedTo : entry);
|
|
2061
|
+
tracerStore.set(nextTracers);
|
|
2062
|
+
await loadHistory({ showLoading: true });
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
loadHistory({ showLoading: true });
|
|
2066
|
+
window.addEventListener("popstate", () => loadHistory({ showLoading: true }));
|
|
2067
|
+
window.addEventListener("vidfarm:editor-tracers-changed", () => loadHistory());
|
|
2068
|
+
if (hasTracerModal) {
|
|
2069
|
+
addTracerButton.addEventListener("click", () => openTracerModal());
|
|
2070
|
+
modalSubmit.addEventListener("click", () => submitTracerModal());
|
|
2071
|
+
modalCancel.addEventListener("click", () => closeTracerModal());
|
|
2072
|
+
modalInput.addEventListener("keydown", (event) => {
|
|
2073
|
+
if (event.key === "Enter") {
|
|
2074
|
+
event.preventDefault();
|
|
2075
|
+
submitTracerModal();
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
if (event.key === "Escape") {
|
|
2079
|
+
event.preventDefault();
|
|
2080
|
+
closeTracerModal();
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
modalBackdrop.addEventListener("click", (event) => {
|
|
2084
|
+
if (event.target === modalBackdrop) {
|
|
2085
|
+
closeTracerModal();
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
if (hasMediaModal) {
|
|
2090
|
+
mediaModalClose.addEventListener("click", () => closeMediaModal());
|
|
2091
|
+
mediaModalBackdrop.addEventListener("click", (event) => {
|
|
2092
|
+
if (event.target === mediaModalBackdrop) {
|
|
2093
|
+
closeMediaModal();
|
|
2094
|
+
}
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
if (hasHttpModal) {
|
|
2098
|
+
httpModalClose.addEventListener("click", () => closeHttpModal());
|
|
2099
|
+
httpModalBackdrop.addEventListener("click", (event) => {
|
|
2100
|
+
if (event.target === httpModalBackdrop) {
|
|
2101
|
+
closeHttpModal();
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
window.addEventListener("keydown", (event) => {
|
|
2106
|
+
if (event.key === "Escape") {
|
|
2107
|
+
if (hasHttpModal && httpModalBackdrop.hidden === false) {
|
|
2108
|
+
closeHttpModal();
|
|
2109
|
+
return;
|
|
2110
|
+
}
|
|
2111
|
+
if (hasMediaModal && mediaModalBackdrop.getAttribute("data-open") === "true") {
|
|
2112
|
+
closeMediaModal();
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
if (hasTracerModal && modalBackdrop.getAttribute("data-open") === "true") {
|
|
2116
|
+
closeTracerModal();
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
historyRoot.addEventListener("click", (event) => {
|
|
2121
|
+
const target = event.target;
|
|
2122
|
+
if (!(target instanceof Element)) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
const previewButton = target.closest("[data-preview-url]");
|
|
2126
|
+
if (previewButton instanceof HTMLButtonElement) {
|
|
2127
|
+
event.preventDefault();
|
|
2128
|
+
event.stopPropagation();
|
|
2129
|
+
const url = previewButton.getAttribute("data-preview-url") || "";
|
|
2130
|
+
const kind = previewButton.getAttribute("data-preview-kind") || "file";
|
|
2131
|
+
const label = previewButton.getAttribute("data-preview-label") || "Output preview";
|
|
2132
|
+
if (url) {
|
|
2133
|
+
openMediaModal(url, kind, label);
|
|
2134
|
+
}
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
const expandMediaButton = target.closest("[data-editor-expand-media]");
|
|
2138
|
+
if (expandMediaButton instanceof HTMLButtonElement) {
|
|
2139
|
+
event.preventDefault();
|
|
2140
|
+
event.stopPropagation();
|
|
2141
|
+
const key = expandMediaButton.getAttribute("data-editor-expand-media") || "";
|
|
2142
|
+
if (key) {
|
|
2143
|
+
expandedPreviewGroups.add(key);
|
|
2144
|
+
renderGroups(lastHistoryEntries, lastSelectedTracers);
|
|
2145
|
+
}
|
|
2146
|
+
return;
|
|
2147
|
+
}
|
|
2148
|
+
const httpDetailButton = target.closest("[data-editor-http-detail]");
|
|
2149
|
+
if (httpDetailButton instanceof HTMLButtonElement) {
|
|
2150
|
+
event.preventDefault();
|
|
2151
|
+
event.stopPropagation();
|
|
2152
|
+
try {
|
|
2153
|
+
openHttpModal(JSON.parse(decodeURIComponent(httpDetailButton.getAttribute("data-editor-http-detail") || "")));
|
|
2154
|
+
} catch (error) {
|
|
2155
|
+
console.error(error);
|
|
2156
|
+
}
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
const refreshButton = target.closest("[data-editor-history-refresh]");
|
|
2160
|
+
if (refreshButton instanceof HTMLButtonElement) {
|
|
2161
|
+
event.preventDefault();
|
|
2162
|
+
event.stopPropagation();
|
|
2163
|
+
void loadHistory({ triggerButton: refreshButton });
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
const menuToggle = target.closest("[data-editor-history-menu-toggle]");
|
|
2167
|
+
if (menuToggle instanceof HTMLButtonElement) {
|
|
2168
|
+
event.preventDefault();
|
|
2169
|
+
event.stopPropagation();
|
|
2170
|
+
const wrap = menuToggle.closest("[data-editor-history-menu-wrap]");
|
|
2171
|
+
const isOpen = wrap instanceof HTMLElement && wrap.getAttribute("data-open") === "true";
|
|
2172
|
+
document.querySelectorAll("[data-editor-history-menu-wrap]").forEach((entry) => entry.removeAttribute("data-open"));
|
|
2173
|
+
if (wrap instanceof HTMLElement && !isOpen) {
|
|
2174
|
+
wrap.setAttribute("data-open", "true");
|
|
2175
|
+
}
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
const copyButton = target.closest("[data-editor-history-copy]");
|
|
2179
|
+
if (copyButton instanceof HTMLButtonElement) {
|
|
2180
|
+
event.preventDefault();
|
|
2181
|
+
event.stopPropagation();
|
|
2182
|
+
const tracer = copyButton.getAttribute("data-editor-history-copy") || "";
|
|
2183
|
+
document.querySelectorAll("[data-editor-history-menu-wrap]").forEach((entry) => entry.removeAttribute("data-open"));
|
|
2184
|
+
if (!tracer) {
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
void copyText(tracer).then((copied) => {
|
|
2188
|
+
if (!copied) {
|
|
2189
|
+
window.prompt("Copy tracer", tracer);
|
|
2190
|
+
}
|
|
2191
|
+
}).catch((error) => {
|
|
2192
|
+
console.error(error);
|
|
2193
|
+
window.prompt("Copy tracer", tracer);
|
|
2194
|
+
});
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
const renameButton = target.closest("[data-editor-history-rename]");
|
|
2198
|
+
if (renameButton instanceof HTMLButtonElement) {
|
|
2199
|
+
event.preventDefault();
|
|
2200
|
+
event.stopPropagation();
|
|
2201
|
+
const tracer = renameButton.getAttribute("data-editor-history-rename") || "";
|
|
2202
|
+
document.querySelectorAll("[data-editor-history-menu-wrap]").forEach((entry) => entry.removeAttribute("data-open"));
|
|
2203
|
+
const nextTracer = window.prompt("Rename tracer", tracer);
|
|
2204
|
+
if (nextTracer === null || !nextTracer.trim() || nextTracer.trim() === tracer) {
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
void renameStoredTracer(tracer, nextTracer.trim()).catch((error) => {
|
|
2208
|
+
console.error(error);
|
|
2209
|
+
window.alert("Unable to rename tracer.");
|
|
2210
|
+
});
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
const archiveButton = target.closest("[data-editor-history-archive]");
|
|
2214
|
+
if (archiveButton instanceof HTMLButtonElement) {
|
|
2215
|
+
event.preventDefault();
|
|
2216
|
+
event.stopPropagation();
|
|
2217
|
+
const tracer = archiveButton.getAttribute("data-editor-history-archive") || "";
|
|
2218
|
+
document.querySelectorAll("[data-editor-history-menu-wrap]").forEach((entry) => entry.removeAttribute("data-open"));
|
|
2219
|
+
if (!tracer || tracer.startsWith("archived_")) {
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
const confirmed = window.confirm('Archive "' + tracer + '"? This renames its POST logs and jobs to "archived_' + tracer + '".');
|
|
2223
|
+
if (confirmed) {
|
|
2224
|
+
void renameStoredTracer(tracer, "archived_" + tracer).catch((error) => {
|
|
2225
|
+
console.error(error);
|
|
2226
|
+
window.alert("Unable to archive tracer.");
|
|
2227
|
+
});
|
|
2228
|
+
}
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
const removeButton = target.closest("[data-editor-history-remove]");
|
|
2232
|
+
if (removeButton instanceof HTMLButtonElement) {
|
|
2233
|
+
event.preventDefault();
|
|
2234
|
+
event.stopPropagation();
|
|
2235
|
+
const tracer = removeButton.getAttribute("data-editor-history-remove") || "";
|
|
2236
|
+
document.querySelectorAll("[data-editor-history-menu-wrap]").forEach((entry) => entry.removeAttribute("data-open"));
|
|
2237
|
+
if (!tracer) {
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
const confirmed = window.confirm('Remove "' + tracer + '" from this page view? This does not delete its runs. You can still find them in Job Runs.');
|
|
2241
|
+
if (confirmed) {
|
|
2242
|
+
tracerStore.remove(tracer);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
});
|
|
2246
|
+
document.addEventListener("click", (event) => {
|
|
2247
|
+
const target = event.target;
|
|
2248
|
+
if (!(target instanceof Element)) {
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
const copyButton = target.closest("[data-editor-copy-content]");
|
|
2252
|
+
if (!(copyButton instanceof HTMLButtonElement)) {
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
event.preventDefault();
|
|
2256
|
+
const value = copyButton.getAttribute("data-editor-copy-content") || "";
|
|
2257
|
+
const label = copyButton.getAttribute("data-editor-copy-label") || "Copied text";
|
|
2258
|
+
if (!value) {
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
showCopyingFeedback(copyButton, label);
|
|
2262
|
+
void copyText(value).then((copied) => {
|
|
2263
|
+
if (!copied) {
|
|
2264
|
+
showCopyErrorFeedback(copyButton, label);
|
|
2265
|
+
window.prompt(label, value);
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
showCopyFeedback(copyButton, label);
|
|
2269
|
+
}).catch((error) => {
|
|
2270
|
+
console.error(error);
|
|
2271
|
+
showCopyErrorFeedback(copyButton, label);
|
|
2272
|
+
window.prompt(label, value);
|
|
2273
|
+
});
|
|
2274
|
+
});
|
|
2275
|
+
})();
|
|
2276
|
+
</script>
|
|
2277
|
+
`
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
function renderPreview(url, alt) {
|
|
2281
|
+
if (/\.(mp4|webm|ogg|mov)(\?|#|$)/i.test(url)) {
|
|
2282
|
+
return `<video class="editor-preview" src="${escapeAttribute(url)}" controls playsinline preload="metadata" aria-label="${escapeAttribute(alt)}"></video>`;
|
|
2283
|
+
}
|
|
2284
|
+
return `<img class="editor-preview" src="${escapeAttribute(url)}" alt="${escapeAttribute(alt)}" loading="lazy" decoding="async" />`;
|
|
2285
|
+
}
|
|
2286
|
+
function renderQuickstartTextarea(label, value, rows) {
|
|
2287
|
+
const text = value.trim() || "Not configured for this template yet.";
|
|
2288
|
+
return `
|
|
2289
|
+
<div class="editor-quickstart-field">
|
|
2290
|
+
<div class="editor-quickstart-field-head">
|
|
2291
|
+
<span>${escapeHtml(label)}</span>
|
|
2292
|
+
<button
|
|
2293
|
+
type="button"
|
|
2294
|
+
class="editor-quickstart-copy"
|
|
2295
|
+
data-editor-copy-content="${escapeAttribute(text)}"
|
|
2296
|
+
data-editor-copy-label="${escapeAttribute(label)}"
|
|
2297
|
+
aria-label="Copy ${escapeAttribute(label)}"
|
|
2298
|
+
title="Copy ${escapeAttribute(label)}"
|
|
2299
|
+
>
|
|
2300
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
2301
|
+
<rect x="9" y="9" width="10" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="2"></rect>
|
|
2302
|
+
<path d="M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
|
|
2303
|
+
</svg>
|
|
2304
|
+
</button>
|
|
2305
|
+
</div>
|
|
2306
|
+
<textarea class="editor-quickstart-textarea" readonly rows="${rows}" spellcheck="false" aria-label="${escapeAttribute(label)}">${escapeHtml(text)}</textarea>
|
|
2307
|
+
</div>
|
|
2308
|
+
`;
|
|
2309
|
+
}
|