@hienlh/ppm 0.9.93 → 0.9.94
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/CHANGELOG.md +10 -0
- package/dist/web/assets/ai-settings-section-LMO_cfIW.js +1 -0
- package/dist/web/assets/api-client-o_6TmLGC.js +1 -0
- package/dist/web/assets/api-settings-CoKe_BdR.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-CUZIB1Vq.js +1 -0
- package/dist/web/assets/arrow-up-Dtrfv490.js +1 -0
- package/dist/web/assets/chat-tab-DQNdrUvL.js +10 -0
- package/dist/web/assets/chevron-right-BzAdxJRG.js +1 -0
- package/dist/web/assets/code-CuravVys.js +1 -0
- package/dist/web/assets/code-editor-B4XNYHnl.js +8 -0
- package/dist/web/assets/columns-2-4fQcE4PF.js +1 -0
- package/dist/web/assets/conflict-editor-BcsRDSCw.js +19 -0
- package/dist/web/assets/createLucideIcon-BjHrJDVb.js +1 -0
- package/dist/web/assets/{csv-preview-BZRICDP0.js → csv-preview-BizIVMyb.js} +2 -2
- package/dist/web/assets/database-D4DIhgi-.js +1 -0
- package/dist/web/assets/database-viewer-CfzAAtm3.js +2 -0
- package/dist/web/assets/diff-viewer-DgA9z9Ux.js +4 -0
- package/dist/web/assets/dist-C5IgeqrV.js +1 -0
- package/dist/web/assets/dist-im4ynINo.js +11 -0
- package/dist/web/assets/esm-K1XIK4vc.js +2 -0
- package/dist/web/assets/extension-store-3yZYn07W.js +1 -0
- package/dist/web/assets/{extension-webview-C1d6fezE.js → extension-webview-gHGB2Nw2.js} +2 -2
- package/dist/web/assets/gitGraph-HDMCJU4V-CtOMUphQ.js +1 -0
- package/dist/web/assets/index-B4mGNywE.js +26 -0
- package/dist/web/assets/index-BZ4G-2BK.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BCrPCWGY.js +1 -0
- package/dist/web/assets/input-CHRMley8.js +1 -0
- package/dist/web/assets/keybindings-store-BAuymsWd.js +1 -0
- package/dist/web/assets/keybindings-store-BKyNIeFB.js +1 -0
- package/dist/web/assets/{lib-DSLzfeW0.js → lib-D_kRA9p6.js} +1 -1
- package/dist/web/assets/markdown-renderer-sIjU5LtB.js +3 -0
- package/dist/web/assets/packet-RMMSAZCW-D_OqB-zi.js +1 -0
- package/dist/web/assets/pie-UPGHQEXC-WUHpLNJz.js +1 -0
- package/dist/web/assets/plus-51UQ45rf.js +1 -0
- package/dist/web/assets/port-forwarding-tab-BMXnuRuI.js +1 -0
- package/dist/web/assets/postgres-viewer-B6Wj5xiN.js +3 -0
- package/dist/web/assets/project-store-Ciq-cK1O.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-HQIIecVM.js +1 -0
- package/dist/web/assets/react-GqWghJ-L.js +1 -0
- package/dist/web/assets/refresh-cw-CSFrDtiu.js +1 -0
- package/dist/web/assets/scroll-area-DwWF9FpN.js +1 -0
- package/dist/web/assets/settings-store-B470PCWf.js +2 -0
- package/dist/web/assets/settings-tab-BKQo79HU.js +1 -0
- package/dist/web/assets/{sql-query-editor-DaePHpQI.js → sql-query-editor-DZ9xskL8.js} +1 -1
- package/dist/web/assets/sqlite-viewer-CytNesG3.js +1 -0
- package/dist/web/assets/square-nsMa3iMk.js +1 -0
- package/dist/web/assets/tab-store-DZbiYk7y.js +1 -0
- package/dist/web/assets/table-Dq575bPF.js +1 -0
- package/dist/web/assets/terminal-tab-DjfxKMSB.js +1 -0
- package/dist/web/assets/text-wrap-Cn6BNQfq.js +1 -0
- package/dist/web/assets/trash-2-CJYoLw7Q.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-0wLgUUTz.js +1 -0
- package/dist/web/assets/{use-monaco-theme-CM4IMROI.js → use-monaco-theme-OY18iXNi.js} +1 -1
- package/dist/web/assets/vendor-markdown-0Mxgxy0L.js +295 -0
- package/dist/web/assets/vendor-mermaid-B2SLgECS.js +2657 -0
- package/dist/web/assets/vendor-ui-B-T_damt.js +45 -0
- package/dist/web/assets/vendor-xterm-ejLe7-tK.js +36 -0
- package/dist/web/assets/x-DlFGzN8d.js +1 -0
- package/dist/web/index.html +26 -21
- package/dist/web/sw.js +1 -1
- package/docs/code-standards.md +56 -4
- package/docs/journals/260415-frontend-memory-optimization.md +73 -0
- package/docs/project-changelog.md +11 -1
- package/docs/system-architecture.md +36 -0
- package/package.json +1 -1
- package/src/web/components/chat/message-list.tsx +59 -22
- package/src/web/components/chat/tool-cards.tsx +11 -4
- package/src/web/components/database/data-grid.tsx +2 -1
- package/src/web/components/editor/code-editor.tsx +14 -8
- package/src/web/components/editor/conflict-editor.tsx +2 -1
- package/src/web/components/editor/diff-viewer.tsx +2 -1
- package/src/web/components/editor/editor-breadcrumb.tsx +2 -1
- package/src/web/components/explorer/file-tree.tsx +6 -5
- package/src/web/components/explorer/search-panel.tsx +2 -1
- package/src/web/components/git/git-status-panel.tsx +2 -1
- package/src/web/components/layout/add-project-form.tsx +2 -1
- package/src/web/components/layout/mobile-drawer.tsx +2 -1
- package/src/web/components/layout/mobile-nav.tsx +2 -1
- package/src/web/components/layout/panel-layout.tsx +3 -3
- package/src/web/components/layout/project-bar.tsx +7 -6
- package/src/web/components/layout/project-bottom-sheet.tsx +2 -1
- package/src/web/components/layout/sidebar.tsx +5 -4
- package/src/web/components/layout/status-bar.tsx +5 -4
- package/src/web/components/layout/tab-bar.tsx +3 -3
- package/src/web/components/layout/tab-content.tsx +2 -1
- package/src/web/components/postgres/postgres-viewer.tsx +7 -5
- package/src/web/components/settings/settings-tab.tsx +2 -1
- package/src/web/components/shared/markdown-code-block.tsx +10 -8
- package/src/web/components/terminal/terminal-tab.tsx +3 -3
- package/src/web/hooks/use-chat.ts +4 -1
- package/vite.config.ts +17 -0
- package/dist/web/assets/_basePickBy-Bj0dI1ei.js +0 -1
- package/dist/web/assets/_baseUniq-CyzdZeQH.js +0 -1
- package/dist/web/assets/ai-settings-section-Bo9lCaTd.js +0 -1
- package/dist/web/assets/api-client-BvxmRZUi.js +0 -1
- package/dist/web/assets/api-settings-CUxg9RE5.js +0 -1
- package/dist/web/assets/arc-CxgHJ7Z4.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-DDFO_NKq.js +0 -1
- package/dist/web/assets/architectureDiagram-2XIMDMQ5-D16OotsC.js +0 -36
- package/dist/web/assets/array-BFDiaBgf.js +0 -1
- package/dist/web/assets/arrow-up-I9-21gkR.js +0 -1
- package/dist/web/assets/blockDiagram-WCTKOSBZ-Ct57Wtfk.js +0 -132
- package/dist/web/assets/c4Diagram-IC4MRINW-BIymcNsg.js +0 -10
- package/dist/web/assets/channel-wumTB1if.js +0 -1
- package/dist/web/assets/chat-tab-CC721_mQ.js +0 -10
- package/dist/web/assets/chevron-right-DY_wImxB.js +0 -1
- package/dist/web/assets/chunk-4BX2VUAB-CENmY7Kw.js +0 -1
- package/dist/web/assets/chunk-55IACEB6-DhZGI1l3.js +0 -1
- package/dist/web/assets/chunk-7E7YKBS2-DZcnC7Ow.js +0 -1
- package/dist/web/assets/chunk-7R4GIKGN-y8bfHEy-.js +0 -80
- package/dist/web/assets/chunk-C72U2L5F-BHPkfQj2.js +0 -1
- package/dist/web/assets/chunk-EGIJ26TM-nant2LXl.js +0 -1
- package/dist/web/assets/chunk-FMBD7UC4-Bog4cpN-.js +0 -15
- package/dist/web/assets/chunk-GEFDOKGD-86LFbsAC.js +0 -2
- package/dist/web/assets/chunk-GLR3WWYH-Re-5eSlQ.js +0 -2
- package/dist/web/assets/chunk-HHEYEP7N-C45i5G_3.js +0 -1
- package/dist/web/assets/chunk-JSJVCQXG-23eG9mgt.js +0 -1
- package/dist/web/assets/chunk-KX2RTZJC-CHj8TnTB.js +0 -1
- package/dist/web/assets/chunk-KYZI473N-gqRLpJ4w.js +0 -53
- package/dist/web/assets/chunk-L3YUKLVL-DnSMmNFC.js +0 -1
- package/dist/web/assets/chunk-MX3YWQON-B6g1ZH9X.js +0 -1
- package/dist/web/assets/chunk-NQ4KR5QH-DX32345Y.js +0 -220
- package/dist/web/assets/chunk-O4XLMI2P-Vp_V4P-b.js +0 -7
- package/dist/web/assets/chunk-OZEHJAEY-lKq2SWjA.js +0 -1
- package/dist/web/assets/chunk-PQ6SQG4A-Bik13fTV.js +0 -1
- package/dist/web/assets/chunk-PU5JKC2W-DD95Rx35.js +0 -70
- package/dist/web/assets/chunk-QZHKN3VN-N3VXx1VH.js +0 -1
- package/dist/web/assets/chunk-R5LLSJPH-dRhXRnrb.js +0 -1
- package/dist/web/assets/chunk-WL4C6EOR-B1iIvLOG.js +0 -189
- package/dist/web/assets/chunk-XIRO2GV7-DZBoNl1_.js +0 -1
- package/dist/web/assets/chunk-XPW4576I-CgLyyW03.js +0 -32
- package/dist/web/assets/chunk-XZSTWKYB-DjV8xl5A.js +0 -94
- package/dist/web/assets/chunk-YBOYWFTD-D_ILLe6_.js +0 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-mr-Cb1me.js +0 -1
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-BKe8_uda.js +0 -1
- package/dist/web/assets/clone--z5KLAuR.js +0 -1
- package/dist/web/assets/code-editor-BZ0xwZ4Z.js +0 -8
- package/dist/web/assets/columns-2-IeETSfON.js +0 -1
- package/dist/web/assets/conflict-editor-Bwls2-yk.js +0 -19
- package/dist/web/assets/cose-bilkent-S5V4N54A-BGNPFv3x.js +0 -1
- package/dist/web/assets/cytoscape.esm-C8i2jUzT.js +0 -321
- package/dist/web/assets/dagre-CkhlMHnx.js +0 -1
- package/dist/web/assets/dagre-KLK3FWXG-Cnp996VG.js +0 -4
- package/dist/web/assets/database-CgTomMxt.js +0 -1
- package/dist/web/assets/database-viewer-DiXWqOJH.js +0 -2
- package/dist/web/assets/defaultLocale-ZeknFqNe.js +0 -1
- package/dist/web/assets/diagram-E7M64L7V-BZF0tSOr.js +0 -24
- package/dist/web/assets/diagram-IFDJBPK2-nUcO8sN8.js +0 -43
- package/dist/web/assets/diagram-P4PSJMXO-CW0eCkwC.js +0 -24
- package/dist/web/assets/diff-viewer-CC-RmeV5.js +0 -4
- package/dist/web/assets/dist-CM0oD8tQ.js +0 -1
- package/dist/web/assets/dist-DZmJeHOA.js +0 -1
- package/dist/web/assets/erDiagram-INFDFZHY-DSkriYZ9.js +0 -70
- package/dist/web/assets/flowDiagram-PKNHOUZH-CFYAfZBx.js +0 -162
- package/dist/web/assets/ganttDiagram-A5KZAMGK-KSn4XAU4.js +0 -292
- package/dist/web/assets/gitGraph-HDMCJU4V-OkvBPi6H.js +0 -1
- package/dist/web/assets/gitGraphDiagram-K3NZZRJ6-BMgjjVys.js +0 -65
- package/dist/web/assets/graphlib-BWe1iK_s.js +0 -1
- package/dist/web/assets/index-BcIyrJiY.js +0 -26
- package/dist/web/assets/index-Chf0otez.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BDU2_bYD.js +0 -1
- package/dist/web/assets/infoDiagram-LFFYTUFH-Diq4Cyc3.js +0 -2
- package/dist/web/assets/init-0VJVrkRJ.js +0 -1
- package/dist/web/assets/input-BHj0veau.js +0 -45
- package/dist/web/assets/isArrayLikeObject-ClzWCpcm.js +0 -1
- package/dist/web/assets/isEmpty-BfLnxq-B.js +0 -1
- package/dist/web/assets/ishikawaDiagram-PHBUUO56-CiVEvp8o.js +0 -70
- package/dist/web/assets/journeyDiagram-4ABVD52K-CG_v5Aho.js +0 -139
- package/dist/web/assets/jsx-runtime-BRW_vwa9.js +0 -1
- package/dist/web/assets/kanban-definition-K7BYSVSG-miB0-_Zq.js +0 -89
- package/dist/web/assets/keybindings-store-BIufrOzJ.js +0 -1
- package/dist/web/assets/line-CSuSrJ9J.js +0 -1
- package/dist/web/assets/linear-DFN_MPsw.js +0 -1
- package/dist/web/assets/markdown-renderer-C5UPA1-7.js +0 -306
- package/dist/web/assets/math-CRc16Nj6.js +0 -1
- package/dist/web/assets/mermaid-parser.core-CFdP1Z5_.js +0 -4
- package/dist/web/assets/mindmap-definition-YRQLILUH-pYPWwASE.js +0 -68
- package/dist/web/assets/ordinal-DpFn432U.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BwpIpYB3.js +0 -1
- package/dist/web/assets/path-INs8XTPH.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BPgAfmes.js +0 -1
- package/dist/web/assets/pieDiagram-SKSYHLDU-Dovdlvhu.js +0 -30
- package/dist/web/assets/plus-DQGIb4mQ.js +0 -1
- package/dist/web/assets/port-forwarding-tab-DmifthYH.js +0 -1
- package/dist/web/assets/postgres-viewer-Bo7jEQfQ.js +0 -13
- package/dist/web/assets/preload-helper-mr3rCizq.js +0 -1
- package/dist/web/assets/quadrantDiagram-337W2JSQ-TXe6cU_F.js +0 -7
- package/dist/web/assets/radar-KQ55EAFF-TqxBkWx-.js +0 -1
- package/dist/web/assets/react-0tkk-ztn.js +0 -1
- package/dist/web/assets/react-dom-Bpkvzu3U.js +0 -1
- package/dist/web/assets/react-nm2Ru1Pt.js +0 -1
- package/dist/web/assets/refresh-cw-Clk8fdUD.js +0 -1
- package/dist/web/assets/requirementDiagram-Z7DCOOCP-CuiiuGS9.js +0 -73
- package/dist/web/assets/rough.esm-eLccZ4OJ.js +0 -1
- package/dist/web/assets/sankeyDiagram-WA2Y5GQK-BbRmhv0t.js +0 -10
- package/dist/web/assets/scroll-area-BpXCNme3.js +0 -1
- package/dist/web/assets/sequenceDiagram-2WXFIKYE-B2D8IQDb.js +0 -145
- package/dist/web/assets/settings-tab-D9GicyA9.js +0 -1
- package/dist/web/assets/sqlite-viewer-pacZlViY.js +0 -1
- package/dist/web/assets/square-vBdqj0bF.js +0 -1
- package/dist/web/assets/src-CqyWLlNZ.js +0 -1
- package/dist/web/assets/stateDiagram-RAJIS63D-ylr4HxPu.js +0 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D6zvxf3M.js +0 -1
- package/dist/web/assets/table-Bi27fEaN.js +0 -1
- package/dist/web/assets/terminal-tab-DpzE3yoD.js +0 -36
- package/dist/web/assets/text-wrap-D_OmSzhp.js +0 -1
- package/dist/web/assets/timeline-definition-YZTLITO2-pMv1grvM.js +0 -61
- package/dist/web/assets/trash-2-CNuB-htI.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-Kck06FKU.js +0 -1
- package/dist/web/assets/vennDiagram-LZ73GAT5-C-rkIUbo.js +0 -34
- package/dist/web/assets/x-Dw3TjeY_.js +0 -1
- package/dist/web/assets/xychartDiagram-JWTSCODW-CtpjAakO.js +0 -7
- /package/dist/web/assets/{csv-parser-i7fjqP2H.js → csv-parser--2WJNgS7.js} +0 -0
- /package/dist/web/assets/{katex-DR0kdMDv.js → katex-CKoArbIw.js} +0 -0
- /package/dist/web/assets/{chunk-CFjPhJqf.js → rolldown-runtime-FhOqtrmT.js} +0 -0
- /package/dist/web/assets/{sql-completion-provider-B8uUWWej.js → sql-completion-provider-C3cq9j99.js} +0 -0
- /package/dist/web/assets/{utils-DX8jb5qv.js → utils-ChWX7pZv.js} +0 -0
- /package/dist/web/assets/{terminal-tab-BrP-ENHg.css → vendor-xterm-BrP-ENHg.css} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-BjHrJDVb.js";var t=e(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]),n=e(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),r=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{n,t as r,r as t};
|
package/dist/web/index.html
CHANGED
|
@@ -39,27 +39,32 @@
|
|
|
39
39
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
40
40
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
41
41
|
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
42
|
-
<script type="module" crossorigin src="/assets/index-
|
|
43
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
44
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
45
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
46
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
47
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
48
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
49
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
50
|
-
<link rel="modulepreload" crossorigin href="/assets/input-
|
|
51
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
52
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
53
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
54
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
55
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
56
|
-
<link rel="modulepreload" crossorigin href="/assets/api-
|
|
57
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
58
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
59
|
-
<link rel="modulepreload" crossorigin href="/assets/chevron-right-
|
|
60
|
-
<link rel="modulepreload" crossorigin href="/assets/database-
|
|
61
|
-
<link rel="modulepreload" crossorigin href="/assets/react-
|
|
62
|
-
<link rel="
|
|
42
|
+
<script type="module" crossorigin src="/assets/index-B4mGNywE.js"></script>
|
|
43
|
+
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-FhOqtrmT.js">
|
|
44
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-mermaid-B2SLgECS.js">
|
|
45
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-0Mxgxy0L.js">
|
|
46
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-ui-B-T_damt.js">
|
|
47
|
+
<link rel="modulepreload" crossorigin href="/assets/utils-ChWX7pZv.js">
|
|
48
|
+
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BjHrJDVb.js">
|
|
49
|
+
<link rel="modulepreload" crossorigin href="/assets/x-DlFGzN8d.js">
|
|
50
|
+
<link rel="modulepreload" crossorigin href="/assets/input-CHRMley8.js">
|
|
51
|
+
<link rel="modulepreload" crossorigin href="/assets/scroll-area-DwWF9FpN.js">
|
|
52
|
+
<link rel="modulepreload" crossorigin href="/assets/dist-C5IgeqrV.js">
|
|
53
|
+
<link rel="modulepreload" crossorigin href="/assets/plus-51UQ45rf.js">
|
|
54
|
+
<link rel="modulepreload" crossorigin href="/assets/refresh-cw-CSFrDtiu.js">
|
|
55
|
+
<link rel="modulepreload" crossorigin href="/assets/trash-2-CJYoLw7Q.js">
|
|
56
|
+
<link rel="modulepreload" crossorigin href="/assets/api-client-o_6TmLGC.js">
|
|
57
|
+
<link rel="modulepreload" crossorigin href="/assets/api-settings-CoKe_BdR.js">
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/ai-settings-section-LMO_cfIW.js">
|
|
59
|
+
<link rel="modulepreload" crossorigin href="/assets/chevron-right-BzAdxJRG.js">
|
|
60
|
+
<link rel="modulepreload" crossorigin href="/assets/database-D4DIhgi-.js">
|
|
61
|
+
<link rel="modulepreload" crossorigin href="/assets/react-GqWghJ-L.js">
|
|
62
|
+
<link rel="modulepreload" crossorigin href="/assets/extension-store-3yZYn07W.js">
|
|
63
|
+
<link rel="modulepreload" crossorigin href="/assets/keybindings-store-BAuymsWd.js">
|
|
64
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-store-DZbiYk7y.js">
|
|
65
|
+
<link rel="modulepreload" crossorigin href="/assets/project-store-Ciq-cK1O.js">
|
|
66
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-store-B470PCWf.js">
|
|
67
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BZ4G-2BK.css">
|
|
63
68
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
64
69
|
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
65
70
|
<div id="root"></div>
|
package/dist/web/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"2acfba999ac6948556cd14fc22ee7ac9","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":null,"url":"assets/xychartDiagram-JWTSCODW-CtpjAakO.js"},{"revision":null,"url":"assets/x-Dw3TjeY_.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-C-rkIUbo.js"},{"revision":null,"url":"assets/utils-DX8jb5qv.js"},{"revision":null,"url":"assets/use-monaco-theme-CM4IMROI.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-Kck06FKU.js"},{"revision":null,"url":"assets/trash-2-CNuB-htI.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-pMv1grvM.js"},{"revision":null,"url":"assets/text-wrap-D_OmSzhp.js"},{"revision":null,"url":"assets/terminal-tab-DpzE3yoD.js"},{"revision":null,"url":"assets/terminal-tab-BrP-ENHg.css"},{"revision":null,"url":"assets/table-Bi27fEaN.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-D6zvxf3M.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-ylr4HxPu.js"},{"revision":null,"url":"assets/src-CqyWLlNZ.js"},{"revision":null,"url":"assets/square-vBdqj0bF.js"},{"revision":null,"url":"assets/sqlite-viewer-pacZlViY.js"},{"revision":null,"url":"assets/sql-query-editor-DaePHpQI.js"},{"revision":null,"url":"assets/sql-completion-provider-B8uUWWej.js"},{"revision":null,"url":"assets/settings-tab-D9GicyA9.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-B2D8IQDb.js"},{"revision":null,"url":"assets/scroll-area-BpXCNme3.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-BbRmhv0t.js"},{"revision":null,"url":"assets/rough.esm-eLccZ4OJ.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-CuiiuGS9.js"},{"revision":null,"url":"assets/refresh-cw-Clk8fdUD.js"},{"revision":null,"url":"assets/react-nm2Ru1Pt.js"},{"revision":null,"url":"assets/react-dom-Bpkvzu3U.js"},{"revision":null,"url":"assets/react-0tkk-ztn.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-TqxBkWx-.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-TXe6cU_F.js"},{"revision":null,"url":"assets/preload-helper-mr3rCizq.js"},{"revision":null,"url":"assets/postgres-viewer-Bo7jEQfQ.js"},{"revision":null,"url":"assets/port-forwarding-tab-DmifthYH.js"},{"revision":null,"url":"assets/plus-DQGIb4mQ.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-Dovdlvhu.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-BPgAfmes.js"},{"revision":null,"url":"assets/path-INs8XTPH.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-BwpIpYB3.js"},{"revision":null,"url":"assets/ordinal-DpFn432U.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-pYPWwASE.js"},{"revision":null,"url":"assets/mermaid-parser.core-CFdP1Z5_.js"},{"revision":null,"url":"assets/math-CRc16Nj6.js"},{"revision":null,"url":"assets/markdown-renderer-C5UPA1-7.js"},{"revision":null,"url":"assets/linear-DFN_MPsw.js"},{"revision":null,"url":"assets/line-CSuSrJ9J.js"},{"revision":null,"url":"assets/lib-DSLzfeW0.js"},{"revision":null,"url":"assets/keybindings-store-BIufrOzJ.js"},{"revision":null,"url":"assets/katex-DR0kdMDv.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-miB0-_Zq.js"},{"revision":null,"url":"assets/jsx-runtime-BRW_vwa9.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-CG_v5Aho.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-CiVEvp8o.js"},{"revision":null,"url":"assets/isEmpty-BfLnxq-B.js"},{"revision":null,"url":"assets/isArrayLikeObject-ClzWCpcm.js"},{"revision":null,"url":"assets/input-BHj0veau.js"},{"revision":null,"url":"assets/init-0VJVrkRJ.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-Diq4Cyc3.js"},{"revision":null,"url":"assets/info-3K5VOQVL-BDU2_bYD.js"},{"revision":null,"url":"assets/index-Chf0otez.css"},{"revision":null,"url":"assets/index-BcIyrJiY.js"},{"revision":null,"url":"assets/graphlib-BWe1iK_s.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-BMgjjVys.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-OkvBPi6H.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-KSn4XAU4.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-CFYAfZBx.js"},{"revision":null,"url":"assets/extension-webview-C1d6fezE.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-DSkriYZ9.js"},{"revision":null,"url":"assets/dist-DZmJeHOA.js"},{"revision":null,"url":"assets/dist-CM0oD8tQ.js"},{"revision":null,"url":"assets/diff-viewer-CC-RmeV5.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO-CW0eCkwC.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-nUcO8sN8.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-BZF0tSOr.js"},{"revision":null,"url":"assets/defaultLocale-ZeknFqNe.js"},{"revision":null,"url":"assets/database-viewer-DiXWqOJH.js"},{"revision":null,"url":"assets/database-CgTomMxt.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-Cnp996VG.js"},{"revision":null,"url":"assets/dagre-CkhlMHnx.js"},{"revision":null,"url":"assets/cytoscape.esm-C8i2jUzT.js"},{"revision":null,"url":"assets/csv-preview-BZRICDP0.js"},{"revision":null,"url":"assets/csv-parser-i7fjqP2H.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-BGNPFv3x.js"},{"revision":null,"url":"assets/conflict-editor-Bwls2-yk.js"},{"revision":null,"url":"assets/columns-2-IeETSfON.js"},{"revision":null,"url":"assets/code-editor-BZ0xwZ4Z.js"},{"revision":null,"url":"assets/clone--z5KLAuR.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-BKe8_uda.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-mr-Cb1me.js"},{"revision":null,"url":"assets/chunk-YBOYWFTD-D_ILLe6_.js"},{"revision":null,"url":"assets/chunk-XZSTWKYB-DjV8xl5A.js"},{"revision":null,"url":"assets/chunk-XPW4576I-CgLyyW03.js"},{"revision":null,"url":"assets/chunk-XIRO2GV7-DZBoNl1_.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-B1iIvLOG.js"},{"revision":null,"url":"assets/chunk-R5LLSJPH-dRhXRnrb.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-N3VXx1VH.js"},{"revision":null,"url":"assets/chunk-PU5JKC2W-DD95Rx35.js"},{"revision":null,"url":"assets/chunk-PQ6SQG4A-Bik13fTV.js"},{"revision":null,"url":"assets/chunk-OZEHJAEY-lKq2SWjA.js"},{"revision":null,"url":"assets/chunk-O4XLMI2P-Vp_V4P-b.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-DX32345Y.js"},{"revision":null,"url":"assets/chunk-MX3YWQON-B6g1ZH9X.js"},{"revision":null,"url":"assets/chunk-L3YUKLVL-DnSMmNFC.js"},{"revision":null,"url":"assets/chunk-KYZI473N-gqRLpJ4w.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-CHj8TnTB.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-23eG9mgt.js"},{"revision":null,"url":"assets/chunk-HHEYEP7N-C45i5G_3.js"},{"revision":null,"url":"assets/chunk-GLR3WWYH-Re-5eSlQ.js"},{"revision":null,"url":"assets/chunk-GEFDOKGD-86LFbsAC.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-Bog4cpN-.js"},{"revision":null,"url":"assets/chunk-EGIJ26TM-nant2LXl.js"},{"revision":null,"url":"assets/chunk-CFjPhJqf.js"},{"revision":null,"url":"assets/chunk-C72U2L5F-BHPkfQj2.js"},{"revision":null,"url":"assets/chunk-7R4GIKGN-y8bfHEy-.js"},{"revision":null,"url":"assets/chunk-7E7YKBS2-DZcnC7Ow.js"},{"revision":null,"url":"assets/chunk-55IACEB6-DhZGI1l3.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-CENmY7Kw.js"},{"revision":null,"url":"assets/chevron-right-DY_wImxB.js"},{"revision":null,"url":"assets/chat-tab-CC721_mQ.js"},{"revision":null,"url":"assets/channel-wumTB1if.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-BIymcNsg.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-Ct57Wtfk.js"},{"revision":null,"url":"assets/arrow-up-I9-21gkR.js"},{"revision":null,"url":"assets/array-BFDiaBgf.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-D16OotsC.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-DDFO_NKq.js"},{"revision":null,"url":"assets/arc-CxgHJ7Z4.js"},{"revision":null,"url":"assets/api-settings-CUxg9RE5.js"},{"revision":null,"url":"assets/api-client-BvxmRZUi.js"},{"revision":null,"url":"assets/ai-settings-section-Bo9lCaTd.js"},{"revision":null,"url":"assets/_baseUniq-CyzdZeQH.js"},{"revision":null,"url":"assets/_basePickBy-Bj0dI1ei.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":"79c8870653c8f419f2e3323085e1f4be","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.png`,badge:`/icon-192.png`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
|
1
|
+
try{self[`workbox:core:7.3.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.3.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.3.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.3.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&!(t.origin!==location.origin&&n.index!==0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}function B(e){O().precache(e)}function V(e,t){B(e),z(t)}V([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"bb17db0c4e0bcb9022212d56deaeeeaf","url":"index.html"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-512.svg"},{"revision":"a0fb34fc84eb148d51812cd62669f20d","url":"icon-192.svg"},{"revision":"948e060affb598c339be40d69e1f6f9c","url":"monacoeditorwork/ts.worker.bundle.js"},{"revision":"a5d8a1acfc29c2a4c882a54ffc93def3","url":"monacoeditorwork/json.worker.bundle.js"},{"revision":"d0f94ce046cf8cf09605ee7664dac557","url":"monacoeditorwork/html.worker.bundle.js"},{"revision":"a424156a79b9c1b907db93aa3180585a","url":"monacoeditorwork/editor.worker.bundle.js"},{"revision":"b3a7f967560c9816492a1567b3f7f0dc","url":"monacoeditorwork/css.worker.bundle.js"},{"revision":null,"url":"assets/x-DlFGzN8d.js"},{"revision":null,"url":"assets/vendor-xterm-ejLe7-tK.js"},{"revision":null,"url":"assets/vendor-xterm-BrP-ENHg.css"},{"revision":null,"url":"assets/vendor-ui-B-T_damt.js"},{"revision":null,"url":"assets/vendor-mermaid-B2SLgECS.js"},{"revision":null,"url":"assets/vendor-markdown-0Mxgxy0L.js"},{"revision":null,"url":"assets/utils-ChWX7pZv.js"},{"revision":null,"url":"assets/use-monaco-theme-OY18iXNi.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-0wLgUUTz.js"},{"revision":null,"url":"assets/trash-2-CJYoLw7Q.js"},{"revision":null,"url":"assets/text-wrap-Cn6BNQfq.js"},{"revision":null,"url":"assets/terminal-tab-DjfxKMSB.js"},{"revision":null,"url":"assets/table-Dq575bPF.js"},{"revision":null,"url":"assets/tab-store-DZbiYk7y.js"},{"revision":null,"url":"assets/square-nsMa3iMk.js"},{"revision":null,"url":"assets/sqlite-viewer-CytNesG3.js"},{"revision":null,"url":"assets/sql-query-editor-DZ9xskL8.js"},{"revision":null,"url":"assets/sql-completion-provider-C3cq9j99.js"},{"revision":null,"url":"assets/settings-tab-BKQo79HU.js"},{"revision":null,"url":"assets/settings-store-B470PCWf.js"},{"revision":null,"url":"assets/scroll-area-DwWF9FpN.js"},{"revision":null,"url":"assets/rolldown-runtime-FhOqtrmT.js"},{"revision":null,"url":"assets/refresh-cw-CSFrDtiu.js"},{"revision":null,"url":"assets/react-GqWghJ-L.js"},{"revision":null,"url":"assets/radar-KQ55EAFF-HQIIecVM.js"},{"revision":null,"url":"assets/project-store-Ciq-cK1O.js"},{"revision":null,"url":"assets/postgres-viewer-B6Wj5xiN.js"},{"revision":null,"url":"assets/port-forwarding-tab-BMXnuRuI.js"},{"revision":null,"url":"assets/plus-51UQ45rf.js"},{"revision":null,"url":"assets/pie-UPGHQEXC-WUHpLNJz.js"},{"revision":null,"url":"assets/packet-RMMSAZCW-D_OqB-zi.js"},{"revision":null,"url":"assets/markdown-renderer-sIjU5LtB.js"},{"revision":null,"url":"assets/lib-D_kRA9p6.js"},{"revision":null,"url":"assets/keybindings-store-BKyNIeFB.js"},{"revision":null,"url":"assets/keybindings-store-BAuymsWd.js"},{"revision":null,"url":"assets/katex-CKoArbIw.js"},{"revision":null,"url":"assets/input-CHRMley8.js"},{"revision":null,"url":"assets/info-3K5VOQVL-BCrPCWGY.js"},{"revision":null,"url":"assets/index-BZ4G-2BK.css"},{"revision":null,"url":"assets/index-B4mGNywE.js"},{"revision":null,"url":"assets/gitGraph-HDMCJU4V-CtOMUphQ.js"},{"revision":null,"url":"assets/extension-webview-gHGB2Nw2.js"},{"revision":null,"url":"assets/extension-store-3yZYn07W.js"},{"revision":null,"url":"assets/esm-K1XIK4vc.js"},{"revision":null,"url":"assets/dist-im4ynINo.js"},{"revision":null,"url":"assets/dist-C5IgeqrV.js"},{"revision":null,"url":"assets/diff-viewer-DgA9z9Ux.js"},{"revision":null,"url":"assets/database-viewer-CfzAAtm3.js"},{"revision":null,"url":"assets/database-D4DIhgi-.js"},{"revision":null,"url":"assets/csv-preview-BizIVMyb.js"},{"revision":null,"url":"assets/csv-parser--2WJNgS7.js"},{"revision":null,"url":"assets/createLucideIcon-BjHrJDVb.js"},{"revision":null,"url":"assets/conflict-editor-BcsRDSCw.js"},{"revision":null,"url":"assets/columns-2-4fQcE4PF.js"},{"revision":null,"url":"assets/code-editor-B4XNYHnl.js"},{"revision":null,"url":"assets/code-CuravVys.js"},{"revision":null,"url":"assets/chevron-right-BzAdxJRG.js"},{"revision":null,"url":"assets/chat-tab-DQNdrUvL.js"},{"revision":null,"url":"assets/arrow-up-Dtrfv490.js"},{"revision":null,"url":"assets/architecture-PBZL5I3N-CUZIB1Vq.js"},{"revision":null,"url":"assets/api-settings-CoKe_BdR.js"},{"revision":null,"url":"assets/api-client-o_6TmLGC.js"},{"revision":null,"url":"assets/ai-settings-section-LMO_cfIW.js"},{"revision":null,"url":"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2"},{"revision":null,"url":"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2"},{"revision":null,"url":"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2"},{"revision":null,"url":"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2"},{"revision":null,"url":"assets/KaTeX_Script-Regular-D3wIWfF6.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2"},{"revision":null,"url":"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2"},{"revision":null,"url":"assets/KaTeX_Math-Italic-t53AETM-.woff2"},{"revision":null,"url":"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Regular-B22Nviop.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2"},{"revision":null,"url":"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2"},{"revision":null,"url":"assets/KaTeX_Main-Bold-Cx986IdX.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2"},{"revision":null,"url":"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2"},{"revision":null,"url":"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2"},{"revision":null,"url":"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2"},{"revision":"79c8870653c8f419f2e3323085e1f4be","url":"manifest.webmanifest"}]),self.addEventListener(`push`,e=>{e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{if(t.some(e=>e.visibilityState===`visible`))return;let n=e.data?.json()??{title:`PPM`,body:`Chat completed`};return self.registration.showNotification(n.title,{body:n.body,icon:`/icon-192.png`,badge:`/icon-192.png`,tag:`ppm-chat-done`,silent:!1,data:{url:self.location.origin}})}))}),self.addEventListener(`notificationclick`,e=>{e.notification.close(),e.waitUntil(self.clients.matchAll({type:`window`,includeUncontrolled:!0}).then(t=>{for(let e of t)if(e.url.includes(self.location.origin)&&`focus`in e)return e.focus();return self.clients.openWindow(e.notification.data?.url||`/`)}))});
|
package/docs/code-standards.md
CHANGED
|
@@ -146,8 +146,8 @@ export function ChatTab() {
|
|
|
146
146
|
}
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
### Zustand Stores
|
|
150
|
-
Define stores as singleton exports. Use
|
|
149
|
+
### Zustand Stores (useShallow)
|
|
150
|
+
Define stores as singleton exports. Use `useShallow` when destructuring state to prevent unnecessary re-renders:
|
|
151
151
|
|
|
152
152
|
```typescript
|
|
153
153
|
// Good: src/web/stores/chat-store.ts
|
|
@@ -156,10 +156,28 @@ export const chatStore = create<ChatState>((set) => ({
|
|
|
156
156
|
addMessage: (msg) => set((state) => ({ messages: [...state.messages, msg] })),
|
|
157
157
|
}));
|
|
158
158
|
|
|
159
|
-
// Usage with
|
|
159
|
+
// Usage with useShallow (avoids full re-render on object mutations)
|
|
160
|
+
const { messages, addMessage } = chatStore(useShallow((state) => ({
|
|
161
|
+
messages: state.messages,
|
|
162
|
+
addMessage: state.addMessage,
|
|
163
|
+
})));
|
|
164
|
+
|
|
165
|
+
// Single selector still works without useShallow
|
|
160
166
|
const messages = chatStore((state) => state.messages);
|
|
161
167
|
```
|
|
162
168
|
|
|
169
|
+
### Component Memoization (React.memo)
|
|
170
|
+
Memoize expensive components to prevent re-renders from parent updates:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Good: Memoized heavy component
|
|
174
|
+
export const CodeEditor = memo(function CodeEditor({ filePath }: Props) {
|
|
175
|
+
return <MonacoEditor path={filePath} />;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Memoized components: CodeEditor, MessageBubble, ProjectBar, ProjectAvatar, TerminalTab, PanelLayout, Sidebar, StatusBar, StatusBarEntry, TabBar, TreeNode
|
|
179
|
+
```
|
|
180
|
+
|
|
163
181
|
### Custom Hooks
|
|
164
182
|
Extract logic into hooks for reusability. Return stable references:
|
|
165
183
|
|
|
@@ -616,13 +634,47 @@ type FileStatus =
|
|
|
616
634
|
## Performance Conventions
|
|
617
635
|
|
|
618
636
|
### Code Splitting
|
|
619
|
-
Use React.lazy() for routes and heavy
|
|
637
|
+
Use `React.lazy()` + `Suspense` for routes, tab components, and heavy renderers:
|
|
620
638
|
|
|
621
639
|
```typescript
|
|
622
640
|
// Good: Lazy-load terminal component
|
|
623
641
|
const TerminalTab = lazy(() => import("./terminal-tab"));
|
|
642
|
+
|
|
643
|
+
// Good: Lazy-load markdown renderer on 3+ sites
|
|
644
|
+
const MarkdownRenderer = lazy(() => import("./markdown-renderer"));
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Vendor Chunk Splitting (vite.config.ts)
|
|
648
|
+
Manually split large vendor libraries into separate chunks for better caching:
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
// Chunks: vendor-monaco, vendor-mermaid, vendor-xterm, vendor-markdown, vendor-ui
|
|
652
|
+
manualChunks(id: string) {
|
|
653
|
+
if (id.includes("node_modules/monaco-editor")) return "vendor-monaco";
|
|
654
|
+
if (id.includes("node_modules/mermaid")) return "vendor-mermaid";
|
|
655
|
+
if (id.includes("node_modules/@xterm")) return "vendor-xterm";
|
|
656
|
+
// ... etc
|
|
657
|
+
}
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### Dynamic Imports (On-Demand Loading)
|
|
661
|
+
Load heavy libraries only when needed:
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
// Good: Mermaid diagram support on-demand in markdown
|
|
665
|
+
let mermaidPromise: Promise<typeof import("mermaid")> | null = null;
|
|
666
|
+
async function loadMermaid() {
|
|
667
|
+
if (!mermaidPromise) {
|
|
668
|
+
mermaidPromise = import("mermaid").then((mod) => mod.default);
|
|
669
|
+
}
|
|
670
|
+
return mermaidPromise;
|
|
671
|
+
}
|
|
624
672
|
```
|
|
625
673
|
|
|
674
|
+
### Chat Pagination & Message Caps
|
|
675
|
+
- **Chat history:** Load 50 messages per page with load-more button
|
|
676
|
+
- **Team activity:** Cap `teamActivityRef` at 500 messages to prevent unbounded growth
|
|
677
|
+
|
|
626
678
|
### Memoization
|
|
627
679
|
Memoize expensive computations and callbacks:
|
|
628
680
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Frontend Memory Optimization: Four Phases of Rendering & Bundle Reduction
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-04-15 18:00
|
|
4
|
+
**Severity**: Medium
|
|
5
|
+
**Component**: Frontend (React, Vite bundles)
|
|
6
|
+
**Status**: Resolved (with incident)
|
|
7
|
+
|
|
8
|
+
## What Happened
|
|
9
|
+
|
|
10
|
+
Completed 4-phase memory and rendering optimization across the React codebase. Added shallow equality checks, memoization, lazy loading, and code splitting to reduce initial bundle size and re-render overhead. Process was interrupted by a critical git incident mid-session.
|
|
11
|
+
|
|
12
|
+
## The Brutal Truth
|
|
13
|
+
|
|
14
|
+
This was simultaneously a win and a disaster. The optimization work itself is solid—17 files now use `useShallow` to prevent unnecessary re-renders, 11 heavy components wrapped in `React.memo`, and critical libraries (mermaid, markdown, xterm) are now lazy-loaded. But a subagent ran `git reset --hard HEAD` without warning, destroying ALL uncommitted changes. Had to re-implement everything from scratch. Incredibly frustrating because the technical work was already done—it just got erased.
|
|
15
|
+
|
|
16
|
+
## Technical Details
|
|
17
|
+
|
|
18
|
+
**Phase 1 (Shallow Equality)**
|
|
19
|
+
- Added `useShallow` to 17 files with destructured store selector calls
|
|
20
|
+
- Prevents re-renders when store object reference changes but content doesn't
|
|
21
|
+
- Affected: hooks, chat, sidebar, tree, editor, terminal components
|
|
22
|
+
|
|
23
|
+
**Phase 2 (Chat Pagination)**
|
|
24
|
+
- PAGE_SIZE=50 pagination with load-more button in message-list.tsx
|
|
25
|
+
- Capped teamActivityRef at 500 messages in use-chat.ts
|
|
26
|
+
- Prevents DOM from holding thousands of message elements
|
|
27
|
+
|
|
28
|
+
**Phase 3 (Lazy Loading)**
|
|
29
|
+
- React.lazy for MarkdownRenderer (3 call sites, 175KB bundle)
|
|
30
|
+
- Dynamic import for mermaid in markdown-code-block.tsx with promise caching
|
|
31
|
+
- React.lazy for CodeMirror in postgres-viewer.tsx
|
|
32
|
+
- Fallback suspense boundaries in place
|
|
33
|
+
|
|
34
|
+
**Phase 4 (Code Splitting)**
|
|
35
|
+
- Vite manualChunks: vendor-monaco (lazy), vendor-mermaid (2.4MB lazy), vendor-xterm (344KB lazy), vendor-markdown (597KB lazy), vendor-ui (128KB shared)
|
|
36
|
+
- React.memo on TreeNode
|
|
37
|
+
- Initial bundle reduced to 495KB
|
|
38
|
+
|
|
39
|
+
## Code Review Fixes Applied
|
|
40
|
+
|
|
41
|
+
1. Rules of Hooks violation in MessageList—moved hooks above early returns
|
|
42
|
+
2. Pagination reset on every streaming tick—fixed deps to stable `messages[0]?.id`
|
|
43
|
+
3. onFork inline closure defeating MessageBubble memo—made stable with useCallback
|
|
44
|
+
4. Variable shadowing (`s` in tool-cards.tsx)—renamed to `state`
|
|
45
|
+
5. Mermaid import race condition—caching promise instead of module
|
|
46
|
+
|
|
47
|
+
## What We Tried
|
|
48
|
+
|
|
49
|
+
Had the work implemented successfully. Subagent spawned mid-session executed `git reset --hard HEAD` as part of cleanup routine, destroying all 26 modified files in one command. Recovered by re-implementing changes from notes and code review feedback.
|
|
50
|
+
|
|
51
|
+
## Root Cause Analysis
|
|
52
|
+
|
|
53
|
+
The incident happened because there was no git safety protocol when spawning subagents. The subagent was clearing uncommitted work thinking it was cleaning up, not realizing the changes hadn't been committed yet. No blocking commit before delegation meant work was vulnerable.
|
|
54
|
+
|
|
55
|
+
The optimization work itself: good decisions across the board. Shallow equality catches the most common re-render patterns. Lazy loading only targets heavy libraries (mermaid is 2.4MB—absolutely needs deferral). Pagination capping is necessary given unbounded message streams. Code splitting is strategic: vendor chunks reduce main bundle pressure.
|
|
56
|
+
|
|
57
|
+
## Lessons Learned
|
|
58
|
+
|
|
59
|
+
1. **Always commit before spawning subagents.** Even exploratory work needs a safety commit. Do not delegate with uncommitted changes in working tree.
|
|
60
|
+
2. **Shallow equality is the most impactful optimization.** It catches destructured store selectors without requiring component restructuring. Worth doing broadly.
|
|
61
|
+
3. **Lazy load by file size threshold.** Mermaid (2.4MB), markdown renderer (175KB), and xterm (344KB) were obvious candidates. Sub-100KB libraries don't justify the async boundary cost.
|
|
62
|
+
4. **Pagination is non-negotiable for unbounded collections.** Streaming chat creates thousands of messages. Without cap, DOM pressure degrades linearly.
|
|
63
|
+
5. **Code review catches subtle bugs.** The Rules of Hooks violation and race condition were hard to spot in original implementation but obvious in review.
|
|
64
|
+
|
|
65
|
+
## Next Steps
|
|
66
|
+
|
|
67
|
+
1. Commit optimizations with `git commit -m "perf: frontend memory optimization — shallow equality, lazy loading, pagination"`
|
|
68
|
+
2. Test pagination UX on low-end devices to verify load-more doesn't feel janky
|
|
69
|
+
3. Monitor bundle size in CI to catch regression
|
|
70
|
+
4. Document code splitting strategy in `docs/performance.md`
|
|
71
|
+
|
|
72
|
+
**Commits:** 26 files modified, 178 insertions, 88 deletions
|
|
73
|
+
**Bundle impact:** Initial +0% (495KB), lazy vendor chunks defer 3.5MB to first use
|
|
@@ -6,9 +6,19 @@ All notable changes to PPM are documented here. Format follows [Keep a Changelog
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## [Unreleased] — Git-Graph Stash Management, Rebase, Conflict Resolution + Worktree CRUD
|
|
9
|
+
## [Unreleased] — Frontend Memory Optimization + Git-Graph Stash Management, Rebase, Conflict Resolution + Worktree CRUD
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
|
+
- **Frontend Memory & Performance Optimizations** — Reduce re-renders, lazy-load heavy components, code splitting
|
|
13
|
+
- **useShallow pattern:** All destructured Zustand store calls now use `useShallow` (36 usage sites) to prevent re-renders on object mutations
|
|
14
|
+
- **React.memo wrapping:** 10 heavy components memoized (CodeEditor, MessageBubble, ProjectBar, ProjectAvatar, TerminalTab, PanelLayout, Sidebar, StatusBar, StatusBarEntry, TabBar, TreeNode)
|
|
15
|
+
- **Lazy loading:** MarkdownRenderer lazy-loaded from 3 sites, CodeMirror on-demand in postgres-viewer
|
|
16
|
+
- **Dynamic import:** Mermaid loaded on-demand in markdown-code-block (only when needed)
|
|
17
|
+
- **Code splitting:** 5 vendor chunks in vite.config.ts (monaco, mermaid, xterm, markdown, ui libraries) for better caching
|
|
18
|
+
- **Chat pagination:** Message history limited to 50 per page with load-more button
|
|
19
|
+
- **Message cap:** Team activity capped at 500 messages to prevent unbounded growth
|
|
20
|
+
|
|
21
|
+
### Added (Git-Graph)
|
|
12
22
|
- **Git Stash Management** — Toolbar popover for interactive stash operations
|
|
13
23
|
- List all stashes with index, hash (abbreviated), and message
|
|
14
24
|
- Apply/Pop/Drop actions per stash via context menu or action buttons
|
|
@@ -1897,6 +1897,42 @@ Would require:
|
|
|
1897
1897
|
|
|
1898
1898
|
---
|
|
1899
1899
|
|
|
1900
|
+
## Frontend Performance Optimization (v0.9.86+)
|
|
1901
|
+
|
|
1902
|
+
### Memory & Re-Render Reduction
|
|
1903
|
+
|
|
1904
|
+
**1. useShallow Pattern (Zustand)**
|
|
1905
|
+
- All destructured store selectors wrapped in `useShallow()` (36 sites)
|
|
1906
|
+
- Prevents unnecessary re-renders when object properties mutate
|
|
1907
|
+
- Example: `const { messages, addMessage } = chatStore(useShallow(...))`
|
|
1908
|
+
|
|
1909
|
+
**2. Component Memoization (React.memo)**
|
|
1910
|
+
- 10 heavy components wrapped (CodeEditor, MessageBubble, ProjectBar, ProjectAvatar, TerminalTab, PanelLayout, Sidebar, StatusBar, StatusBarEntry, TabBar, TreeNode)
|
|
1911
|
+
- Memoization skips re-renders if props unchanged
|
|
1912
|
+
- Paired with `useCallback` to maintain stable references
|
|
1913
|
+
|
|
1914
|
+
**3. Lazy Loading**
|
|
1915
|
+
- MarkdownRenderer lazy-loaded from 3 sites (reduces initial bundle)
|
|
1916
|
+
- CodeMirror on-demand in postgres-viewer
|
|
1917
|
+
- Mermaid diagram support loaded dynamically only when diagram syntax detected
|
|
1918
|
+
|
|
1919
|
+
**4. Code Splitting (vite.config.ts)**
|
|
1920
|
+
- 5 vendor chunks: `vendor-monaco`, `vendor-mermaid`, `vendor-xterm`, `vendor-markdown`, `vendor-ui`
|
|
1921
|
+
- Heavy libraries (>500KB) in separate chunks for better browser caching
|
|
1922
|
+
- Each chunk independently cacheable and updated
|
|
1923
|
+
|
|
1924
|
+
**5. Chat Pagination & Message Caps**
|
|
1925
|
+
- Chat history loads 50 messages per page with load-more button (prevents DOM bloat)
|
|
1926
|
+
- Team activity capped at 500 messages (prevents unbounded growth)
|
|
1927
|
+
|
|
1928
|
+
### Benefits
|
|
1929
|
+
- Faster page load (lazy chunks load on-demand)
|
|
1930
|
+
- Reduced re-render cycles (useShallow + memo)
|
|
1931
|
+
- Lower memory footprint (capped message buffers)
|
|
1932
|
+
- Better caching (vendor chunk stability across versions)
|
|
1933
|
+
|
|
1934
|
+
---
|
|
1935
|
+
|
|
1900
1936
|
## Error Handling Strategy
|
|
1901
1937
|
|
|
1902
1938
|
| Layer | Error Type | Handling |
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { useEffect, useRef, useState, useMemo, useCallback } from "react";
|
|
1
|
+
import { useEffect, useRef, useState, useMemo, useCallback, memo, lazy, Suspense } from "react";
|
|
2
2
|
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
|
3
3
|
import { getAuthToken } from "@/lib/api-client";
|
|
4
4
|
import type { ChatMessage, ChatEvent } from "../../../types/chat";
|
|
5
5
|
import type { SessionPhase } from "../../../types/api";
|
|
6
6
|
import { ToolCard } from "./tool-cards";
|
|
7
|
-
|
|
7
|
+
const MarkdownRenderer = lazy(() =>
|
|
8
|
+
import("@/components/shared/markdown-renderer").then((m) => ({ default: m.MarkdownRenderer }))
|
|
9
|
+
);
|
|
8
10
|
import { cn, basename } from "@/lib/utils";
|
|
9
11
|
|
|
10
12
|
import {
|
|
@@ -67,6 +69,34 @@ export function MessageList({
|
|
|
67
69
|
}: MessageListProps) {
|
|
68
70
|
// Scroll handled by StickToBottom wrapper — no manual scroll logic needed
|
|
69
71
|
|
|
72
|
+
const PAGE_SIZE = 50;
|
|
73
|
+
const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);
|
|
74
|
+
|
|
75
|
+
// Reset visible count when conversation identity changes (not on every streaming tick)
|
|
76
|
+
const conversationId = messages[0]?.id;
|
|
77
|
+
useEffect(() => { setVisibleCount(PAGE_SIZE); }, [conversationId]);
|
|
78
|
+
|
|
79
|
+
const filtered = useMemo(() => messages.filter((msg) => {
|
|
80
|
+
const hasContent = msg.content && msg.content.trim().length > 0;
|
|
81
|
+
const hasEvents = msg.events && msg.events.length > 0;
|
|
82
|
+
// User bubbles only render text — hide SDK tool-result user messages
|
|
83
|
+
// that have no text content (their events are merged into assistant)
|
|
84
|
+
if (msg.role === "user") return hasContent;
|
|
85
|
+
return hasContent || hasEvents;
|
|
86
|
+
}), [messages]);
|
|
87
|
+
|
|
88
|
+
const displayed = useMemo(() => {
|
|
89
|
+
const start = Math.max(0, filtered.length - visibleCount);
|
|
90
|
+
return filtered.slice(start);
|
|
91
|
+
}, [filtered, visibleCount]);
|
|
92
|
+
|
|
93
|
+
const hasMore = visibleCount < filtered.length;
|
|
94
|
+
|
|
95
|
+
// Stable fork handler — avoids new closure per message (preserves MessageBubble memo)
|
|
96
|
+
const handleFork = useCallback((msgContent: string, msgId: string | undefined) => {
|
|
97
|
+
onFork?.(msgContent, msgId);
|
|
98
|
+
}, [onFork]);
|
|
99
|
+
|
|
70
100
|
if (messagesLoading) {
|
|
71
101
|
return (
|
|
72
102
|
<div className="flex flex-col items-center justify-center h-full gap-3 text-text-secondary">
|
|
@@ -85,32 +115,30 @@ export function MessageList({
|
|
|
85
115
|
);
|
|
86
116
|
}
|
|
87
117
|
|
|
88
|
-
const filtered = useMemo(() => messages.filter((msg) => {
|
|
89
|
-
const hasContent = msg.content && msg.content.trim().length > 0;
|
|
90
|
-
const hasEvents = msg.events && msg.events.length > 0;
|
|
91
|
-
// User bubbles only render text — hide SDK tool-result user messages
|
|
92
|
-
// that have no text content (their events are merged into assistant)
|
|
93
|
-
if (msg.role === "user") return hasContent;
|
|
94
|
-
return hasContent || hasEvents;
|
|
95
|
-
}), [messages]);
|
|
96
|
-
|
|
97
118
|
return (
|
|
98
119
|
<div className="relative flex-1 overflow-hidden flex flex-col min-h-0">
|
|
99
120
|
<StickToBottom className="flex-1 overflow-y-auto overflow-x-hidden" resize="smooth" initial="instant">
|
|
100
121
|
<StickToBottom.Content className="p-4 space-y-4">
|
|
101
|
-
{
|
|
122
|
+
{hasMore && (
|
|
123
|
+
<button onClick={() => setVisibleCount((c) => c + PAGE_SIZE)}
|
|
124
|
+
className="w-full py-2 text-xs text-text-secondary hover:text-text-primary bg-surface-elevated/50 hover:bg-surface-elevated rounded-md border border-border/50 transition-colors">
|
|
125
|
+
Load {Math.min(PAGE_SIZE, filtered.length - visibleCount)} more messages...
|
|
126
|
+
</button>
|
|
127
|
+
)}
|
|
128
|
+
{displayed.map((msg, idx) => {
|
|
129
|
+
const globalIdx = filtered.length - displayed.length + idx;
|
|
130
|
+
const prevMsg = globalIdx > 0 ? filtered[globalIdx - 1] : undefined;
|
|
131
|
+
return (
|
|
102
132
|
<MessageBubble
|
|
103
133
|
key={msg.id}
|
|
104
134
|
message={msg}
|
|
105
135
|
isStreaming={isStreaming && msg.id.startsWith("streaming-")}
|
|
106
136
|
projectName={projectName}
|
|
107
|
-
onFork={msg.role === "user" && onFork ?
|
|
108
|
-
|
|
109
|
-
const prevMsg = idx > 0 ? filtered[idx - 1] : undefined;
|
|
110
|
-
onFork(msg.content, prevMsg?.sdkUuid ?? prevMsg?.id);
|
|
111
|
-
} : undefined}
|
|
137
|
+
onFork={msg.role === "user" && onFork ? handleFork : undefined}
|
|
138
|
+
prevMsgId={prevMsg?.sdkUuid ?? prevMsg?.id}
|
|
112
139
|
/>
|
|
113
|
-
)
|
|
140
|
+
);
|
|
141
|
+
})}
|
|
114
142
|
|
|
115
143
|
{pendingApproval && (
|
|
116
144
|
pendingApproval.tool === "AskUserQuestion"
|
|
@@ -142,10 +170,15 @@ function ScrollToBottomButton() {
|
|
|
142
170
|
);
|
|
143
171
|
}
|
|
144
172
|
|
|
145
|
-
function MessageBubble({ message, isStreaming, projectName, onFork }: {
|
|
173
|
+
const MessageBubble = memo(function MessageBubble({ message, isStreaming, projectName, onFork, prevMsgId }: {
|
|
174
|
+
message: ChatMessage; isStreaming: boolean; projectName?: string;
|
|
175
|
+
onFork?: (content: string, messageId: string | undefined) => void;
|
|
176
|
+
prevMsgId?: string
|
|
177
|
+
}) {
|
|
146
178
|
if (message.role === "user") {
|
|
179
|
+
const handleFork = onFork ? () => onFork(message.content, prevMsgId) : undefined;
|
|
147
180
|
return (
|
|
148
|
-
<UserBubble content={message.content} projectName={projectName} onFork={
|
|
181
|
+
<UserBubble content={message.content} projectName={projectName} onFork={handleFork} />
|
|
149
182
|
);
|
|
150
183
|
}
|
|
151
184
|
|
|
@@ -175,7 +208,7 @@ function MessageBubble({ message, isStreaming, projectName, onFork }: { message:
|
|
|
175
208
|
)}
|
|
176
209
|
</div>
|
|
177
210
|
);
|
|
178
|
-
}
|
|
211
|
+
});
|
|
179
212
|
|
|
180
213
|
/** Image extensions that can be previewed inline */
|
|
181
214
|
const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
|
|
@@ -843,7 +876,11 @@ function stripTeammateMessages(text: string): string {
|
|
|
843
876
|
function MarkdownContent({ content, projectName, isStreaming }: { content: string; projectName?: string; isStreaming?: boolean }) {
|
|
844
877
|
const cleaned = stripTeammateMessages(content);
|
|
845
878
|
if (!cleaned) return null;
|
|
846
|
-
return
|
|
879
|
+
return (
|
|
880
|
+
<Suspense fallback={<div className="animate-pulse h-4 bg-muted rounded" />}>
|
|
881
|
+
<MarkdownRenderer content={cleaned} projectName={projectName} codeActions isStreaming={isStreaming} />
|
|
882
|
+
</Suspense>
|
|
883
|
+
);
|
|
847
884
|
}
|
|
848
885
|
|
|
849
886
|
/* ToolCard, ToolSummary, ToolDetails extracted to ./tool-cards.tsx */
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Tool card components for chat message rendering.
|
|
3
3
|
* Handles summary + details for all SDK tool types.
|
|
4
4
|
*/
|
|
5
|
-
import { useState, useMemo } from "react";
|
|
6
|
-
|
|
5
|
+
import { useState, useMemo, lazy, Suspense } from "react";
|
|
6
|
+
const MarkdownRenderer = lazy(() =>
|
|
7
|
+
import("@/components/shared/markdown-renderer").then((m) => ({ default: m.MarkdownRenderer }))
|
|
8
|
+
);
|
|
7
9
|
import {
|
|
8
10
|
ChevronDown,
|
|
9
11
|
ChevronRight,
|
|
@@ -20,6 +22,7 @@ import {
|
|
|
20
22
|
Columns2,
|
|
21
23
|
} from "lucide-react";
|
|
22
24
|
import type { ChatEvent } from "../../../types/chat";
|
|
25
|
+
import { useShallow } from "zustand/react/shallow";
|
|
23
26
|
import { useTabStore } from "@/stores/tab-store";
|
|
24
27
|
import { basename } from "@/lib/utils";
|
|
25
28
|
|
|
@@ -159,7 +162,7 @@ function ToolDetails({
|
|
|
159
162
|
projectName?: string;
|
|
160
163
|
}) {
|
|
161
164
|
const s = (v: unknown) => String(v ?? "");
|
|
162
|
-
const { openTab } = useTabStore();
|
|
165
|
+
const { openTab } = useTabStore(useShallow((state) => ({ openTab: state.openTab })));
|
|
163
166
|
|
|
164
167
|
/** Open a file in a new editor tab */
|
|
165
168
|
const openFile = (filePath: string) => {
|
|
@@ -451,7 +454,11 @@ function SubagentChildren({ events, projectName }: { events: ChatEvent[]; projec
|
|
|
451
454
|
|
|
452
455
|
/** Inline markdown renderer for tool details (prompt, result) */
|
|
453
456
|
function MiniMarkdown({ content, maxHeight = "max-h-48" }: { content: string; maxHeight?: string }) {
|
|
454
|
-
return
|
|
457
|
+
return (
|
|
458
|
+
<Suspense fallback={<div className="animate-pulse h-4 bg-muted rounded" />}>
|
|
459
|
+
<MarkdownRenderer content={content} className={`text-text-secondary overflow-auto ${maxHeight}`} />
|
|
460
|
+
</Suspense>
|
|
461
|
+
);
|
|
455
462
|
}
|
|
456
463
|
|
|
457
464
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback, useMemo, useRef, memo, useEffect } from "react";
|
|
2
2
|
import { Loader2, ChevronLeft, ChevronRight, ChevronUp, ChevronDown, Trash2, Plus, Search, X, Eye, Filter, Pin, PinOff, Columns3 } from "lucide-react";
|
|
3
|
+
import { useShallow } from "zustand/react/shallow";
|
|
3
4
|
import { useTabStore } from "@/stores/tab-store";
|
|
4
5
|
import type { DbColumnInfo } from "./use-database";
|
|
5
6
|
import { ExportButton } from "./export-button";
|
|
@@ -42,7 +43,7 @@ export function DataGrid({
|
|
|
42
43
|
const [insertValues, setInsertValues] = useState<Record<string, string>>({});
|
|
43
44
|
const [insertError, setInsertError] = useState<string | null>(null);
|
|
44
45
|
const [confirmBulkDelete, setConfirmBulkDelete] = useState(false);
|
|
45
|
-
const { openTab } = useTabStore();
|
|
46
|
+
const { openTab } = useTabStore(useShallow((s) => ({ openTab: s.openTab })));
|
|
46
47
|
const openCellViewer = useCallback((cell: { col: string; value: string }) => {
|
|
47
48
|
openTab({
|
|
48
49
|
type: "editor",
|