collabmd 0.1.48 → 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 +61 -5
- package/bin/collabmd.js +3 -0
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -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/{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-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-B3l6Xy65.css → embedded-editor-base-BlCgz6mw.css} +1 -1
- package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
- package/dist/client/assets/{vault-utils-DvoSftJT.js → es-Bfdp096f.js} +13 -13
- 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/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/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/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/mermaid.core-BrY09czX.js +11 -0
- 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-_QTxqKvP.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/{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/{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 +67 -35
- package/integrations/pi/index.ts +94 -0
- package/package.json +41 -32
- 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 +49 -33
- 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/git-feature.js +23 -5
- package/src/client/application/app-shell/presence-feature.js +8 -25
- package/src/client/application/app-shell/ui-feature-shell.js +36 -91
- 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 +4 -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 +3 -1
- package/src/client/application/workspace-route-controller.js +7 -0
- package/src/client/bootstrap/collabmd-app-shell.js +78 -1
- package/src/client/domain/excalidraw-element-link.js +73 -0
- package/src/client/domain/excalidraw-scene.js +21 -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/excalidraw-editor.js +135 -10
- package/src/client/export/export-host.js +3 -1
- package/src/client/export/export-pipeline.js +4 -17
- 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 +11 -0
- package/src/client/infrastructure/editor-view-adapter.js +13 -0
- 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 +27 -18
- 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-explorer-view.js +70 -12
- package/src/client/presentation/file-history-view-controller.js +13 -11
- package/src/client/presentation/git-diff-view-controller.js +35 -43
- package/src/client/presentation/git-panel-controller.js +77 -27
- 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 +20 -78
- package/src/client/presentation/quick-switcher-text-search.js +10 -14
- package/src/client/styles/components/navigation.css +1 -2
- 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 +17 -4
- 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/quick-switcher.css +20 -11
- package/src/client/styles/foundation/themes.css +2 -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 +1 -0
- package/src/client/styles/layout/sidebar.css +7 -4
- package/src/client/styles/primitives/controls.css +21 -54
- package/src/client/styles/style.css +1 -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/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/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/pull-backup-store.js +2 -27
- package/src/server/infrastructure/persistence/vault-file-store.js +9 -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-DuoyznXW.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/document-formatter-Dxl_a8XO.js +0 -2
- package/dist/client/assets/drawio-editor-BVaNNtYp.js +0 -9
- package/dist/client/assets/drawioEditor-BkIBlXx0.js +0 -2
- package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
- package/dist/client/assets/editor-session-DMyVdHLj.js +0 -54
- package/dist/client/assets/excalidraw-editor-BjYaNEMY.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-ChqF_d82.js +0 -2
- package/dist/client/assets/export-page-Dyu0XCbu.js +0 -57
- package/dist/client/assets/exportDocument-CJBx4Xjx.css +0 -1
- package/dist/client/assets/exportDocument-Dgvfa2Sd.js +0 -2
- 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-CSNIMyOP.css +0 -1
- package/dist/client/assets/index-DG3N2Ps-.js +0 -2
- package/dist/client/assets/main-D0wCxpVn.js +0 -903
- package/dist/client/assets/mermaid.core-BJRLUQZE.js +0 -11
- package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
- package/dist/client/assets/preview-render-compiler-CrJIooVD.js +0 -35
- package/dist/client/assets/preview-render-compiler-O0JxBVNF.js +0 -1
- package/dist/client/assets/preview-render-profile-B4RWYWHt.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-CaEjEtq_.js +0 -1
- 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-BkwdFjx0.js +0 -6
- 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/{excalidraw-editor-BbSbI80a.css → excalidrawEditor-BbSbI80a.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();
|
|
@@ -346,10 +346,10 @@ function renderSortPanel(result) {
|
|
|
346
346
|
<div class="bases-panel-section">
|
|
347
347
|
<div class="bases-panel-title">Group by</div>
|
|
348
348
|
<div class="bases-sort-row">
|
|
349
|
-
<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">
|
|
350
350
|
${createSelectOptions(result, { allowBlank: true, selected: viewConfig.groupBy?.property ?? '' })}
|
|
351
351
|
</select>
|
|
352
|
-
<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'}>
|
|
353
353
|
${groupDirections.map((direction) => `<option value="${escapeHtml(direction.id)}"${direction.id === (viewConfig.groupBy?.direction ?? 'asc') ? ' selected' : ''}>${escapeHtml(direction.label)}</option>`).join('')}
|
|
354
354
|
</select>
|
|
355
355
|
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-clear-group-by${viewConfig.groupBy?.property ? '' : ' disabled'}>Clear</button>
|
|
@@ -366,15 +366,15 @@ function renderSortPanel(result) {
|
|
|
366
366
|
];
|
|
367
367
|
return `
|
|
368
368
|
<div class="bases-sort-row">
|
|
369
|
-
<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">
|
|
370
370
|
${createSelectOptions(result, { selected: sortConfig.property })}
|
|
371
371
|
</select>
|
|
372
|
-
<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">
|
|
373
373
|
${directions.map((direction) => `<option value="${escapeHtml(direction.id)}"${direction.id === sortConfig.direction ? ' selected' : ''}>${escapeHtml(direction.label)}</option>`).join('')}
|
|
374
374
|
</select>
|
|
375
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:up"${index === 0 ? ' disabled' : ''}>↑</button>
|
|
376
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-sort-move="${index}:down"${index === sorts.length - 1 ? ' disabled' : ''}>↓</button>
|
|
377
|
-
<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>
|
|
378
378
|
</div>
|
|
379
379
|
`;
|
|
380
380
|
}).join('')}
|
|
@@ -389,6 +389,10 @@ function encodePath(path = []) {
|
|
|
389
389
|
return path.join('.');
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
+
function formatFilterPath(path = []) {
|
|
393
|
+
return path.map((index) => index + 1).join('.');
|
|
394
|
+
}
|
|
395
|
+
|
|
392
396
|
function decodePath(value = '') {
|
|
393
397
|
return String(value ?? '')
|
|
394
398
|
.split('.')
|
|
@@ -773,9 +777,10 @@ function renderFilterSuggestionList(presentation, currentValue = '') {
|
|
|
773
777
|
|
|
774
778
|
function renderFilterValueCombobox(result, rule, path, entry) {
|
|
775
779
|
const presentation = buildFilterValuePresentation(result, rule, path, entry);
|
|
780
|
+
const filterLabel = `Filter ${formatFilterPath(path)}`;
|
|
776
781
|
return `
|
|
777
782
|
<div class="bases-filter-value-combobox${presentation.suggestionsEnabled ? ' has-suggestions' : ''}">
|
|
778
|
-
<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' : ''}>
|
|
779
784
|
${renderFilterSuggestionList(presentation, rule.value ?? '')}
|
|
780
785
|
</div>
|
|
781
786
|
`;
|
|
@@ -783,17 +788,18 @@ function renderFilterValueCombobox(result, rule, path, entry) {
|
|
|
783
788
|
|
|
784
789
|
function renderFilterRule(result, rule, path, entry) {
|
|
785
790
|
const presentation = buildFilterValuePresentation(result, rule, path, entry);
|
|
791
|
+
const filterLabel = `Filter ${formatFilterPath(path)}`;
|
|
786
792
|
|
|
787
793
|
return `
|
|
788
794
|
<div class="bases-filter-row">
|
|
789
|
-
<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">
|
|
790
796
|
${getPropertyOptionsMarkup(result, rule.propertyId)}
|
|
791
797
|
</select>
|
|
792
|
-
<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">
|
|
793
799
|
${presentation.operators.map((operator) => `<option value="${escapeHtml(operator)}"${operator === rule.operator ? ' selected' : ''}>${escapeHtml(operator)}</option>`).join('')}
|
|
794
800
|
</select>
|
|
795
801
|
${renderFilterValueCombobox(result, rule, path, entry)}
|
|
796
|
-
<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>
|
|
797
803
|
</div>
|
|
798
804
|
`;
|
|
799
805
|
}
|
|
@@ -819,6 +825,7 @@ function syncFilterValueCombobox(entry, result, path, { fallbackToFullRender = t
|
|
|
819
825
|
combobox.classList.toggle('has-suggestions', presentation.suggestionsEnabled);
|
|
820
826
|
input.className = presentation.valueInputClasses;
|
|
821
827
|
input.disabled = presentation.valueDisabled;
|
|
828
|
+
input.setAttribute('aria-label', `Filter ${formatFilterPath(path)} value`);
|
|
822
829
|
if (input.value !== String(rule.value ?? '')) {
|
|
823
830
|
input.value = String(rule.value ?? '');
|
|
824
831
|
}
|
|
@@ -861,17 +868,18 @@ function forEachFilterRule(node, callback, path = []) {
|
|
|
861
868
|
|
|
862
869
|
function renderFilterGroup(result, group, path, entry, { isRoot = false } = {}) {
|
|
863
870
|
const encodedPath = encodePath(path);
|
|
871
|
+
const groupLabel = isRoot ? 'Root filter group' : `Filter group ${formatFilterPath(path)}`;
|
|
864
872
|
return `
|
|
865
873
|
<div class="bases-filter-group"${isRoot ? ' data-base-filter-root' : ''}>
|
|
866
874
|
<div class="bases-filter-group-header">
|
|
867
|
-
<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">
|
|
868
876
|
${['and', 'or', 'not'].map((conjunction) => `<option value="${conjunction}"${group.conjunction === conjunction ? ' selected' : ''}>${escapeHtml({
|
|
869
877
|
and: 'All the following are true',
|
|
870
878
|
not: 'None of the following are true',
|
|
871
879
|
or: 'Any of the following are true',
|
|
872
880
|
}[conjunction])}</option>`).join('')}
|
|
873
881
|
</select>
|
|
874
|
-
${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>`}
|
|
875
883
|
</div>
|
|
876
884
|
<div class="bases-filter-children">
|
|
877
885
|
${(group.children ?? []).map((child, index) => (
|
|
@@ -881,8 +889,8 @@ function renderFilterGroup(result, group, path, entry, { isRoot = false } = {})
|
|
|
881
889
|
)).join('')}
|
|
882
890
|
</div>
|
|
883
891
|
<div class="bases-filter-actions-row">
|
|
884
|
-
<button type="button" class="${escapeHtml(buttonClassNames({ variant: 'secondary', size: 'compact' }))}" data-base-filter-add-rule="${escapeHtml(encodedPath)}">Add filter</button>
|
|
885
|
-
<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>
|
|
886
894
|
</div>
|
|
887
895
|
</div>
|
|
888
896
|
`;
|
|
@@ -911,6 +919,7 @@ function renderFilterPanel(result, entry) {
|
|
|
911
919
|
${mode === 'advanced'
|
|
912
920
|
? `
|
|
913
921
|
<label class="bases-filter-advanced-label">
|
|
922
|
+
<span class="bases-panel-title">Filter expression</span>
|
|
914
923
|
<textarea class="${escapeHtml(inputClassNames({ extra: 'bases-filter-advanced' }))}" data-base-filter-advanced>${escapeHtml(rawText)}</textarea>
|
|
915
924
|
</label>
|
|
916
925
|
<div class="bases-filter-actions-row">
|
|
@@ -1687,7 +1696,7 @@ export class BasesPreviewController {
|
|
|
1687
1696
|
entry.requestVersion = requestVersion;
|
|
1688
1697
|
const hasShell = Boolean(findShellElement(entry));
|
|
1689
1698
|
if (!hasShell) {
|
|
1690
|
-
replaceChildrenFromHtml(entry.placeholder, '<div class="preview-shell">Loading base…</div>');
|
|
1699
|
+
replaceChildrenFromHtml(entry.placeholder, '<div class="preview-shell" role="status" aria-live="polite">Loading base…</div>');
|
|
1691
1700
|
}
|
|
1692
1701
|
try {
|
|
1693
1702
|
const response = await this.vaultApiClient.queryBase({
|
|
@@ -1711,11 +1720,11 @@ export class BasesPreviewController {
|
|
|
1711
1720
|
const shell = findShellElement(entry);
|
|
1712
1721
|
const content = shell?.querySelector?.('[data-base-content]') ?? null;
|
|
1713
1722
|
if (content) {
|
|
1714
|
-
replaceChildrenFromHtml(content, `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1723
|
+
replaceChildrenFromHtml(content, `<div class="preview-shell" role="alert">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1715
1724
|
return;
|
|
1716
1725
|
}
|
|
1717
1726
|
}
|
|
1718
|
-
replaceChildrenFromHtml(entry.placeholder, `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1727
|
+
replaceChildrenFromHtml(entry.placeholder, `<div class="preview-shell" role="alert">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
|
|
1719
1728
|
}
|
|
1720
1729
|
}
|
|
1721
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
|
|