@jxsuite/studio 6.1.1 → 8.0.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-5wtzce5g.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/color-area-6rbra5dy.js +4 -0
- package/dist/chunks/color-field-gy56c94g.js +4 -0
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
- package/dist/chunks/combobox-72h32ejk.js +4 -0
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
- package/dist/chunks/icons-63bjtbs7.js +4 -0
- package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
- package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/listbox-c421cf8c.js +4 -0
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/menu-bdpzbfvs.js +4 -0
- package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/split-c9zfdgxf.js +4 -0
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/studio-6m380wp7.js +5 -0
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/studio-8tr6cfrc.js +5 -0
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/studio-bbe4c90a.js +5 -0
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/studio-k7evxqh4.js +5 -0
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -0
- package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-yypz28gq.js +4 -0
- package/dist/chunks/tree-9xa4hm7n.js +4 -0
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/ws-client-bv552sfx.js +4 -0
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +106 -107
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +17 -16
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +270 -53
- package/src/browse/library-model.ts +194 -134
- package/src/browse/library-pane.ts +748 -440
- package/src/browse/library-preview.ts +161 -26
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +40 -10
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +260 -77
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +175 -148
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +147 -61
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +120 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +104 -75
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +269 -158
- package/src/canvas/iframe-inline-edit.ts +49 -30
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +30 -25
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +25 -21
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +36 -21
- package/src/canvas/iframe-render.ts +84 -35
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +10 -3
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +7 -2
- package/src/canvas/surface-registry.ts +27 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +13 -11
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +55 -28
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +56 -43
- package/src/commands/levels.ts +14 -8
- package/src/commands/live-context.ts +9 -7
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +22 -11
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +11 -9
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +54 -62
- package/src/content/entry-editor.ts +137 -32
- package/src/content/entry-fields.ts +25 -8
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +38 -15
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- package/src/editor/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +78 -48
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +29 -22
- package/src/editor/inline-edit-apply.ts +79 -17
- package/src/editor/inline-edit.ts +76 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +14 -5
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +76 -42
- package/src/editor/slash-menu.ts +52 -14
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +89 -20
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +92 -41
- package/src/files/files.ts +248 -239
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +97 -2
- package/src/files/media-paths.ts +3 -0
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +15 -5
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +91 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +21 -11
- package/src/github/github-publish.ts +28 -23
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +25 -23
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -33
- package/src/grid/grid-panel.ts +65 -6
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +9 -31
- package/src/grid/grid-view.ts +45 -23
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +100 -31
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +61 -34
- package/src/hosting/document.ts +2 -2
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +3 -3
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +51 -20
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +38 -14
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +57 -46
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +36 -26
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +63 -26
- package/src/panels/data-grid.ts +18 -11
- package/src/panels/dnd.ts +115 -138
- package/src/panels/editors.ts +52 -21
- package/src/panels/elements-panel.ts +19 -5
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +78 -54
- package/src/panels/frontmatter-fields.ts +33 -28
- package/src/panels/git-diff-open.ts +10 -6
- package/src/panels/head-panel.ts +488 -202
- package/src/panels/i18n-panel.ts +20 -12
- package/src/panels/imports-panel.ts +25 -47
- package/src/panels/jump-bar.ts +75 -31
- package/src/panels/layers-panel.ts +130 -101
- package/src/panels/left-panel.ts +25 -11
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +140 -49
- package/src/panels/pane-grid.ts +55 -26
- package/src/panels/panel-registry.ts +36 -46
- package/src/panels/properties-panel.ts +182 -124
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +201 -45
- package/src/panels/seo-modal.ts +54 -125
- package/src/panels/settings-menu.ts +63 -61
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +156 -135
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +253 -206
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +195 -60
- package/src/panels/stylebook-layers-panel.ts +48 -89
- package/src/panels/stylebook-panel.ts +60 -27
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +143 -49
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +59 -31
- package/src/platforms/cloud.ts +373 -176
- package/src/platforms/default-platform.ts +14 -8
- package/src/platforms/devserver.ts +180 -142
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +20 -9
- package/src/publish/pages-service.ts +66 -27
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +88 -22
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-panel.ts +10 -6
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- package/src/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +74 -51
- package/src/services/cem-export.ts +149 -58
- package/src/services/cf-settings.ts +4 -4
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +20 -14
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +29 -9
- package/src/services/settings/definitions.ts +25 -14
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +128 -70
- package/src/settings/css-vars-editor.ts +119 -32
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +42 -14
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +101 -28
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +17 -7
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +28 -11
- package/src/settings/schema-field-ui.ts +12 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +186 -166
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +536 -477
- package/src/site-context.ts +101 -32
- package/src/state.ts +68 -57
- package/src/store.ts +54 -34
- package/src/studio.ts +219 -116
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +40 -7
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/token-ref.ts +5 -4
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +33 -38
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +17 -16
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +145 -105
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +35 -11
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +59 -31
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +111 -77
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +26 -11
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +47 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +44 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +8 -7
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +49 -25
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +25 -39
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +5 -29
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +29 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +22 -79
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +17 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +32 -12
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +82 -16
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +9 -16
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +14 -8
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +88 -36
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +42 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +56 -29
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +6 -8
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- package/src/tabs/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +99 -48
- package/src/tabs/transact.ts +98 -53
- package/src/types.ts +53 -43
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +104 -56
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +57 -31
- package/src/ui/media-picker.ts +300 -47
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +14 -12
- package/src/ui/schema-form.ts +372 -97
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +29 -3
- package/src/utils/base64.ts +6 -4
- package/src/utils/edit-display.ts +366 -111
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/local-day.ts +18 -0
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +14 -16
- package/src/workspace/session.ts +81 -50
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +165 -47
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-va2wwra4.js +0 -4
- package/dist/chunks/adapter-f93pafd7.js +0 -4
- package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
- package/dist/chunks/cf-settings-125tdm0w.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-ax2f1fnn.js +0 -4
- package/dist/chunks/content-source-108aqtk1.js +0 -4
- package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-pfgdmkb0.js +0 -4
- package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
- package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
- package/dist/chunks/file-ops-meej5mqf.js +0 -4
- package/dist/chunks/files-44vp8a2s.js +0 -4
- package/dist/chunks/format-host-7q1petb9.js +0 -4
- package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
- package/dist/chunks/git-panel-zngbymvd.js +0 -4
- package/dist/chunks/grid-view-sx9vynsp.js +0 -51
- package/dist/chunks/icons-p44xhjf0.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
- package/dist/chunks/index-wkyfjeqz.js +0 -4
- package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
- package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
- package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
- package/dist/chunks/layers-xd92fg8d.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
- package/dist/chunks/media-picker-0svzkdyb.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/menu-5c55ea3d.js +0 -4
- package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
- package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
- package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
- package/dist/chunks/notify-0xgtn8q1.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-v1qctbe6.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
- package/dist/chunks/quick-search-a54e6t5n.js +0 -4
- package/dist/chunks/references-gmqp82fs.js +0 -4
- package/dist/chunks/right-panel-v7t9awbk.js +0 -4
- package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0bhx5hz6.js +0 -5
- package/dist/chunks/studio-0k1ddnyy.js +0 -6
- package/dist/chunks/studio-1b04pd0j.js +0 -64
- package/dist/chunks/studio-4dwbj6gb.js +0 -5
- package/dist/chunks/studio-4tanh828.js +0 -5
- package/dist/chunks/studio-55h4mstj.js +0 -4
- package/dist/chunks/studio-5tnvjkz4.js +0 -5
- package/dist/chunks/studio-60dqgb0c.js +0 -5
- package/dist/chunks/studio-61dp09qg.js +0 -9
- package/dist/chunks/studio-63epcrj2.js +0 -5
- package/dist/chunks/studio-74k29dy9.js +0 -5
- package/dist/chunks/studio-7vg6jcd3.js +0 -5
- package/dist/chunks/studio-7zx31knw.js +0 -9
- package/dist/chunks/studio-8bxk97km.js +0 -5
- package/dist/chunks/studio-933e30n4.js +0 -5
- package/dist/chunks/studio-98wnwhbg.js +0 -5
- package/dist/chunks/studio-9mccjwjh.js +0 -14
- package/dist/chunks/studio-a2ke1e4t.js +0 -5
- package/dist/chunks/studio-e3a2a6v3.js +0 -4
- package/dist/chunks/studio-e81q1vb9.js +0 -5
- package/dist/chunks/studio-epgrmqqm.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-g1shz58g.js +0 -5
- package/dist/chunks/studio-gf0fz03c.js +0 -5
- package/dist/chunks/studio-gjtpe62q.js +0 -6
- package/dist/chunks/studio-gkskhg7m.js +0 -5
- package/dist/chunks/studio-gx4dnjzd.js +0 -5
- package/dist/chunks/studio-j03zga3y.js +0 -9
- package/dist/chunks/studio-jhpxeckz.js +0 -5
- package/dist/chunks/studio-k01r7ykp.js +0 -5
- package/dist/chunks/studio-kk7h30ne.js +0 -7
- package/dist/chunks/studio-kt1zqney.js +0 -5
- package/dist/chunks/studio-m3cwhvye.js +0 -5
- package/dist/chunks/studio-mcayt6hz.js +0 -5
- package/dist/chunks/studio-myjcghv3.js +0 -5
- package/dist/chunks/studio-n8bxwc3y.js +0 -4
- package/dist/chunks/studio-ngm8gvpb.js +0 -5
- package/dist/chunks/studio-nj5a01jy.js +0 -928
- package/dist/chunks/studio-pcgz8heb.js +0 -5
- package/dist/chunks/studio-qcsq0t15.js +0 -5
- package/dist/chunks/studio-qkstvve9.js +0 -5
- package/dist/chunks/studio-qv1pwd3c.js +0 -5
- package/dist/chunks/studio-rc6dvxjb.js +0 -7
- package/dist/chunks/studio-s8dmmz66.js +0 -5
- package/dist/chunks/studio-sp5xzbj4.js +0 -6
- package/dist/chunks/studio-szsjbj0g.js +0 -5
- package/dist/chunks/studio-t1xzawhr.js +0 -16
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- package/dist/chunks/studio-vrmcjf9g.js +0 -7
- package/dist/chunks/studio-vyc0b4he.js +0 -10
- package/dist/chunks/studio-w0cgf6jg.js +0 -5
- package/dist/chunks/studio-w3hskzqk.js +0 -5
- package/dist/chunks/studio-xgrgcdyh.js +0 -9
- package/dist/chunks/studio-xz2yxfcb.js +0 -5
- package/dist/chunks/studio-y6n42tgs.js +0 -5
- package/dist/chunks/studio-yb560vxr.js +0 -5
- package/dist/chunks/studio-yn9f8vtx.js +0 -5
- package/dist/chunks/studio-yw05w8f0.js +0 -7
- package/dist/chunks/studio-z16sgavc.js +0 -5
- package/dist/chunks/studio-zey7zsdw.js +0 -12
- package/dist/chunks/studio-zyqn40w4.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-2frah6h1.js +0 -14
- package/dist/chunks/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -701
- package/src/panels/git-panel.ts +0 -1120
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -231
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -272
package/src/grid/grid-panel.ts
CHANGED
|
@@ -41,6 +41,7 @@ import { createGridController, getGridController } from "./grid-controller";
|
|
|
41
41
|
import { createCsvFileSource } from "./sources/csv-file-source";
|
|
42
42
|
import { loadedGridEngine, loadGridEngine } from "./grid-lazy";
|
|
43
43
|
import { parseGridTabId } from "./grid-source";
|
|
44
|
+
import { clearGridReveal, pendingGridReveal } from "./grid-reveal";
|
|
44
45
|
import { mountGridPanelSurface } from "../surfaces/grid-panel";
|
|
45
46
|
import { openGridViewsSurface } from "../surfaces/grid-views";
|
|
46
47
|
import { openGridReplaceSurface } from "../surfaces/grid-replace";
|
|
@@ -56,6 +57,7 @@ import {
|
|
|
56
57
|
saveViewAs,
|
|
57
58
|
} from "./grid-layout";
|
|
58
59
|
import { argsSchema, stringArg, stringProperty } from "../commands/command-args";
|
|
60
|
+
import type { CommandArgValues } from "../commands/command-args";
|
|
59
61
|
import type { EffectScope } from "@vue/reactivity";
|
|
60
62
|
import type { GridController } from "./grid-controller";
|
|
61
63
|
import type { GridLayout, GridSortSpec } from "./grid-layout";
|
|
@@ -69,7 +71,7 @@ import type {
|
|
|
69
71
|
GridPanelView,
|
|
70
72
|
} from "../surfaces/grid-panel";
|
|
71
73
|
import type { GridViewsSurfaceHandle, GridViewsView } from "../surfaces/grid-views";
|
|
72
|
-
import type {
|
|
74
|
+
import type { PopoverSurfaceHandle } from "../ui/popover-surface";
|
|
73
75
|
|
|
74
76
|
interface ActiveGridPanel {
|
|
75
77
|
/** The pane whose stage this grid is drawn on. */
|
|
@@ -85,7 +87,7 @@ interface ActiveGridPanel {
|
|
|
85
87
|
/** Where that panel was opened, so a re-projection cannot move it back to the origin. */
|
|
86
88
|
viewsAt: { x: number; y: number };
|
|
87
89
|
/** Find & replace while it is open. */
|
|
88
|
-
replace:
|
|
90
|
+
replace: PopoverSurfaceHandle | null;
|
|
89
91
|
/**
|
|
90
92
|
* Rebuild the engine over the same controller.
|
|
91
93
|
*
|
|
@@ -614,15 +616,66 @@ export function renderGridMode(surface: CanvasSurface, tab: Tab) {
|
|
|
614
616
|
}
|
|
615
617
|
restored = true;
|
|
616
618
|
const layout = loadGridLayout(engine.source.id);
|
|
617
|
-
|
|
618
|
-
engine.setGrouping(layout?.groupBy ?? null);
|
|
619
|
+
restoreStoredOrder(engine, layout);
|
|
619
620
|
view.setSearch(layout?.filter ?? "");
|
|
620
621
|
});
|
|
621
622
|
}
|
|
623
|
+
revealRequested(engine, panel, tab.documentPath);
|
|
622
624
|
});
|
|
623
625
|
});
|
|
624
626
|
}
|
|
625
627
|
|
|
628
|
+
/**
|
|
629
|
+
* Put the stored sort and grouping back on a freshly built engine, asking the controller only for
|
|
630
|
+
* what differs from the order it already holds.
|
|
631
|
+
*
|
|
632
|
+
* The controller outlives the panel: leaving the grid's workspace and coming back rebuilds the
|
|
633
|
+
* table but keeps the controller, so on every return after the first the stored order IS the
|
|
634
|
+
* controller's order. Asking for it anyway was not free. Each of `setSort` and `setGrouping`
|
|
635
|
+
* re-projects the rows into the view, and a view still building parks that as a refresh it runs the
|
|
636
|
+
* moment it is built, so every open rendered its rows twice (the second time measuring every row's
|
|
637
|
+
* height again); a remote-sorting source re-queried its backend for the same rows on top. An
|
|
638
|
+
* explicit change (a saved view applied, a header in the Views popover) still goes straight to the
|
|
639
|
+
* controller, so re-asking for the order you are looking at keeps its meaning there.
|
|
640
|
+
*/
|
|
641
|
+
export function restoreStoredOrder(engine: GridController, layout: GridLayout | null): void {
|
|
642
|
+
const sort = layout?.sort ?? null;
|
|
643
|
+
const { query, grouping } = engine.state;
|
|
644
|
+
const sortHeld =
|
|
645
|
+
sort === null
|
|
646
|
+
? query.orderBy === undefined
|
|
647
|
+
: query.orderBy === sort.field && query.dir === sort.dir;
|
|
648
|
+
if (!sortHeld) {
|
|
649
|
+
void engine.setSort(sort);
|
|
650
|
+
}
|
|
651
|
+
const groupBy = layout?.groupBy ?? null;
|
|
652
|
+
if (grouping !== groupBy) {
|
|
653
|
+
engine.setGrouping(groupBy);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Land on the row a record's opener asked for (`grid-reveal.ts`), once the engine and the rows
|
|
659
|
+
* exist. The position counts the file's data rows as loaded, so it names a row whatever order a
|
|
660
|
+
* saved view sorts them into. The request is taken either way: a row that is gone is not revealed
|
|
661
|
+
* later by surprise.
|
|
662
|
+
*/
|
|
663
|
+
function revealRequested(
|
|
664
|
+
engine: GridController,
|
|
665
|
+
panel: ActiveGridPanel,
|
|
666
|
+
path: string | null | undefined,
|
|
667
|
+
): void {
|
|
668
|
+
const position = pendingGridReveal(path);
|
|
669
|
+
if (position === undefined || !path || !panel.view || engine.state.loading) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
clearGridReveal(path);
|
|
673
|
+
const row = engine.state.rows[position];
|
|
674
|
+
if (row) {
|
|
675
|
+
void panel.view.revealRow(row.key);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
626
679
|
/** The frame a tab with no grid source draws: one sentence, and no controls to press. */
|
|
627
680
|
function missingView(): GridPanelView {
|
|
628
681
|
return {
|
|
@@ -692,6 +745,12 @@ function requireSurface(commandId: string) {
|
|
|
692
745
|
return surface;
|
|
693
746
|
}
|
|
694
747
|
|
|
748
|
+
/** A saved view, addressed by the grid it was saved for. */
|
|
749
|
+
interface SavedViewRef {
|
|
750
|
+
gridId: string;
|
|
751
|
+
name: string;
|
|
752
|
+
}
|
|
753
|
+
|
|
695
754
|
/**
|
|
696
755
|
* Saved views, as commands.
|
|
697
756
|
*
|
|
@@ -703,10 +762,10 @@ function requireSurface(commandId: string) {
|
|
|
703
762
|
* @returns {AnyCommand[]}
|
|
704
763
|
*/
|
|
705
764
|
export function gridViewCommands(): AnyCommand[] {
|
|
706
|
-
const viewNameArg = (commandId: string, args:
|
|
765
|
+
const viewNameArg = (commandId: string, args: CommandArgValues): SavedViewRef => {
|
|
707
766
|
const { controller } = requireSurface(commandId);
|
|
708
767
|
const gridId = controller.source.id;
|
|
709
|
-
const name = stringArg(commandId, args
|
|
768
|
+
const name = stringArg(commandId, args, "name");
|
|
710
769
|
const known = listSavedViews(gridId).map((view) => view.name);
|
|
711
770
|
if (!known.includes(name)) {
|
|
712
771
|
throw new RangeError(
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The row a file's grid should land on when it opens: a file-backed collection's record.
|
|
3
|
+
*
|
|
4
|
+
* A collection whose `source` names one file (`./content/projects.csv`) is written in that file's
|
|
5
|
+
* grid, so opening one of its records in the Content home opens the file (`specs/studio.md` §22.5).
|
|
6
|
+
* Opening the whole table and leaving the reader to find the row they clicked is not opening the
|
|
7
|
+
* record, so the opener names the record's position here and the grid selects that row and scrolls
|
|
8
|
+
* it into view once its rows have loaded.
|
|
9
|
+
*
|
|
10
|
+
* Reactive and keyed by the file's path, so a request reaches a grid that is already on screen as
|
|
11
|
+
* well as one still loading: the grid panel's one effect reads it, applies it and takes it.
|
|
12
|
+
*
|
|
13
|
+
* @docs studio/projects/browse
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { reactive } from "../reactivity";
|
|
17
|
+
|
|
18
|
+
/** File path → the position of the row to reveal, among the file's data rows from 0. */
|
|
19
|
+
const pending = reactive(new Map<string, number>());
|
|
20
|
+
|
|
21
|
+
/** Ask the grid of `path` to reveal the row at `position` (its place among the data rows, from 0). */
|
|
22
|
+
export function requestGridReveal(path: string, position: number): void {
|
|
23
|
+
pending.set(path, position);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The row the grid of `path` is asked to reveal, or `undefined`. Reading it tracks it. */
|
|
27
|
+
export function pendingGridReveal(path: string | null | undefined): number | undefined {
|
|
28
|
+
return path ? pending.get(path) : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Drop the request for `path` once the grid has acted on it. */
|
|
32
|
+
export function clearGridReveal(path: string): void {
|
|
33
|
+
pending.delete(path);
|
|
34
|
+
}
|
package/src/grid/grid-source.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* pending edits; they never see the grid engine. Grid tabs over non-file sources are "virtual" —
|
|
7
7
|
* their tab id is a `grid://` URI rather than a document path.
|
|
8
8
|
*/
|
|
9
|
+
import { isNonNullObject } from "@jxsuite/schema/guards";
|
|
9
10
|
import type { JsonSchema } from "../ui/schema-form";
|
|
10
11
|
|
|
11
12
|
/** A single cell value. JSON-shaped so batches serialize cleanly. */
|
|
@@ -126,14 +127,7 @@ export function cellValuesEqual(a: GridCellValue, b: GridCellValue): boolean {
|
|
|
126
127
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
127
128
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
128
129
|
}
|
|
129
|
-
if (
|
|
130
|
-
a !== null &&
|
|
131
|
-
b !== null &&
|
|
132
|
-
typeof a === "object" &&
|
|
133
|
-
typeof b === "object" &&
|
|
134
|
-
!Array.isArray(a) &&
|
|
135
|
-
!Array.isArray(b)
|
|
136
|
-
) {
|
|
130
|
+
if (isNonNullObject(a) && isNonNullObject(b) && !Array.isArray(a) && !Array.isArray(b)) {
|
|
137
131
|
return a.$ref === b.$ref;
|
|
138
132
|
}
|
|
139
133
|
return false;
|
|
@@ -144,18 +138,14 @@ export function cellValuesEqual(a: GridCellValue, b: GridCellValue): boolean {
|
|
|
144
138
|
const GRID_SCHEME = "grid://";
|
|
145
139
|
|
|
146
140
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* `library` is the odd one and deliberately so: the Library is a source over this same contract
|
|
150
|
-
* (`browse/library-source.ts`) but its tab's editor kind is `library`, not `grid` — Table is one of
|
|
151
|
-
* its five layouts rather than its identity. It lives in this id space because "which virtual tab
|
|
152
|
-
* is this?" has exactly one answer per window and there is no second scheme worth inventing.
|
|
153
|
-
* Category and layout are VIEW state and are deliberately absent from the id: a Library that
|
|
154
|
-
* changed identity when you clicked "Pages" would open a second tab per filter.
|
|
141
|
+
* Placeholder document for grid tabs: the grid never reads it, and save routes to the controller.
|
|
142
|
+
* Every tab takes its own `structuredClone` of it.
|
|
155
143
|
*/
|
|
144
|
+
export const GRID_STUB_DOCUMENT = { children: [], tagName: "div" };
|
|
145
|
+
|
|
146
|
+
/** The virtual sources a grid tab id can name. */
|
|
156
147
|
export type GridTabRef =
|
|
157
148
|
| { kind: "pages" }
|
|
158
|
-
| { kind: "library" }
|
|
159
149
|
| { kind: "collection"; name: string }
|
|
160
150
|
| { kind: "data"; connection: string; table: string };
|
|
161
151
|
|
|
@@ -165,9 +155,6 @@ export function makeGridTabId(ref: GridTabRef): string {
|
|
|
165
155
|
case "pages": {
|
|
166
156
|
return `${GRID_SCHEME}pages`;
|
|
167
157
|
}
|
|
168
|
-
case "library": {
|
|
169
|
-
return `${GRID_SCHEME}library`;
|
|
170
|
-
}
|
|
171
158
|
case "collection": {
|
|
172
159
|
return `${GRID_SCHEME}collection/${encodeURIComponent(ref.name)}`;
|
|
173
160
|
}
|
|
@@ -191,9 +178,6 @@ export function parseGridTabId(id: string): GridTabRef | null {
|
|
|
191
178
|
if (parts[0] === "pages" && parts.length === 1) {
|
|
192
179
|
return { kind: "pages" };
|
|
193
180
|
}
|
|
194
|
-
if (parts[0] === "library" && parts.length === 1) {
|
|
195
|
-
return { kind: "library" };
|
|
196
|
-
}
|
|
197
181
|
if (parts[0] === "collection" && parts.length === 2 && parts[1]) {
|
|
198
182
|
return { kind: "collection", name: decodeURIComponent(parts[1]) };
|
|
199
183
|
}
|
|
@@ -208,11 +192,8 @@ export function parseGridTabId(id: string): GridTabRef | null {
|
|
|
208
192
|
}
|
|
209
193
|
|
|
210
194
|
/**
|
|
211
|
-
* Short human label for a virtual tab ("posts · grid", "users @ main · grid", "Pages · grid").
|
|
212
|
-
*
|
|
213
|
-
* The Library is just "Library": the `· grid` suffix distinguishes a grid over a source from the
|
|
214
|
-
* document tab of the same name, and the Library has no document tab to be confused with — nor is a
|
|
215
|
-
* grid what it is, only what one of its layouts draws.
|
|
195
|
+
* Short human label for a virtual tab ("posts · grid", "users @ main · grid", "Pages · grid"). The
|
|
196
|
+
* `· grid` suffix distinguishes a grid over a source from the document tab of the same name.
|
|
216
197
|
*/
|
|
217
198
|
export function gridTabLabel(id: string): string | null {
|
|
218
199
|
const ref = parseGridTabId(id);
|
|
@@ -223,9 +204,6 @@ export function gridTabLabel(id: string): string | null {
|
|
|
223
204
|
case "pages": {
|
|
224
205
|
return "Pages · grid";
|
|
225
206
|
}
|
|
226
|
-
case "library": {
|
|
227
|
-
return "Library";
|
|
228
|
-
}
|
|
229
207
|
case "collection": {
|
|
230
208
|
return `${ref.name} · grid`;
|
|
231
209
|
}
|
package/src/grid/grid-view.ts
CHANGED
|
@@ -37,6 +37,7 @@ import type {
|
|
|
37
37
|
ColumnComponent,
|
|
38
38
|
ColumnDefinition,
|
|
39
39
|
RowComponent,
|
|
40
|
+
RowData,
|
|
40
41
|
} from "tabulator-tables";
|
|
41
42
|
import type { GridCellValue, GridColumn } from "./grid-source";
|
|
42
43
|
import type { GridController } from "./grid-controller";
|
|
@@ -51,6 +52,12 @@ export interface GridView {
|
|
|
51
52
|
getSelectedRowKeys: () => string[];
|
|
52
53
|
/** Local text filter across all columns (empty clears). */
|
|
53
54
|
setSearch: (term: string) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Select one row's cells and scroll it into view, once the table is built.
|
|
57
|
+
*
|
|
58
|
+
* @returns False when no row the table shows carries the key (filtered out, or gone).
|
|
59
|
+
*/
|
|
60
|
+
revealRow: (rowKey: string) => Promise<boolean>;
|
|
54
61
|
destroy: () => void;
|
|
55
62
|
}
|
|
56
63
|
|
|
@@ -89,7 +96,7 @@ function makeHost(className: string): HTMLElement {
|
|
|
89
96
|
return host;
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
function sorterForColumn(column: GridColumn): ColumnDefinition["sorter"] {
|
|
99
|
+
function sorterForColumn(column: GridColumn): ColumnDefinition<GridCellValue>["sorter"] {
|
|
93
100
|
switch (column.kind) {
|
|
94
101
|
case "number": {
|
|
95
102
|
return "number";
|
|
@@ -98,8 +105,7 @@ function sorterForColumn(column: GridColumn): ColumnDefinition["sorter"] {
|
|
|
98
105
|
return "boolean";
|
|
99
106
|
}
|
|
100
107
|
case "array": {
|
|
101
|
-
return (a:
|
|
102
|
-
cellToText(a as GridCellValue).localeCompare(cellToText(b as GridCellValue));
|
|
108
|
+
return (a: GridCellValue, b: GridCellValue) => cellToText(a).localeCompare(cellToText(b));
|
|
103
109
|
}
|
|
104
110
|
default: {
|
|
105
111
|
return "string";
|
|
@@ -119,9 +125,9 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
119
125
|
let built = false;
|
|
120
126
|
let pendingRefresh = false;
|
|
121
127
|
|
|
122
|
-
const rowKeyOf = (row: RowComponent) => String(row.getData()[ROW_KEY_FIELD] ?? "");
|
|
128
|
+
const rowKeyOf = (row: RowComponent<GridCellValue>) => String(row.getData()[ROW_KEY_FIELD] ?? "");
|
|
123
129
|
|
|
124
|
-
const paintRow = (row: RowComponent) => {
|
|
130
|
+
const paintRow = (row: RowComponent<GridCellValue>) => {
|
|
125
131
|
const rowState = buffer.rowState(rowKeyOf(row));
|
|
126
132
|
const el = row.getElement();
|
|
127
133
|
el.classList.toggle("jx-grid-row--pending-delete", rowState === "pending-delete");
|
|
@@ -129,7 +135,7 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
129
135
|
el.classList.toggle("jx-grid-row--stale", rowState === "stale");
|
|
130
136
|
};
|
|
131
137
|
|
|
132
|
-
const paintCell = (cell: CellComponent) => {
|
|
138
|
+
const paintCell = (cell: CellComponent<GridCellValue>) => {
|
|
133
139
|
const cellState = buffer.cellState(rowKeyOf(cell.getRow()), cell.getField());
|
|
134
140
|
const el = cell.getElement();
|
|
135
141
|
el.classList.toggle("jx-grid-cell--dirty", cellState === "dirty");
|
|
@@ -147,10 +153,11 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
147
153
|
(column.editable || (column.insertOnly === true && buffer.isInsertKey(rowKey))) &&
|
|
148
154
|
buffer.rowState(rowKey) !== "pending-delete";
|
|
149
155
|
|
|
150
|
-
const columnDefs: ColumnDefinition[] = columns.map((column) => {
|
|
156
|
+
const columnDefs: ColumnDefinition<GridCellValue>[] = columns.map((column) => {
|
|
151
157
|
const baseFormatter = formatterForColumn(column, makeHost);
|
|
152
158
|
return {
|
|
153
|
-
editable: (cell: CellComponent) =>
|
|
159
|
+
editable: (cell: CellComponent<GridCellValue>) =>
|
|
160
|
+
cellEditable(column, rowKeyOf(cell.getRow())),
|
|
154
161
|
// Image/reference cells edit through an anchored popover (dblclick), not an editor session.
|
|
155
162
|
editor: hasPopoverEditor(column) ? undefined : editorForColumn(column, makeHost),
|
|
156
163
|
field: column.field,
|
|
@@ -215,12 +222,17 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
215
222
|
|
|
216
223
|
controller.bindView({ refreshData });
|
|
217
224
|
|
|
218
|
-
table
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
/* Settles once the table is built: a reveal asked for before then waits for it, because the
|
|
226
|
+
engine has no rows to find, and its default range would replace the one the reveal drew. */
|
|
227
|
+
const whenBuilt = new Promise<void>((resolve) => {
|
|
228
|
+
table.on("tableBuilt", () => {
|
|
229
|
+
built = true;
|
|
230
|
+
if (pendingRefresh) {
|
|
231
|
+
pendingRefresh = false;
|
|
232
|
+
refreshData();
|
|
233
|
+
}
|
|
234
|
+
resolve();
|
|
235
|
+
});
|
|
224
236
|
});
|
|
225
237
|
|
|
226
238
|
/*
|
|
@@ -254,7 +266,7 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
254
266
|
};
|
|
255
267
|
const unregisterProbe = registerGridProbe(probe);
|
|
256
268
|
|
|
257
|
-
table.on("cellEdited", (cell: CellComponent) => {
|
|
269
|
+
table.on("cellEdited", (cell: CellComponent<GridCellValue>) => {
|
|
258
270
|
if (suppress) {
|
|
259
271
|
return;
|
|
260
272
|
}
|
|
@@ -267,7 +279,7 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
267
279
|
const value = coerceCellInput(cell.getValue(), column);
|
|
268
280
|
buffer.setCell(rowKey, field, value);
|
|
269
281
|
// Normalize what the table shows to the typed value (e.g. pasted "42" in a number column).
|
|
270
|
-
if (!cellValuesEqual(value, cell.getValue()
|
|
282
|
+
if (!cellValuesEqual(value, cell.getValue())) {
|
|
271
283
|
suppress = true;
|
|
272
284
|
try {
|
|
273
285
|
cell.setValue(value, true);
|
|
@@ -287,7 +299,7 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
287
299
|
saveGridLayout(gridId, { order: ordered.map((c) => c.getField()) });
|
|
288
300
|
});
|
|
289
301
|
|
|
290
|
-
table.on("cellDblClick", (_event:
|
|
302
|
+
table.on("cellDblClick", (_event: MouseEvent, cell: CellComponent<GridCellValue>) => {
|
|
291
303
|
const column = columnByField.get(cell.getField());
|
|
292
304
|
const rowKey = rowKeyOf(cell.getRow());
|
|
293
305
|
if (!column || !hasPopoverEditor(column) || !cellEditable(column, rowKey)) {
|
|
@@ -383,6 +395,20 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
383
395
|
|
|
384
396
|
refreshData,
|
|
385
397
|
|
|
398
|
+
async revealRow(rowKey: string) {
|
|
399
|
+
await whenBuilt;
|
|
400
|
+
const row = table.getRow(rowKey);
|
|
401
|
+
const cells = row ? row.getCells() : [];
|
|
402
|
+
const [first] = cells;
|
|
403
|
+
const last = cells.at(-1);
|
|
404
|
+
if (!first || !last) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
table.addRange(first, last);
|
|
408
|
+
await table.scrollToRow(rowKey, "center", false).catch(() => {});
|
|
409
|
+
return true;
|
|
410
|
+
},
|
|
411
|
+
|
|
386
412
|
setSearch(term: string) {
|
|
387
413
|
const query = term.trim().toLowerCase();
|
|
388
414
|
if (query === "") {
|
|
@@ -390,12 +416,8 @@ export function createGridView(host: HTMLElement, controller: GridController): G
|
|
|
390
416
|
return;
|
|
391
417
|
}
|
|
392
418
|
const fields = columns.map((column) => column.field);
|
|
393
|
-
table.setFilter((data:
|
|
394
|
-
fields.some((field) =>
|
|
395
|
-
cellToText(data[field] as GridCellValue)
|
|
396
|
-
.toLowerCase()
|
|
397
|
-
.includes(query),
|
|
398
|
-
),
|
|
419
|
+
table.setFilter((data: RowData<GridCellValue>) =>
|
|
420
|
+
fields.some((field) => cellToText(data[field]).toLowerCase().includes(query)),
|
|
399
421
|
);
|
|
400
422
|
},
|
|
401
423
|
};
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
validateRedirects,
|
|
42
42
|
} from "./redirects";
|
|
43
43
|
import { optionalStringArg, stringProperty } from "../commands/command-args";
|
|
44
|
+
import { GRID_STUB_DOCUMENT } from "./grid-source";
|
|
44
45
|
import type { RedirectConfig, RedirectRule, RedirectTarget } from "./redirects";
|
|
45
46
|
import type {
|
|
46
47
|
CommitResult,
|
|
@@ -67,8 +68,10 @@ export const REDIRECTS_TAB_ID = "grid://redirects";
|
|
|
67
68
|
/** Who the Problems list attributes a redirect finding to. Also the key it clears them by. */
|
|
68
69
|
export const REDIRECTS_PROBLEM_SOURCE = "Redirects";
|
|
69
70
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
71
|
+
/** The one key a redirect commit patches; `undefined` removes `redirects` from project.json. */
|
|
72
|
+
interface RedirectsPatch {
|
|
73
|
+
redirects: RedirectConfig | undefined;
|
|
74
|
+
}
|
|
72
75
|
|
|
73
76
|
/** Extensions the router treats as pages. Anything else under `pages/` is an asset, not a route. */
|
|
74
77
|
const PAGE_EXTENSIONS = [".json", ".md", ".html"];
|
|
@@ -120,7 +123,7 @@ export function redirectRow(rule: RedirectRule, index: number): GridRow {
|
|
|
120
123
|
|
|
121
124
|
/** The live redirects map, straight off the configuration document. */
|
|
122
125
|
function currentConfig(): RedirectConfig | undefined {
|
|
123
|
-
return projectState?.projectConfig?.redirects
|
|
126
|
+
return projectState?.projectConfig?.redirects;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
/**
|
|
@@ -133,7 +136,10 @@ function parseTarget(raw: string): RedirectTarget {
|
|
|
133
136
|
return REWRITE;
|
|
134
137
|
}
|
|
135
138
|
const value = Number(trimmed);
|
|
136
|
-
|
|
139
|
+
/* SAFETY: deliberately unchecked, per the doc above. Every rule built from cells reaches
|
|
140
|
+
`ruleErrors` in `commit()`, which tests `status` against REDIRECT_TARGETS and refuses the whole
|
|
141
|
+
batch before `configFromRules` can write an unrecognised target to project.json. */
|
|
142
|
+
return (Number.isInteger(value) ? value : trimmed) as RedirectTarget;
|
|
137
143
|
}
|
|
138
144
|
|
|
139
145
|
/** A cell bag back to a rule. An unrecognised target is refused by {@link ruleErrors}. */
|
|
@@ -327,9 +333,12 @@ export function createRedirectsSource(): GridSource {
|
|
|
327
333
|
// `undefined` CLEARS the key (see `commitProjectConfig`): an empty table should leave no
|
|
328
334
|
// `"redirects": {}` behind. The local type spells the undefined out, which
|
|
329
335
|
// `exactOptionalPropertyTypes` will not let `Partial<ProjectConfig>` do.
|
|
330
|
-
const patch:
|
|
336
|
+
const patch: RedirectsPatch = {
|
|
331
337
|
redirects: next.length > 0 ? configFromRules(next) : undefined,
|
|
332
338
|
};
|
|
339
|
+
/* SAFETY: `commitProjectConfig` spreads the patch onto the document and documents an own
|
|
340
|
+
`undefined` as "clear this key"; the only other value is a RedirectConfig, which is
|
|
341
|
+
structurally ProjectConfig["redirects"]. Only the spelling of "absent" differs. */
|
|
333
342
|
const commit = await commitProjectConfig(patch as Partial<ProjectConfig>);
|
|
334
343
|
if (!commit.ok) {
|
|
335
344
|
// `commitProjectConfig` already filed the Problem; repeating it would list one failure
|
package/src/grid/redirects.ts
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { REDIRECT_STATUSES } from "@jxsuite/schema/defs";
|
|
29
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
29
30
|
import { parseCsv } from "./csv-codec";
|
|
30
31
|
|
|
31
32
|
/** One redirect rule, flattened out of `project.json`'s two accepted spellings. */
|
|
@@ -128,17 +129,17 @@ export function routePattern(route: string): string {
|
|
|
128
129
|
/** Flatten `project.json`'s redirects map into rules, in declaration order. */
|
|
129
130
|
export function rulesFromConfig(config: RedirectConfig | undefined): RedirectRule[] {
|
|
130
131
|
return Object.entries(config ?? {}).map(([source, target]) => {
|
|
131
|
-
if (
|
|
132
|
+
if (isString(target)) {
|
|
132
133
|
return { destination: target, source, status: DEFAULT_REDIRECT_STATUS };
|
|
133
134
|
}
|
|
134
135
|
if ("rewrite" in target) {
|
|
135
136
|
return { destination: target.destination, source, status: REWRITE };
|
|
136
137
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
};
|
|
138
|
+
/* SAFETY: project.json's schema declares `status` as `enum: [...REDIRECT_STATUSES]`, the same
|
|
139
|
+
constant RedirectTarget is built from. A hand-edited file that breaks it is still caught:
|
|
140
|
+
every rule passes the grid's `ruleErrors` status check before anything is written back. */
|
|
141
|
+
const status = (target.status ?? DEFAULT_REDIRECT_STATUS) as RedirectTarget;
|
|
142
|
+
return { destination: target.destination, source, status };
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -151,7 +152,7 @@ export function rulesFromConfig(config: RedirectConfig | undefined): RedirectRul
|
|
|
151
152
|
* level down. A later duplicate source wins, which is what a JSON object means anyway; the grid
|
|
152
153
|
* refuses duplicates before they get here.
|
|
153
154
|
*/
|
|
154
|
-
export function configFromRules(rules: readonly RedirectRule[])
|
|
155
|
+
export function configFromRules(rules: readonly RedirectRule[]) {
|
|
155
156
|
const config: RedirectConfig = {};
|
|
156
157
|
for (const rule of rules) {
|
|
157
158
|
if (rule.status === REWRITE) {
|
|
@@ -189,11 +190,14 @@ function ruleFor(rules: readonly RedirectRule[], path: string): RedirectRule | u
|
|
|
189
190
|
);
|
|
190
191
|
}
|
|
191
192
|
|
|
193
|
+
/** The path a chain of rules walks, and whether it came back to a source it already visited. */
|
|
194
|
+
interface RedirectWalk {
|
|
195
|
+
path: string[];
|
|
196
|
+
looped: boolean;
|
|
197
|
+
}
|
|
198
|
+
|
|
192
199
|
/** Follow destinations from a rule until they stop resolving. Returns the path walked. */
|
|
193
|
-
function walk(
|
|
194
|
-
rules: readonly RedirectRule[],
|
|
195
|
-
start: RedirectRule,
|
|
196
|
-
): { path: string[]; looped: boolean } {
|
|
200
|
+
function walk(rules: readonly RedirectRule[], start: RedirectRule): RedirectWalk {
|
|
197
201
|
const path = [start.source];
|
|
198
202
|
const seen = new Set([normalizePath(start.source)]);
|
|
199
203
|
let current = start;
|
|
@@ -309,9 +313,7 @@ function parseStatus(token: string | undefined): RedirectTarget | null {
|
|
|
309
313
|
return REWRITE;
|
|
310
314
|
}
|
|
311
315
|
const value = Number(raw);
|
|
312
|
-
return (
|
|
313
|
-
? (value as RedirectTarget)
|
|
314
|
-
: null;
|
|
316
|
+
return REDIRECT_STATUSES.find((status) => status === value) ?? null;
|
|
315
317
|
}
|
|
316
318
|
|
|
317
319
|
/** Netlify/Cloudflare `_redirects`: `source destination [status]`, `#` comments, blank lines. */
|
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
* parser extension's `coerceCSVRows` (currency-stripped numbers, `"true"` booleans, comma-split
|
|
9
9
|
* arrays) so grid edits round-trip identically to the runtime content loader.
|
|
10
10
|
*/
|
|
11
|
+
import {
|
|
12
|
+
isBoolean,
|
|
13
|
+
isJsonObject,
|
|
14
|
+
isNonNullObject,
|
|
15
|
+
isNumber,
|
|
16
|
+
isString,
|
|
17
|
+
} from "@jxsuite/schema/guards";
|
|
18
|
+
import type { ContentTypeSchema, JsonValue } from "@jxsuite/schema/types";
|
|
11
19
|
import type { GridCellValue, GridColumn, GridColumnKind } from "./grid-source";
|
|
12
20
|
import type { JsonSchema } from "../ui/schema-form";
|
|
13
21
|
import { isMediaFormat } from "../utils/studio-utils";
|
|
@@ -93,17 +101,17 @@ export interface ColumnsFromSchemaOptions {
|
|
|
93
101
|
* required properties in declaration order, then the rest in declaration order.
|
|
94
102
|
*/
|
|
95
103
|
export function columnsFromSchema(
|
|
96
|
-
schema:
|
|
104
|
+
schema: ContentTypeSchema | null | undefined,
|
|
97
105
|
opts: ColumnsFromSchemaOptions = {},
|
|
98
106
|
): GridColumn[] {
|
|
99
|
-
const props = Object.entries(schema?.properties ?? {})
|
|
107
|
+
const props: [string, PropSchema][] = Object.entries(schema?.properties ?? {});
|
|
100
108
|
const required = new Set(schema?.required);
|
|
101
109
|
const readonly = new Set(opts.readonlyFields);
|
|
102
110
|
|
|
103
111
|
const columns = props.map(([field, prop]): GridColumn => {
|
|
104
112
|
const kind = readonly.has(field) ? "readonly" : kindForProp(prop);
|
|
105
113
|
const enumLen = Array.isArray(prop.enum)
|
|
106
|
-
? Math.max(...
|
|
114
|
+
? Math.max(...prop.enum.map((v) => String(v).length), 4)
|
|
107
115
|
: 0;
|
|
108
116
|
return {
|
|
109
117
|
editable: kind !== "readonly",
|
|
@@ -144,9 +152,10 @@ export function inferColumnsFromRows(
|
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
return fields.map((field): GridColumn => {
|
|
147
|
-
const values = sample
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
const values = sample.flatMap((row) => {
|
|
156
|
+
const value = row[field];
|
|
157
|
+
return value === null || value === undefined || value === "" ? [] : [value];
|
|
158
|
+
});
|
|
150
159
|
const kind = inferKind(values);
|
|
151
160
|
const maxLen = Math.max(...values.map((v) => cellToText(v).length), field.length, 4);
|
|
152
161
|
return {
|
|
@@ -167,14 +176,11 @@ function inferKind(values: Exclude<GridCellValue, null>[]): GridColumnKind {
|
|
|
167
176
|
return "array";
|
|
168
177
|
}
|
|
169
178
|
const texts = values.map(String);
|
|
170
|
-
if (
|
|
171
|
-
values.every((v) => typeof v === "boolean") ||
|
|
172
|
-
texts.every((t) => /^(true|false)$/i.test(t))
|
|
173
|
-
) {
|
|
179
|
+
if (values.every((v) => isBoolean(v)) || texts.every((t) => /^(true|false)$/i.test(t))) {
|
|
174
180
|
return "boolean";
|
|
175
181
|
}
|
|
176
182
|
if (
|
|
177
|
-
values.every((v) =>
|
|
183
|
+
values.every((v) => isNumber(v)) ||
|
|
178
184
|
texts.every((t) => t.trim() !== "" && !Number.isNaN(Number(t.replaceAll(/[$€£¥,\s]/g, ""))))
|
|
179
185
|
) {
|
|
180
186
|
return "number";
|
|
@@ -194,13 +200,13 @@ function inferKind(values: Exclude<GridCellValue, null>[]): GridColumnKind {
|
|
|
194
200
|
* Coerce editor/clipboard input to the column's typed value. Empty input clears to null. Number and
|
|
195
201
|
* array semantics mirror the parser extension's coerceCSVRows.
|
|
196
202
|
*/
|
|
197
|
-
export function coerceCellInput(raw:
|
|
203
|
+
export function coerceCellInput(raw: JsonValue | undefined, col: GridColumn): GridCellValue {
|
|
198
204
|
if (raw === null || raw === undefined) {
|
|
199
205
|
return null;
|
|
200
206
|
}
|
|
201
207
|
switch (col.kind) {
|
|
202
208
|
case "number": {
|
|
203
|
-
if (
|
|
209
|
+
if (isNumber(raw)) {
|
|
204
210
|
return Number.isNaN(raw) ? null : raw;
|
|
205
211
|
}
|
|
206
212
|
const cleaned = String(raw)
|
|
@@ -213,7 +219,7 @@ export function coerceCellInput(raw: unknown, col: GridColumn): GridCellValue {
|
|
|
213
219
|
return Number.isNaN(n) ? null : n;
|
|
214
220
|
}
|
|
215
221
|
case "boolean": {
|
|
216
|
-
if (
|
|
222
|
+
if (isBoolean(raw)) {
|
|
217
223
|
return raw;
|
|
218
224
|
}
|
|
219
225
|
return String(raw).trim().toLowerCase() === "true";
|
|
@@ -233,9 +239,9 @@ export function coerceCellInput(raw: unknown, col: GridColumn): GridCellValue {
|
|
|
233
239
|
case "reference": {
|
|
234
240
|
// Relationship VALUES are plain target-entry ids ("jane-doe") — the $ref lives on the
|
|
235
241
|
// Schema property, not in the data (specs/relationships.md; parser resolveContentTypeRefs).
|
|
236
|
-
if (
|
|
237
|
-
const ref =
|
|
238
|
-
return
|
|
242
|
+
if (isJsonObject(raw) && "$ref" in raw) {
|
|
243
|
+
const ref = raw.$ref;
|
|
244
|
+
return isString(ref) && ref !== "" ? ref : null;
|
|
239
245
|
}
|
|
240
246
|
const text = String(raw).trim();
|
|
241
247
|
return text === "" ? null : text;
|
|
@@ -248,14 +254,14 @@ export function coerceCellInput(raw: unknown, col: GridColumn): GridCellValue {
|
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
/** Plain-text projection of a cell value — display, clipboard, and CSV share it. */
|
|
251
|
-
export function cellToText(value: GridCellValue): string {
|
|
257
|
+
export function cellToText(value: GridCellValue | undefined): string {
|
|
252
258
|
if (value === null || value === undefined) {
|
|
253
259
|
return "";
|
|
254
260
|
}
|
|
255
261
|
if (Array.isArray(value)) {
|
|
256
262
|
return value.join(", ");
|
|
257
263
|
}
|
|
258
|
-
if (
|
|
264
|
+
if (isNonNullObject(value)) {
|
|
259
265
|
return value.$ref;
|
|
260
266
|
}
|
|
261
267
|
return String(value);
|