@jxsuite/studio 5.3.0 → 5.4.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/data/css-meta.json +28 -27
- package/dist/chunks/{cf-account-picker-nwnwdm6p.js → cf-account-picker-3f08rry6.js} +21 -18
- package/dist/chunks/{cf-settings-adg74qsk.js → cf-settings-m79r7p5y.js} +4 -4
- package/dist/chunks/{components-5y78e05d.js → components-xm826zjw.js} +3 -3
- package/dist/chunks/{content-source-4rzvmp0m.js → content-source-jt7rbcbc.js} +22 -22
- package/dist/chunks/{convert-to-repeater-jxsv62v7.js → convert-to-repeater-vg38bq99.js} +22 -22
- package/dist/chunks/{editor-3qhbg51x.js → editor-ddy019sn.js} +2 -2
- package/dist/chunks/entry-commands-64nb2a9a.js +42 -0
- package/dist/chunks/{extension-sections-2mrptyek.js → extension-sections-r73an5s6.js} +30 -29
- package/dist/chunks/{file-ops-knfqshrm.js → file-ops-3xan8mnj.js} +21 -21
- package/dist/chunks/{files-y6fr4he9.js → files-egsb0ry8.js} +28 -28
- package/dist/chunks/{format-host-1k4qrcqd.js → format-host-mym8qnd0.js} +3 -3
- package/dist/chunks/{fs-events-3y6y0nrm.js → fs-events-z2gg8qjt.js} +4 -4
- package/dist/chunks/{git-panel-2rkrsjva.js → git-panel-a05atk6q.js} +20 -20
- package/dist/chunks/{grid-view-1p6hsyjx.css → grid-view-3g1h2re8.css} +956 -139
- package/dist/chunks/{grid-view-a7b87n2c.js → grid-view-qaqer9kr.js} +24 -24
- package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
- package/dist/chunks/{iframe-host-scpw01h8.js → iframe-host-psetcv20.js} +11 -11
- package/dist/chunks/{index-n4j7qxyr.js → index-9yjae3hz.js} +4 -4
- package/dist/chunks/{javascript-4abzjcy9.css → javascript-bc9z461d.css} +688 -54
- package/dist/chunks/{javascript-xvrfrpkb.js → javascript-hr5sg57n.js} +2 -2
- package/dist/chunks/{jsonMode-vvmpmk34.css → jsonMode-qqd9nm1t.css} +1120 -303
- package/dist/chunks/{jsonMode-tyx2kj6p.js → jsonMode-zs88v0wr.js} +4 -4
- package/dist/chunks/layers-panel-83a16ytx.js +41 -0
- package/dist/chunks/{layers-jnvdbqva.js → layers-s6mc01ry.js} +3 -3
- package/dist/chunks/{media-picker-f66nav16.js → media-picker-nhn6rv4w.js} +11 -11
- package/dist/chunks/{menu-1dfhry4s.js → menu-8j4qxjrp.js} +4 -4
- package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
- package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
- package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
- package/dist/chunks/{monaco-setup-km6abc6q.js → monaco-setup-gsjdysze.js} +6 -6
- package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
- package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
- package/dist/chunks/quick-search-c63mkt3b.js +47 -0
- package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
- package/dist/chunks/right-panel-t5n8wttg.js +45 -0
- package/dist/chunks/{studio-ze46gzjh.js → studio-01269reb.js} +7 -7
- package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
- package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
- package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
- package/dist/chunks/{studio-d1n2bykn.js → studio-3nprwbd9.js} +117 -25
- package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
- package/dist/chunks/{studio-151w0xnh.js → studio-482eeazk.js} +20 -20
- package/dist/chunks/{studio-cgprcdxn.js → studio-4998spet.js} +10 -9
- package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
- package/dist/chunks/{studio-rtskkm43.js → studio-5w26wza5.js} +3 -3
- package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
- package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
- package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
- package/dist/chunks/{studio-6gryj0sg.js → studio-9vsvz7w7.js} +6 -6
- package/dist/chunks/{studio-50wfwy44.js → studio-9wm0xzpf.js} +19 -19
- package/dist/chunks/{studio-0j7r7s9g.js → studio-ag3z6shb.js} +10 -4
- package/dist/chunks/studio-aj9drheq.js +177 -0
- package/dist/chunks/{studio-xajk70w0.js → studio-apv9x70c.js} +189 -130
- package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
- package/dist/chunks/{studio-nfx354t1.js → studio-bh47w0cy.js} +9 -10
- package/dist/chunks/{studio-gk2twyh4.js → studio-dgdm6vvt.js} +264 -52
- package/dist/chunks/{studio-gtfq1dkz.js → studio-dwdcr2e8.js} +4 -4
- package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
- package/dist/chunks/{studio-27q131j3.js → studio-fqpkpq1t.js} +7 -4
- package/dist/chunks/{studio-c0qgc3tn.js → studio-fy320dfc.js} +62 -68
- package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
- package/dist/chunks/{studio-g33v4fe9.js → studio-jfhxy8h3.js} +7 -7
- package/dist/chunks/{studio-ab87phj1.js → studio-kwewmhhq.js} +4 -4
- package/dist/chunks/{studio-7rrb1esn.js → studio-m58xn8at.js} +25 -24
- package/dist/chunks/{studio-fzjx96t2.js → studio-mfkh1q8d.js} +17 -17
- package/dist/chunks/{studio-drg8qj9k.js → studio-mrh0a92f.js} +17 -17
- package/dist/chunks/{studio-jt27ta6x.js → studio-mt79tn56.js} +3 -3
- package/dist/chunks/{studio-b66rsh78.js → studio-ne593z1j.js} +38 -31
- package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
- package/dist/chunks/{studio-dd1qqkry.js → studio-qxye31h7.js} +7 -7
- package/dist/chunks/{studio-ye9drbk8.js → studio-rav5bpmp.js} +73 -52
- package/dist/chunks/{studio-6kvgrkrp.js → studio-rwmmbrth.js} +6 -6
- package/dist/chunks/{studio-b7xacrwe.js → studio-sceg8ws0.js} +8 -8
- package/dist/chunks/{studio-msc1ee1m.js → studio-sjas5b3a.js} +19 -13
- package/dist/chunks/{studio-a65w20ex.js → studio-vd67b66d.js} +3 -3
- package/dist/chunks/{studio-7144epdr.js → studio-w475cbf9.js} +10 -10
- package/dist/chunks/{studio-4f3psrk1.js → studio-w7gpcvfj.js} +9 -9
- package/dist/chunks/{studio-nsgw7dbk.js → studio-xrbfdxgk.js} +7 -7
- package/dist/chunks/{studio-ke09tn9k.js → studio-y49b6mjv.js} +35 -35
- package/dist/chunks/{studio-j0w60gft.js → studio-ygvr9e4q.js} +10 -10
- package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
- package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
- package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
- package/dist/chunks/{workspace-np10mayv.js → workspace-b9k2frks.js} +5 -5
- package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
- package/dist/codicon.ttf +0 -0
- package/dist/iframe-entry.js +18 -16
- package/dist/studio.css +956 -139
- package/dist/studio.js +1453 -830
- package/dist/workers/editor.worker.js +196 -107
- package/dist/workers/json.worker.js +196 -107
- package/dist/workers/ts.worker.js +196 -107
- package/package.json +15 -14
- package/src/about/about-modal.ts +4 -3
- package/src/browse/library-commands.ts +15 -13
- package/src/browse/library-pane.ts +2 -2
- package/src/canvas/canvas-render.ts +97 -83
- package/src/canvas/canvas-surface.ts +2 -2
- package/src/canvas/canvas-utils.ts +42 -32
- package/src/canvas/diff-toolbar.ts +21 -2
- package/src/canvas/diff-view.ts +30 -6
- package/src/canvas/iframe-entry.ts +2 -2
- package/src/canvas/iframe-host.ts +5 -5
- package/src/canvas/iframe-interaction.ts +7 -6
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-protocol.ts +6 -5
- package/src/canvas/iframe-render.ts +3 -3
- package/src/canvas/popover-state.ts +1 -1
- package/src/canvas/stage-scrollbar.ts +112 -0
- package/src/canvas/surface-registry.ts +9 -2
- package/src/collab/collab-commands.ts +8 -6
- package/src/collab/collab-session.ts +4 -4
- package/src/collab/collab-state.ts +4 -4
- package/src/collab/presence-chips.ts +3 -3
- package/src/commands/app-commands.ts +7 -7
- package/src/commands/budget.ts +17 -16
- package/src/commands/command-args.ts +10 -9
- package/src/commands/context.ts +20 -10
- package/src/commands/defaults.ts +30 -29
- package/src/commands/levels.ts +8 -6
- package/src/commands/live-context.ts +12 -10
- package/src/commands/reference.ts +5 -5
- package/src/commands/registry.ts +2 -2
- package/src/content/draft-state.ts +9 -8
- package/src/content/entry-commands.ts +16 -14
- package/src/content/entry-editor.ts +2 -2
- package/src/content/entry-fields.ts +1 -1
- package/src/editor/context-menu.ts +4 -4
- package/src/editor/convert-to-component.ts +6 -5
- package/src/editor/inline-edit.ts +3 -3
- package/src/editor/shortcuts.ts +88 -20
- package/src/editor/slash-menu.ts +11 -10
- package/src/files/elements.ts +4 -5
- package/src/files/file-ops.ts +1 -1
- package/src/files/files.ts +21 -17
- package/src/files/serialize-document.ts +1 -1
- package/src/format/convert-file.ts +5 -5
- package/src/github/github-auth-status.ts +107 -0
- package/src/github/github-auth.ts +18 -82
- package/src/github/github-publish.ts +7 -6
- package/src/grid/cell-editors.ts +8 -7
- package/src/grid/grid-layout.ts +1 -1
- package/src/grid/grid-open.ts +6 -5
- package/src/grid/grid-panel.ts +13 -12
- package/src/grid/redirects-grid.ts +14 -11
- package/src/grid/redirects.ts +10 -5
- package/src/grid/sources/content-source.ts +10 -9
- package/src/hosting/document.ts +28 -1
- package/src/hosting/stage.ts +15 -4
- package/src/i18n/i18n-commands.ts +9 -7
- package/src/new-project/location-fields.ts +16 -3
- package/src/new-project/new-project-modal.ts +23 -7
- package/src/page-params.ts +6 -6
- package/src/panels/activity-panel.ts +11 -10
- package/src/panels/ai-chat/chat-view.ts +27 -14
- package/src/panels/ai-chat/composer.ts +10 -3
- package/src/panels/ai-panel.ts +87 -29
- package/src/panels/block-action-bar.ts +59 -33
- package/src/panels/bottom-dock.ts +22 -22
- package/src/panels/data-explorer.ts +9 -9
- package/src/panels/data-grid.ts +1 -1
- package/src/panels/editors.ts +8 -8
- package/src/panels/elements-panel.ts +7 -8
- package/src/panels/empty-state.ts +1 -1
- package/src/panels/events-panel.ts +13 -12
- package/src/panels/formula-workspace.ts +8 -5
- package/src/panels/frontmatter-fields.ts +4 -1
- package/src/panels/frontmatter-panel.ts +18 -18
- package/src/panels/git-panel.ts +19 -13
- package/src/panels/head-panel.ts +9 -10
- package/src/panels/i18n-panel.ts +6 -4
- package/src/panels/imports-panel.ts +1 -1
- package/src/panels/jump-bar.ts +20 -18
- package/src/panels/layers-panel.ts +19 -17
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/navigator-panels.ts +8 -8
- package/src/panels/overlays.ts +1 -1
- package/src/panels/pane-context.ts +56 -28
- package/src/panels/pane-grid.ts +9 -8
- package/src/panels/panel-registry.ts +47 -19
- package/src/panels/problems-panel.ts +11 -12
- package/src/panels/properties-panel.ts +21 -20
- package/src/panels/provenance.ts +3 -3
- package/src/panels/quick-search.ts +15 -11
- package/src/panels/right-panel.ts +4 -3
- package/src/panels/seo-modal.ts +5 -4
- package/src/panels/settings-menu.ts +9 -9
- package/src/panels/settings-pane.ts +3 -3
- package/src/panels/signals-panel.ts +16 -9
- package/src/panels/statement-editor.ts +12 -9
- package/src/panels/style-panel.ts +45 -41
- package/src/panels/stylebook-panel.ts +0 -1
- package/src/panels/tab-strip.ts +26 -23
- package/src/platform-errors.ts +2 -2
- package/src/platform.ts +44 -4
- package/src/platforms/cloud.ts +11 -1
- package/src/platforms/default-platform.ts +141 -4
- package/src/platforms/devserver.ts +23 -3
- package/src/publish/deploy-checklist.ts +11 -10
- package/src/publish/publish-commands.ts +9 -8
- package/src/services/a11y-report.ts +1 -1
- package/src/services/ai-ask.ts +39 -16
- package/src/services/ai-command-tools.ts +28 -14
- package/src/services/ai-import-tools.ts +43 -29
- package/src/services/ai-project-tools.ts +20 -38
- package/src/services/ai-settings.ts +55 -2
- package/src/services/ai-tools.ts +69 -58
- package/src/services/ai-write-report.ts +4 -4
- package/src/services/ai-writes.ts +74 -55
- package/src/services/automation.ts +12 -12
- package/src/services/clock.ts +2 -1
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +69 -6
- package/src/services/directory-picker.ts +93 -27
- package/src/services/document-assistant.ts +86 -17
- package/src/services/gated-registry.ts +4 -3
- package/src/services/idle.ts +5 -4
- package/src/services/live-surfaces.ts +2 -1
- package/src/services/notify.ts +9 -7
- package/src/services/popover-report.ts +3 -3
- package/src/services/preview-eval.ts +1 -1
- package/src/services/project-adoption.ts +34 -1
- package/src/services/project-path.ts +53 -0
- package/src/services/settings/kernel.ts +13 -2
- package/src/services/tool-executor.ts +135 -30
- package/src/services/tool-outcomes.ts +143 -0
- package/src/settings/contexts-section.ts +8 -8
- package/src/settings/contributed-section.ts +6 -6
- package/src/settings/css-vars-editor.ts +6 -5
- package/src/settings/extension-commands.ts +19 -18
- package/src/settings/extension-sections.ts +7 -7
- package/src/settings/extensions-section.ts +3 -3
- package/src/settings/general-settings.ts +21 -18
- package/src/settings/preferences-accounts.ts +3 -3
- package/src/settings/preferences-dialog.ts +9 -8
- package/src/settings/preferences-sections.ts +1 -1
- package/src/settings/project-sections.ts +2 -2
- package/src/settings/section-registry.ts +7 -6
- package/src/settings/settings-document.ts +41 -43
- package/src/shell/tree.ts +29 -0
- package/src/shell.ts +63 -55
- package/src/site-context.ts +1 -1
- package/src/store.ts +2 -2
- package/src/studio.ts +46 -28
- package/src/style/live-preview.ts +8 -8
- package/src/style/project-styles.ts +8 -9
- package/src/style/token-ref.ts +2 -2
- package/src/surfaces/about.json +6 -2
- package/src/surfaces/add-repo.json +2 -2
- package/src/surfaces/add-repo.ts +2 -2
- package/src/surfaces/ai-chat.json +14 -6
- package/src/surfaces/ai-chat.ts +4 -2
- package/src/surfaces/ai-credentials-form.json +53 -49
- package/src/surfaces/ai-credentials-form.ts +18 -4
- package/src/surfaces/ai-managed-connect.json +4 -4
- package/src/surfaces/block-action-bar.json +4 -4
- package/src/surfaces/block-action-bar.ts +3 -3
- package/src/surfaces/boot-failure.json +228 -0
- package/src/surfaces/boot-failure.ts +156 -0
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +9 -40
- package/src/surfaces/canvas-stage.ts +9 -9
- package/src/surfaces/cf-account-picker.json +11 -8
- package/src/surfaces/commandbar.ts +11 -10
- package/src/surfaces/convert-repeater.ts +3 -2
- package/src/surfaces/dialog.json +7 -1
- package/src/surfaces/dialog.ts +2 -2
- package/src/surfaces/doc-header.json +6 -13
- package/src/surfaces/doc-header.ts +4 -5
- package/src/surfaces/entry-editor.json +1 -1
- package/src/surfaces/entry-editor.ts +2 -1
- package/src/surfaces/expression-editor.json +5 -5
- package/src/surfaces/files-panel.json +4 -3
- package/src/surfaces/files-panel.ts +1 -1
- package/src/surfaces/formula-palette.json +2 -2
- package/src/surfaces/formula-palette.ts +1 -1
- package/src/surfaces/git-panel.json +167 -109
- package/src/surfaces/git-panel.ts +2 -2
- package/src/surfaces/github-auth.json +2 -1
- package/src/surfaces/github-publish.ts +3 -3
- package/src/surfaces/grid-open.json +1 -1
- package/src/surfaces/grid-panel.json +2 -2
- package/src/surfaces/grid-views.json +1 -1
- package/src/surfaces/inspector-dock.json +2 -2
- package/src/surfaces/jump-bar.json +1 -1
- package/src/surfaces/jump-bar.ts +1 -1
- package/src/surfaces/library-pane.ts +2 -1
- package/src/surfaces/logic-panel.json +7 -7
- package/src/surfaces/logic-panel.ts +6 -4
- package/src/surfaces/logic-workspace.json +2 -2
- package/src/surfaces/logic-workspace.ts +2 -2
- package/src/surfaces/media-browser.ts +3 -3
- package/src/surfaces/media-pane.ts +2 -1
- package/src/surfaces/menu.ts +5 -5
- package/src/surfaces/new-project.json +1 -1
- package/src/surfaces/pane-context.json +86 -57
- package/src/surfaces/pane-context.ts +2 -1
- package/src/surfaces/pane-grid.json +3 -3
- package/src/surfaces/panel-activity.json +2 -1
- package/src/surfaces/panel-deploy-checklist.json +1 -1
- package/src/surfaces/panel-elements.ts +2 -1
- package/src/surfaces/panel-i18n.ts +2 -1
- package/src/surfaces/panel-outline.json +1 -1
- package/src/surfaces/panel-outline.ts +4 -3
- package/src/surfaces/panel-page.json +2 -2
- package/src/surfaces/panel-page.ts +4 -1
- package/src/surfaces/panel-problems.json +4 -3
- package/src/surfaces/panel-problems.ts +2 -2
- package/src/surfaces/panel-signals.json +23 -8
- package/src/surfaces/panel-signals.ts +5 -1
- package/src/surfaces/panel-stylebook-layers.json +1 -1
- package/src/surfaces/panel-stylebook-layers.ts +2 -2
- package/src/surfaces/preferences.json +21 -8
- package/src/surfaces/preferences.ts +9 -1
- package/src/surfaces/properties-panel.json +4 -4
- package/src/surfaces/properties-panel.ts +2 -2
- package/src/surfaces/publish.json +1 -1
- package/src/surfaces/publish.ts +2 -1
- package/src/surfaces/push-plan.json +4 -3
- package/src/surfaces/rail.json +2 -2
- package/src/surfaces/rail.ts +10 -4
- package/src/surfaces/reference-field.json +1 -1
- package/src/surfaces/schema-form.json +2 -2
- package/src/surfaces/schema-form.ts +1 -1
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +2 -2
- package/src/surfaces/settings-contributed.ts +2 -1
- package/src/surfaces/settings-css-vars.json +4 -4
- package/src/surfaces/settings-deploy.json +4 -4
- package/src/surfaces/settings-deploy.ts +2 -1
- package/src/surfaces/settings-extensions.json +6 -6
- package/src/surfaces/settings-extensions.ts +6 -2
- package/src/surfaces/settings-locales.json +4 -4
- package/src/surfaces/settings-overview.ts +2 -1
- package/src/surfaces/settings-pane.ts +3 -2
- package/src/surfaces/settings-rawjson.ts +1 -1
- package/src/surfaces/slash-menu.ts +4 -4
- package/src/surfaces/statements.json +3 -3
- package/src/surfaces/statusbar.ts +23 -23
- package/src/surfaces/style-panel.json +9 -5
- package/src/surfaces/style-panel.ts +3 -3
- package/src/surfaces/tab-strip.json +2 -2
- package/src/surfaces/target-line.json +1 -1
- package/src/surfaces/target-line.ts +12 -10
- package/src/surfaces/welcome.json +7 -2
- package/src/tabs/doc-op-apply.ts +5 -5
- package/src/tabs/patch-ops.ts +3 -3
- package/src/tabs/project-config.ts +10 -10
- package/src/tabs/selection.ts +1 -1
- package/src/tabs/tab.ts +13 -14
- package/src/tabs/transact.ts +18 -24
- package/src/types.ts +27 -3
- package/src/ui/ai-credentials-form.ts +74 -16
- package/src/ui/ai-managed-connect.ts +68 -19
- package/src/ui/color-selector.ts +1 -1
- package/src/ui/expression-editor.ts +3 -3
- package/src/ui/form-controls.ts +6 -5
- package/src/ui/formula-catalog.ts +4 -4
- package/src/ui/formula-chips.ts +2 -2
- package/src/ui/layers.ts +20 -18
- package/src/ui/panel-resize.ts +5 -5
- package/src/ui/popover-surface.ts +2 -2
- package/src/ui/progress-modal.ts +3 -3
- package/src/ui/regions.ts +14 -9
- package/src/ui/schema-form.ts +10 -9
- package/src/ui/timing.ts +9 -7
- package/src/ui/value-source.ts +4 -4
- package/src/ui/virtual-window.ts +1 -1
- package/src/utils/base64.ts +20 -1
- package/src/utils/canvas-media.ts +1 -1
- package/src/utils/studio-utils.ts +0 -31
- package/src/view.ts +4 -3
- package/src/workspace/pane-derive.ts +14 -13
- package/src/workspace/session.ts +7 -6
- package/src/workspace/workspace.ts +49 -39
- package/styles/canvas.css +1 -27
- package/styles/inspector.css +4 -3
- package/styles/overlays.css +1 -1
- package/styles/tokens.css +17 -1
- package/styles/tokens.json +6 -1
- package/dist/chunks/entry-commands-1wnsqn5d.js +0 -42
- package/dist/chunks/layers-panel-73gfkcga.js +0 -41
- package/dist/chunks/publish-panel-z1zd2da1.js +0 -27
- package/dist/chunks/quick-search-zdv7h8ht.js +0 -47
- package/dist/chunks/right-panel-889vbnm5.js +0 -45
- package/dist/chunks/studio-727xh0e3.js +0 -76
- package/src/files/json-layout.ts +0 -474
- package/src/services/ai-turn-signal.ts +0 -70
|
@@ -46,6 +46,13 @@
|
|
|
46
46
|
* on the desktop it is in the launcher's `0600` credential store and this module holds it only in
|
|
47
47
|
* memory for the session. `settings/preferences-accounts.ts` lists it as _stored or not_ and is the
|
|
48
48
|
* only place it can be revoked (`studio.md` §15 rule 1).
|
|
49
|
+
*
|
|
50
|
+
* The credential STATE (whether one exists, where, how to clear it) lives in
|
|
51
|
+
* `github-auth-status.ts` and is re-exported here. This module keeps only the sign-in FLOW, which
|
|
52
|
+
* is the half that needs `notify` and the device-flow dialog surface — a launcher's PAL-init bundle
|
|
53
|
+
* wants the state without ever wanting the flow, and importing this whole file for
|
|
54
|
+
* `hydrateGithubToken` alone used to cost it a second copy of Lit's runtime
|
|
55
|
+
* (`github-auth-status.ts`'s own header has the full account).
|
|
49
56
|
*/
|
|
50
57
|
|
|
51
58
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
@@ -53,74 +60,18 @@ import { notify } from "../services/notify";
|
|
|
53
60
|
import { layerHost } from "../ui/layers";
|
|
54
61
|
import { openGithubAuthSurface } from "../surfaces/github-auth";
|
|
55
62
|
import type { GithubAuthSurfaceHandle } from "../surfaces/github-auth";
|
|
63
|
+
import { getGithubToken, nativeAuth, setNativeToken, STORAGE_KEY } from "./github-auth-status";
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
interface NativeGithubAuth {
|
|
67
|
-
signIn: (force?: boolean) => Promise<{ token: string }>;
|
|
68
|
-
signOut: () => Promise<{ ok: boolean }>;
|
|
69
|
-
status: () => Promise<{ stored: boolean }>;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function nativeAuth(): NativeGithubAuth | null {
|
|
73
|
-
return (
|
|
74
|
-
(globalThis as unknown as { __jxPlatform?: { githubAuth?: NativeGithubAuth } }).__jxPlatform
|
|
75
|
-
?.githubAuth ?? null
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The token the desktop store handed us this session.
|
|
81
|
-
*
|
|
82
|
-
* On the desktop the token at rest is a `0600` file in the user's config directory, **not**
|
|
83
|
-
* `localStorage` — so it is not readable by script in the webview between sessions, and it does not
|
|
84
|
-
* survive in a place a stray extension or a copied profile can reach. Holding it in a module
|
|
85
|
-
* variable is what keeps {@link getGithubToken} synchronous for its callers.
|
|
86
|
-
*/
|
|
87
|
-
let nativeToken: string | null = null;
|
|
88
|
-
|
|
89
|
-
/** Whether the desktop store holds a token, as of the last time it was asked. */
|
|
90
|
-
let nativeStored = false;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Record that the desktop's credential store does (or does not) hold a token.
|
|
94
|
-
*
|
|
95
|
-
* The launcher calls this once at startup. It carries a **boolean, not the token**: the accounts
|
|
96
|
-
* pane only needs to know whether one exists, and handing the webview a credential it has not been
|
|
97
|
-
* asked to use is the exposure the 0600 store exists to remove. When a sign-in does happen the
|
|
98
|
-
* token arrives through {@link authenticateGithub} and lives in memory for that session.
|
|
99
|
-
*
|
|
100
|
-
* @param {boolean} stored
|
|
101
|
-
*/
|
|
102
|
-
export function hydrateGithubToken(stored: boolean): void {
|
|
103
|
-
nativeStored = stored;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Whether a GitHub credential exists, wherever it lives.
|
|
108
|
-
*
|
|
109
|
-
* Separate from {@link getGithubToken} because the two questions genuinely differ on the desktop: a
|
|
110
|
-
* token can be stored on disk and not yet in this session's memory, and the accounts pane asks
|
|
111
|
-
* "signed in?" while rendering — synchronously — where an API caller asks for the credential itself
|
|
112
|
-
* and can await it.
|
|
113
|
-
*
|
|
114
|
-
* @returns {boolean}
|
|
115
|
-
*/
|
|
116
|
-
export function githubTokenStored(): boolean {
|
|
117
|
-
return nativeToken !== null || nativeStored || localStorage.getItem(STORAGE_KEY) !== null;
|
|
118
|
-
}
|
|
65
|
+
// Every other caller in Studio still reaches these through this module.
|
|
66
|
+
export {
|
|
67
|
+
clearGithubToken,
|
|
68
|
+
getGithubToken,
|
|
69
|
+
githubTokenLocation,
|
|
70
|
+
githubTokenStored,
|
|
71
|
+
hydrateGithubToken,
|
|
72
|
+
} from "./github-auth-status";
|
|
119
73
|
|
|
120
|
-
|
|
121
|
-
export function githubTokenLocation(): "desktop" | "browser" {
|
|
122
|
-
return nativeAuth() ? "desktop" : "browser";
|
|
123
|
-
}
|
|
74
|
+
const CLIENT_ID = "Ov23liYVlMFpgjOEPXJH";
|
|
124
75
|
|
|
125
76
|
/** One key for the whole sign-in, so a second attempt REPLACES the first report. */
|
|
126
77
|
const NOTIFY_KEY = "github.auth";
|
|
@@ -156,21 +107,6 @@ interface TokenResponse {
|
|
|
156
107
|
error?: string;
|
|
157
108
|
}
|
|
158
109
|
|
|
159
|
-
export function getGithubToken() {
|
|
160
|
-
return nativeToken ?? localStorage.getItem(STORAGE_KEY);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function clearGithubToken() {
|
|
164
|
-
nativeToken = null;
|
|
165
|
-
nativeStored = false;
|
|
166
|
-
localStorage.removeItem(STORAGE_KEY);
|
|
167
|
-
// Fire-and-forget: the accounts pane's revoke is synchronous, and a store that failed to forget
|
|
168
|
-
// The token is not something the user can act on from there.
|
|
169
|
-
void nativeAuth()
|
|
170
|
-
?.signOut()
|
|
171
|
-
.catch(() => {});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
110
|
/** The request never completed — a Problem, with the one sentence that covers both causes. */
|
|
175
111
|
function reportUnreachable(error: unknown): void {
|
|
176
112
|
notify.error("Could not reach GitHub to sign in.", {
|
|
@@ -241,7 +177,7 @@ export async function authenticateGithub() {
|
|
|
241
177
|
if (native) {
|
|
242
178
|
try {
|
|
243
179
|
const { token } = await native.signIn();
|
|
244
|
-
|
|
180
|
+
setNativeToken(token);
|
|
245
181
|
return token;
|
|
246
182
|
} catch (error) {
|
|
247
183
|
reportRefused("GitHub sign-in was not completed.", errorMessage(error));
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
* Create a GitHub repository for a local project, add it as `origin`, and push.
|
|
4
4
|
*
|
|
5
5
|
* **This is not publishing, and it used to say it was.** Two unrelated operations shared the verb
|
|
6
|
-
* (
|
|
7
|
-
* provider that then builds the site. A user who wanted the second and found the
|
|
8
|
-
* repository and no site, and a user who wanted the first read "Publish to
|
|
9
|
-
* expected a URL. The function, the dialog headline, the activity title and
|
|
10
|
-
* now all say _Create GitHub Repository_; `Publish:` belongs to
|
|
6
|
+
* (`docs/studio/publish.md`): this one creates a git repository, and `publish/publish-panel.ts`
|
|
7
|
+
* connects a hosting provider that then builds the site. A user who wanted the second and found the
|
|
8
|
+
* first got a GitHub repository and no site, and a user who wanted the first read "Publish to
|
|
9
|
+
* GitHub" and reasonably expected a URL. The function, the dialog headline, the activity title and
|
|
10
|
+
* the notification source now all say _Create GitHub Repository_; `Publish:` belongs to
|
|
11
|
+
* `publish/publish-commands.ts`.
|
|
11
12
|
*
|
|
12
13
|
* **It is an Activity, not three toasts.** Three `notify.info` lines sharing one key replaced each
|
|
13
14
|
* other in a corner while a multi-second, three-request, partially-committing operation ran with no
|
|
14
15
|
* log and no cancel — and its middle step (`gitAddRemote`) had no error path at all, so a remote
|
|
15
16
|
* that already existed failed the push with a message about pushing. `beginActivity` gives it the
|
|
16
17
|
* ordered steps, the captured log, and `fail()`, which raises the Problem the failure needs and
|
|
17
|
-
* carries the log as its detail (§
|
|
18
|
+
* carries the log as its detail (§16.4). The caller therefore never also notifies.
|
|
18
19
|
*
|
|
19
20
|
* **The dialog is a document.** `surfaces/github-publish.json` collects the name, the description
|
|
20
21
|
* and the visibility; this module keeps the token, the requests and the activity. What it used to
|
package/src/grid/cell-editors.ts
CHANGED
|
@@ -40,13 +40,14 @@
|
|
|
40
40
|
* registry keyed to nodes the engine has already thrown away — and would repaint asynchronously
|
|
41
41
|
* while the reader scrolls.
|
|
42
42
|
*
|
|
43
|
-
* So the boundary is the cell, and it is the same boundary §9.4 already
|
|
44
|
-
* engine is an island, and this file is the inside of it. The two kinds
|
|
45
|
-
* a cell escaped it by leaving the cell entirely, and that is the shape
|
|
46
|
-
* to take — a document ANCHORED at the cell, not mounted in it. What
|
|
47
|
-
* rest is a synchronous mount path in the runtime (a document rendered
|
|
48
|
-
* the kit already registered, no awaits), at which point 1 and 2 dissolve
|
|
49
|
-
* lifetime problem is left, which needs a teardown hook Tabulator does not
|
|
43
|
+
* So the boundary is the cell, and it is the same boundary studio-ui-guidelines.md §9.4 already
|
|
44
|
+
* draws around Tabulator: the engine is an island, and this file is the inside of it. The two kinds
|
|
45
|
+
* whose picker is bigger than a cell escaped it by leaving the cell entirely, and that is the shape
|
|
46
|
+
* any future conversion has to take — a document ANCHORED at the cell, not mounted in it. What
|
|
47
|
+
* would actually unblock the rest is a synchronous mount path in the runtime (a document rendered
|
|
48
|
+
* into a detached host with the kit already registered, no awaits), at which point 1 and 2 dissolve
|
|
49
|
+
* and only the formatter's lifetime problem is left, which needs a teardown hook Tabulator does not
|
|
50
|
+
* have.
|
|
50
51
|
*/
|
|
51
52
|
import { html, render } from "lit-html";
|
|
52
53
|
/* The two cell editors below are re-rendered while they are open — the pill editor calls its own
|
package/src/grid/grid-layout.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the grid shipped; a saved view is the same record with three more facets and a name, written to
|
|
6
6
|
* the same key. The alternative — a second `jx-grid-views:` store beside this one — is how a grid
|
|
7
7
|
* ends up with a column order that a view cannot capture and a view that a resize does not update,
|
|
8
|
-
* which is the class of bug
|
|
8
|
+
* which is the class of bug saved views (site-architecture.md §7.2) must avoid by construction.
|
|
9
9
|
*
|
|
10
10
|
* **The working layout is the truth; a view is a copy of it.** Every control writes the working
|
|
11
11
|
* layout (`saveGridLayout`), so a grid remembers how you left it whether or not you ever name a
|
package/src/grid/grid-open.ts
CHANGED
|
@@ -250,8 +250,8 @@ export async function openGridSourcePicker(): Promise<void> {
|
|
|
250
250
|
* `collection.editInGrid` used to be a press on the file tree's context-menu row, matched by the
|
|
251
251
|
* item's rendered label ("Edit Collection in Grid") through an XPath — so the shot that used it
|
|
252
252
|
* also had to open the menu first, and renaming the row broke both steps. Naming the COLLECTION
|
|
253
|
-
* instead of the control is what
|
|
254
|
-
* action, and only one of them is addressable.
|
|
253
|
+
* instead of the control is what the shot contract's R1 (`scripts/screenshots/README.md`) asks for:
|
|
254
|
+
* the menu row and the command are the same action, and only one of them is addressable.
|
|
255
255
|
*
|
|
256
256
|
* Both refuse a source the project does not declare. `data.openGrid` is additionally gated on the
|
|
257
257
|
* platform serving the data routes (`capability.dataRows`), so on a build without them the command
|
|
@@ -272,8 +272,8 @@ export function gridCommands(): AnyCommand[] {
|
|
|
272
272
|
group: "5_data",
|
|
273
273
|
requires: "a project that declares content collections",
|
|
274
274
|
when: (ctx) => ctx.project.open,
|
|
275
|
-
/* No `aiTool`, by §12.4's first deletion rule: this opens a surface
|
|
276
|
-
not a tool surface. */
|
|
275
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface
|
|
276
|
+
for a person; the grid is not a tool surface. */
|
|
277
277
|
run: (_commandCtx, args) => {
|
|
278
278
|
const name = stringArg("collection.editInGrid", args, "name");
|
|
279
279
|
const declared = collectionDirs().map((c) => c.name);
|
|
@@ -308,7 +308,8 @@ export function gridCommands(): AnyCommand[] {
|
|
|
308
308
|
requires: "a platform that serves the data routes",
|
|
309
309
|
when: (ctx) => ctx.project.open,
|
|
310
310
|
enablement: (ctx) => ctx.capability.dataRows,
|
|
311
|
-
/* No `aiTool`, by §12.4's first deletion rule: this opens a surface
|
|
311
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface
|
|
312
|
+
for a person. */
|
|
312
313
|
run: (_commandCtx, args) => {
|
|
313
314
|
const table = stringArg("data.openGrid", args, "table");
|
|
314
315
|
openConnectorGrid(optionalStringArg("data.openGrid", args, "connection"), table);
|
package/src/grid/grid-panel.ts
CHANGED
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
* palette, and the host node arriving all reach the surface through
|
|
25
25
|
* {@link ActiveGridPanel.bump}.
|
|
26
26
|
*
|
|
27
|
-
* **The panel owns the view state** (
|
|
28
|
-
* one store, the grid id as its key, so "per collection" needs no code —
|
|
29
|
-
* drives them onto the four surfaces they touch: the engine (column order,
|
|
30
|
-
* applied by a REBUILD, which is cheap because the data never leaves the
|
|
31
|
-
* controller (sort and grouping, which are row order and belong to the data), and
|
|
32
|
-
* filter box. Applying a view is therefore one function with one order of
|
|
33
|
-
* controls that each half-remember what the others did.
|
|
27
|
+
* **The panel owns the view state** (saved views, site-architecture.md §7.2). Saved views persist
|
|
28
|
+
* through `grid-layout.ts` — one store, the grid id as its key, so "per collection" needs no code —
|
|
29
|
+
* and this module is what drives them onto the four surfaces they touch: the engine (column order,
|
|
30
|
+
* width and visibility, applied by a REBUILD, which is cheap because the data never leaves the
|
|
31
|
+
* controller), the controller (sort and grouping, which are row order and belong to the data), and
|
|
32
|
+
* the surface's own filter box. Applying a view is therefore one function with one order of
|
|
33
|
+
* operations, not five controls that each half-remember what the others did.
|
|
34
34
|
*/
|
|
35
35
|
import { effect, effectScope, reactive } from "../reactivity";
|
|
36
36
|
import { showConfirmDialog, showPromptDialog } from "../ui/layers";
|
|
@@ -259,9 +259,9 @@ function projectViews(controller: GridController, at: { x: number; y: number }):
|
|
|
259
259
|
* The View panel: saved views, then the four facets one of them is made of.
|
|
260
260
|
*
|
|
261
261
|
* One control rather than four, because the chrome budget is a cap on named things in the toolbar
|
|
262
|
-
* (
|
|
263
|
-
* working layout and applies immediately — there is no Apply button, so there is no state in
|
|
264
|
-
* the panel shows something the grid is not already doing.
|
|
262
|
+
* (studio-ui-guidelines.md §12.2) and these four are only ever adjusted together. Each edit writes
|
|
263
|
+
* the working layout and applies immediately — there is no Apply button, so there is no state in
|
|
264
|
+
* which the panel shows something the grid is not already doing.
|
|
265
265
|
*/
|
|
266
266
|
function openViewPopover(
|
|
267
267
|
controller: GridController,
|
|
@@ -727,7 +727,8 @@ export function gridViewCommands(): AnyCommand[] {
|
|
|
727
727
|
requires: "a grid on screen",
|
|
728
728
|
when: (ctx) => ctx.project.open,
|
|
729
729
|
enablement: () => activeGridSurface() !== null,
|
|
730
|
-
/* No `aiTool`, by §12.4's second deletion rule: it prompts for a
|
|
730
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: it prompts for a
|
|
731
|
+
name. */
|
|
731
732
|
run: async () => {
|
|
732
733
|
const { controller, panel } = requireSurface("grid.saveView");
|
|
733
734
|
await promptSaveView(controller, panel);
|
|
@@ -744,7 +745,7 @@ export function gridViewCommands(): AnyCommand[] {
|
|
|
744
745
|
requires: "a grid on screen",
|
|
745
746
|
when: (ctx) => ctx.project.open,
|
|
746
747
|
enablement: () => activeGridSurface() !== null,
|
|
747
|
-
/* No `aiTool`, by §12.4's first deletion rule: chrome. */
|
|
748
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: chrome. */
|
|
748
749
|
run: (_ctx, args) => {
|
|
749
750
|
const { gridId, name } = viewNameArg("grid.applyView", args);
|
|
750
751
|
const { panel } = requireSurface("grid.applyView");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Redirects as a {@link GridSource} — the editor §11.4 asks for, over the
|
|
4
|
-
* is.
|
|
3
|
+
* Redirects as a {@link GridSource} — the editor site-architecture.md §11.4 asks for, over the
|
|
4
|
+
* table the grid already is.
|
|
5
5
|
*
|
|
6
6
|
* `project.json`'s `redirects` map is tabular, so it does not need a bespoke editor: it needs the
|
|
7
7
|
* one Studio already has. Columns, inline editing, add/delete rows, undo, the dirty dot, ⌘S,
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* **Every write goes through the one door.** Rows commit with {@link commitProjectConfig}, so a
|
|
15
15
|
* redirect edit is a transaction on the `project.json` document with the same undo, the same
|
|
16
|
-
* serialisation and the same refusal-with-a-Problem as every other configuration write (
|
|
17
|
-
* module never touches `platform.writeFile`.
|
|
16
|
+
* serialisation and the same refusal-with-a-Problem as every other configuration write (§17.1).
|
|
17
|
+
* This module never touches `platform.writeFile`.
|
|
18
18
|
*
|
|
19
19
|
* **Row keys are positions.** A redirect's identity in `project.json` IS its source string, and the
|
|
20
20
|
* source is the cell an author most often edits — so keying rows by it would turn every rename into
|
|
@@ -403,9 +403,10 @@ export async function openRedirectsGrid(): Promise<GridController> {
|
|
|
403
403
|
* The paste box.
|
|
404
404
|
*
|
|
405
405
|
* It is `showPromptDialog` with a multiline field, not a dialog of its own. An import is one value
|
|
406
|
-
* the author pastes and one answer they give, which is what that flow already is
|
|
407
|
-
* needed was a field tall enough to read the value back
|
|
408
|
-
* formats are column-aligned in the file they were copied
|
|
406
|
+
* the author pastes and one answer they give, which is what that flow already is
|
|
407
|
+
* (studio-ui-guidelines.md §12.5); what it needed was a field tall enough to read the value back
|
|
408
|
+
* in, and a monospaced one, because both formats are column-aligned in the file they were copied
|
|
409
|
+
* out of.
|
|
409
410
|
*/
|
|
410
411
|
export function promptRedirectImport(): Promise<string | null> {
|
|
411
412
|
return showPromptDialog("Import Redirects", {
|
|
@@ -503,8 +504,9 @@ export function redirectsCommands(): AnyCommand[] {
|
|
|
503
504
|
group: "5_data",
|
|
504
505
|
requires: "an open project",
|
|
505
506
|
when: (ctx) => ctx.project.open,
|
|
506
|
-
/* No `aiTool`, by §12.4's first deletion rule: this opens a surface
|
|
507
|
-
check it runs on the way is `validate_redirects`, which is
|
|
507
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface
|
|
508
|
+
for a person, and the check it runs on the way is `validate_redirects`, which is
|
|
509
|
+
projected. */
|
|
508
510
|
run: async () => {
|
|
509
511
|
await openRedirectsGrid();
|
|
510
512
|
reportRedirectProblems(rulesFromConfig(currentConfig()), await projectRoutes());
|
|
@@ -568,8 +570,9 @@ export function redirectsCommands(): AnyCommand[] {
|
|
|
568
570
|
group: "5_data",
|
|
569
571
|
requires: "an open project",
|
|
570
572
|
when: (ctx) => ctx.project.open,
|
|
571
|
-
/* No `aiTool`, by §12.4's second deletion rule: without `text`, `run`
|
|
572
|
-
the person answers, and the staged rows are a surface for that person
|
|
573
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: without `text`, `run`
|
|
574
|
+
awaits a paste dialog the person answers, and the staged rows are a surface for that person
|
|
575
|
+
to review. */
|
|
573
576
|
run: async (_ctx, args) => {
|
|
574
577
|
const given = optionalStringArg("redirects.import", args, "text");
|
|
575
578
|
const text = given ?? (await promptRedirectImport());
|
package/src/grid/redirects.ts
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* - **Shadow** — the project has a real route the rule's source covers. On a host that serves static
|
|
18
18
|
* assets before consulting `_redirects` (Netlify, Cloudflare Pages) the page wins and the rule is
|
|
19
19
|
* dead config; in `dist/` the compiler's own meta-refresh file overwrites the page and warns
|
|
20
|
-
* (§11.1). Two hosts, two answers, and neither is what the author intended
|
|
20
|
+
* (site-architecture.md §11.1). Two hosts, two answers, and neither is what the author intended
|
|
21
|
+
* by writing both.
|
|
21
22
|
*
|
|
22
23
|
* **What is deliberately NOT decided.** A destination containing `:param` or `*` is not followed:
|
|
23
24
|
* its concrete target depends on the request, so calling it a chain would be a guess. Nothing is
|
|
@@ -67,7 +68,10 @@ export function normalizePath(path: string): string {
|
|
|
67
68
|
return trimmed.length > 1 && trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Whether a path is a URLPattern (site-architecture.md §11.2) rather than a literal — `:param` or
|
|
73
|
+
* `*`.
|
|
74
|
+
*/
|
|
71
75
|
export function isPattern(path: string): boolean {
|
|
72
76
|
return path.includes(":") || path.includes("*");
|
|
73
77
|
}
|
|
@@ -80,9 +84,10 @@ export function isExternal(path: string): boolean {
|
|
|
80
84
|
/**
|
|
81
85
|
* Whether `path` is covered by `pattern`.
|
|
82
86
|
*
|
|
83
|
-
* URLPattern-lite over pathname segments, which is all §11.2 uses: `:name`
|
|
84
|
-
* non-empty segment and `*` matches the rest, including nothing. Enough to
|
|
85
|
-
* ever fire for that request", which is the only question chain, loop and
|
|
87
|
+
* URLPattern-lite over pathname segments, which is all site-architecture.md §11.2 uses: `:name`
|
|
88
|
+
* matches exactly one non-empty segment and `*` matches the rest, including nothing. Enough to
|
|
89
|
+
* answer "does this rule ever fire for that request", which is the only question chain, loop and
|
|
90
|
+
* shadow ask.
|
|
86
91
|
*/
|
|
87
92
|
export function matchesPattern(pattern: string, path: string): boolean {
|
|
88
93
|
const p = normalizePath(pattern).split("/");
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
* Collections type their columns from the content-type schema (plus inferred extras found in the
|
|
13
13
|
* data); the pages grid is fully inference-driven.
|
|
14
14
|
*
|
|
15
|
-
* **A collection listing obeys the draft perspective (§7.6).**
|
|
16
|
-
* the one flag and the one definition of what a draft is, and
|
|
17
|
-
* testing `draft === true` itself — which is what makes "including
|
|
18
|
-
* as it does on the tab chip. It can, because that module imports
|
|
19
|
-
* richer `content/entry-model.ts` asks THIS file where a collection's
|
|
20
|
-
* to it would be the cycle `import/no-cycle` rejects.
|
|
15
|
+
* **A collection listing obeys the draft perspective (site-architecture.md §7.6).**
|
|
16
|
+
* `content/draft-state.ts` owns both the one flag and the one definition of what a draft is, and
|
|
17
|
+
* this source calls it rather than testing `draft === true` itself — which is what makes "including
|
|
18
|
+
* drafts" mean the same thing here as it does on the tab chip. It can, because that module imports
|
|
19
|
+
* nothing but `reactivity`: the richer `content/entry-model.ts` asks THIS file where a collection's
|
|
20
|
+
* entries live, so an edge back to it would be the cycle `import/no-cycle` rejects.
|
|
21
21
|
*/
|
|
22
22
|
import { getPlatform } from "../../platform";
|
|
23
23
|
import { projectState } from "../../store";
|
|
@@ -207,9 +207,10 @@ interface EntryFileSourceOptions {
|
|
|
207
207
|
/** Inferred columns to front-load, in order (e.g. title/description for pages). */
|
|
208
208
|
priorityFields?: string[];
|
|
209
209
|
/**
|
|
210
|
-
* Whether this listing is subject to the draft perspective (§7.6) —
|
|
211
|
-
* tree is not. A draft is a property of a content ENTRY: a page
|
|
212
|
-
* vanish from the only tree that lists it, with no collection schema
|
|
210
|
+
* Whether this listing is subject to the draft perspective (site-architecture.md §7.6) —
|
|
211
|
+
* collections are, the pages tree is not. A draft is a property of a content ENTRY: a page
|
|
212
|
+
* carrying `draft: true` would vanish from the only tree that lists it, with no collection schema
|
|
213
|
+
* to explain why.
|
|
213
214
|
*/
|
|
214
215
|
drafts?: boolean;
|
|
215
216
|
}
|
package/src/hosting/document.ts
CHANGED
|
@@ -24,6 +24,20 @@ import type { AssetBase } from "./layout";
|
|
|
24
24
|
/** The default base: the tree served at the document's own directory, in the package's own shape. */
|
|
25
25
|
export const IN_PLACE: AssetBase = { mode: "nested", prefix: "./" };
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The marker a document carries when it declares boot modules: `<meta name="jx-boot"
|
|
29
|
+
* content="launcher">`.
|
|
30
|
+
*
|
|
31
|
+
* It is how the studio entry tells "nobody registered an adapter because this is the dev server"
|
|
32
|
+
* from "somebody was supposed to and did not". The two looked identical from inside the bundle, and
|
|
33
|
+
* Studio answered both with the dev-server adapter, so a launcher whose boot script 404'd or failed
|
|
34
|
+
* to parse got a window that drew, fetched `/__studio/*` from an origin with nothing behind it, and
|
|
35
|
+
* failed on the first click. A meta rather than a script global because it is in the markup before
|
|
36
|
+
* any script runs, and so survives exactly the failures it exists to report: a boot module that
|
|
37
|
+
* never loaded cannot have set anything. `platforms/default-platform.ts` is the reader.
|
|
38
|
+
*/
|
|
39
|
+
export const BOOT_META = { name: "jx-boot", content: "launcher" } as const;
|
|
40
|
+
|
|
27
41
|
export interface DocumentOptions {
|
|
28
42
|
/** Where the asset tree is mounted. Defaults to {@link IN_PLACE}. */
|
|
29
43
|
readonly base?: AssetBase | undefined;
|
|
@@ -39,6 +53,12 @@ export interface DocumentOptions {
|
|
|
39
53
|
* or publishes the `__jxCloud` signal for the studio entry to build the adapter from. It must do
|
|
40
54
|
* so SYNCHRONOUSLY — a module script with top-level await does not block a later script tag, and
|
|
41
55
|
* the entry reads the global as it evaluates.
|
|
56
|
+
*
|
|
57
|
+
* **Declaring a boot module turns the dev-server fallback off.** A non-empty list stamps
|
|
58
|
+
* {@link BOOT_META} into the head, and a studio entry that then finds no adapter and no cloud
|
|
59
|
+
* signal draws a boot-failure screen instead of registering the dev-server adapter
|
|
60
|
+
* (`platforms/default-platform.ts`). A host that serves the HTTP protocol at its own origin and
|
|
61
|
+
* wants that fallback declares no boot module.
|
|
42
62
|
*/
|
|
43
63
|
readonly boot?: readonly string[] | undefined;
|
|
44
64
|
/** Document title. Defaults to "Jx Studio". */
|
|
@@ -66,12 +86,19 @@ export function studioShellHtml(options: DocumentOptions = {}): string {
|
|
|
66
86
|
.map((path) => ` <link rel="stylesheet" href="${url(path)}" />`)
|
|
67
87
|
.join("\n");
|
|
68
88
|
const boot = (options.boot ?? []).map((mod) => ` ${scriptTag(mod)}`).join("\n");
|
|
89
|
+
/* Only when there IS a boot module: `packages/studio/index.html` is generated with none and CI
|
|
90
|
+
diffs it byte for byte, and the dev server it is served by is the one host that should fall
|
|
91
|
+
back. The `<head>` below stays a literal, attribute-free tag — Electrobun's macOS CEF path
|
|
92
|
+
injects its preload by splicing after that exact string. */
|
|
93
|
+
const bootMeta = boot
|
|
94
|
+
? ` <meta name="${BOOT_META.name}" content="${BOOT_META.content}" />\n`
|
|
95
|
+
: "";
|
|
69
96
|
return `<!doctype html>
|
|
70
97
|
<html lang="en">
|
|
71
98
|
<head>
|
|
72
99
|
<meta charset="utf-8" />
|
|
73
100
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
74
|
-
<title>${options.title ?? "Jx Studio"}</title>
|
|
101
|
+
${bootMeta} <title>${options.title ?? "Jx Studio"}</title>
|
|
75
102
|
<link rel="icon" href="${url(STUDIO_FAVICON)}" />
|
|
76
103
|
${links}
|
|
77
104
|
</head>
|
package/src/hosting/stage.ts
CHANGED
|
@@ -23,6 +23,17 @@ import type { DocumentOptions } from "./document";
|
|
|
23
23
|
/** The installed package root, resolved off this module rather than off a caller's cwd. */
|
|
24
24
|
export const STUDIO_PACKAGE_DIR = resolve(import.meta.dir, "..", "..");
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Normalize a `Glob.scan` result to forward slashes. Private and un-exported, like
|
|
28
|
+
* `project-session.ts`'s own `toPosix()`: this is the one module under `src/` that touches
|
|
29
|
+
* filesystem paths at all, and its published `files` entry (`package.json`) covers `src/` but not
|
|
30
|
+
* the repo's dev-tooling `scripts/lib/posix-path.ts`, so a cross-boundary import here would 404 for
|
|
31
|
+
* anyone who installed this package rather than checked out the monorepo.
|
|
32
|
+
*/
|
|
33
|
+
function toPosix(p: string): string {
|
|
34
|
+
return p.replaceAll("\\", "/");
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
export interface StageOptions {
|
|
27
38
|
/** Package root to read from — an installed copy, or a `--link` checkout. */
|
|
28
39
|
readonly from?: string | undefined;
|
|
@@ -108,13 +119,13 @@ export async function stageStudioAssets(
|
|
|
108
119
|
const dest = destOf(destDir, a.path, layout);
|
|
109
120
|
if (a.dir) {
|
|
110
121
|
await mkdir(dest, { recursive: true });
|
|
111
|
-
for (const
|
|
112
|
-
const posix =
|
|
122
|
+
for (const rawRel of new Glob("**/*").scanSync(src)) {
|
|
123
|
+
const posix = toPosix(rawRel);
|
|
113
124
|
if (skipMap(posix)) {
|
|
114
125
|
continue;
|
|
115
126
|
}
|
|
116
|
-
const file = join(src,
|
|
117
|
-
const to = join(dest,
|
|
127
|
+
const file = join(src, posix);
|
|
128
|
+
const to = join(dest, posix);
|
|
118
129
|
await mkdir(dirname(to), { recursive: true });
|
|
119
130
|
await cp(file, to);
|
|
120
131
|
written.push(`${a.path}/${posix}`);
|
|
@@ -204,8 +204,8 @@ export function i18nCommands(): AnyCommand[] {
|
|
|
204
204
|
with its `requires` sentence. The palette's availability is the person's contract; an
|
|
205
205
|
argument-only gate needs a shape the registry does not have. Same on `createTranslation`. */
|
|
206
206
|
when: (ctx) => ctx.project.isMultilingual && ctx.document.open,
|
|
207
|
-
/* No `aiTool`, by §12.4's first deletion rule: this opens a surface
|
|
208
|
-
model has `open_document` for the file it names. */
|
|
207
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface
|
|
208
|
+
for a person, and the model has `open_document` for the file it names. */
|
|
209
209
|
run: async (_ctx, args) => {
|
|
210
210
|
const source = addressedDocument("i18n.openTranslation", args);
|
|
211
211
|
const locale = stringArg("i18n.openTranslation", args, "locale");
|
|
@@ -261,10 +261,11 @@ export function i18nCommands(): AnyCommand[] {
|
|
|
261
261
|
/* The document history cannot hold this: the change is a file that did not exist, and
|
|
262
262
|
`undo: "project"` would claim `project.json` moved, which it did not. */
|
|
263
263
|
undo: "none",
|
|
264
|
-
/* No `aiTool`, by §12.4's second deletion rule: `createFileIn` awaits
|
|
265
|
-
for the name, which the loop does not count as interactive, and a
|
|
266
|
-
with nothing thrown — a report would describe a file that was never
|
|
267
|
-
`name` argument that skips the prompt is the way back in, and is a UX
|
|
264
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `createFileIn` awaits
|
|
265
|
+
the New File prompt for the name, which the loop does not count as interactive, and a
|
|
266
|
+
cancel resolves `null` with nothing thrown — a report would describe a file that was never
|
|
267
|
+
made. An optional `name` argument that skips the prompt is the way back in, and is a UX
|
|
268
|
+
call (issue 273). */
|
|
268
269
|
run: async (_ctx, args) => {
|
|
269
270
|
const source = addressedDocument("i18n.createTranslation", args);
|
|
270
271
|
const locale = stringArg("i18n.createTranslation", args, "locale");
|
|
@@ -319,7 +320,8 @@ export function i18nCommands(): AnyCommand[] {
|
|
|
319
320
|
group: "2_view",
|
|
320
321
|
requires: "a project that declares more than one language",
|
|
321
322
|
when: (ctx) => ctx.project.isMultilingual,
|
|
322
|
-
/* No `aiTool`, by §12.4's first deletion rule: the panel is a surface
|
|
323
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: the panel is a surface
|
|
324
|
+
for a person. */
|
|
323
325
|
/* The panel is off the rail — it spends no rail slot and shifts no ⌘1-8 chord — so this
|
|
324
326
|
command and the generated `panel.focus.i18n` are its only two doors, and both open the
|
|
325
327
|
same one. The TITLES must differ even though the behaviour does not: the palette is a flat
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Two shapes, chosen by the platform's `createDestination` (specs/desktop.md §4.5):
|
|
5
5
|
*
|
|
6
6
|
* - `"path"` (desktop, dev server): a required **Location** (absolute parent directory) plus the
|
|
7
|
-
* folder name.
|
|
8
|
-
*
|
|
9
|
-
* did not name.
|
|
7
|
+
* folder name. The Browse… button is backed by `pickDirectory` wherever the platform has one:
|
|
8
|
+
* desktop's system dialog, and the dev server's `showDirectoryPicker` in a Chromium browser.
|
|
9
|
+
* Elsewhere the path is typed. Nothing is ever written to a directory the user did not name.
|
|
10
10
|
* - `"repo"` (cloud): the repository location — owner (personal account or organization), the
|
|
11
11
|
* repository name, and its visibility.
|
|
12
12
|
*
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* @docs studio/projects/create
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { errorMessage } from "@jxsuite/schema/parse";
|
|
24
25
|
import { getPlatform } from "../platform";
|
|
25
26
|
import type { CreateProjectDestination, RepoInfo } from "../types";
|
|
26
27
|
|
|
@@ -253,6 +254,13 @@ export function setLocationVisibility(value: string): void {
|
|
|
253
254
|
* Re-entrant by refusal rather than by disabling alone: the button is drawn disabled while the
|
|
254
255
|
* native dialog is up, and a synthetic click does not consult that.
|
|
255
256
|
*
|
|
257
|
+
* **Never a silent no-op, and never a rejection.** `null` from `pickDirectory` is the user
|
|
258
|
+
* cancelling, so nothing is said and the standing state is left alone. Anything else rejects with a
|
|
259
|
+
* displayable message (see `StudioPlatform.pickDirectory`), which lands in the destination error
|
|
260
|
+
* under the Location field, where typing a path clears it. The modal calls this as `void
|
|
261
|
+
* browseLocation(...)`, so a rejection escaping here would be an unhandled one: the exact "picked a
|
|
262
|
+
* folder and nothing happened" this contract exists to rule out.
|
|
263
|
+
*
|
|
256
264
|
* @param rerender Repaint the wizard — once for the busy label, once for the answer.
|
|
257
265
|
*/
|
|
258
266
|
export async function browseLocation(rerender: () => void): Promise<void> {
|
|
@@ -268,6 +276,11 @@ export async function browseLocation(rerender: () => void): Promise<void> {
|
|
|
268
276
|
_parent = picked;
|
|
269
277
|
_error = "";
|
|
270
278
|
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
/* The dialog could not open, the folder could not be tagged, the backend was unreachable or
|
|
281
|
+
found no match, an RPC timed out. Whatever the platform, the sentence goes under Location. */
|
|
282
|
+
_error =
|
|
283
|
+
errorMessage(error) || "The folder could not be chosen. Type its path into Location instead.";
|
|
271
284
|
} finally {
|
|
272
285
|
_browsing = false;
|
|
273
286
|
rerender();
|
|
@@ -46,7 +46,8 @@ import { getPlatform } from "../platform";
|
|
|
46
46
|
import { installUrlOf } from "../platform-errors";
|
|
47
47
|
import { hasAiCredentials } from "../services/ai-models";
|
|
48
48
|
import { setPendingAgentPrompt } from "../services/agent-seed";
|
|
49
|
-
import {
|
|
49
|
+
import { adoptCreatedProject } from "../services/project-adoption";
|
|
50
|
+
import { notify } from "../services/notify";
|
|
50
51
|
import { runImportHandoff } from "../services/import-seed";
|
|
51
52
|
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
52
53
|
import { createManagedConnect } from "../ui/ai-managed-connect";
|
|
@@ -328,14 +329,29 @@ function finish(result: { root: string; config: ProjectConfig } | null) {
|
|
|
328
329
|
|
|
329
330
|
/**
|
|
330
331
|
* Every path out of the wizard that produced a project HERE: initialise version control for it,
|
|
331
|
-
* then hand it to the caller. A scaffold is not a repository
|
|
332
|
-
* away.
|
|
332
|
+
* open it, then hand it to the caller. A scaffold is not a repository and an unopened project is
|
|
333
|
+
* not a created one, and Delete and Rename are one click away.
|
|
333
334
|
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
335
|
+
* `adoptCreatedProject` is the same sequence `create_project`/`import_site` run — this is the third
|
|
336
|
+
* caller `services/project-adoption.ts`'s own doc comment already names. It is what makes
|
|
337
|
+
* `project.new` from the command palette work at all while a project is open: that entry point
|
|
338
|
+
* never looks at what this promise resolves with (`newProjectCommands` below fires and forgets), so
|
|
339
|
+
* adopting has to happen HERE rather than being left to whichever caller opened the wizard.
|
|
340
|
+
*
|
|
341
|
+
* The Import path does not come through here — `import_site` creates the project, so it already
|
|
342
|
+
* runs this same sequence itself.
|
|
336
343
|
*/
|
|
337
344
|
async function finishCreated(result: { root: string; config: ProjectConfig }) {
|
|
338
|
-
await
|
|
345
|
+
const { adopted, error, openedElsewhere } = await adoptCreatedProject(result.root, {
|
|
346
|
+
// The wizard runs outside the agent loop — there is never a batch to flush and re-anchor.
|
|
347
|
+
getTab: () => null,
|
|
348
|
+
});
|
|
349
|
+
if (!adopted && !openedElsewhere) {
|
|
350
|
+
notify.warn("Created the project, but could not open it here.", {
|
|
351
|
+
...(error === null ? {} : { detail: error }),
|
|
352
|
+
source: "New Project",
|
|
353
|
+
});
|
|
354
|
+
}
|
|
339
355
|
finish(result);
|
|
340
356
|
}
|
|
341
357
|
|
|
@@ -680,7 +696,7 @@ export function newProjectCommands(): AnyCommand[] {
|
|
|
680
696
|
menus: ["commandbar/overflow", "palette"],
|
|
681
697
|
group: "1_file",
|
|
682
698
|
/* No `aiTool`: application-level, refused at registration; it opens the wizard, and the
|
|
683
|
-
model's own door is `create_project` / `import_site` (§12.4). */
|
|
699
|
+
model's own door is `create_project` / `import_site` (studio-ui-guidelines.md §12.4). */
|
|
684
700
|
run: (_commandCtx, args) => {
|
|
685
701
|
const tab =
|
|
686
702
|
(args as { tab?: unknown }).tab === undefined
|