@jxsuite/studio 3.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/chunks/{2020-xp8vnwma.js → 2020-n6tfwnda.js} +2 -2
- package/dist/chunks/Overlay.dev-etqjwyf9.js +23 -0
- package/dist/chunks/cf-account-picker-en86v7x7.js +163 -0
- package/dist/chunks/{cf-settings-zj2cj1ar.js → cf-settings-45fgyx8y.js} +6 -5
- package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
- package/dist/chunks/content-source-48xg86wj.js +49 -0
- package/dist/chunks/{convert-to-repeater-6vvx96n2.js → convert-to-repeater-43tfn7cs.js} +33 -25
- package/dist/chunks/entry-commands-e63f1xc0.js +46 -0
- package/dist/chunks/{extension-sections-kwzvpemr.js → extension-sections-txv08xxg.js} +34 -26
- package/dist/chunks/file-ops-wbh4hhsx.js +48 -0
- package/dist/chunks/files-3kfkwhk4.js +93 -0
- package/dist/chunks/{focus-trap.esm-ggawf1hy.js → focus-trap.esm-9t2drp0g.js} +6 -5
- package/dist/chunks/{format-host-8fr3545e.js → format-host-w16q81tf.js} +3 -3
- package/dist/chunks/fs-events-hrrg328g.js +21 -0
- package/dist/chunks/{git-panel-g01d93vc.js → git-panel-532whr1y.js} +22 -16
- package/dist/chunks/{index-nj44jpzj.js → index-wcnt3r9g.js} +2 -2
- package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8er6gbxy.js} +6 -4
- package/dist/chunks/layers-panel-07hm7g5j.js +67 -0
- package/dist/chunks/layers-q75tj2mf.js +45 -0
- package/dist/chunks/lit-html-j055mkh8.js +22 -0
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
- package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-vx9bhp1d.js} +4 -4
- package/dist/chunks/notify-yjm79n4s.js +30 -0
- package/dist/chunks/parse-24d0gay3.js +19 -0
- package/dist/chunks/platform-ba1j1gbh.js +16 -0
- package/dist/chunks/publish-panel-v9st96ja.js +29 -0
- package/dist/chunks/quick-search-zccjp6gv.js +66 -0
- package/dist/chunks/references-3qx8fkyp.js +29 -0
- package/dist/chunks/right-panel-vm3b6kwy.js +46 -0
- package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +18 -0
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
- package/dist/chunks/sp-tooltip.dev-4sastdnw.js +15 -0
- package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
- package/dist/chunks/{studio-wdt9y92a.js → studio-0bq6eh7v.js} +2 -2
- package/dist/chunks/studio-1ngbejft.js +181 -0
- package/dist/chunks/studio-1wagb550.js +118 -0
- package/dist/chunks/{studio-j595e748.js → studio-2b946z26.js} +172 -95
- package/dist/chunks/{studio-pkp61mh8.js → studio-3bqpr0zh.js} +25 -17
- package/dist/chunks/{studio-k4jvjcfx.js → studio-4b5z1x43.js} +46 -12
- package/dist/chunks/{studio-ry1vz5sv.js → studio-4n2b5gzb.js} +15 -13
- package/dist/chunks/{studio-p5dja96s.js → studio-4r1pv6zf.js} +2 -2
- package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
- package/dist/chunks/{studio-tzx3xmvx.js → studio-5fx3g9jg.js} +33 -52
- package/dist/chunks/{studio-rh1cnamv.js → studio-5myknm0a.js} +565 -135
- package/dist/chunks/studio-6yw4y3my.js +91 -0
- package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
- package/dist/chunks/studio-92ab2jqe.js +282 -0
- package/dist/chunks/{studio-6z5eyjwn.js → studio-950k0dx6.js} +72 -135
- package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
- package/dist/chunks/studio-9n4mrmnb.js +184 -0
- package/dist/chunks/{studio-hcxzyk3x.js → studio-ahn3pdgx.js} +6 -6
- package/dist/chunks/studio-b55y6ewx.js +498 -0
- package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
- package/dist/chunks/studio-cft9r4r7.js +119 -0
- package/dist/chunks/{studio-dc8s8heb.js → studio-cmb03bg5.js} +6904 -8321
- package/dist/chunks/studio-dm19q43r.js +195 -0
- package/dist/chunks/{studio-2x9zbxmx.js → studio-ef49pnzx.js} +11 -9
- package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
- package/dist/chunks/{studio-5efrtn1m.js → studio-ew0djmhg.js} +23 -19
- package/dist/chunks/{studio-tr20m8g8.js → studio-f3wqjtk5.js} +39 -3
- package/dist/chunks/{studio-xntfdy1x.js → studio-fbf92ckf.js} +36 -23
- package/dist/chunks/{studio-4q0wznzf.js → studio-gcye7qka.js} +442 -126
- package/dist/chunks/{studio-7p35254k.js → studio-gfgb8pe6.js} +36 -193
- package/dist/chunks/studio-jc994dnr.js +1066 -0
- package/dist/chunks/{studio-hj2se583.js → studio-jkftxyvz.js} +69 -3423
- package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
- package/dist/chunks/{studio-kfpek536.js → studio-kyh9avvv.js} +2 -2
- package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
- package/dist/chunks/studio-msd847zn.js +1315 -0
- package/dist/chunks/{studio-g5gdqnyd.js → studio-mtfnaqs9.js} +19 -19
- package/dist/chunks/{studio-7ejemhej.js → studio-n6j9t10q.js} +6 -6
- package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
- package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
- package/dist/chunks/studio-q43a5y9h.js +394 -0
- package/dist/chunks/studio-q7v10cg2.js +106 -0
- package/dist/chunks/{studio-6kv3apa9.js → studio-q9jd1a60.js} +27 -11
- package/dist/chunks/studio-qcy05dp8.js +1743 -0
- package/dist/chunks/{studio-a0yp7syn.js → studio-qjy2z9bv.js} +29 -132
- package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
- package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
- package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
- package/dist/chunks/studio-t7qb9db8.js +665 -0
- package/dist/chunks/studio-tmc5emrw.js +8 -0
- package/dist/chunks/{studio-r5xbtctf.js → studio-trxrabqf.js} +292 -2297
- package/dist/chunks/studio-wcy8trfx.js +263 -0
- package/dist/chunks/{studio-3dkcd4c5.js → studio-x4qkdat5.js} +62 -57
- package/dist/chunks/studio-x813zp48.js +195 -0
- package/dist/chunks/{studio-qpfq7xhm.js → studio-xrapxwwc.js} +22 -285
- package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
- package/dist/chunks/{studio-8ezdegcx.js → studio-zqazsct2.js} +40 -36
- package/dist/chunks/workspace-fjx52ryv.js +89 -0
- package/dist/iframe-entry.js +141 -56
- package/dist/manifest.json +7 -0
- package/dist/studio.js +2605 -1950
- package/favicon.ico +0 -0
- package/index.html +1 -0
- package/package.json +20 -18
- package/src/about/about-modal.ts +4 -3
- package/src/browse/library-pane.ts +57 -3
- package/src/canvas/canvas-render.ts +23 -1
- package/src/canvas/iframe-patch.ts +47 -21
- package/src/canvas/iframe-render.ts +22 -6
- package/src/commands/app-commands.ts +4 -0
- package/src/commands/command-args.ts +29 -0
- package/src/commands/context.ts +15 -1
- package/src/commands/defaults.ts +29 -1
- package/src/commands/levels.ts +16 -0
- package/src/commands/live-context.ts +3 -0
- package/src/content/collection-match.ts +267 -0
- package/src/content/entry-commands.ts +38 -29
- package/src/content/entry-fields.ts +6 -0
- package/src/editor/shortcuts.ts +5 -0
- package/src/files/file-ops.ts +10 -42
- package/src/files/files.ts +487 -59
- package/src/files/fs-events.ts +9 -0
- package/src/files/gitignore.ts +432 -0
- package/src/files/media-paths.ts +13 -42
- package/src/files/media-usage.ts +41 -131
- package/src/files/serialize-document.ts +60 -0
- package/src/format/convert-file.ts +511 -0
- package/src/format/format-choices.ts +199 -0
- package/src/grid/grid-view.ts +16 -2
- package/src/hosting/document.ts +2 -0
- package/src/hosting/layout.ts +8 -0
- package/src/media/media-open.ts +58 -0
- package/src/media/media-pane.ts +310 -0
- package/src/new-project/import-tab.ts +357 -163
- package/src/new-project/location-fields.ts +8 -5
- package/src/new-project/new-project-modal.ts +27 -34
- package/src/packages/ensure-deps.ts +14 -7
- package/src/packages/jxsuite-update.ts +11 -11
- package/src/page-params.ts +10 -46
- package/src/panels/activity-bar.ts +45 -16
- package/src/panels/ai-chat/attached-context.ts +6 -1
- package/src/panels/ai-chat/chat-view.ts +255 -13
- package/src/panels/ai-chat/composer.ts +31 -97
- package/src/panels/ai-panel.ts +116 -2
- package/src/panels/navigator-panels.ts +7 -6
- package/src/panels/settings-menu.ts +799 -0
- package/src/panels/toolbar.ts +135 -15
- package/src/platforms/cloud.ts +261 -70
- package/src/platforms/devserver.ts +67 -33
- package/src/preview/preview-overlay.ts +226 -0
- package/src/publish/publish-panel.ts +62 -2
- package/src/services/ai-ask.ts +247 -0
- package/src/services/ai-import-tools.ts +532 -0
- package/src/services/ai-models.ts +108 -1
- package/src/services/ai-project-tools.ts +20 -26
- package/src/services/ai-system-prompt.ts +88 -2
- package/src/services/ai-turn-signal.ts +70 -0
- package/src/services/connection.ts +74 -0
- package/src/services/context-manager.ts +101 -1
- package/src/services/document-assistant.ts +45 -4
- package/src/services/import-client.ts +33 -6
- package/src/services/import-run.ts +158 -0
- package/src/services/import-seed.ts +120 -0
- package/src/services/jx-validate.ts +58 -6
- package/src/services/project-adoption.ts +71 -0
- package/src/services/references.ts +0 -0
- package/src/services/settings/definitions.ts +17 -0
- package/src/services/tool-executor.ts +45 -2
- package/src/settings/contexts-section.ts +45 -3
- package/src/settings/dependencies-editor.ts +43 -23
- package/src/settings/general-settings.ts +30 -12
- package/src/settings/preferences-accounts.ts +193 -12
- package/src/settings/preferences-dialog.ts +93 -59
- package/src/settings/preferences-sections.ts +57 -0
- package/src/settings/settings-document.ts +65 -9
- package/src/studio.ts +33 -6
- package/src/tabs/transact.ts +42 -19
- package/src/types.ts +129 -7
- package/src/ui/ai-managed-connect.ts +62 -13
- package/src/ui/ai-model-picker.ts +189 -0
- package/src/ui/cf-account-picker.ts +200 -0
- package/src/ui/choice-field.ts +72 -0
- package/src/ui/layers.ts +83 -5
- package/src/utils/studio-utils.ts +22 -52
- package/styles/forced-colors.css +7 -0
- package/styles/overlays.css +256 -0
- package/styles/panels.css +13 -1
- package/styles/shell.css +147 -0
- package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
- package/dist/chunks/content-source-7fy9qrm0.js +0 -40
- package/dist/chunks/files-xcybanxe.js +0 -70
- package/dist/chunks/layers-panel-27essgkc.js +0 -60
- package/dist/chunks/publish-panel-09sy2bab.js +0 -22
- package/dist/chunks/quick-search-sefb61v8.js +0 -55
- package/dist/chunks/right-panel-9r32jd5j.js +0 -39
- package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
- package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
- package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
- package/dist/chunks/studio-bw5dz6km.js +0 -608
- package/dist/chunks/studio-c31yb4t6.js +0 -55
- package/src/canvas/site-style-css.ts +0 -117
|
@@ -30,6 +30,7 @@ import { installUrlOf } from "../platform-errors";
|
|
|
30
30
|
import { hasAiCredentials } from "../services/ai-models";
|
|
31
31
|
import { setPendingAgentPrompt } from "../services/agent-seed";
|
|
32
32
|
import { initProjectRepo } from "../files/files";
|
|
33
|
+
import { runImportHandoff } from "../services/import-seed";
|
|
33
34
|
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
34
35
|
import { createManagedConnect } from "../ui/ai-managed-connect";
|
|
35
36
|
import {
|
|
@@ -39,14 +40,10 @@ import {
|
|
|
39
40
|
resetLocationFields,
|
|
40
41
|
} from "./location-fields";
|
|
41
42
|
import {
|
|
42
|
-
|
|
43
|
+
handoffImport,
|
|
43
44
|
importButtonLabel,
|
|
44
|
-
isImportRunning,
|
|
45
|
-
renderImportProgress,
|
|
46
45
|
renderImportSource,
|
|
47
|
-
renderImportStatus,
|
|
48
46
|
resetImportTab,
|
|
49
|
-
startImport,
|
|
50
47
|
validateImportSource,
|
|
51
48
|
} from "./import-tab";
|
|
52
49
|
import type { ProjectConfig } from "@jxsuite/schema/types";
|
|
@@ -211,9 +208,6 @@ export function closeNewProjectModal() {
|
|
|
211
208
|
if (!_handle || _creating) {
|
|
212
209
|
return;
|
|
213
210
|
}
|
|
214
|
-
if (isImportRunning()) {
|
|
215
|
-
cancelImport(importCtxFor(renderModal));
|
|
216
|
-
}
|
|
217
211
|
_handle.close();
|
|
218
212
|
_handle = null;
|
|
219
213
|
if (_resolve) {
|
|
@@ -223,7 +217,7 @@ export function closeNewProjectModal() {
|
|
|
223
217
|
}
|
|
224
218
|
|
|
225
219
|
/** Close the modal and resolve its promise with a created/imported project. */
|
|
226
|
-
function finish(result: { root: string; config: ProjectConfig }) {
|
|
220
|
+
function finish(result: { root: string; config: ProjectConfig } | null) {
|
|
227
221
|
_creating = false;
|
|
228
222
|
if (_handle) {
|
|
229
223
|
_handle.close();
|
|
@@ -236,8 +230,12 @@ function finish(result: { root: string; config: ProjectConfig }) {
|
|
|
236
230
|
}
|
|
237
231
|
|
|
238
232
|
/**
|
|
239
|
-
* Every path out of the wizard that produced a project: initialise version control for it,
|
|
240
|
-
* hand it to the caller. A scaffold is not a repository, and Delete and Rename are one click
|
|
233
|
+
* Every path out of the wizard that produced a project HERE: initialise version control for it,
|
|
234
|
+
* then hand it to the caller. A scaffold is not a repository, and Delete and Rename are one click
|
|
235
|
+
* away.
|
|
236
|
+
*
|
|
237
|
+
* The Import path does not come through here any more — `import_site` creates the project, so the
|
|
238
|
+
* obligation moved with it into `services/project-adoption.ts`, which both bootstrap tools share.
|
|
241
239
|
*/
|
|
242
240
|
async function finishCreated(result: { root: string; config: ProjectConfig }) {
|
|
243
241
|
await initProjectRepo(result.root);
|
|
@@ -275,9 +273,13 @@ function importCtxFor(rerender: () => void): ImportTabCtx {
|
|
|
275
273
|
credsForm: credsForm(),
|
|
276
274
|
form: _form,
|
|
277
275
|
managedConnect: managedConnect(),
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
276
|
+
/* The wizard creates nothing on this path. `import_site` is `no-project` tiered and does the
|
|
277
|
+
creating — including the git init every create path owes (`specs/desktop.md` §4.5), which
|
|
278
|
+
moved into `adoptCreatedProject` with it. The modal resolves `null`, the same as a dismissal,
|
|
279
|
+
because nothing was created HERE. */
|
|
280
|
+
onHandoff: (brief) => {
|
|
281
|
+
finish(null);
|
|
282
|
+
void runImportHandoff(brief);
|
|
281
283
|
},
|
|
282
284
|
rerender,
|
|
283
285
|
resolveDestination: () => validateParams(),
|
|
@@ -338,7 +340,7 @@ function renderModal() {
|
|
|
338
340
|
};
|
|
339
341
|
|
|
340
342
|
const onTabChange = (e: Event) => {
|
|
341
|
-
if (_creating
|
|
343
|
+
if (_creating) {
|
|
342
344
|
return;
|
|
343
345
|
}
|
|
344
346
|
_tab = (e.target as HTMLElement & { selected: string }).selected as NewProjectTab;
|
|
@@ -363,7 +365,7 @@ function renderModal() {
|
|
|
363
365
|
};
|
|
364
366
|
|
|
365
367
|
const goBack = () => {
|
|
366
|
-
if (_creating
|
|
368
|
+
if (_creating) {
|
|
367
369
|
return;
|
|
368
370
|
}
|
|
369
371
|
_step = "source";
|
|
@@ -524,7 +526,12 @@ function renderModal() {
|
|
|
524
526
|
})}
|
|
525
527
|
${
|
|
526
528
|
_tab === "import"
|
|
527
|
-
?
|
|
529
|
+
? html`
|
|
530
|
+
<div class="new-project-tab-intro">
|
|
531
|
+
The assistant runs the import and reports as it goes — this dialog closes as soon as
|
|
532
|
+
it starts.
|
|
533
|
+
</div>
|
|
534
|
+
`
|
|
528
535
|
: html`
|
|
529
536
|
<div class="new-project-tab-intro">
|
|
530
537
|
The site's address, deployment target and design tokens are project settings — set
|
|
@@ -542,15 +549,6 @@ function renderModal() {
|
|
|
542
549
|
Cancel
|
|
543
550
|
</sp-button>
|
|
544
551
|
`;
|
|
545
|
-
if (isImportRunning()) {
|
|
546
|
-
// One cancel, not two: the run's own Cancel is the step's Cancel, and dismissing the modal
|
|
547
|
-
// (Escape, the underlay, the header ✕) aborts the run on the way out.
|
|
548
|
-
return html`
|
|
549
|
-
<sp-button variant="secondary" @click=${() => cancelImport(importCtx)}>
|
|
550
|
-
Cancel Import
|
|
551
|
-
</sp-button>
|
|
552
|
-
`;
|
|
553
|
-
}
|
|
554
552
|
if (_step === "source") {
|
|
555
553
|
const gated = (_tab === "import" || _tab === "agent") && !aiGateOpen();
|
|
556
554
|
return html`
|
|
@@ -561,7 +559,7 @@ function renderModal() {
|
|
|
561
559
|
const primary =
|
|
562
560
|
_tab === "import"
|
|
563
561
|
? html`
|
|
564
|
-
<sp-button variant="accent" @click=${() =>
|
|
562
|
+
<sp-button variant="accent" @click=${() => handoffImport(importCtx)}>
|
|
565
563
|
${importButtonLabel()}
|
|
566
564
|
</sp-button>
|
|
567
565
|
`
|
|
@@ -583,12 +581,7 @@ function renderModal() {
|
|
|
583
581
|
`;
|
|
584
582
|
};
|
|
585
583
|
|
|
586
|
-
const bodyTpl = () =>
|
|
587
|
-
if (isImportRunning()) {
|
|
588
|
-
return renderImportProgress();
|
|
589
|
-
}
|
|
590
|
-
return _step === "source" ? sourceBodyTpl() : paramsBodyTpl();
|
|
591
|
-
};
|
|
584
|
+
const bodyTpl = () => (_step === "source" ? sourceBodyTpl() : paramsBodyTpl());
|
|
592
585
|
|
|
593
586
|
const tpl = html`
|
|
594
587
|
<sp-underlay open @close=${closeNewProjectModal}></sp-underlay>
|
|
@@ -602,7 +595,7 @@ function renderModal() {
|
|
|
602
595
|
</sp-action-button>
|
|
603
596
|
</div>
|
|
604
597
|
${
|
|
605
|
-
_step === "source"
|
|
598
|
+
_step === "source"
|
|
606
599
|
? html`
|
|
607
600
|
<div class="new-project-tabs">
|
|
608
601
|
<sp-tabs selected=${_tab} quiet @change=${onTabChange}>
|
|
@@ -3,30 +3,36 @@
|
|
|
3
3
|
* Ensure the active project's dependencies are installed before the editor loads. When the backend
|
|
4
4
|
* reports node_modules is missing, run `bun install` behind a blocking progress modal so component
|
|
5
5
|
* and format resolution see the real dependency tree. No-op on platforms without package support.
|
|
6
|
+
*
|
|
7
|
+
* It REPORTS whether an install actually ran, because "format resolution sees the real dependency
|
|
8
|
+
* tree" was only half true: project activation fetches the format registry before calling this, and
|
|
9
|
+
* `loadFormats` memoises its answer — so on a fresh clone the empty registry it got survived the
|
|
10
|
+
* whole session, and the New File picker offered nothing but JSON in a project whose `project.json`
|
|
11
|
+
* enables the markdown extension. The caller re-fetches on a true.
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
import { getPlatform } from "../platform";
|
|
9
15
|
import { showProgressModal } from "../ui/progress-modal";
|
|
10
16
|
import { shouldInstallAutomation } from "../services/automation";
|
|
11
17
|
|
|
12
|
-
export async function ensureDependenciesInstalled(): Promise<
|
|
18
|
+
export async function ensureDependenciesInstalled(): Promise<boolean> {
|
|
13
19
|
// Automation/screenshot runs open projects read-only to drive the canvas — they must never mutate
|
|
14
20
|
// The project on disk (a `bun install` would litter node_modules/bun.lock into starter templates).
|
|
15
21
|
if (shouldInstallAutomation(location.search)) {
|
|
16
|
-
return;
|
|
22
|
+
return false;
|
|
17
23
|
}
|
|
18
24
|
const platform = getPlatform();
|
|
19
25
|
if (!platform.dependenciesNeedInstall || !platform.installDependencies) {
|
|
20
|
-
return;
|
|
26
|
+
return false;
|
|
21
27
|
}
|
|
22
28
|
let needs = false;
|
|
23
29
|
try {
|
|
24
30
|
needs = await platform.dependenciesNeedInstall();
|
|
25
31
|
} catch {
|
|
26
|
-
return;
|
|
32
|
+
return false;
|
|
27
33
|
}
|
|
28
34
|
if (!needs) {
|
|
29
|
-
return;
|
|
35
|
+
return false;
|
|
30
36
|
}
|
|
31
37
|
const progress = showProgressModal({
|
|
32
38
|
status: "Running bun install…",
|
|
@@ -36,10 +42,11 @@ export async function ensureDependenciesInstalled(): Promise<void> {
|
|
|
36
42
|
const result = await platform.installDependencies();
|
|
37
43
|
if (result.ok) {
|
|
38
44
|
progress.done();
|
|
39
|
-
|
|
40
|
-
progress.fail(result.log ?? "bun install failed");
|
|
45
|
+
return true;
|
|
41
46
|
}
|
|
47
|
+
progress.fail(result.log ?? "bun install failed");
|
|
42
48
|
} catch (error) {
|
|
43
49
|
progress.fail(error instanceof Error ? error.message : String(error));
|
|
44
50
|
}
|
|
51
|
+
return false;
|
|
45
52
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* build` and the project's types — not the running app. There is no reason for them to match
|
|
17
17
|
* Studio, and pinning them to it was the residue of an assumption that is no longer true.
|
|
18
18
|
*
|
|
19
|
-
* The registry lookup is `platform.
|
|
19
|
+
* The registry lookup is `platform.packageVersions()`, the same seam the dependencies editor uses.
|
|
20
20
|
* A host that does not offer it (the cloud session, which manages dependencies server-side) simply
|
|
21
21
|
* gets no prompt: without the registry there is no honest target, and guessing is what this
|
|
22
22
|
* replaced.
|
|
@@ -50,21 +50,22 @@ export interface JxsuiteUpdate {
|
|
|
50
50
|
*/
|
|
51
51
|
export async function checkJxsuiteUpdate(): Promise<JxsuiteUpdate[]> {
|
|
52
52
|
const platform = getPlatform();
|
|
53
|
-
if (!platform.
|
|
53
|
+
if (!platform.packageVersions) {
|
|
54
54
|
return [];
|
|
55
55
|
}
|
|
56
56
|
let reported;
|
|
57
57
|
try {
|
|
58
|
-
reported = await platform.
|
|
58
|
+
reported = await platform.packageVersions();
|
|
59
59
|
} catch {
|
|
60
60
|
return [];
|
|
61
61
|
}
|
|
62
62
|
const outdated: JxsuiteUpdate[] = [];
|
|
63
63
|
for (const p of reported) {
|
|
64
64
|
/*
|
|
65
|
-
* `isUpgrade`, not merely "differs from latest". `
|
|
66
|
-
*
|
|
67
|
-
* the publish landed — would otherwise be
|
|
65
|
+
* `isUpgrade`, not merely "differs from latest". `packageVersions` reports the registry's answer
|
|
66
|
+
* for every dependency, current ones included, and a project deliberately pinned AHEAD of the
|
|
67
|
+
* registry — a prerelease, or a range bumped before the publish landed — would otherwise be
|
|
68
|
+
* offered a downgrade described as an update.
|
|
68
69
|
*/
|
|
69
70
|
if (p.name.startsWith(JXSUITE_PREFIX) && isUpgrade(p.current, p.latest)) {
|
|
70
71
|
outdated.push({ current: p.current, dev: Boolean(p.dev), latest: p.latest, name: p.name });
|
|
@@ -146,11 +147,10 @@ export async function maybePromptJxsuiteUpdate(projectRoot: string): Promise<voi
|
|
|
146
147
|
// That is not hypothetical: it put this dialog into the middle of 33 committed screenshots,
|
|
147
148
|
// Including docs/images/hero.png, which is the jxsuite.com marketing hero.
|
|
148
149
|
//
|
|
149
|
-
// Correct pins are NOT sufficient on their own.
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
// Next patch release of any @jxsuite package.
|
|
150
|
+
// Correct pins are NOT sufficient on their own. This compares the range's BASE version against
|
|
151
|
+
// The registry's `latest`, not whether the range resolves it — so a project pinned `^1.4.1` is
|
|
152
|
+
// Behind the moment 1.4.2 publishes, and every starter shot would be scrimmed again by the next
|
|
153
|
+
// Patch release of any @jxsuite package.
|
|
154
154
|
if (shouldInstallAutomation(location.search)) {
|
|
155
155
|
return;
|
|
156
156
|
}
|
package/src/page-params.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* matching built page.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { documentUrlPattern as routePattern } from "@jxsuite/site/routes";
|
|
13
14
|
import { getPlatform } from "./platform";
|
|
14
15
|
import { loadExtensions } from "./format/format-host";
|
|
15
16
|
import type { JxMutableNode, JxPathsDef } from "@jxsuite/schema/types";
|
|
@@ -17,54 +18,17 @@ import type { JxMutableNode, JxPathsDef } from "@jxsuite/schema/types";
|
|
|
17
18
|
/** Param name → candidate values, in `$paths` declaration order. */
|
|
18
19
|
export type ParamValues = Record<string, string[]>;
|
|
19
20
|
|
|
20
|
-
/** Bracket route segments: `[param]` (named) and `[...param]` (catch-all). */
|
|
21
|
-
const PARAM_SEGMENT = /\[\.\.\.(\w+)\]|\[(\w+)\]/g;
|
|
22
|
-
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* Route derivation is `@jxsuite/site/routes`, re-exported so this module stays the studio's one
|
|
23
|
+
* import for everything `$params`.
|
|
26
24
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* These two used to be written out here, under a docblock admitting they mirrored the compiler's
|
|
26
|
+
* `fileToRoute`. A mirror is a copy that nothing checks, and a route is the worst place to keep
|
|
27
|
+
* one: a disagreement is a page that renders on the canvas and 404s in a browser. The studio cannot
|
|
28
|
+
* import `@jxsuite/compiler` (its graph carries `sharp` and `esbuild`, and this bundles for a
|
|
29
|
+
* browser), so the rules moved down to the package both CAN import.
|
|
29
30
|
*/
|
|
30
|
-
export
|
|
31
|
-
if (!documentPath) {
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
const params: string[] = [];
|
|
35
|
-
for (const match of documentPath.matchAll(PARAM_SEGMENT)) {
|
|
36
|
-
params.push((match[1] ?? match[2])!);
|
|
37
|
-
}
|
|
38
|
-
return params;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* URL pattern for a page document path, mirroring the compiler's `fileToRoute`:
|
|
43
|
-
* `pages/products/[sku].json` → `/products/:sku`, `pages/index.json` → `/`.
|
|
44
|
-
*
|
|
45
|
-
* @param {string | null | undefined} documentPath
|
|
46
|
-
* @returns {string}
|
|
47
|
-
*/
|
|
48
|
-
export function documentUrlPattern(documentPath: string | null | undefined) {
|
|
49
|
-
if (!documentPath) {
|
|
50
|
-
return "/";
|
|
51
|
-
}
|
|
52
|
-
let urlPath = documentPath
|
|
53
|
-
.replace(/^\.\//, "")
|
|
54
|
-
.replace(/^pages\//, "")
|
|
55
|
-
.replace(/\.[^/.]+$/, "");
|
|
56
|
-
if (urlPath.endsWith("/index")) {
|
|
57
|
-
urlPath = urlPath.slice(0, -6) || "/";
|
|
58
|
-
} else if (urlPath === "index") {
|
|
59
|
-
urlPath = "/";
|
|
60
|
-
}
|
|
61
|
-
if (!urlPath.startsWith("/")) {
|
|
62
|
-
urlPath = `/${urlPath}`;
|
|
63
|
-
}
|
|
64
|
-
return urlPath.replaceAll(PARAM_SEGMENT, (_match, spread: string, named: string) =>
|
|
65
|
-
spread ? "*" : `:${named}`,
|
|
66
|
-
);
|
|
67
|
-
}
|
|
31
|
+
export { documentUrlPattern, dynamicRouteParams } from "@jxsuite/site/routes";
|
|
68
32
|
|
|
69
33
|
/**
|
|
70
34
|
* The `$paths` declaration of an open document. JSON pages carry it on the document root;
|
|
@@ -289,7 +253,7 @@ export function substitutePreviewParams(
|
|
|
289
253
|
doc.state.$page = {
|
|
290
254
|
params: { ...params },
|
|
291
255
|
title: typeof doc.title === "string" ? doc.title : "",
|
|
292
|
-
url:
|
|
256
|
+
url: routePattern(documentPath),
|
|
293
257
|
};
|
|
294
258
|
return doc;
|
|
295
259
|
}
|
|
@@ -30,6 +30,12 @@ import type { PanelRecord } from "./panel-registry";
|
|
|
30
30
|
import type { CommandContext } from "../commands/context";
|
|
31
31
|
import type { EffectScope } from "@vue/reactivity";
|
|
32
32
|
import { activeRegistry } from "../commands/active-registry";
|
|
33
|
+
import {
|
|
34
|
+
dismissSettingsMenu,
|
|
35
|
+
isSettingsMenuOpen,
|
|
36
|
+
openSettingsMenu,
|
|
37
|
+
SETTINGS_MENU_PLACEMENT,
|
|
38
|
+
} from "./settings-menu";
|
|
33
39
|
import type { TemplateResult } from "lit-html";
|
|
34
40
|
|
|
35
41
|
let _scope: EffectScope | null = null;
|
|
@@ -55,6 +61,9 @@ export function mount() {
|
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
export function unmount() {
|
|
64
|
+
// Before the scope stops: an unmounted rail must not leave the menu's document-level capture
|
|
65
|
+
// Keydown listener behind, answering for a gear that is no longer on screen.
|
|
66
|
+
dismissSettingsMenu();
|
|
58
67
|
_scope?.stop();
|
|
59
68
|
_scope = null;
|
|
60
69
|
}
|
|
@@ -168,36 +177,56 @@ function railButton(panel: PanelRecord, ctx: CommandContext): TemplateResult {
|
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
/**
|
|
171
|
-
* The rail foot:
|
|
180
|
+
* The rail foot: the ⚙ **Settings** menu.
|
|
172
181
|
*
|
|
173
182
|
* It was two hand-authored buttons calling two module functions directly — the exact shape §2
|
|
174
|
-
* principle 1 bans
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* reachable by name.
|
|
183
|
+
* principle 1 bans — and then, for a release, one button that ran `app.preferences` and nothing
|
|
184
|
+
* else. That was the right shape for a pinned SLOT: a slot holds one thing, so it held the
|
|
185
|
+
* application's settings, and project configuration went to the ⬢ menu and the palette because a
|
|
186
|
+
* slot at application level could not honestly offer it.
|
|
179
187
|
*
|
|
180
|
-
*
|
|
188
|
+
* **This reverses that, and the reason it is not a regression is that the gear is no longer a
|
|
189
|
+
* slot.** A menu may host two levels — `commandbar/overflow` has admitted application, project and
|
|
190
|
+
* document since the matrix was written — because a menu prints each row's own name, chord and gate
|
|
191
|
+
* beside it, so nothing about a row's level has to be inferred from where the control sits. The
|
|
192
|
+
* levels are still separated: `settings/menu` is a matrix row admitting exactly application and
|
|
193
|
+
* project, and the menu draws a divider where the level changes. Its one-click meaning is gone
|
|
194
|
+
* deliberately: ⌘, still opens Preferences from anywhere, and the menu's first row prints that
|
|
195
|
+
* chord.
|
|
196
|
+
*
|
|
197
|
+
* Rendered FROM the placement, so a record joins the gear by declaring `settings/menu` and there is
|
|
198
|
+
* nothing here to update in step. With no project open the two project rows hide themselves and the
|
|
199
|
+
* menu is Preferences alone — which is the correct answer on the welcome screen, and the reason the
|
|
200
|
+
* button's own visibility asks the placement rather than one id.
|
|
181
201
|
*/
|
|
182
202
|
function railFooterTpl(): TemplateResult {
|
|
183
203
|
const registry = activeRegistry();
|
|
184
|
-
|
|
185
|
-
if (!registry || !command || !registry.isVisible("app.preferences")) {
|
|
204
|
+
if (!registry || registry.forPlacement(SETTINGS_MENU_PLACEMENT).length === 0) {
|
|
186
205
|
return html`${nothing}`;
|
|
187
206
|
}
|
|
188
|
-
const
|
|
207
|
+
const open = isSettingsMenuOpen();
|
|
189
208
|
return html`
|
|
190
209
|
<button
|
|
191
210
|
type="button"
|
|
192
|
-
class="rail-item"
|
|
193
|
-
data-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
211
|
+
class="rail-item${open ? " rail-item--menu-open" : ""}"
|
|
212
|
+
data-rail-menu="settings"
|
|
213
|
+
aria-haspopup="menu"
|
|
214
|
+
aria-expanded=${open ? "true" : "false"}
|
|
215
|
+
title="Settings"
|
|
216
|
+
@click=${(event: MouseEvent) => {
|
|
217
|
+
openSettingsMenu(event.currentTarget as HTMLElement, { rerender: renderActivityBar });
|
|
218
|
+
}}
|
|
219
|
+
@keydown=${(event: KeyboardEvent) => {
|
|
220
|
+
// The menu-button convention: either arrow opens, and the menu takes the keyboard from
|
|
221
|
+
// There. Enter and Space are the button's own activation and already reach `@click`.
|
|
222
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
223
|
+
event.preventDefault();
|
|
224
|
+
openSettingsMenu(event.currentTarget as HTMLElement, { rerender: renderActivityBar });
|
|
225
|
+
}
|
|
197
226
|
}}
|
|
198
227
|
>
|
|
199
228
|
<span class="rail-icon"><sp-icon-settings size="m"></sp-icon-settings></span>
|
|
200
|
-
<span class="rail-label">
|
|
229
|
+
<span class="rail-label">Settings</span>
|
|
201
230
|
</button>
|
|
202
231
|
`;
|
|
203
232
|
}
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
export const ATTACHED_CONTEXT_DELIMITER = "---- attached context ----";
|
|
16
16
|
|
|
17
17
|
export interface ContextChip {
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* `"import"` is not attachable from the composer's menu — it is stamped by the New Project Import
|
|
20
|
+
* hand-off, which needs the same channel for a different reason: the run's parameters must reach
|
|
21
|
+
* the model, and message content is the only thing the streaming payload carries.
|
|
22
|
+
*/
|
|
23
|
+
kind: "page" | "selection" | "import";
|
|
19
24
|
/** Short chip label, e.g. the page path or `<h1>`. */
|
|
20
25
|
label: string;
|
|
21
26
|
/** The context line embedded into the message content. */
|