collabmd 0.1.47 → 0.1.49
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 +70 -11
- package/bin/collabmd.js +3 -0
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -0
- package/dist/client/assets/JetBrainsMono-Regular-BQaDgvhP.woff2 +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CdVZqicp.js +1 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-I39sYjHI.js → architectureDiagram-5GKGNRK7-wUo0bXif.js} +3 -3
- package/dist/client/assets/babel-CY5KOv-I.js +16 -0
- package/dist/client/assets/{blockDiagram-NRAW4CY4-C6DtJy5Y.js → blockDiagram-I7D4REHJ-BRSK3m49.js} +4 -4
- package/dist/client/assets/browser-utils-DbXSMI-6.js +1 -0
- package/dist/client/assets/{c4Diagram-UCG6FXSJ-CtWtxS9_.js → c4Diagram-7LVT6UL2-yD2poxqw.js} +1 -1
- package/dist/client/assets/channel-Fa4GS_-F.js +1 -0
- package/dist/client/assets/chunk-2E4U76K2-BPnTT-J3.js +2 -0
- package/dist/client/assets/{chunk-TEH6E4GO-DVayPj-q.js → chunk-4HAMMTFA-DStbIfJ1.js} +20 -20
- package/dist/client/assets/{chunk-75Z2AOVW-CdFSaPjz.js → chunk-75Z2AOVW-C5pGd3W9.js} +1 -1
- package/dist/client/assets/{chunk-CLGD4ZFX-DQLgbQrv.js → chunk-CLGD4ZFX-BMeArk03.js} +1 -1
- package/dist/client/assets/chunk-DU6HZSFF-Zkp69c6c.js +127 -0
- package/dist/client/assets/{chunk-F27PBJKO-CNHIFhjo.js → chunk-F27PBJKO-D4xNct1r.js} +1 -1
- package/dist/client/assets/{chunk-GMAD6QVW-CbcBqPM5.js → chunk-GMAD6QVW-NZ6WpDb8.js} +1 -1
- package/dist/client/assets/{chunk-OBVCFTLP-BJR7u1jh.js → chunk-GVQU2GXP-D8SDprfX.js} +1 -1
- package/dist/client/assets/{chunk-G27WJ6UU-D9-eg537.js → chunk-IMKFNOWR-D8jEuU3Q.js} +2 -2
- package/dist/client/assets/{chunk-JQ64N6SF-DSFNH4bh.js → chunk-L3NEJ4N5-aijKP-eh.js} +1 -1
- package/dist/client/assets/chunk-OSK3NFVY-CCbLQAMa.js +10 -0
- package/dist/client/assets/{chunk-P2QGCYS3-BRpqY32H.js → chunk-P2QGCYS3-Oag_FdCq.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-Cb4SlVZF.js → chunk-POPQ4Y6H-CYnpIgXT.js} +1 -1
- package/dist/client/assets/{chunk-PWAF6VOD-Cz8IwBB5.js → chunk-PWAF6VOD-JSNrcBmP.js} +1 -1
- package/dist/client/assets/{chunk-RM4UPSZO-CWRwxNWJ.js → chunk-RM4UPSZO-DOWllDY8.js} +4 -4
- package/dist/client/assets/{chunk-RHFEMEQ7-CWY8cf4H.js → chunk-SHT3W25Y-BiQGljao.js} +5 -5
- package/dist/client/assets/{chunk-SVP7TREG-CyHOmcac.js → chunk-SVP7TREG-DB485R5x.js} +1 -1
- package/dist/client/assets/{chunk-LCL6LL3I-DmDkVukh.js → chunk-TICWLB2K-8rAVvoS3.js} +4 -4
- package/dist/client/assets/{chunk-CKBBP62Z-DG26UiBv.js → chunk-TLUHSLCS-DTY5v0aj.js} +2 -2
- package/dist/client/assets/classDiagram-ZZMXUADV-BsQWoR3Q.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BsQWoR3Q.js +1 -0
- package/dist/client/assets/{comment-thread-store-CdcwrObc.js → comment-thread-store-CX98zR6q.js} +1 -1
- package/dist/client/assets/comment-threads-BnRwo5B9.js +4 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CdTPi2yO.js → cynefinDiagram-5FMLGOSQ-rTz9RhFH.js} +1 -1
- package/dist/client/assets/{dagre-3AP2YEHR-5gtJtd0O.js → dagre-GXQ25YYZ-Cr67wLpQ.js} +2 -2
- package/dist/client/assets/{diagram-S7CK7UJ4-BudWz9WU.js → diagram-S7CK7UJ4-DywERe__.js} +2 -2
- package/dist/client/assets/{diagram-UQ7AKVKN-3v4rbH-s.js → diagram-UQ7AKVKN-CNYlXtu4.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-0H1a61Bn.js +3 -0
- package/dist/client/assets/{diagram-VX7I27RA-C_-rj0sw.js → diagram-VX7I27RA-CsJbsx5F.js} +1 -1
- package/dist/client/assets/{diagram-Z3DM3KII-B4yxavgj.js → diagram-Z3DM3KII-D0mLxEgI.js} +1 -1
- package/dist/client/assets/dist--hk9I5HQ.js +1 -0
- package/dist/client/assets/{dist-DutPuFmC.js → dist-B1XEa-Zs.js} +1 -1
- package/dist/client/assets/dist-Bd1JucQF.js +1 -0
- package/dist/client/assets/{dist-DZAAWTG-.js → dist-C0G3AaXG.js} +1 -1
- package/dist/client/assets/dist-ChRoo3IB.js +9 -0
- package/dist/client/assets/dist-Dm4w5UId.js +1 -0
- package/dist/client/assets/{dist-B_yQaEv_.js → dist-DpYDHR9p.js} +1 -1
- package/dist/client/assets/{dist-CietwTVS.js → dist-DzNmC81X.js} +1 -1
- package/dist/client/assets/{dist-DDUn5zTz.js → dist-GvvCNBe4.js} +1 -1
- package/dist/client/assets/dist-JaU3aRlD.js +19 -0
- package/dist/client/assets/{dist-Bw3VIE_v.js → dist-TW8iFRyW.js} +1 -1
- package/dist/client/assets/{dist-Dir5dDKZ.js → dist-jVU5Be5P.js} +1 -1
- package/dist/client/assets/document-formatter-rDDjRfZ2.js +2 -0
- package/dist/client/assets/drawioEditor-JubEEha7.js +9 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-HeTxHpCU.js +1 -0
- package/dist/client/assets/editor-session-Bk6oIvSr.js +54 -0
- package/dist/client/assets/embedded-editor-base-BlCgz6mw.css +1 -0
- package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
- package/dist/client/assets/{es-CAsWR6hG.js → es-Bfdp096f.js} +13 -13
- package/dist/client/assets/estree-CuT_pB8K.js +44 -0
- package/dist/client/assets/excalidraw-element-link-YLIaTnVF.js +7 -0
- package/dist/client/assets/{excalidraw-scene-BOben2gr.js → excalidraw-scene-6uROebca.js} +1 -1
- package/dist/client/assets/{excalidraw-editor-BlcN6umJ.css → excalidrawEditor-BbSbI80a.css} +1 -1
- package/dist/client/assets/excalidrawEditor-dBMbRX_S.js +9 -0
- package/dist/client/assets/export-page-CRRQ2NEl.js +57 -0
- package/dist/client/assets/exportDocument-BlQRd9_m.js +2 -0
- package/dist/client/assets/exportDocument-CNSbjZwu.css +1 -0
- package/dist/client/assets/{file-icon-svg-CQAjlWjK.js → file-icon-svg-Y_kpF957.js} +1 -1
- package/dist/client/assets/file-kind-BwMIcZbi.js +1 -0
- package/dist/client/assets/file-search-DDLyyLDU.js +1 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D5Gy0wmg.js +1 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DtKHAbez.js → ganttDiagram-EL5Y4UJY-BHgOYiZz.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-oue8fQ5o.js → gitGraphDiagram-WWUBYQGX-Dl__X3Sk.js} +1 -1
- package/dist/client/assets/html-Cdnr2qzU.js +25 -0
- package/dist/client/assets/image-ZVKINSPA-DgzW5zAy.js +1 -0
- package/dist/client/assets/index-D3RER1SZ.js +1023 -0
- package/dist/client/assets/index-DREVKl_K.css +1 -0
- package/dist/client/assets/{infoDiagram-RXCK75RN-BMzo6KIn.js → infoDiagram-27XIBGKW-DBpoANC9.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BIM3h287.js → ishikawaDiagram-5VMMS53U-BMPC6hfp.js} +1 -1
- package/dist/client/assets/{journeyDiagram-EYS64GPL-mF6Lh8O-.js → journeyDiagram-3NMN7TZE-B1sApUmM.js} +2 -2
- package/dist/client/assets/{kanban-definition-3QL26DDD-DLN2NyoR.js → kanban-definition-UXKFOSKX-C9yP4td1.js} +4 -4
- package/dist/client/assets/{line-BfTWJmgf.js → line-BFl3ujec.js} +1 -1
- package/dist/client/assets/markdown-CByV-4CU.js +70 -0
- package/dist/client/assets/{mermaid.core-CLZBlpIW.js → mermaid.core-BrY09czX.js} +5 -5
- package/dist/client/assets/mermaid.core-DfcNfOTv.js +1 -0
- package/dist/client/assets/{mindmap-definition-FBJOCRG2-CRyHaHTk.js → mindmap-definition-YA3MSWOX-BUQHcYbK.js} +8 -8
- package/dist/client/assets/pegDiagram-XKGWAZYB-Bi2Iml7Z.js +1 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-B5OZPb88.js → pieDiagram-E7YTZNPT-_gYXnMoi.js} +1 -1
- package/dist/client/assets/preview-render-compiler-CfxJYldJ.js +41 -0
- package/dist/client/assets/preview-render-compiler-Cu8_i9iS.js +1 -0
- package/dist/client/assets/{preview-render-worker-BmN79bVc.js → preview-render-worker-c4Yi93qW.js} +41 -35
- package/dist/client/assets/prod-BiJL30sl.js +1 -0
- package/dist/client/assets/prod-qAk7rHa4.js +177 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Drrw14YH.js → quadrantDiagram-AXDQQJYC-DwexhEhd.js} +1 -1
- package/dist/client/assets/quick-switcher-controller-BoIK_wuG.js +1 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BVA5UbMu.js +1 -0
- package/dist/client/assets/{requirementDiagram-EFPCY7ZU-CRZG6mRB.js → requirementDiagram-BXWQKSXE-C4cKwiIw.js} +2 -2
- package/dist/client/assets/runtime-config-DcmnGcXU.js +1 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DvarEJpo.js → sankeyDiagram-P5KCCOFB-B5HHkRT2.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-B4oWlb-w.js → sequenceDiagram-WJ2MYXX4-BX6jqJFD.js} +6 -6
- package/dist/client/assets/standalone-6z5x8CWe.js +29 -0
- package/dist/client/assets/{stateDiagram-HBIQ2CUA-qbHIIqRZ.js → stateDiagram-D77RDMKH-CmqxyRGx.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-zoLLQVyh.js +1 -0
- package/dist/client/assets/{swimlanes-XN3QIQJK-xB6CtUGj.js → swimlanes-42K2YHIH-Bmgb9Zld.js} +1 -1
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DS-KQN37.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-Lj_yTNlY.js → timeline-definition-24CTP7MA-BA-lVH6P.js} +1 -1
- package/dist/client/assets/vault-api-client-iZLhMJKe.js +6 -0
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BekRp5Y0.js → vennDiagram-4TSXK5OY-DNdUC_Xj.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdnV_Hdm.js → wardleyDiagram-VM6X3IG4-C2oY-YbF.js} +1 -1
- package/dist/client/assets/wiki-link-resolver-DFIwErjc.js +1 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DufGwNSB.js → xychartDiagram-S5SC5T6Z-CoIR8CBX.js} +1 -1
- package/dist/client/assets/yaml-9ltHPDNO.js +154 -0
- package/dist/client/assets/{yjs-provider-reset-guard-DE0vINDP.js → yjs-provider-reset-guard-9ul1qF6k.js} +1 -1
- package/dist/client/drawio-editor.html +11 -3
- package/dist/client/excalidraw-editor.html +45 -2
- package/dist/client/export-document.html +3 -3
- package/dist/client/index.html +106 -52
- package/integrations/pi/index.ts +94 -0
- package/package.json +41 -29
- package/src/client/app/drawio-editor.html +2 -2
- package/src/client/app/excalidraw-editor.html +2 -2
- package/src/client/app/export-document.html +1 -1
- package/src/client/app/index.html +88 -50
- package/src/client/app/main-entry.js +15 -1
- package/src/client/application/app-shell/chat-feature.js +7 -22
- package/src/client/application/app-shell/export-feature.js +17 -1
- package/src/client/application/app-shell/git-feature.js +51 -14
- package/src/client/application/app-shell/presence-feature.js +8 -25
- package/src/client/application/app-shell/ui-feature-identity.js +13 -0
- package/src/client/application/app-shell/ui-feature-shell.js +199 -99
- package/src/client/application/app-shell/ui-feature-sidebar.js +43 -7
- package/src/client/application/app-shell/ui-feature-tab-activity.js +19 -6
- package/src/client/application/app-shell/ui-feature-toolbar.js +16 -129
- package/src/client/application/app-shell-elements.js +8 -0
- package/src/client/application/preview-render-compiler.js +1 -87
- package/src/client/application/preview-render-scheduler.js +8 -24
- package/src/client/application/preview-renderer.js +2 -2
- package/src/client/application/webmcp-diagram-renderer.js +47 -0
- package/src/client/application/workspace-coordinator.js +23 -4
- package/src/client/application/workspace-preview-controller.js +120 -2
- package/src/client/application/workspace-route-controller.js +11 -1
- package/src/client/assets/vendor/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
- package/src/client/assets/vendor/jetbrains-mono/OFL.txt +93 -0
- package/src/client/bootstrap/collabmd-app-shell.js +99 -6
- package/src/client/domain/document-formatter.js +193 -0
- package/src/client/domain/excalidraw-element-link.js +73 -0
- package/src/client/domain/excalidraw-scene.js +21 -0
- package/src/client/domain/file-search.js +73 -0
- package/src/client/domain/git-labels.js +5 -0
- package/src/client/domain/hash-routes.js +8 -0
- package/src/client/domain/room.js +1 -5
- package/src/client/domain/runtime-paths.js +5 -0
- package/src/client/domain/vault-paths.js +6 -4
- package/src/client/domain/wiki-link-completions.js +20 -20
- package/src/client/drawio-editor.js +8 -3
- package/src/client/excalidraw-editor.js +287 -16
- package/src/client/export/export-host.js +59 -36
- package/src/client/export/export-page.js +14 -4
- package/src/client/export/export-pipeline.js +270 -42
- package/src/client/infrastructure/agent-connection-api-client.js +23 -0
- package/src/client/infrastructure/auth-client.js +3 -13
- package/src/client/infrastructure/editor-session.js +15 -0
- package/src/client/infrastructure/editor-view-adapter.js +73 -14
- package/src/client/infrastructure/excalidraw-room-client.js +80 -1
- package/src/client/infrastructure/git-api-client.js +39 -33
- package/src/client/infrastructure/lobby-presence.js +2 -5
- package/src/client/infrastructure/runtime-config.js +11 -1
- package/src/client/infrastructure/tab-activity-lock.js +2 -5
- package/src/client/infrastructure/vault-api-client.js +33 -26
- package/src/client/infrastructure/webmcp-tool-registry.js +283 -0
- package/src/client/infrastructure/workspace-sync-client.js +6 -4
- package/src/client/presentation/agent-connection-controller.js +255 -0
- package/src/client/presentation/backlinks-panel.js +3 -0
- package/src/client/presentation/bases-preview-controller.js +59 -26
- package/src/client/presentation/comment-ui/comment-ui-card.js +4 -2
- package/src/client/presentation/create-menu-presenter.js +19 -16
- package/src/client/presentation/excalidraw-embed-controller.js +164 -4
- package/src/client/presentation/file-action-controller.js +15 -2
- package/src/client/presentation/file-explorer-controller.js +3 -0
- package/src/client/presentation/file-explorer-view.js +71 -12
- package/src/client/presentation/file-history-view-controller.js +19 -12
- package/src/client/presentation/file-tree-state.js +1 -11
- package/src/client/presentation/git-diff-view-controller.js +70 -53
- package/src/client/presentation/git-panel-controller.js +86 -32
- package/src/client/presentation/image-lightbox-controller.js +20 -16
- package/src/client/presentation/layout-controller.js +3 -1
- package/src/client/presentation/quick-switcher-controller.js +74 -232
- package/src/client/presentation/quick-switcher-text-search.js +10 -14
- package/src/client/styles/components/navigation.css +1 -2
- package/src/client/styles/components/scrollbars.css +10 -0
- package/src/client/styles/export-document.css +44 -29
- package/src/client/styles/features/agent-connection.css +202 -0
- package/src/client/styles/features/collaboration-chat.css +8 -1
- package/src/client/styles/features/collaboration-dialogs.css +16 -1
- package/src/client/styles/features/collaboration-presence.css +30 -5
- package/src/client/styles/features/diff-toolbar.css +1 -1
- package/src/client/styles/features/media-lightbox.css +12 -3
- package/src/client/styles/features/preview-markdown.css +54 -0
- package/src/client/styles/features/quick-switcher.css +20 -11
- package/src/client/styles/foundation/themes.css +2 -0
- package/src/client/styles/foundation/tokens.css +8 -0
- package/src/client/styles/layout/editor-page.css +25 -11
- package/src/client/styles/layout/responsive.css +2 -20
- package/src/client/styles/layout/shell.css +77 -24
- package/src/client/styles/layout/sidebar.css +7 -4
- package/src/client/styles/layout/view-modes.css +2 -0
- package/src/client/styles/overrides/codemirror.css +31 -19
- package/src/client/styles/primitives/controls.css +21 -54
- package/src/client/styles/style.css +1 -0
- package/src/client/styles/surfaces/excalidraw-editor.css +42 -0
- package/src/domain/agent-tool-definitions.js +796 -0
- package/src/domain/collabmd-content-capabilities.js +149 -0
- package/src/domain/collaboration-protocol.js +2 -0
- package/src/domain/comment-threads.js +3 -5
- package/src/domain/diagram-source.js +50 -0
- package/src/domain/editable-content-revision.js +10 -0
- package/src/domain/editable-text.js +3 -0
- package/src/domain/exact-text-edits.js +69 -0
- package/src/domain/excalidraw-agent-scene.js +522 -0
- package/src/domain/excalidraw-agent-verification.js +460 -0
- package/src/domain/excalidraw-room-codec.js +1 -5
- package/src/domain/file-kind.js +12 -1
- package/src/domain/video-embed.js +76 -0
- package/src/server/application/agent-connection-service.js +178 -0
- package/src/server/application/agent-content-service.js +773 -0
- package/src/server/application/workspace-reconciliation.js +5 -7
- package/src/server/config/env.js +51 -1
- package/src/server/create-app-server.js +36 -0
- package/src/server/domain/bases/base-query-service.js +1 -5
- package/src/server/domain/collaboration/collaboration-room.js +121 -25
- package/src/server/domain/collaboration/protocol.js +4 -0
- package/src/server/domain/hosted-workspace.js +21 -0
- package/src/server/domain/markdown-reference-extractor.js +15 -1
- package/src/server/domain/ripgrep-search-service.js +110 -37
- package/src/server/infrastructure/git/git-service.js +19 -1
- package/src/server/infrastructure/git/history-service.js +1 -1
- package/src/server/infrastructure/git/local-exclude.js +25 -0
- package/src/server/infrastructure/git/parsers.js +19 -17
- package/src/server/infrastructure/git/path-utils.js +0 -16
- package/src/server/infrastructure/git/status-service.js +1 -1
- package/src/server/infrastructure/git/untracked-files.js +12 -21
- package/src/server/infrastructure/http/create-agent-api-handler.js +171 -0
- package/src/server/infrastructure/http/create-git-api-command-handler.js +32 -0
- package/src/server/infrastructure/http/create-request-handler.js +28 -0
- package/src/server/infrastructure/http/create-static-handler.js +6 -0
- package/src/server/infrastructure/mcp/create-agent-mcp-handler.js +199 -0
- package/src/server/infrastructure/persistence/agent-connection-store.js +120 -0
- package/src/server/infrastructure/persistence/path-utils.js +10 -4
- package/src/server/infrastructure/persistence/pull-backup-store.js +2 -27
- package/src/server/infrastructure/persistence/vault-file-store.js +11 -2
- package/src/server/shared/agent-tool-image.js +22 -0
- package/src/server/shared/agent-tool-rate-limiter.js +20 -0
- package/src/server/startup/git-remote-bootstrap.js +5 -33
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js +0 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-BNDLzJ7L.js +0 -1
- package/dist/client/assets/browser-utils--H_DkyEF.js +0 -1
- package/dist/client/assets/channel-CaoKA_We.js +0 -1
- package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +0 -2
- package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +0 -127
- package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +0 -10
- package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +0 -1
- package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +0 -1
- package/dist/client/assets/comment-threads-9J6Em-_y.js +0 -4
- package/dist/client/assets/comment-ui-shared-DWkk9Vh3.js +0 -7
- package/dist/client/assets/diagram-VSXAHHWV-CQRVEZR7.js +0 -3
- package/dist/client/assets/dist-73RPdcyU.js +0 -1
- package/dist/client/assets/dist-CH-sQu3r.js +0 -1
- package/dist/client/assets/drawio-editor-BjrxTe3l.js +0 -9
- package/dist/client/assets/drawioEditor-DUVZjSSr.js +0 -2
- package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
- package/dist/client/assets/editor-session-DfZuRgB_.js +0 -54
- package/dist/client/assets/embedded-editor-base-DvMynhKu.css +0 -1
- package/dist/client/assets/excalidraw-editor-D7pnUCLH.js +0 -9
- package/dist/client/assets/excalidraw-mermaid-stub-BNckbX2n.js +0 -1
- package/dist/client/assets/excalidraw-mermaid-stub-DE5FTiZB.js +0 -1
- package/dist/client/assets/excalidrawEditor-B0jOK3lv.js +0 -2
- package/dist/client/assets/export-page-Bs3xE1fg.js +0 -57
- package/dist/client/assets/exportDocument-Dg9MjkIk.js +0 -2
- package/dist/client/assets/exportDocument-PnYU3v1s.css +0 -1
- package/dist/client/assets/file-kind-BbqgGzpc.js +0 -1
- package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +0 -1
- package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +0 -1
- package/dist/client/assets/index-BIpgxyGZ.css +0 -1
- package/dist/client/assets/index-Z5sI0Bj-.js +0 -2
- package/dist/client/assets/main-Dwnj9Gaq.js +0 -903
- package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
- package/dist/client/assets/preview-render-compiler-BApvlLLo.js +0 -35
- package/dist/client/assets/preview-render-compiler-BQ_3h9vD.js +0 -1
- package/dist/client/assets/preview-render-profile-CE-5rVTC.js +0 -1
- package/dist/client/assets/prod-BiYPMR1i.js +0 -177
- package/dist/client/assets/prod-VxdGZ5Ly.js +0 -1
- package/dist/client/assets/quick-switcher-controller-ButWPmCI.js +0 -12
- package/dist/client/assets/railroadDiagram-O6MQD6OU-BPifP0MB.js +0 -1
- package/dist/client/assets/runtime-config-BLrEKVO1.js +0 -1
- package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +0 -1
- package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +0 -8
- package/dist/client/assets/vault-api-client-_LpV1aIn.js +0 -6
- package/dist/client/assets/vault-utils-wdQ0RNR9.js +0 -1
- package/src/client/app/drawio-editor-entry.js +0 -1
- package/src/client/app/excalidraw-editor-entry.js +0 -1
- package/src/client/excalidraw-mermaid-stub.js +0 -7
- package/src/client/main.js +0 -16
- /package/dist/client/assets/{drawio-editor-UQQ8XHou.css → drawioEditor-UQQ8XHou.css} +0 -0
- /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { escapeHtml } from '../domain/vault-utils.js';
|
|
2
|
+
|
|
3
|
+
function createAgentSetup({ authRequired, endpoint }) {
|
|
4
|
+
return [
|
|
5
|
+
`MCP endpoint: ${endpoint}`,
|
|
6
|
+
'Transport: Streamable HTTP',
|
|
7
|
+
`Authorization: ${authRequired ? 'Bearer $COLLABMD_ACCESS_TOKEN' : 'None'}`,
|
|
8
|
+
].join('\n');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createAgentTokenExport(token) {
|
|
12
|
+
return `export COLLABMD_ACCESS_TOKEN='${String(token).replaceAll("'", "'\\''")}'`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatDate(value) {
|
|
16
|
+
return value ? new Date(value).toLocaleString() : 'Never';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class AgentConnectionController {
|
|
20
|
+
constructor({ apiClient, closeToolbarMenu, content, dialog, runtimeConfig, toastController, trigger }) {
|
|
21
|
+
this.apiClient = apiClient;
|
|
22
|
+
this.closeToolbarMenu = closeToolbarMenu;
|
|
23
|
+
this.content = content;
|
|
24
|
+
this.dialog = dialog;
|
|
25
|
+
this.runtimeConfig = runtimeConfig;
|
|
26
|
+
this.toastController = toastController;
|
|
27
|
+
this.trigger = trigger;
|
|
28
|
+
this.secretToken = '';
|
|
29
|
+
this.config = {
|
|
30
|
+
authRequired: runtimeConfig.auth?.strategy !== 'none',
|
|
31
|
+
endpoint: runtimeConfig.agentAccess?.endpoint || '',
|
|
32
|
+
managed: Boolean(runtimeConfig.agentAccess?.managed),
|
|
33
|
+
};
|
|
34
|
+
this.endpoint = new URL(this.config.endpoint, window.location.origin).toString();
|
|
35
|
+
|
|
36
|
+
this.trigger?.classList.toggle('hidden', !runtimeConfig.agentAccess?.enabled);
|
|
37
|
+
this.trigger?.addEventListener('click', () => void this.open());
|
|
38
|
+
this.dialog?.addEventListener('close', () => {
|
|
39
|
+
this.secretToken = '';
|
|
40
|
+
this.content?.replaceChildren();
|
|
41
|
+
this.trigger?.focus?.();
|
|
42
|
+
});
|
|
43
|
+
this.dialog?.addEventListener('click', (event) => void this.handleClick(event));
|
|
44
|
+
this.dialog?.addEventListener('submit', (event) => void this.handleSubmit(event));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async open() {
|
|
48
|
+
this.closeToolbarMenu?.();
|
|
49
|
+
this.dialog?.showModal?.();
|
|
50
|
+
this.renderStatus('Loading Agent Access…');
|
|
51
|
+
try {
|
|
52
|
+
const connections = this.config.managed
|
|
53
|
+
? (await this.apiClient.listConnections()).connections
|
|
54
|
+
: [];
|
|
55
|
+
this.renderOverview(connections);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
this.renderStatus(error.message || 'Failed to load Agent Access', { error: true });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
renderStatus(message, { error = false } = {}) {
|
|
62
|
+
if (!this.content) return;
|
|
63
|
+
this.content.innerHTML = `<p class="agent-connection-status${error ? ' is-error' : ''}" role="status">${escapeHtml(message)}</p>`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
renderOverview(connections = []) {
|
|
67
|
+
const connectionMarkup = connections.length > 0
|
|
68
|
+
? connections.map((connection) => `
|
|
69
|
+
<article class="agent-connection-card">
|
|
70
|
+
<div>
|
|
71
|
+
<strong>${escapeHtml(connection.label)}</strong>
|
|
72
|
+
<span>${escapeHtml(connection.scopes.join(', '))}</span>
|
|
73
|
+
<small>Expires ${escapeHtml(formatDate(connection.expiresAt))}</small>
|
|
74
|
+
</div>
|
|
75
|
+
<button class="ui-button ui-button--secondary ui-button--compact" type="button" data-agent-revoke="${escapeHtml(connection.id)}">Revoke</button>
|
|
76
|
+
</article>
|
|
77
|
+
`).join('')
|
|
78
|
+
: `
|
|
79
|
+
<div class="agent-connection-empty">
|
|
80
|
+
<strong>Connect your first agent</strong>
|
|
81
|
+
<p>Choose its access, create a secure token, then copy the setup into your agent.</p>
|
|
82
|
+
</div>
|
|
83
|
+
`;
|
|
84
|
+
const management = this.config.managed
|
|
85
|
+
? `<button class="ui-button ui-button--primary" type="button" data-agent-create>${connections.length > 0 ? 'New connection' : 'Start setup'}</button>`
|
|
86
|
+
: `
|
|
87
|
+
<section class="agent-connection-empty">
|
|
88
|
+
<strong>No authentication required</strong>
|
|
89
|
+
<ol class="agent-connection-steps">
|
|
90
|
+
<li>Copy the connection details below into your agent.</li>
|
|
91
|
+
<li>Add this CollabMD MCP endpoint and restart the agent.</li>
|
|
92
|
+
<li>Anyone who can reach this no-auth workspace can use its read and edit tools.</li>
|
|
93
|
+
</ol>
|
|
94
|
+
</section>
|
|
95
|
+
`;
|
|
96
|
+
const connectionsSection = this.config.managed
|
|
97
|
+
? `
|
|
98
|
+
<section class="agent-connection-section">
|
|
99
|
+
<h3>Connections</h3>
|
|
100
|
+
<div class="agent-connection-list">${connectionMarkup}</div>
|
|
101
|
+
</section>
|
|
102
|
+
`
|
|
103
|
+
: '';
|
|
104
|
+
this.content.innerHTML = `
|
|
105
|
+
${connectionsSection}
|
|
106
|
+
${this.config.managed ? '' : management}
|
|
107
|
+
<details class="agent-connection-details">
|
|
108
|
+
<summary>Connection details</summary>
|
|
109
|
+
<code>${escapeHtml(this.endpoint)}</code>
|
|
110
|
+
<p>Streamable HTTP · ${this.config.authRequired ? 'Bearer token' : 'No authentication'} · Read and edit tools</p>
|
|
111
|
+
</details>
|
|
112
|
+
<div class="agent-connection-actions">
|
|
113
|
+
${this.config.managed ? management : '<button class="ui-button ui-button--primary" type="button" data-agent-copy-setup>Copy connection details</button>'}
|
|
114
|
+
<button class="ui-button ui-button--ghost" type="button" data-agent-close>Close</button>
|
|
115
|
+
</div>
|
|
116
|
+
<p class="agent-connection-live" role="status" aria-live="polite"></p>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
renderCreate() {
|
|
121
|
+
this.content.innerHTML = `
|
|
122
|
+
<form class="agent-connection-form" data-agent-create-form>
|
|
123
|
+
<header class="agent-connection-step-header">
|
|
124
|
+
<span>Step 1 of 2</span>
|
|
125
|
+
<h3>Choose access</h3>
|
|
126
|
+
<p>You can revoke this connection at any time.</p>
|
|
127
|
+
</header>
|
|
128
|
+
<label class="app-dialog-field">
|
|
129
|
+
<span class="app-dialog-label">Connection name</span>
|
|
130
|
+
<input class="ui-input" name="label" maxlength="80" value="My Agent" required>
|
|
131
|
+
</label>
|
|
132
|
+
<fieldset class="agent-connection-scopes">
|
|
133
|
+
<legend>Access</legend>
|
|
134
|
+
<label><input type="checkbox" checked disabled> Read Vault Content</label>
|
|
135
|
+
<label><input type="checkbox" name="edit" checked> Edit and create supported text files</label>
|
|
136
|
+
</fieldset>
|
|
137
|
+
<p class="agent-connection-note">Token expires after 30 days and can be revoked here. Delete, rename, Git, and publish are not exposed.</p>
|
|
138
|
+
<div class="agent-connection-actions">
|
|
139
|
+
<button class="ui-button ui-button--secondary" type="button" data-agent-back>Back</button>
|
|
140
|
+
<button class="ui-button ui-button--primary" type="submit">Create secure token</button>
|
|
141
|
+
</div>
|
|
142
|
+
<p class="agent-connection-live" role="status" aria-live="polite"></p>
|
|
143
|
+
</form>
|
|
144
|
+
`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
renderToken({ token }) {
|
|
148
|
+
this.secretToken = token;
|
|
149
|
+
const setup = createAgentSetup({
|
|
150
|
+
authRequired: this.config.authRequired,
|
|
151
|
+
endpoint: this.endpoint,
|
|
152
|
+
});
|
|
153
|
+
this.content.innerHTML = `
|
|
154
|
+
<header class="agent-connection-step-header">
|
|
155
|
+
<span>Step 2 of 2</span>
|
|
156
|
+
<h3>Finish setup in your MCP client</h3>
|
|
157
|
+
<p class="agent-connection-warning">The token is shown once. Finish these steps before closing.</p>
|
|
158
|
+
</header>
|
|
159
|
+
<ol class="agent-connection-steps agent-connection-steps--setup">
|
|
160
|
+
<li>
|
|
161
|
+
<div><strong>Save the access token</strong><span>Run the copied command in the terminal that starts your MCP client.</span></div>
|
|
162
|
+
<button class="ui-button ui-button--primary" type="button" data-agent-copy-token>Copy token command</button>
|
|
163
|
+
</li>
|
|
164
|
+
<li>
|
|
165
|
+
<div><strong>Add this workspace</strong><span>Paste the setup into your MCP client.</span></div>
|
|
166
|
+
<button class="ui-button ui-button--secondary" type="button" data-agent-copy-setup>Copy MCP setup</button>
|
|
167
|
+
</li>
|
|
168
|
+
</ol>
|
|
169
|
+
<details class="agent-connection-details">
|
|
170
|
+
<summary>View manual setup</summary>
|
|
171
|
+
<input class="ui-input agent-connection-token" value="${escapeHtml(token)}" readonly aria-label="Agent Connection token">
|
|
172
|
+
<pre><code>${escapeHtml(setup)}</code></pre>
|
|
173
|
+
</details>
|
|
174
|
+
<div class="agent-connection-actions">
|
|
175
|
+
<button class="ui-button ui-button--primary" type="button" data-agent-close>Done</button>
|
|
176
|
+
</div>
|
|
177
|
+
<p class="agent-connection-live" role="status" aria-live="polite"></p>
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async refresh() {
|
|
182
|
+
const connections = this.config.managed
|
|
183
|
+
? (await this.apiClient.listConnections()).connections
|
|
184
|
+
: [];
|
|
185
|
+
this.renderOverview(connections);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
setLiveMessage(message) {
|
|
189
|
+
const live = this.content?.querySelector('.agent-connection-live');
|
|
190
|
+
if (live) live.textContent = message;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async copy(text, message) {
|
|
194
|
+
await navigator.clipboard.writeText(text);
|
|
195
|
+
this.setLiveMessage(message);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async handleClick(event) {
|
|
199
|
+
const target = event.target.closest('button');
|
|
200
|
+
if (!target) return;
|
|
201
|
+
if (target.dataset.agentClose != null) {
|
|
202
|
+
this.dialog.close();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (target.dataset.agentCreate != null) {
|
|
206
|
+
this.renderCreate();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (target.dataset.agentBack != null) {
|
|
210
|
+
await this.refresh();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (target.dataset.agentCopyToken != null) {
|
|
214
|
+
await this.copy(createAgentTokenExport(this.secretToken), 'Token command copied — run it in the agent terminal.');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (target.dataset.agentCopySetup != null) {
|
|
218
|
+
await this.copy(createAgentSetup({
|
|
219
|
+
authRequired: this.config.authRequired,
|
|
220
|
+
endpoint: this.endpoint,
|
|
221
|
+
}), 'Setup copied — add it to your MCP client.');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (target.dataset.agentRevoke) {
|
|
225
|
+
if (!window.confirm('Revoke this Agent Connection?')) return;
|
|
226
|
+
try {
|
|
227
|
+
await this.apiClient.revokeConnection(target.dataset.agentRevoke);
|
|
228
|
+
await this.refresh();
|
|
229
|
+
this.setLiveMessage('Agent Connection revoked');
|
|
230
|
+
} catch (error) {
|
|
231
|
+
this.toastController?.show(error.message || 'Failed to revoke Agent Connection');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async handleSubmit(event) {
|
|
237
|
+
const form = event.target.closest('[data-agent-create-form]');
|
|
238
|
+
if (!form) return;
|
|
239
|
+
event.preventDefault();
|
|
240
|
+
const data = new FormData(form);
|
|
241
|
+
const submit = form.querySelector('[type="submit"]');
|
|
242
|
+
submit.disabled = true;
|
|
243
|
+
try {
|
|
244
|
+
const result = await this.apiClient.createConnection({
|
|
245
|
+
clientKind: 'generic',
|
|
246
|
+
label: data.get('label'),
|
|
247
|
+
scopes: data.get('edit') === 'on' ? ['vault:read', 'vault:edit'] : ['vault:read'],
|
|
248
|
+
});
|
|
249
|
+
this.renderToken(result);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
this.setLiveMessage(error.message || 'Failed to create Agent Connection');
|
|
252
|
+
submit.disabled = false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -13,6 +13,7 @@ export class BacklinksPanel {
|
|
|
13
13
|
headerPanelElement = null,
|
|
14
14
|
inlinePanelElement = null,
|
|
15
15
|
loadBacklinks = null,
|
|
16
|
+
onBeforeToggle = null,
|
|
16
17
|
onFileSelect,
|
|
17
18
|
panelElement,
|
|
18
19
|
}) {
|
|
@@ -21,6 +22,7 @@ export class BacklinksPanel {
|
|
|
21
22
|
this.panelRoot = panelElement;
|
|
22
23
|
this.inlinePanel = inlinePanelElement;
|
|
23
24
|
this.loadBacklinks = loadBacklinks;
|
|
25
|
+
this.onBeforeToggle = onBeforeToggle;
|
|
24
26
|
this.onFileSelect = onFileSelect;
|
|
25
27
|
|
|
26
28
|
this._expanded = false;
|
|
@@ -102,6 +104,7 @@ export class BacklinksPanel {
|
|
|
102
104
|
this.panels.forEach((refs) => {
|
|
103
105
|
refs.header?.addEventListener('click', () => {
|
|
104
106
|
if (this._backlinks.length === 0) return;
|
|
107
|
+
this.onBeforeToggle?.();
|
|
105
108
|
this._expanded = !this._expanded;
|
|
106
109
|
this._pendingOutsidePointer = null;
|
|
107
110
|
this._applyExpandState();
|
|
@@ -10,6 +10,26 @@ function createShellKey() {
|
|
|
10
10
|
return `base-${Math.random().toString(36).slice(2, 10)}`;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
function replaceChildrenFromHtml(target, html) {
|
|
14
|
+
const markup = String(html ?? '');
|
|
15
|
+
if (typeof DOMParser === 'function' && typeof target?.replaceChildren === 'function') {
|
|
16
|
+
const parsed = new DOMParser().parseFromString(`<body>${markup}</body>`, 'text/html');
|
|
17
|
+
target.replaceChildren(...parsed.body.childNodes);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Node tests use lightweight DOM doubles without parsing APIs.
|
|
22
|
+
Reflect.set(target, 'innerHTML', markup);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function insertAfterFromHtml(target, html) {
|
|
26
|
+
if (typeof DOMParser !== 'function' || typeof target?.after !== 'function') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const parsed = new DOMParser().parseFromString(`<body>${String(html ?? '')}</body>`, 'text/html');
|
|
30
|
+
target.after(...parsed.body.childNodes);
|
|
31
|
+
}
|
|
32
|
+
|
|
13
33
|
function looksLikeHexColor(value = '') {
|
|
14
34
|
return /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/iu.test(String(value ?? '').trim());
|
|
15
35
|
}
|
|
@@ -326,10 +346,10 @@ function renderSortPanel(result) {
|
|
|
326
346
|
<div class="bases-panel-section">
|
|
327
347
|
<div class="bases-panel-title">Group by</div>
|
|
328
348
|
<div class="bases-sort-row">
|
|
329
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-property' }))}" data-base-group-by-property>
|
|
349
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-property' }))}" data-base-group-by-property aria-label="Group by property">
|
|
330
350
|
${createSelectOptions(result, { allowBlank: true, selected: viewConfig.groupBy?.property ?? '' })}
|
|
331
351
|
</select>
|
|
332
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-direction' }))}" data-base-group-by-direction${viewConfig.groupBy?.property ? '' : ' disabled'}>
|
|
352
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-direction' }))}" data-base-group-by-direction aria-label="Group direction"${viewConfig.groupBy?.property ? '' : ' disabled'}>
|
|
333
353
|
${groupDirections.map((direction) => `<option value="${escapeHtml(direction.id)}"${direction.id === (viewConfig.groupBy?.direction ?? 'asc') ? ' selected' : ''}>${escapeHtml(direction.label)}</option>`).join('')}
|
|
334
354
|
</select>
|
|
335
355
|
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-clear-group-by${viewConfig.groupBy?.property ? '' : ' disabled'}>Clear</button>
|
|
@@ -346,15 +366,15 @@ function renderSortPanel(result) {
|
|
|
346
366
|
];
|
|
347
367
|
return `
|
|
348
368
|
<div class="bases-sort-row">
|
|
349
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-property' }))}" data-base-sort-property="${index}">
|
|
369
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-property' }))}" data-base-sort-property="${index}" aria-label="Sort rule ${index + 1} property">
|
|
350
370
|
${createSelectOptions(result, { selected: sortConfig.property })}
|
|
351
371
|
</select>
|
|
352
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-direction' }))}" data-base-sort-direction="${index}">
|
|
372
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-sort-direction' }))}" data-base-sort-direction="${index}" aria-label="Sort rule ${index + 1} direction">
|
|
353
373
|
${directions.map((direction) => `<option value="${escapeHtml(direction.id)}"${direction.id === sortConfig.direction ? ' selected' : ''}>${escapeHtml(direction.label)}</option>`).join('')}
|
|
354
374
|
</select>
|
|
355
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:up"${index === 0 ? ' disabled' : ''}>↑</button>
|
|
356
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:down"${index === sorts.length - 1 ? ' disabled' : ''}>↓</button>
|
|
357
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-delete="${index}">Delete</button>
|
|
375
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:up" aria-label="Move sort rule ${index + 1} up"${index === 0 ? ' disabled' : ''}>↑</button>
|
|
376
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:down" aria-label="Move sort rule ${index + 1} down"${index === sorts.length - 1 ? ' disabled' : ''}>↓</button>
|
|
377
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-delete="${index}" aria-label="Delete sort rule ${index + 1}">Delete</button>
|
|
358
378
|
</div>
|
|
359
379
|
`;
|
|
360
380
|
}).join('')}
|
|
@@ -369,6 +389,10 @@ function encodePath(path = []) {
|
|
|
369
389
|
return path.join('.');
|
|
370
390
|
}
|
|
371
391
|
|
|
392
|
+
function formatFilterPath(path = []) {
|
|
393
|
+
return path.map((index) => index + 1).join('.');
|
|
394
|
+
}
|
|
395
|
+
|
|
372
396
|
function decodePath(value = '') {
|
|
373
397
|
return String(value ?? '')
|
|
374
398
|
.split('.')
|
|
@@ -617,7 +641,11 @@ function parseRawFilterText(text = '') {
|
|
|
617
641
|
}
|
|
618
642
|
|
|
619
643
|
if (normalized.startsWith('{') || normalized.startsWith('[')) {
|
|
620
|
-
|
|
644
|
+
try {
|
|
645
|
+
return JSON.parse(normalized);
|
|
646
|
+
} catch (error) {
|
|
647
|
+
throw new Error('Invalid advanced filter JSON', { cause: error });
|
|
648
|
+
}
|
|
621
649
|
}
|
|
622
650
|
|
|
623
651
|
return normalized;
|
|
@@ -749,9 +777,10 @@ function renderFilterSuggestionList(presentation, currentValue = '') {
|
|
|
749
777
|
|
|
750
778
|
function renderFilterValueCombobox(result, rule, path, entry) {
|
|
751
779
|
const presentation = buildFilterValuePresentation(result, rule, path, entry);
|
|
780
|
+
const filterLabel = `Filter ${formatFilterPath(path)}`;
|
|
752
781
|
return `
|
|
753
782
|
<div class="bases-filter-value-combobox${presentation.suggestionsEnabled ? ' has-suggestions' : ''}">
|
|
754
|
-
<input class="${escapeHtml(presentation.valueInputClasses)}" type="text" value="${escapeHtml(rule.value ?? '')}" data-base-filter-value="${escapeHtml(presentation.encodedPath)}"${presentation.suggestionsEnabled ? ` aria-controls="${presentation.suggestionListId}" aria-haspopup="listbox" aria-autocomplete="list" autocomplete="off"` : ''}${presentation.valueDisabled ? ' disabled' : ''}>
|
|
783
|
+
<input class="${escapeHtml(presentation.valueInputClasses)}" type="text" value="${escapeHtml(rule.value ?? '')}" data-base-filter-value="${escapeHtml(presentation.encodedPath)}" aria-label="${filterLabel} value"${presentation.suggestionsEnabled ? ` aria-controls="${presentation.suggestionListId}" aria-haspopup="listbox" aria-autocomplete="list" autocomplete="off"` : ''}${presentation.valueDisabled ? ' disabled' : ''}>
|
|
755
784
|
${renderFilterSuggestionList(presentation, rule.value ?? '')}
|
|
756
785
|
</div>
|
|
757
786
|
`;
|
|
@@ -759,17 +788,18 @@ function renderFilterValueCombobox(result, rule, path, entry) {
|
|
|
759
788
|
|
|
760
789
|
function renderFilterRule(result, rule, path, entry) {
|
|
761
790
|
const presentation = buildFilterValuePresentation(result, rule, path, entry);
|
|
791
|
+
const filterLabel = `Filter ${formatFilterPath(path)}`;
|
|
762
792
|
|
|
763
793
|
return `
|
|
764
794
|
<div class="bases-filter-row">
|
|
765
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-property' }))}" data-base-filter-property="${escapeHtml(presentation.encodedPath)}">
|
|
795
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-property' }))}" data-base-filter-property="${escapeHtml(presentation.encodedPath)}" aria-label="${filterLabel} property">
|
|
766
796
|
${getPropertyOptionsMarkup(result, rule.propertyId)}
|
|
767
797
|
</select>
|
|
768
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-operator' }))}" data-base-filter-operator="${escapeHtml(presentation.encodedPath)}">
|
|
798
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-operator' }))}" data-base-filter-operator="${escapeHtml(presentation.encodedPath)}" aria-label="${filterLabel} operator">
|
|
769
799
|
${presentation.operators.map((operator) => `<option value="${escapeHtml(operator)}"${operator === rule.operator ? ' selected' : ''}>${escapeHtml(operator)}</option>`).join('')}
|
|
770
800
|
</select>
|
|
771
801
|
${renderFilterValueCombobox(result, rule, path, entry)}
|
|
772
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-remove="${escapeHtml(presentation.encodedPath)}">Delete</button>
|
|
802
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-remove="${escapeHtml(presentation.encodedPath)}" aria-label="Delete ${filterLabel.toLowerCase()}">Delete</button>
|
|
773
803
|
</div>
|
|
774
804
|
`;
|
|
775
805
|
}
|
|
@@ -795,6 +825,7 @@ function syncFilterValueCombobox(entry, result, path, { fallbackToFullRender = t
|
|
|
795
825
|
combobox.classList.toggle('has-suggestions', presentation.suggestionsEnabled);
|
|
796
826
|
input.className = presentation.valueInputClasses;
|
|
797
827
|
input.disabled = presentation.valueDisabled;
|
|
828
|
+
input.setAttribute('aria-label', `Filter ${formatFilterPath(path)} value`);
|
|
798
829
|
if (input.value !== String(rule.value ?? '')) {
|
|
799
830
|
input.value = String(rule.value ?? '');
|
|
800
831
|
}
|
|
@@ -814,7 +845,7 @@ function syncFilterValueCombobox(entry, result, path, { fallbackToFullRender = t
|
|
|
814
845
|
const suggestionList = combobox.querySelector('.bases-filter-suggestion-list');
|
|
815
846
|
suggestionList?.remove?.();
|
|
816
847
|
if (presentation.suggestionsEnabled) {
|
|
817
|
-
input
|
|
848
|
+
insertAfterFromHtml(input, renderFilterSuggestionList(presentation, rule.value ?? ''));
|
|
818
849
|
}
|
|
819
850
|
|
|
820
851
|
return true;
|
|
@@ -837,17 +868,18 @@ function forEachFilterRule(node, callback, path = []) {
|
|
|
837
868
|
|
|
838
869
|
function renderFilterGroup(result, group, path, entry, { isRoot = false } = {}) {
|
|
839
870
|
const encodedPath = encodePath(path);
|
|
871
|
+
const groupLabel = isRoot ? 'Root filter group' : `Filter group ${formatFilterPath(path)}`;
|
|
840
872
|
return `
|
|
841
873
|
<div class="bases-filter-group"${isRoot ? ' data-base-filter-root' : ''}>
|
|
842
874
|
<div class="bases-filter-group-header">
|
|
843
|
-
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-conjunction' }))}" data-base-filter-conjunction="${escapeHtml(encodedPath)}">
|
|
875
|
+
<select class="${escapeHtml(inputClassNames({ extra: 'bases-select bases-filter-conjunction' }))}" data-base-filter-conjunction="${escapeHtml(encodedPath)}" aria-label="${groupLabel} condition">
|
|
844
876
|
${['and', 'or', 'not'].map((conjunction) => `<option value="${conjunction}"${group.conjunction === conjunction ? ' selected' : ''}>${escapeHtml({
|
|
845
877
|
and: 'All the following are true',
|
|
846
878
|
not: 'None of the following are true',
|
|
847
879
|
or: 'Any of the following are true',
|
|
848
880
|
}[conjunction])}</option>`).join('')}
|
|
849
881
|
</select>
|
|
850
|
-
${isRoot ? '' : `<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-remove="${escapeHtml(encodedPath)}">Delete group</button>`}
|
|
882
|
+
${isRoot ? '' : `<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-remove="${escapeHtml(encodedPath)}" aria-label="Delete ${groupLabel.toLowerCase()}">Delete group</button>`}
|
|
851
883
|
</div>
|
|
852
884
|
<div class="bases-filter-children">
|
|
853
885
|
${(group.children ?? []).map((child, index) => (
|
|
@@ -857,8 +889,8 @@ function renderFilterGroup(result, group, path, entry, { isRoot = false } = {})
|
|
|
857
889
|
)).join('')}
|
|
858
890
|
</div>
|
|
859
891
|
<div class="bases-filter-actions-row">
|
|
860
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-add-rule="${escapeHtml(encodedPath)}">Add filter</button>
|
|
861
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-add-group="${escapeHtml(encodedPath)}">Add filter group</button>
|
|
892
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-add-rule="${escapeHtml(encodedPath)}" aria-label="Add filter to ${groupLabel.toLowerCase()}">Add filter</button>
|
|
893
|
+
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-add-group="${escapeHtml(encodedPath)}" aria-label="Add filter group to ${groupLabel.toLowerCase()}">Add filter group</button>
|
|
862
894
|
</div>
|
|
863
895
|
</div>
|
|
864
896
|
`;
|
|
@@ -887,6 +919,7 @@ function renderFilterPanel(result, entry) {
|
|
|
887
919
|
${mode === 'advanced'
|
|
888
920
|
? `
|
|
889
921
|
<label class="bases-filter-advanced-label">
|
|
922
|
+
<span class="bases-panel-title">Filter expression</span>
|
|
890
923
|
<textarea class="${escapeHtml(inputClassNames({ extra: 'bases-filter-advanced' }))}" data-base-filter-advanced>${escapeHtml(rawText)}</textarea>
|
|
891
924
|
</label>
|
|
892
925
|
<div class="bases-filter-actions-row">
|
|
@@ -1091,14 +1124,14 @@ function updateShellContent(entry, result, {
|
|
|
1091
1124
|
} = {}) {
|
|
1092
1125
|
const shell = findShellElement(entry);
|
|
1093
1126
|
if (!shell?.querySelector) {
|
|
1094
|
-
entry.placeholder
|
|
1127
|
+
replaceChildrenFromHtml(entry.placeholder, renderShellHtml(result, entry));
|
|
1095
1128
|
markPlaceholderHydrated(entry.placeholder);
|
|
1096
1129
|
return;
|
|
1097
1130
|
}
|
|
1098
1131
|
|
|
1099
1132
|
const tabsSlot = shell.querySelector('[data-base-tabs]');
|
|
1100
1133
|
if (tabs && tabsSlot) {
|
|
1101
|
-
tabsSlot
|
|
1134
|
+
replaceChildrenFromHtml(tabsSlot, renderViewTabs(result));
|
|
1102
1135
|
}
|
|
1103
1136
|
|
|
1104
1137
|
const metaSlot = shell.querySelector('[data-base-meta]');
|
|
@@ -1108,24 +1141,24 @@ function updateShellContent(entry, result, {
|
|
|
1108
1141
|
|
|
1109
1142
|
const actionSlot = shell.querySelector('[data-base-action-slot]');
|
|
1110
1143
|
if (actions && actionSlot) {
|
|
1111
|
-
actionSlot
|
|
1144
|
+
replaceChildrenFromHtml(actionSlot, renderActionButtons(result, entry));
|
|
1112
1145
|
}
|
|
1113
1146
|
|
|
1114
1147
|
const panelSlot = shell.querySelector('[data-base-panel-slot]');
|
|
1115
1148
|
if (panel && panelSlot) {
|
|
1116
1149
|
const panelState = capturePanelState(panelSlot);
|
|
1117
|
-
panelSlot
|
|
1150
|
+
replaceChildrenFromHtml(panelSlot, renderPanel(result, entry));
|
|
1118
1151
|
restorePanelState(panelSlot, panelState);
|
|
1119
1152
|
}
|
|
1120
1153
|
|
|
1121
1154
|
const summarySlot = shell.querySelector('[data-base-summary-slot]');
|
|
1122
1155
|
if (summary && summarySlot) {
|
|
1123
|
-
summarySlot
|
|
1156
|
+
replaceChildrenFromHtml(summarySlot, renderSummaryBar(result.summaries));
|
|
1124
1157
|
}
|
|
1125
1158
|
|
|
1126
1159
|
const content = shell.querySelector('[data-base-content]');
|
|
1127
1160
|
if (body && content) {
|
|
1128
|
-
content
|
|
1161
|
+
replaceChildrenFromHtml(content, renderViewBody(result));
|
|
1129
1162
|
}
|
|
1130
1163
|
|
|
1131
1164
|
const input = shell.querySelector('.bases-search-input');
|
|
@@ -1663,7 +1696,7 @@ export class BasesPreviewController {
|
|
|
1663
1696
|
entry.requestVersion = requestVersion;
|
|
1664
1697
|
const hasShell = Boolean(findShellElement(entry));
|
|
1665
1698
|
if (!hasShell) {
|
|
1666
|
-
entry.placeholder
|
|
1699
|
+
replaceChildrenFromHtml(entry.placeholder, '<div class="preview-shell" role="status" aria-live="polite">Loading base…</div>');
|
|
1667
1700
|
}
|
|
1668
1701
|
try {
|
|
1669
1702
|
const response = await this.vaultApiClient.queryBase({
|
|
@@ -1687,11 +1720,11 @@ export class BasesPreviewController {
|
|
|
1687
1720
|
const shell = findShellElement(entry);
|
|
1688
1721
|
const content = shell?.querySelector?.('[data-base-content]') ?? null;
|
|
1689
1722
|
if (content) {
|
|
1690
|
-
content
|
|
1723
|
+
replaceChildrenFromHtml(content, `<div class="preview-shell" role="alert">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1691
1724
|
return;
|
|
1692
1725
|
}
|
|
1693
1726
|
}
|
|
1694
|
-
entry.placeholder
|
|
1727
|
+
replaceChildrenFromHtml(entry.placeholder, `<div class="preview-shell" role="alert">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1695
1728
|
}
|
|
1696
1729
|
}
|
|
1697
1730
|
|
|
@@ -314,7 +314,8 @@ function createComposer() {
|
|
|
314
314
|
textarea.className = inputClassNames({ extra: 'comment-card-input' });
|
|
315
315
|
textarea.rows = 4;
|
|
316
316
|
textarea.maxLength = COMMENT_BODY_MAX_LENGTH;
|
|
317
|
-
textarea.
|
|
317
|
+
textarea.setAttribute('aria-label', 'Add comment');
|
|
318
|
+
textarea.placeholder = 'Add context, feedback, or a question…';
|
|
318
319
|
textarea.value = this.activeCard?.composerDraft?.value ?? '';
|
|
319
320
|
|
|
320
321
|
const actions = document.createElement('div');
|
|
@@ -575,7 +576,8 @@ function createReplyComposer(thread) {
|
|
|
575
576
|
textarea.className = inputClassNames({ extra: 'comment-card-input' });
|
|
576
577
|
textarea.rows = 3;
|
|
577
578
|
textarea.maxLength = COMMENT_BODY_MAX_LENGTH;
|
|
578
|
-
textarea.
|
|
579
|
+
textarea.setAttribute('aria-label', 'Reply to thread');
|
|
580
|
+
textarea.placeholder = 'Reply to thread…';
|
|
579
581
|
textarea.value = draft?.value ?? '';
|
|
580
582
|
|
|
581
583
|
const actions = document.createElement('div');
|
|
@@ -13,7 +13,7 @@ function getFocusableItems(container) {
|
|
|
13
13
|
return [];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
return Array.from(container.querySelectorAll('.create-menu-item'));
|
|
16
|
+
return Array.from(container.querySelectorAll('.create-menu-item, .file-action-sheet-item:not(:disabled)'));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export class CreateMenuPresenter {
|
|
@@ -23,10 +23,10 @@ export class CreateMenuPresenter {
|
|
|
23
23
|
this.mobileBreakpointQuery = mobileBreakpointQuery;
|
|
24
24
|
this.activeAnchor = null;
|
|
25
25
|
this.desktopMenu = null;
|
|
26
|
-
this.mobileBackdrop = null;
|
|
27
26
|
this.mobileSheet = null;
|
|
28
27
|
this.documentPointerDownHandler = null;
|
|
29
28
|
this.windowResizeHandler = null;
|
|
29
|
+
this.blockingModalHandler = () => this.close();
|
|
30
30
|
this.boundClose = () => this.close();
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -71,15 +71,12 @@ export class CreateMenuPresenter {
|
|
|
71
71
|
this.desktopMenu = null;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
if (this.mobileBackdrop) {
|
|
75
|
-
this.mobileBackdrop.remove();
|
|
76
|
-
this.mobileBackdrop = null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
74
|
if (this.mobileSheet) {
|
|
75
|
+
if (this.mobileSheet.open) this.mobileSheet.close();
|
|
80
76
|
this.mobileSheet.remove();
|
|
81
77
|
this.mobileSheet = null;
|
|
82
78
|
}
|
|
79
|
+
document.removeEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
|
|
83
80
|
|
|
84
81
|
if (this.documentPointerDownHandler) {
|
|
85
82
|
document.removeEventListener('pointerdown', this.documentPointerDownHandler);
|
|
@@ -136,13 +133,9 @@ export class CreateMenuPresenter {
|
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
openMobileSheet({ items, title }) {
|
|
139
|
-
const
|
|
140
|
-
backdrop.type = 'button';
|
|
141
|
-
backdrop.className = 'file-action-sheet-backdrop';
|
|
142
|
-
backdrop.setAttribute('aria-label', `Close ${title.toLowerCase()} menu`);
|
|
143
|
-
|
|
144
|
-
const sheet = document.createElement('div');
|
|
136
|
+
const sheet = document.createElement('dialog');
|
|
145
137
|
sheet.className = 'file-action-sheet create-action-sheet';
|
|
138
|
+
sheet.setAttribute('aria-label', title);
|
|
146
139
|
|
|
147
140
|
const header = document.createElement('div');
|
|
148
141
|
header.className = 'create-action-sheet-header';
|
|
@@ -163,13 +156,21 @@ export class CreateMenuPresenter {
|
|
|
163
156
|
});
|
|
164
157
|
sheet.appendChild(cancelButton);
|
|
165
158
|
|
|
166
|
-
|
|
159
|
+
sheet.addEventListener('cancel', (event) => {
|
|
160
|
+
event.preventDefault();
|
|
167
161
|
this.close();
|
|
168
162
|
});
|
|
163
|
+
sheet.addEventListener('click', (event) => {
|
|
164
|
+
const bounds = sheet.getBoundingClientRect();
|
|
165
|
+
if (event.clientX < bounds.left || event.clientX > bounds.right
|
|
166
|
+
|| event.clientY < bounds.top || event.clientY > bounds.bottom) this.close();
|
|
167
|
+
});
|
|
169
168
|
|
|
170
|
-
document.body.append(
|
|
171
|
-
this.
|
|
169
|
+
document.body.append(sheet);
|
|
170
|
+
document.addEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
|
|
172
171
|
this.mobileSheet = sheet;
|
|
172
|
+
sheet.showModal();
|
|
173
|
+
getFocusableItems(sheet)[0]?.focus();
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
renderMenuItems(container, items, { mobile = false } = {}) {
|
|
@@ -198,6 +199,8 @@ export class CreateMenuPresenter {
|
|
|
198
199
|
const icon = document.createElement('span');
|
|
199
200
|
icon.className = 'create-menu-item-icon';
|
|
200
201
|
icon.setAttribute('aria-hidden', 'true');
|
|
202
|
+
// Menu icons are fixed application-owned markup.
|
|
203
|
+
// pi-lens-ignore: no-inner-html-js
|
|
201
204
|
icon.innerHTML = item.icon || '';
|
|
202
205
|
button.appendChild(icon);
|
|
203
206
|
|