@jxsuite/studio 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +21080 -32585
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -53
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +30 -1
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +7 -1
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* Activity — where a long operation lives while it runs, and what it leaves behind (plan §7.3).
|
|
4
|
+
*
|
|
5
|
+
* What this replaces: `ui/progress-modal.ts` was **the only surface in Studio with a real error
|
|
6
|
+
* view** — a red headline, the captured log in a `<pre>`, an explicit Close — and it had four call
|
|
7
|
+
* sites, all package operations. It blocked the whole app, offered no cancel, and vanished
|
|
8
|
+
* completely on success, so a `bun install` that hung had no exit and one that failed had a log you
|
|
9
|
+
* could read exactly once. Every OTHER long operation — git clone, publish, media upload, site
|
|
10
|
+
* import, project open — got a three-second grey line or nothing at all.
|
|
11
|
+
*
|
|
12
|
+
* An activity is a **record**, like a notification and a command:
|
|
13
|
+
*
|
|
14
|
+
* - It is **persistent** — a finished operation stays on the list, with its log, until the list is
|
|
15
|
+
* cleared, so "what did the import actually do?" is answerable after the fact;
|
|
16
|
+
* - It is **inspectable** — the log is the same captured output the modal used to show, and it is
|
|
17
|
+
* attached to the entry rather than to a modal that is about to close;
|
|
18
|
+
* - It can be **cancelled** — an operation that hands over a `cancel` callback gets a Cancel button
|
|
19
|
+
* on its row, which is the affordance a hung install has never had;
|
|
20
|
+
* - And it **fails into Problems** — {@link ActivityHandle.fail} raises a `notify.error` carrying the
|
|
21
|
+
* log as its `detail`, so the failure outlives the run and carries a Retry command. That is
|
|
22
|
+
* §7.3's "the progress modal's error view is promoted into Problems", in one function.
|
|
23
|
+
*
|
|
24
|
+
* **Nothing here blocks.** `showProgressModal` still exists for the four dependency-install sites
|
|
25
|
+
* §7.3 keeps blocking, and it is now a thin front end over {@link beginActivity} — so even the
|
|
26
|
+
* blocking case leaves an inspectable entry behind, and closing the modal no longer loses it.
|
|
27
|
+
*
|
|
28
|
+
* `services/idle.ts` reads {@link activityIdleBlockers}: an open operation means the app is not
|
|
29
|
+
* settled, which is the §13.6 S4 obligation every phase's checklist carries.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { html, nothing } from "lit-html";
|
|
33
|
+
import { renderDeployChecklist } from "../publish/deploy-checklist";
|
|
34
|
+
import { repeat } from "lit-html/directives/repeat.js";
|
|
35
|
+
import { reactive } from "../reactivity";
|
|
36
|
+
import { now } from "../services/clock";
|
|
37
|
+
import { notify } from "../services/notify";
|
|
38
|
+
import { registerPanel } from "./panel-registry";
|
|
39
|
+
import { renderEmptyState } from "./empty-state";
|
|
40
|
+
import type { PanelBody } from "./panel-registry";
|
|
41
|
+
import type { TemplateResult } from "lit-html";
|
|
42
|
+
|
|
43
|
+
/** How an operation ended, or that it has not. */
|
|
44
|
+
export const ACTIVITY_STATES = ["running", "done", "failed", "cancelled"] as const;
|
|
45
|
+
|
|
46
|
+
export type ActivityState = (typeof ACTIVITY_STATES)[number];
|
|
47
|
+
|
|
48
|
+
/** One named phase of an operation — "Install dependencies", "Sync with the remote". */
|
|
49
|
+
export interface ActivityStep {
|
|
50
|
+
label: string;
|
|
51
|
+
state: "pending" | "running" | "done" | "failed";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* One operation, as recorded.
|
|
56
|
+
*
|
|
57
|
+
* Mutable and reactive on purpose: an activity is the one record in the app that CHANGES while you
|
|
58
|
+
* watch it, which is the whole difference between it and a
|
|
59
|
+
* {@link import("../services/notify") .Notification}. A host repaints by reading it.
|
|
60
|
+
*/
|
|
61
|
+
export interface ActivityEntry {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
readonly title: string;
|
|
64
|
+
/** The line under the title — what the operation is doing right now. */
|
|
65
|
+
status: string;
|
|
66
|
+
state: ActivityState;
|
|
67
|
+
/** The captured output, one entry per chunk. Rendered in the expanded row. */
|
|
68
|
+
log: string[];
|
|
69
|
+
steps: ActivityStep[];
|
|
70
|
+
/** Epoch ms from {@link now}, so a pinned clock pins the duration a row prints. */
|
|
71
|
+
readonly startedAt: number;
|
|
72
|
+
endedAt: number | null;
|
|
73
|
+
/** Who is running it: "Packages", "Source Control", "Publish". Printed beside the title. */
|
|
74
|
+
readonly source?: string;
|
|
75
|
+
/** Whether a `cancel` callback was handed over — the row draws Cancel iff this is true. */
|
|
76
|
+
cancellable: boolean;
|
|
77
|
+
/** Whether this row's log is unfolded. A view flag, on the record, so a repaint keeps it. */
|
|
78
|
+
expanded: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Every operation this session, oldest first — running and finished alike.
|
|
83
|
+
*
|
|
84
|
+
* Exported as the array rather than behind a getter for the same reason `notify`'s stores are: that
|
|
85
|
+
* is what makes it trackable, so a lit render effect that reads it re-runs when an operation
|
|
86
|
+
* starts, logs a line or ends, with no subscription to remember to release.
|
|
87
|
+
*/
|
|
88
|
+
export const activities: ActivityEntry[] = reactive([]);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* How many FINISHED entries are kept. Running ones are never retired — an operation the app is
|
|
92
|
+
* still doing is not history, and dropping it would take its Cancel button with it.
|
|
93
|
+
*/
|
|
94
|
+
export const MAX_FINISHED_ACTIVITIES = 20;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Entry id → the callback that stops it.
|
|
98
|
+
*
|
|
99
|
+
* Held beside the record rather than on it: a closure inside a reactive proxy is a value effects
|
|
100
|
+
* would track and nothing would ever compare, and the record is otherwise plain data. The record
|
|
101
|
+
* carries `cancellable` so a renderer never needs this map.
|
|
102
|
+
*/
|
|
103
|
+
const _cancels = new Map<string, () => void>();
|
|
104
|
+
|
|
105
|
+
let _seq = 0;
|
|
106
|
+
|
|
107
|
+
/** Monotonic within a page load, and stable enough to be a lit `repeat` key. */
|
|
108
|
+
function nextId(): string {
|
|
109
|
+
_seq += 1;
|
|
110
|
+
return `a${_seq}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Whether an entry has stopped. */
|
|
114
|
+
export function isFinished(entry: ActivityEntry): boolean {
|
|
115
|
+
return entry.state !== "running";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Drop the oldest finished entries once there are more than {@link MAX_FINISHED_ACTIVITIES}. */
|
|
119
|
+
function retireOldest(): void {
|
|
120
|
+
let excess = activities.filter((entry) => isFinished(entry)).length - MAX_FINISHED_ACTIVITIES;
|
|
121
|
+
while (excess > 0) {
|
|
122
|
+
const at = activities.findIndex((entry) => isFinished(entry));
|
|
123
|
+
if (at === -1) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
_cancels.delete(activities[at]!.id);
|
|
127
|
+
activities.splice(at, 1);
|
|
128
|
+
excess -= 1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** What {@link beginActivity} is told about an operation up front. */
|
|
133
|
+
export interface ActivityOptions {
|
|
134
|
+
/** What the operation IS — "Open project", "Update dependencies". Never changes. */
|
|
135
|
+
title: string;
|
|
136
|
+
/** What it is doing right now. Changes as it goes. */
|
|
137
|
+
status?: string;
|
|
138
|
+
/** Who is running it — "Packages", "Source Control". Groups nothing yet; printed on the row. */
|
|
139
|
+
source?: string;
|
|
140
|
+
/** The plan, declared up front so the row shows how far along it is. */
|
|
141
|
+
steps?: readonly string[];
|
|
142
|
+
/**
|
|
143
|
+
* Stop the operation.
|
|
144
|
+
*
|
|
145
|
+
* Its presence is what draws the Cancel button, so an operation that cannot honestly be stopped
|
|
146
|
+
* must not pass one — a Cancel that does nothing is the failure §7 exists to end, restated as a
|
|
147
|
+
* button.
|
|
148
|
+
*/
|
|
149
|
+
cancel?: () => void;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** The live handle an operation drives its own entry through. */
|
|
153
|
+
export interface ActivityHandle {
|
|
154
|
+
readonly id: string;
|
|
155
|
+
/** The record itself, for a caller that wants to read its own log back. */
|
|
156
|
+
readonly entry: ActivityEntry;
|
|
157
|
+
/** Replace the line under the title. */
|
|
158
|
+
setStatus: (text: string) => void;
|
|
159
|
+
/** Append captured output. Blank chunks are dropped, so a trailing newline is not a log line. */
|
|
160
|
+
log: (chunk: string) => void;
|
|
161
|
+
/** Mark `label` as the running step; every step before it is done. Appends an unplanned one. */
|
|
162
|
+
step: (label: string) => void;
|
|
163
|
+
/** Finish successfully. */
|
|
164
|
+
done: (status?: string) => void;
|
|
165
|
+
/**
|
|
166
|
+
* Finish with a failure — and raise the Problem that outlives it.
|
|
167
|
+
*
|
|
168
|
+
* The log goes into the notification's `detail`, so the persistent, inspectable error view §7.3
|
|
169
|
+
* asks for is the Problems row, not a modal that has to stay open to be read.
|
|
170
|
+
*/
|
|
171
|
+
fail: (message: string, opts?: { action?: string; path?: string }) => void;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Start recording an operation.
|
|
176
|
+
*
|
|
177
|
+
* @param {ActivityOptions} options
|
|
178
|
+
* @returns {ActivityHandle}
|
|
179
|
+
*/
|
|
180
|
+
export function beginActivity(options: ActivityOptions): ActivityHandle {
|
|
181
|
+
const entry: ActivityEntry = {
|
|
182
|
+
cancellable: options.cancel !== undefined,
|
|
183
|
+
endedAt: null,
|
|
184
|
+
expanded: false,
|
|
185
|
+
id: nextId(),
|
|
186
|
+
log: [],
|
|
187
|
+
startedAt: now(),
|
|
188
|
+
state: "running",
|
|
189
|
+
status: options.status ?? "",
|
|
190
|
+
steps: (options.steps ?? []).map((label) => ({ label, state: "pending" as const })),
|
|
191
|
+
title: options.title,
|
|
192
|
+
...(options.source === undefined ? {} : { source: options.source }),
|
|
193
|
+
};
|
|
194
|
+
if (options.cancel) {
|
|
195
|
+
_cancels.set(entry.id, options.cancel);
|
|
196
|
+
}
|
|
197
|
+
activities.push(entry);
|
|
198
|
+
// The PROXY, not the literal: writing through the raw object a `reactive()` array was handed
|
|
199
|
+
// Skips every effect depending on it, which is the one bug that would make a running operation
|
|
200
|
+
// Look frozen. Read back before anything is retired, so the reference is unambiguous.
|
|
201
|
+
const live = activities.at(-1) as ActivityEntry;
|
|
202
|
+
retireOldest();
|
|
203
|
+
|
|
204
|
+
const finish = (state: ActivityState, status?: string) => {
|
|
205
|
+
if (isFinished(live)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
live.state = state;
|
|
209
|
+
live.endedAt = now();
|
|
210
|
+
if (status !== undefined) {
|
|
211
|
+
live.status = status;
|
|
212
|
+
}
|
|
213
|
+
for (const step of live.steps) {
|
|
214
|
+
step.state = step.state === "done" ? "done" : state === "done" ? "done" : "failed";
|
|
215
|
+
}
|
|
216
|
+
live.cancellable = false;
|
|
217
|
+
_cancels.delete(live.id);
|
|
218
|
+
retireOldest();
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
done(status?: string) {
|
|
223
|
+
finish("done", status);
|
|
224
|
+
},
|
|
225
|
+
entry: live,
|
|
226
|
+
fail(message: string, opts: { action?: string; path?: string } = {}) {
|
|
227
|
+
// An operation that has already ended does not get to raise a Problem: the first outcome is
|
|
228
|
+
// The one that happened, and a late `fail()` after a successful `done()` would put a failure
|
|
229
|
+
// On a list whose whole promise is that everything on it still needs fixing.
|
|
230
|
+
if (isFinished(live)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const detail = live.log.join("\n");
|
|
234
|
+
finish("failed", message);
|
|
235
|
+
notify.error(message, {
|
|
236
|
+
source: live.source ?? live.title,
|
|
237
|
+
...(detail === "" ? {} : { detail }),
|
|
238
|
+
...(opts.action === undefined ? {} : { action: opts.action }),
|
|
239
|
+
...(opts.path === undefined ? {} : { path: opts.path }),
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
id: live.id,
|
|
243
|
+
log(chunk: string) {
|
|
244
|
+
const text = chunk.replace(/\s+$/, "");
|
|
245
|
+
if (text !== "") {
|
|
246
|
+
live.log.push(text);
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
setStatus(text: string) {
|
|
250
|
+
if (!isFinished(live)) {
|
|
251
|
+
live.status = text;
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
step(label: string) {
|
|
255
|
+
let at = live.steps.findIndex((step) => step.label === label);
|
|
256
|
+
if (at === -1) {
|
|
257
|
+
live.steps.push({ label, state: "pending" });
|
|
258
|
+
at = live.steps.length - 1;
|
|
259
|
+
}
|
|
260
|
+
for (const [index, step] of live.steps.entries()) {
|
|
261
|
+
step.state = index < at ? "done" : index === at ? "running" : step.state;
|
|
262
|
+
}
|
|
263
|
+
live.status = label;
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** One entry by id, or `undefined`. */
|
|
269
|
+
export function activityById(id: string): ActivityEntry | undefined {
|
|
270
|
+
return activities.find((entry) => entry.id === id);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Everything still running, oldest first — what the badge counts and idle waits on. */
|
|
274
|
+
export function runningActivities(): ActivityEntry[] {
|
|
275
|
+
return activities.filter((entry) => !isFinished(entry));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Stop an operation: run its callback, mark it cancelled. Returns whether anything was stopped.
|
|
280
|
+
*
|
|
281
|
+
* The callback runs BEFORE the state changes, so an implementation that throws leaves the entry
|
|
282
|
+
* honestly still running rather than claiming a cancellation that did not happen.
|
|
283
|
+
*/
|
|
284
|
+
export function cancelActivity(id: string): boolean {
|
|
285
|
+
const entry = activityById(id);
|
|
286
|
+
const stop = _cancels.get(id);
|
|
287
|
+
if (!entry || !stop || isFinished(entry)) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
stop();
|
|
291
|
+
_cancels.delete(id);
|
|
292
|
+
entry.state = "cancelled";
|
|
293
|
+
entry.endedAt = now();
|
|
294
|
+
entry.cancellable = false;
|
|
295
|
+
entry.status = "Cancelled";
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Drop every finished entry. Returns how many went. Running operations are kept. */
|
|
300
|
+
export function clearFinishedActivities(): number {
|
|
301
|
+
const kept = activities.filter((entry) => !isFinished(entry));
|
|
302
|
+
const removed = activities.length - kept.length;
|
|
303
|
+
activities.splice(0, activities.length, ...kept);
|
|
304
|
+
return removed;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Clear the whole list — tests, and the "close project" path. */
|
|
308
|
+
export function resetActivities(): void {
|
|
309
|
+
activities.splice(0);
|
|
310
|
+
_cancels.clear();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* What is still running, as `services/idle.ts` phrases it.
|
|
315
|
+
*
|
|
316
|
+
* §13.6 S4 puts this on every phase's checklist: an app with an operation in flight has not
|
|
317
|
+
* finished reacting, so a screenshot taken now photographs a half-done import. A FINISHED entry is
|
|
318
|
+
* not a blocker — the list stays on screen forever and waiting for it to empty would never settle.
|
|
319
|
+
*/
|
|
320
|
+
export function activityIdleBlockers(): readonly string[] {
|
|
321
|
+
return runningActivities().map(
|
|
322
|
+
(entry) => `activity: ${entry.title} — ${entry.status || "running"}`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ─── Rendering ────────────────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
/** The state glyphs. One character each: the row's job is a line of text, not an illustration. */
|
|
329
|
+
const STATE_ICON: Readonly<Record<ActivityState, string>> = {
|
|
330
|
+
cancelled: "⊘",
|
|
331
|
+
done: "✓",
|
|
332
|
+
failed: "✕",
|
|
333
|
+
running: "⋯",
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const STEP_ICON: Readonly<Record<ActivityStep["state"], string>> = {
|
|
337
|
+
done: "✓",
|
|
338
|
+
failed: "✕",
|
|
339
|
+
pending: "·",
|
|
340
|
+
running: "⋯",
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
/** How long it took, in the coarsest unit that is still true. */
|
|
344
|
+
export function activityDuration(entry: ActivityEntry, at: number = now()): string {
|
|
345
|
+
const ms = Math.max(0, (entry.endedAt ?? at) - entry.startedAt);
|
|
346
|
+
if (ms < 1000) {
|
|
347
|
+
return `${ms}ms`;
|
|
348
|
+
}
|
|
349
|
+
const seconds = Math.round(ms / 1000);
|
|
350
|
+
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function stepsTpl(entry: ActivityEntry): TemplateResult | typeof nothing {
|
|
354
|
+
if (entry.steps.length === 0) {
|
|
355
|
+
return nothing;
|
|
356
|
+
}
|
|
357
|
+
return html`<ol class="activity-steps">
|
|
358
|
+
${entry.steps.map(
|
|
359
|
+
(step) => html`<li class="activity-step activity-step--${step.state}">
|
|
360
|
+
<span class="activity-step-icon" aria-hidden="true">${STEP_ICON[step.state]}</span>
|
|
361
|
+
${step.label}
|
|
362
|
+
</li>`,
|
|
363
|
+
)}
|
|
364
|
+
</ol>`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function logTpl(entry: ActivityEntry): TemplateResult | typeof nothing {
|
|
368
|
+
if (entry.log.length === 0) {
|
|
369
|
+
return nothing;
|
|
370
|
+
}
|
|
371
|
+
return html`<button
|
|
372
|
+
class="activity-log-toggle"
|
|
373
|
+
aria-expanded=${entry.expanded ? "true" : "false"}
|
|
374
|
+
@click=${() => {
|
|
375
|
+
entry.expanded = !entry.expanded;
|
|
376
|
+
}}
|
|
377
|
+
>
|
|
378
|
+
${entry.expanded ? "Hide log" : `Show log (${entry.log.length} line(s))`}
|
|
379
|
+
</button>
|
|
380
|
+
${entry.expanded ? html`<pre class="activity-log">${entry.log.join("\n")}</pre>` : nothing}`;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** One operation. */
|
|
384
|
+
function activityTpl(entry: ActivityEntry): TemplateResult {
|
|
385
|
+
return html`
|
|
386
|
+
<li class="activity-row activity-row--${entry.state}">
|
|
387
|
+
<span class="activity-icon" aria-hidden="true">${STATE_ICON[entry.state]}</span>
|
|
388
|
+
<div class="activity-body">
|
|
389
|
+
<div class="activity-head">
|
|
390
|
+
<span class="activity-title">${entry.title}</span>
|
|
391
|
+
${entry.source ? html`<span class="activity-source">${entry.source}</span>` : nothing}
|
|
392
|
+
<span class="activity-duration">${activityDuration(entry)}</span>
|
|
393
|
+
</div>
|
|
394
|
+
${entry.status ? html`<div class="activity-status">${entry.status}</div>` : nothing}
|
|
395
|
+
${stepsTpl(entry)} ${logTpl(entry)}
|
|
396
|
+
</div>
|
|
397
|
+
${
|
|
398
|
+
entry.cancellable
|
|
399
|
+
? html`<button
|
|
400
|
+
class="activity-cancel"
|
|
401
|
+
title="Stop this operation"
|
|
402
|
+
@click=${() => {
|
|
403
|
+
cancelActivity(entry.id);
|
|
404
|
+
}}
|
|
405
|
+
>
|
|
406
|
+
Cancel
|
|
407
|
+
</button>`
|
|
408
|
+
: nothing
|
|
409
|
+
}
|
|
410
|
+
</li>
|
|
411
|
+
`;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* The Activity tab's body.
|
|
416
|
+
*
|
|
417
|
+
* Newest LAST, like a log and unlike a menu: an operation that starts while you are reading one
|
|
418
|
+
* that is already running must not push it off the top.
|
|
419
|
+
*/
|
|
420
|
+
export function renderActivityList(): PanelBody {
|
|
421
|
+
// The Deploy checklist lives here because a deploy IS a long operation with a log — which is why
|
|
422
|
+
// P4 folded Deploy into Activity rather than giving it a fifth dock tab. It renders above the
|
|
423
|
+
// Run log and before any operation has started, because its whole job is to say what is missing
|
|
424
|
+
// BEFORE you begin.
|
|
425
|
+
const checklist = renderDeployChecklist();
|
|
426
|
+
if (activities.length === 0) {
|
|
427
|
+
return html`${checklist}${renderEmptyState({
|
|
428
|
+
detail: "Installs, clones, publishes and imports report here while they run.",
|
|
429
|
+
message: "Long operations show their progress, their log and their Cancel button here.",
|
|
430
|
+
})}`;
|
|
431
|
+
}
|
|
432
|
+
const finished = activities.filter((entry) => isFinished(entry)).length;
|
|
433
|
+
return html`
|
|
434
|
+
${checklist}
|
|
435
|
+
<div class="activity-panel">
|
|
436
|
+
${
|
|
437
|
+
finished > 0
|
|
438
|
+
? html`<div class="activity-actions">
|
|
439
|
+
<button
|
|
440
|
+
class="activity-clear"
|
|
441
|
+
@click=${() => {
|
|
442
|
+
clearFinishedActivities();
|
|
443
|
+
}}
|
|
444
|
+
>
|
|
445
|
+
Clear ${finished} finished
|
|
446
|
+
</button>
|
|
447
|
+
</div>`
|
|
448
|
+
: nothing
|
|
449
|
+
}
|
|
450
|
+
<ul class="activity-list">
|
|
451
|
+
${repeat(
|
|
452
|
+
activities,
|
|
453
|
+
(entry) => entry.id,
|
|
454
|
+
(entry) => activityTpl(entry),
|
|
455
|
+
)}
|
|
456
|
+
</ul>
|
|
457
|
+
</div>
|
|
458
|
+
`;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Define the Activity panel. Called by `panels/bottom-dock.ts`, beside the state it writes.
|
|
463
|
+
*
|
|
464
|
+
* `level: "project"` because an operation is a thing done TO a project — an install, a clone, a
|
|
465
|
+
* publish — and the list must not empty itself when the last document closes, which is the same
|
|
466
|
+
* rule that hoisted source control off `TabUi`.
|
|
467
|
+
*/
|
|
468
|
+
export function registerActivityPanel(): void {
|
|
469
|
+
registerPanel({
|
|
470
|
+
id: "activity",
|
|
471
|
+
title: "Activity",
|
|
472
|
+
level: "project",
|
|
473
|
+
dock: "bottom",
|
|
474
|
+
icon: "sp-icon-data",
|
|
475
|
+
// No rail button: the Bottom dock's tabs are reached by ⌘J and `view.setBottomTab`, and a
|
|
476
|
+
// Fifth rail slot for a surface with no steady state would spend chrome §2 principle 9 caps.
|
|
477
|
+
rail: false,
|
|
478
|
+
badge: () => (runningActivities().length > 0 ? runningActivities().length : null),
|
|
479
|
+
render: () => renderActivityList(),
|
|
480
|
+
});
|
|
481
|
+
}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Wraps @jxsuite/markup/md-html (sanitized markdown → HTML) with a per-message cache
|
|
5
5
|
* keyed by message id + content length, so re-renders during streaming only re-parse
|
|
6
|
-
* the message that actually grew.
|
|
7
|
-
*
|
|
6
|
+
* the message that actually grew.
|
|
7
|
+
*
|
|
8
|
+
* The HTML goes through `unsafeHTML`, which is this app's ONE injection sink, and it goes through
|
|
9
|
+
* the Trusted Types policy on the way. md-html already sanitizes — raw HTML dropped, javascript:
|
|
10
|
+
* URLs stripped — and the policy asserts that it did, rather than taking a comment's word for it.
|
|
11
|
+
* A `createHTML` that passed its input through unchanged would satisfy the API and defend nothing.
|
|
8
12
|
*
|
|
9
13
|
* @license MIT
|
|
10
14
|
*/
|
|
@@ -13,6 +17,7 @@ import { html } from "lit-html";
|
|
|
13
17
|
import type { TemplateResult } from "lit-html";
|
|
14
18
|
import { unsafeHTML } from "lit-html/directives/unsafe-html.js";
|
|
15
19
|
import { markdownToHtml } from "@jxsuite/markup/md-html";
|
|
20
|
+
import { trustedHtml } from "../../services/trusted-types";
|
|
16
21
|
|
|
17
22
|
const cache = new Map<string, { len: number; html: string }>();
|
|
18
23
|
|
|
@@ -29,7 +34,7 @@ export function renderMarkdown(id: string, content: string): TemplateResult {
|
|
|
29
34
|
entry = { len: content.length, html: markdownToHtml(content) };
|
|
30
35
|
cache.set(id, entry);
|
|
31
36
|
}
|
|
32
|
-
return html`<div class="ai-msg-md">${unsafeHTML(entry.html)}</div>`;
|
|
37
|
+
return html`<div class="ai-msg-md">${unsafeHTML(String(trustedHtml(entry.html)))}</div>`;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
/** Drop all cached renders (call on session switch / new chat). */
|