@hienlh/ppm 0.23.6 → 0.23.7
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 +84 -0
- package/CLAUDE.md +21 -1
- package/Dockerfile.test +8 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +29 -1
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
- package/dist/web/assets/{ai-resource-editor-Dn_wB-o5.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
- package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
- package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
- package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
- package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
- package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
- package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
- package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
- package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
- package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
- package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
- package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
- package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
- package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
- package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
- package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
- package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
- package/dist/web/assets/{conflict-editor-BA3y-qSH.js → conflict-editor-BpKW_vbL.js} +1 -1
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
- package/dist/web/assets/{csv-preview-BioxkrQF.js → csv-preview-COYdTABa.js} +1 -1
- package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
- package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
- package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
- package/dist/web/assets/{database-viewer-BSoJ0E6p.js → database-viewer-BQcBqCKm.js} +1 -1
- package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
- package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
- package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
- package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
- package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
- package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
- package/dist/web/assets/{designs-sidebar-panel-DHh5QsH9.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
- package/dist/web/assets/{diff-viewer-lctWoSmG.js → diff-viewer-Bj4DT6Mj.js} +1 -1
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
- package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
- package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
- package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
- package/dist/web/assets/{extension-manager-section-rbkXsZVR.js → extension-manager-section-Bu0qcB2i.js} +1 -1
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
- package/dist/web/assets/{extension-webview-uPO0WgCq.js → extension-webview-G_WJ0N52.js} +1 -1
- package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
- package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
- package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
- package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
- package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
- package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
- package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
- package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
- package/dist/web/assets/{files-settings-section-CT7mDb0L.js → files-settings-section-ChZ_CynX.js} +1 -1
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
- package/dist/web/assets/format-bytes-__396eCN.js +1 -0
- package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
- package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
- package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
- package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
- package/dist/web/assets/{general-settings-section-DANPfMRN.js → general-settings-section-MSvDEbFa.js} +1 -1
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
- package/dist/web/assets/{git-log-panel-BJPkLiEw.js → git-log-panel-gw5_a6j3.js} +1 -1
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
- package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
- package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
- package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
- package/dist/web/assets/{glide-data-grid-R4PcAntf.js → glide-data-grid-Db2Cl26B.js} +5 -5
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
- package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
- package/dist/web/assets/index-CtAvmybi.js +52 -0
- package/dist/web/assets/index-CtAvmybi.js.br +0 -0
- package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
- package/dist/web/assets/index-DeCJasyy.css +1 -0
- package/dist/web/assets/index-DeCJasyy.css.br +0 -0
- package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
- package/dist/web/assets/{jira-watcher-section-DHRoyWcG.js → jira-watcher-section-CKSI1Alo.js} +1 -1
- package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-BKej4mUf.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
- package/dist/web/assets/{markdown-renderer-BHtYqkYZ.js → markdown-renderer-D05fAr57.js} +2 -2
- package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
- package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
- package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
- package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
- package/dist/web/assets/{new-design-dialog-DS_XrpTG.js → new-design-dialog-BgmQopJM.js} +1 -1
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
- package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
- package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
- package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
- package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
- package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
- package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
- package/dist/web/assets/{ppmbot-settings-section-D8AES1BA.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
- package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
- package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
- package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
- package/dist/web/assets/{problems-panel-DTBG4beI.js → problems-panel-BgY8oyo9.js} +1 -1
- package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
- package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
- package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
- package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
- package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
- package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
- package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
- package/dist/web/assets/{proxy-settings-section-CqtmbeRj.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
- package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-clipboard-notice-Djt6cpNL.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-readiness-gate-DNJF8TcF.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
- package/dist/web/assets/{schedules-settings-section-BKoPovy2.js → schedules-settings-section-CvbjQM8z.js} +1 -1
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
- package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
- package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
- package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
- package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
- package/dist/web/assets/services-panel-CimW47P8.js +1 -0
- package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
- package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
- package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
- package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
- package/dist/web/assets/{sql-query-editor-BjIMi9Wk.js → sql-query-editor-Dn-cgDrW.js} +1 -1
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
- package/dist/web/assets/{sqlite-viewer-BNcA6Irq.js → sqlite-viewer-B0NfaMjq.js} +1 -1
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
- package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
- package/dist/web/assets/{tab-host-window-content-CIRGNCvi.js → tab-host-window-content-CSrcmKNG.js} +1 -1
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
- package/dist/web/assets/{team-member-sheet-CwXpLi3X.js → team-member-sheet-D4X6nh-x.js} +2 -2
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
- package/dist/web/assets/{team-member-window-content-4swiiDz7.js → team-member-window-content-BxkbGVIL.js} +1 -1
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
- package/dist/web/assets/{terminal-tab-BGcdtMMT.js → terminal-tab-BYo34IqU.js} +3 -3
- package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
- package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
- package/dist/web/assets/{tool-cards-D0-krtA2.js → tool-cards-DvXjOped.js} +4 -4
- package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
- package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
- package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
- package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
- package/dist/web/assets/{use-monaco-theme-C88KphGx.js → use-monaco-theme-UGOzyIhv.js} +1 -1
- package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
- package/dist/web/assets/{use-websocket-Chk9guIU.js → use-websocket-Dpl21cHG.js} +1 -1
- package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
- package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
- package/dist/web/index.html +20 -20
- package/dist/web/index.html.br +0 -0
- package/dist/web/index.html.gz +0 -0
- package/dist/web/sw.js +1 -1
- package/dist/web/sw.js.br +0 -0
- package/dist/web/sw.js.gz +0 -0
- package/docs/deployment-guide.md +23 -0
- package/package.json +1 -1
- package/release-from-worktree.sh +224 -0
- package/src/cli/commands/config-cmd.ts +12 -0
- package/src/providers/claude-agent-sdk.ts +65 -2
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
- package/src/providers/codex-app-server/codex-provider.ts +39 -7
- package/src/providers/provider-probe.ts +63 -0
- package/src/providers/registry.ts +109 -29
- package/src/server/index.ts +9 -0
- package/src/server/middleware/auth.ts +5 -1
- package/src/server/routes/cross-origin-guard.ts +20 -0
- package/src/server/routes/git.ts +40 -4
- package/src/server/routes/lsp.ts +97 -4
- package/src/server/routes/resources.ts +72 -9
- package/src/server/routes/settings.ts +19 -1
- package/src/server/routes/speech.ts +66 -0
- package/src/server/routes/system-services.ts +76 -0
- package/src/server/routes/tunnel.ts +33 -1
- package/src/server/ws/chat.ts +74 -3
- package/src/services/codex-account-login.ts +26 -2
- package/src/services/codex-reset-credit.service.ts +16 -3
- package/src/services/compaction-savings.ts +127 -0
- package/src/services/db.service.ts +123 -8
- package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
- package/src/services/git-refs/for-each-ref.ts +118 -0
- package/src/services/git.service.ts +25 -2
- package/src/services/host-info/spawn-runner.ts +48 -4
- package/src/services/jsonl-transcript-parser.ts +7 -42
- package/src/services/lsp/lsp-install.ts +289 -0
- package/src/services/lsp/lsp-manager.ts +160 -29
- package/src/services/lsp/server-registry.ts +120 -4
- package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
- package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
- package/src/services/read-lines.ts +54 -0
- package/src/services/speech-to-text/whisper-catalog.ts +142 -0
- package/src/services/speech-to-text/whisper-download.ts +113 -0
- package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
- package/src/services/speech-to-text/whisper-install.service.ts +247 -0
- package/src/services/speech-to-text/whisper-paths.ts +62 -0
- package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
- package/src/services/supervisor.ts +94 -11
- package/src/services/system-metrics/cpu-details-linux.ts +252 -0
- package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
- package/src/services/system-metrics/device-collector-linux.ts +31 -0
- package/src/services/system-metrics/device-collector-types.ts +40 -0
- package/src/services/system-metrics/disk-devices-linux.ts +156 -0
- package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
- package/src/services/system-metrics/fans-linux.ts +51 -0
- package/src/services/system-metrics/gpu-api-versions.ts +120 -0
- package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
- package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
- package/src/services/system-metrics/hardware-inventory.ts +50 -0
- package/src/services/system-metrics/linux-fs.ts +43 -0
- package/src/services/system-metrics/memory-darwin.ts +91 -0
- package/src/services/system-metrics/memory-linux.ts +156 -0
- package/src/services/system-metrics/net-devices-linux.ts +114 -0
- package/src/services/system-metrics/net-inventory-linux.ts +100 -0
- package/src/services/system-metrics/partitions-linux.ts +158 -0
- package/src/services/system-metrics/process-collector-linux.ts +58 -6
- package/src/services/system-metrics/process-collector-types.ts +8 -1
- package/src/services/system-metrics/process-details-darwin.ts +166 -0
- package/src/services/system-metrics/process-details-linux.ts +150 -0
- package/src/services/system-metrics/process-grouping.ts +2 -1
- package/src/services/system-metrics/process-rows-builder.ts +2 -0
- package/src/services/system-metrics/process-swap-linux.ts +37 -0
- package/src/services/system-metrics/signal-executor.ts +84 -0
- package/src/services/system-metrics/signal-request-handler.ts +92 -0
- package/src/services/system-metrics/system-metrics-platform.ts +30 -4
- package/src/services/system-metrics/system-metrics-tick.ts +73 -4
- package/src/services/system-metrics/system-metrics.service.ts +87 -2
- package/src/services/system-metrics/udev-db.ts +40 -0
- package/src/services/system-services/app-cgroup-linux.ts +115 -0
- package/src/services/system-services/app-icon-service.ts +31 -0
- package/src/services/system-services/app-icons-linux.ts +124 -0
- package/src/services/system-services/apps-linux.ts +174 -0
- package/src/services/system-services/desktop-entry.ts +103 -0
- package/src/services/system-services/service-guard.ts +124 -0
- package/src/services/system-services/systemd-collector.ts +203 -0
- package/src/services/system-services/systemd-parse.ts +162 -0
- package/src/shared/prompt-cache-idle.ts +197 -0
- package/src/shared/turn-usage.ts +85 -1
- package/src/types/chat.ts +27 -0
- package/src/types/config.ts +14 -0
- package/src/types/git.ts +41 -0
- package/src/types/system-hardware.ts +137 -0
- package/src/types/system-metrics.ts +231 -2
- package/src/types/system-services.ts +73 -0
- package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
- package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
- package/src/web/components/chat/chat-tab.tsx +3 -0
- package/src/web/components/chat/compaction-divider.tsx +48 -0
- package/src/web/components/chat/idle-cache-notice.tsx +67 -0
- package/src/web/components/chat/message-input.tsx +48 -13
- package/src/web/components/chat/message-list.tsx +15 -0
- package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
- package/src/web/components/editor/code-editor.tsx +1 -0
- package/src/web/components/editor/editor-language-service.tsx +11 -3
- package/src/web/components/editor/lsp-status.tsx +115 -13
- package/src/web/components/git/branch-picker.tsx +419 -0
- package/src/web/components/git/branch-select.tsx +34 -0
- package/src/web/components/git/create-worktree-dialog.tsx +17 -16
- package/src/web/components/git/git-repo-picker.tsx +28 -40
- package/src/web/components/layout/status-bar.tsx +42 -19
- package/src/web/components/settings/accounts/account-card.tsx +5 -1
- package/src/web/components/settings/ai-settings-section.tsx +67 -3
- package/src/web/components/settings/appearance-settings-section.tsx +2 -28
- package/src/web/components/settings/language-servers-section.tsx +362 -0
- package/src/web/components/settings/settings-categories.ts +8 -3
- package/src/web/components/settings/settings-section-content.tsx +2 -0
- package/src/web/components/settings/voice-settings-section.tsx +283 -0
- package/src/web/components/system/apps/app-row.tsx +110 -0
- package/src/web/components/system/apps/app-rows.ts +140 -0
- package/src/web/components/system/apps/apps-panel.tsx +129 -0
- package/src/web/components/system/metric-chart-canvas.tsx +79 -3
- package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
- package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
- package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
- package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
- package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
- package/src/web/components/system/overview-cards/net-card.tsx +11 -6
- package/src/web/components/system/overview-device-target.ts +69 -0
- package/src/web/components/system/overview-panel.tsx +15 -1
- package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
- package/src/web/components/system/performance/cpu-detail.tsx +220 -0
- package/src/web/components/system/performance/detail-parts.tsx +149 -0
- package/src/web/components/system/performance/device-list.ts +139 -0
- package/src/web/components/system/performance/disk-detail.tsx +64 -0
- package/src/web/components/system/performance/fans-detail.tsx +35 -0
- package/src/web/components/system/performance/gpu-detail.tsx +116 -0
- package/src/web/components/system/performance/memory-detail.tsx +109 -0
- package/src/web/components/system/performance/nic-detail.tsx +55 -0
- package/src/web/components/system/performance/partition-list.tsx +79 -0
- package/src/web/components/system/performance/performance-panel.tsx +206 -0
- package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
- package/src/web/components/system/process-columns-grid.ts +5 -3
- package/src/web/components/system/process-details-dialog.tsx +116 -0
- package/src/web/components/system/process-group-row.tsx +6 -1
- package/src/web/components/system/process-row-format.ts +6 -0
- package/src/web/components/system/process-row-menu.tsx +72 -0
- package/src/web/components/system/process-row.tsx +7 -1
- package/src/web/components/system/process-table-model.ts +1 -1
- package/src/web/components/system/process-table-sort.ts +8 -4
- package/src/web/components/system/process-table-toolbar.tsx +10 -2
- package/src/web/components/system/process-table-totals.ts +3 -0
- package/src/web/components/system/process-table.tsx +25 -2
- package/src/web/components/system/services/service-action-confirm.tsx +100 -0
- package/src/web/components/system/services/service-columns.ts +103 -0
- package/src/web/components/system/services/service-details-sheet.tsx +97 -0
- package/src/web/components/system/services/service-resources.ts +105 -0
- package/src/web/components/system/services/service-row.tsx +146 -0
- package/src/web/components/system/services/service-rows.ts +92 -0
- package/src/web/components/system/services/service-sort.ts +90 -0
- package/src/web/components/system/services/services-header.tsx +51 -0
- package/src/web/components/system/services/services-panel.tsx +207 -0
- package/src/web/components/system/services/use-services.ts +92 -0
- package/src/web/components/system/sortable-header.tsx +13 -8
- package/src/web/components/system/sysmon-preferences.tsx +85 -0
- package/src/web/components/system/system-monitor-body.tsx +101 -43
- package/src/web/components/system/system-monitor-window-content.tsx +2 -3
- package/src/web/components/system/use-process-signal.ts +87 -0
- package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
- package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
- package/src/web/components/ui/dialog.tsx +14 -1
- package/src/web/components/ui/search-select.tsx +279 -0
- package/src/web/components/ui/start-ellipsis.tsx +18 -0
- package/src/web/hooks/use-chat.ts +28 -0
- package/src/web/hooks/use-global-keybindings.ts +7 -5
- package/src/web/hooks/use-lsp.ts +23 -2
- package/src/web/hooks/use-minute-clock.ts +20 -0
- package/src/web/hooks/use-whisper-voice-input.ts +113 -0
- package/src/web/lib/api-tunnels.ts +19 -0
- package/src/web/lib/branch-select-items.ts +29 -0
- package/src/web/lib/cpu-graph-mode.ts +90 -0
- package/src/web/lib/format-bytes.ts +14 -0
- package/src/web/lib/git-ref-picker.ts +120 -0
- package/src/web/lib/lsp/lsp-client.ts +32 -0
- package/src/web/lib/search-select-rows.ts +55 -0
- package/src/web/lib/temperature.ts +27 -0
- package/src/web/lib/voice-wav.ts +69 -0
- package/src/web/stores/git-status-store.ts +31 -17
- package/src/web/stores/keybindings-store.ts +14 -1
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/styles/globals.css +11 -0
- package/dist/web/assets/accounts-settings-section-DUVO32SQ.js +0 -1
- package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js +0 -1
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js.br +0 -0
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-D-mwEYFZ.js +0 -1
- package/dist/web/assets/api-client-BgedDTvo.js +0 -1
- package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
- package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
- package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
- package/dist/web/assets/appearance-settings-section-tw6TpFb6.js +0 -1
- package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.gz +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-MBuMWp_i.js +0 -1
- package/dist/web/assets/branch-review-tab-MBuMWp_i.js.br +0 -0
- package/dist/web/assets/branch-review-tab-MBuMWp_i.js.gz +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
- package/dist/web/assets/chat-tab-DVvnqhw6.js +0 -1
- package/dist/web/assets/chat-tab-DVvnqhw6.js.br +0 -0
- package/dist/web/assets/chat-tab-DVvnqhw6.js.gz +0 -0
- package/dist/web/assets/chat-tab-DaEHva22.js +0 -15
- package/dist/web/assets/chat-tab-DaEHva22.js.br +0 -0
- package/dist/web/assets/chat-tab-DaEHva22.js.gz +0 -0
- package/dist/web/assets/code-editor-Bu9lhTVp.js +0 -7
- package/dist/web/assets/code-editor-Bu9lhTVp.js.br +0 -0
- package/dist/web/assets/code-editor-Bu9lhTVp.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js +0 -1
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.gz +0 -0
- package/dist/web/assets/conflict-editor-BA3y-qSH.js.br +0 -0
- package/dist/web/assets/conflict-editor-BA3y-qSH.js.gz +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
- package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
- package/dist/web/assets/csv-preview-BioxkrQF.js.br +0 -0
- package/dist/web/assets/csv-preview-BioxkrQF.js.gz +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
- package/dist/web/assets/database-viewer-BSoJ0E6p.js.br +0 -0
- package/dist/web/assets/database-viewer-BSoJ0E6p.js.gz +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
- package/dist/web/assets/design-tab-iU2CviE3.js +0 -33
- package/dist/web/assets/design-tab-iU2CviE3.js.br +0 -0
- package/dist/web/assets/design-tab-iU2CviE3.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.gz +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js +0 -1
- package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
- package/dist/web/assets/diff-viewer-lctWoSmG.js.br +0 -0
- package/dist/web/assets/diff-viewer-lctWoSmG.js.gz +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
- package/dist/web/assets/editor-language-service-fPG56hQO.js +0 -1
- package/dist/web/assets/editor-language-service-fPG56hQO.js.br +0 -0
- package/dist/web/assets/editor-language-service-fPG56hQO.js.gz +0 -0
- package/dist/web/assets/explorer-body-BgF7FsxI.js +0 -2
- package/dist/web/assets/explorer-body-BgF7FsxI.js.br +0 -0
- package/dist/web/assets/explorer-body-BgF7FsxI.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-C21w_7lf.js +0 -1
- package/dist/web/assets/explorer-window-content-C21w_7lf.js.br +0 -0
- package/dist/web/assets/explorer-window-content-C21w_7lf.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-rbkXsZVR.js.br +0 -0
- package/dist/web/assets/extension-manager-section-rbkXsZVR.js.gz +0 -0
- package/dist/web/assets/extension-webview-uPO0WgCq.js.br +0 -0
- package/dist/web/assets/extension-webview-uPO0WgCq.js.gz +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
- package/dist/web/assets/files-settings-section-CT7mDb0L.js.br +0 -0
- package/dist/web/assets/files-settings-section-CT7mDb0L.js.gz +0 -0
- package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
- package/dist/web/assets/general-settings-section-DANPfMRN.js.br +0 -0
- package/dist/web/assets/general-settings-section-DANPfMRN.js.gz +0 -0
- package/dist/web/assets/git-log-panel-BJPkLiEw.js.br +0 -0
- package/dist/web/assets/git-log-panel-BJPkLiEw.js.gz +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
- package/dist/web/assets/glide-data-grid-R4PcAntf.js.br +0 -0
- package/dist/web/assets/glide-data-grid-R4PcAntf.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js +0 -1
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js.br +0 -0
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js.gz +0 -0
- package/dist/web/assets/index-C8nGqkKN.js +0 -52
- package/dist/web/assets/index-C8nGqkKN.js.br +0 -0
- package/dist/web/assets/index-C8nGqkKN.js.gz +0 -0
- package/dist/web/assets/index-DvClbTQx.css +0 -1
- package/dist/web/assets/index-DvClbTQx.css.br +0 -0
- package/dist/web/assets/index-DvClbTQx.css.gz +0 -0
- package/dist/web/assets/keybindings-store-BGKlQQAv.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.br +0 -0
- package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-vDNuKjel.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-DS_XrpTG.js.br +0 -0
- package/dist/web/assets/new-design-dialog-DS_XrpTG.js.gz +0 -0
- package/dist/web/assets/notification-store-Dnnj20Ky.js +0 -1
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
- package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
- package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.gz +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
- package/dist/web/assets/problems-panel-DTBG4beI.js.br +0 -0
- package/dist/web/assets/problems-panel-DTBG4beI.js.gz +0 -0
- package/dist/web/assets/process-table-D_gR2XA6.js +0 -1
- package/dist/web/assets/process-table-D_gR2XA6.js.br +0 -0
- package/dist/web/assets/process-table-D_gR2XA6.js.gz +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
- package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.gz +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-BKoPovy2.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-BKoPovy2.js.gz +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
- package/dist/web/assets/settings-body-k2qPgRFe.js +0 -2
- package/dist/web/assets/settings-body-k2qPgRFe.js.br +0 -0
- package/dist/web/assets/settings-body-k2qPgRFe.js.gz +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
- package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
- package/dist/web/assets/settings-tab-Bb23VdBu.js +0 -1
- package/dist/web/assets/settings-window-content-ClarWusz.js +0 -1
- package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.br +0 -0
- package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js +0 -2
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js.br +0 -0
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-I1Igmoey.js +0 -1
- package/dist/web/assets/system-monitor-window-content-C5SeUv1H.js +0 -1
- package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.gz +0 -0
- package/dist/web/assets/team-member-sheet-CwXpLi3X.js.br +0 -0
- package/dist/web/assets/team-member-sheet-CwXpLi3X.js.gz +0 -0
- package/dist/web/assets/team-member-window-content-4swiiDz7.js.br +0 -0
- package/dist/web/assets/team-member-window-content-4swiiDz7.js.gz +0 -0
- package/dist/web/assets/terminal-tab-BGcdtMMT.js.br +0 -0
- package/dist/web/assets/terminal-tab-BGcdtMMT.js.gz +0 -0
- package/dist/web/assets/tool-cards-D0-krtA2.js.br +0 -0
- package/dist/web/assets/tool-cards-D0-krtA2.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js +0 -16
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js.br +0 -0
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js.gz +0 -0
- package/dist/web/assets/use-lsp-71azTXQz.js +0 -6
- package/dist/web/assets/use-lsp-71azTXQz.js.br +0 -0
- package/dist/web/assets/use-lsp-71azTXQz.js.gz +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
- package/dist/web/assets/video-preview-DxEX-uGo.js +0 -1
- package/dist/web/assets/video-preview-DxEX-uGo.js.br +0 -0
- package/dist/web/assets/video-preview-DxEX-uGo.js.gz +0 -0
- package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
- /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
- /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One process's properties — Mission Center's Details dialog.
|
|
3
|
+
*
|
|
4
|
+
* Fetched when the dialog opens rather than ridden on the tick: it is a handful
|
|
5
|
+
* of `/proc` reads per process and nobody needs a working directory at 0.5 Hz.
|
|
6
|
+
* A field this user cannot read (another user's `exe`, `cwd`) comes back null,
|
|
7
|
+
* which is the normal case on a shared machine and renders as an em dash.
|
|
8
|
+
*/
|
|
9
|
+
import { useEffect, useState } from "react";
|
|
10
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
|
11
|
+
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
12
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
13
|
+
import { api } from "@/lib/api-client";
|
|
14
|
+
import type { ProcessDetails } from "../../../types/system-metrics";
|
|
15
|
+
|
|
16
|
+
export interface ProcessDetailsDialogProps {
|
|
17
|
+
pid: number | null;
|
|
18
|
+
name: string;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function started(ms: number): string {
|
|
23
|
+
return ms > 0 ? new Date(ms).toLocaleString() : "—";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function ProcessDetailsDialog({ pid, name, onClose }: ProcessDetailsDialogProps) {
|
|
27
|
+
const isMobile = useIsMobile();
|
|
28
|
+
const [details, setDetails] = useState<ProcessDetails | null>(null);
|
|
29
|
+
const [error, setError] = useState<string | null>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (pid === null) {
|
|
33
|
+
setDetails(null);
|
|
34
|
+
setError(null);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let live = true;
|
|
38
|
+
setDetails(null);
|
|
39
|
+
setError(null);
|
|
40
|
+
api.get<ProcessDetails>(`/api/system/resources/process/${pid}`)
|
|
41
|
+
.then((d) => { if (live) setDetails(d); })
|
|
42
|
+
.catch((e: unknown) => {
|
|
43
|
+
if (live) setError(e instanceof Error ? e.message : "Could not read the process");
|
|
44
|
+
});
|
|
45
|
+
return () => { live = false; };
|
|
46
|
+
}, [pid]);
|
|
47
|
+
|
|
48
|
+
if (pid === null) return null;
|
|
49
|
+
|
|
50
|
+
const body = (
|
|
51
|
+
<div className="space-y-3" data-testid="sysmon-process-details" data-pid={pid}>
|
|
52
|
+
{error && <p className="text-sm text-error">{error}</p>}
|
|
53
|
+
{!error && details === null && <p className="text-sm text-text-subtle">Reading /proc…</p>}
|
|
54
|
+
{details && (
|
|
55
|
+
<>
|
|
56
|
+
<dl className="grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
|
|
57
|
+
<Field label="PID" value={details.pid} />
|
|
58
|
+
<Field label="Parent PID" value={details.ppid} />
|
|
59
|
+
<Field label="User" value={details.user} />
|
|
60
|
+
<Field label="State" value={details.state} />
|
|
61
|
+
<Field label="Threads" value={details.threads} />
|
|
62
|
+
<Field label="Nice" value={details.nice} />
|
|
63
|
+
<Field label="Started" value={started(details.startedAt)} />
|
|
64
|
+
<Field label="Control group" value={details.cgroup} />
|
|
65
|
+
</dl>
|
|
66
|
+
<Block label="Executable" value={details.exe} />
|
|
67
|
+
<Block label="Working directory" value={details.cwd} />
|
|
68
|
+
{/* The whole line, not the table row's 160 characters: showing it is
|
|
69
|
+
what this dialog is for. Secrets are redacted server-side. */}
|
|
70
|
+
<Block label="Command line" value={details.command} mono />
|
|
71
|
+
</>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (isMobile) {
|
|
77
|
+
return (
|
|
78
|
+
<BottomSheet open onClose={onClose}>
|
|
79
|
+
<div className="px-4 pb-4 space-y-3">
|
|
80
|
+
<h2 className="text-base font-semibold break-all">{name}</h2>
|
|
81
|
+
{body}
|
|
82
|
+
</div>
|
|
83
|
+
</BottomSheet>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return (
|
|
87
|
+
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
|
88
|
+
{/* `sm:` or the primitive's own `sm:max-w-lg` wins and this is dead. */}
|
|
89
|
+
<DialogContent className="sm:max-w-xl">
|
|
90
|
+
<DialogHeader>
|
|
91
|
+
<DialogTitle className="break-all">{name}</DialogTitle>
|
|
92
|
+
</DialogHeader>
|
|
93
|
+
{body}
|
|
94
|
+
</DialogContent>
|
|
95
|
+
</Dialog>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function Field({ label, value }: { label: string; value: string | number | null }) {
|
|
100
|
+
const text = value === null || value === "" ? "—" : String(value);
|
|
101
|
+
return (
|
|
102
|
+
<div className="min-w-0">
|
|
103
|
+
<dt className="text-text-subtle">{label}</dt>
|
|
104
|
+
<dd className="truncate" title={text}>{text}</dd>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function Block({ label, value, mono }: { label: string; value: string | null; mono?: boolean }) {
|
|
110
|
+
return (
|
|
111
|
+
<div className="space-y-1">
|
|
112
|
+
<p className="text-[11px] text-text-subtle">{label}</p>
|
|
113
|
+
<p className={`text-xs break-all ${mono ? "font-mono" : ""}`}>{value ?? "—"}</p>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChevronRight, ChevronDown, X } from "@/lib/icons";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
3
|
import { formatRam } from "@/lib/format-bytes";
|
|
4
|
-
import { cpuColor, formatDiskCell, formatGpuCell, formatNetCell, sumOptionalBps } from "./process-row-format";
|
|
4
|
+
import { cpuColor, formatDiskCell, formatGpuCell, formatNetCell, formatSwapCell, sumOptionalBps } from "./process-row-format";
|
|
5
5
|
import { optionalCellClassName, type ProcessGridResult } from "./process-columns-grid";
|
|
6
6
|
import type { ProcessGroup } from "../../../types/system-metrics";
|
|
7
7
|
|
|
@@ -50,6 +50,11 @@ export function ProcessGroupRow({ group, expanded, grid, killProtected, onToggle
|
|
|
50
50
|
</div>
|
|
51
51
|
<span className={cn("text-right", cpuColor(group.cpu))}>{group.cpu.toFixed(1)}%</span>
|
|
52
52
|
<span className="text-right text-text-secondary">{formatRam(group.ramMB)}</span>
|
|
53
|
+
{grid.columns.swap && (
|
|
54
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "swap"))}>
|
|
55
|
+
{formatSwapCell(group.swapMB)}
|
|
56
|
+
</span>
|
|
57
|
+
)}
|
|
53
58
|
{grid.columns.disk && (
|
|
54
59
|
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "disk"))}>
|
|
55
60
|
{formatDiskCell(group.diskReadBps, group.diskWriteBps)}
|
|
@@ -32,6 +32,12 @@ export function formatDiskCell(readBps?: number, writeBps?: number): string {
|
|
|
32
32
|
return `↓ ${formatBps(readBps ?? 0)} ↑ ${formatBps(writeBps ?? 0)}`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/** Swap has no second half, so it is the one optional cell where `undefined`
|
|
36
|
+
* and 0 are the only two cases — a kernel thread really does swap nothing. */
|
|
37
|
+
export function formatSwapCell(swapMB?: number): string {
|
|
38
|
+
return swapMB === undefined ? "—" : formatRam(swapMB);
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
export function formatNetCell(inBps?: number, outBps?: number): string {
|
|
36
42
|
if (inBps === undefined && outBps === undefined) return "—";
|
|
37
43
|
return `↓ ${formatBps(inBps ?? 0)} ↑ ${formatBps(outBps ?? 0)}`;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A process row's actions — Mission Center's right-click menu: Details, End, and
|
|
3
|
+
* the Send Signal submenu.
|
|
4
|
+
*
|
|
5
|
+
* Right-click on a mouse, long-press on a touch screen, via the adaptive menu.
|
|
6
|
+
* That component only SUPPRESSES the click following a long press; it has no tap
|
|
7
|
+
* handler of its own, so the row's own tap target stays a real button inside the
|
|
8
|
+
* trigger and is passed through as `children` untouched.
|
|
9
|
+
*/
|
|
10
|
+
import type { ReactNode } from "react";
|
|
11
|
+
import {
|
|
12
|
+
ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator,
|
|
13
|
+
ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger,
|
|
14
|
+
} from "@/components/ui/adaptive-context-menu";
|
|
15
|
+
import { SIGNAL_LABELS, UNCATCHABLE_SIGNALS } from "./use-process-signal";
|
|
16
|
+
import type { ProcessInfo, ProcessSignal } from "../../../types/system-metrics";
|
|
17
|
+
|
|
18
|
+
export interface ProcessRowMenuProps {
|
|
19
|
+
proc: ProcessInfo;
|
|
20
|
+
/** Signals this host can deliver, straight off the snapshot. Empty or absent
|
|
21
|
+
* hides the submenu entirely rather than offering something that would 400. */
|
|
22
|
+
signals: readonly ProcessSignal[];
|
|
23
|
+
onDetails: (proc: ProcessInfo) => void;
|
|
24
|
+
onKill: (proc: ProcessInfo) => void;
|
|
25
|
+
onSignal: (proc: ProcessInfo, signal: ProcessSignal, tree: boolean) => void;
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ProcessRowMenu({
|
|
30
|
+
proc, signals, onDetails, onKill, onSignal, children,
|
|
31
|
+
}: ProcessRowMenuProps) {
|
|
32
|
+
return (
|
|
33
|
+
<ContextMenu>
|
|
34
|
+
<ContextMenuTrigger asChild>
|
|
35
|
+
<div className="select-none">{children}</div>
|
|
36
|
+
</ContextMenuTrigger>
|
|
37
|
+
<ContextMenuContent>
|
|
38
|
+
<ContextMenuItem onSelect={() => onDetails(proc)}>Details…</ContextMenuItem>
|
|
39
|
+
{signals.length > 0 && (
|
|
40
|
+
<ContextMenuSub>
|
|
41
|
+
<ContextMenuSubTrigger>Send signal</ContextMenuSubTrigger>
|
|
42
|
+
<ContextMenuSubContent>
|
|
43
|
+
{signals.map((signal) => (
|
|
44
|
+
<ContextMenuItem
|
|
45
|
+
key={signal}
|
|
46
|
+
variant={UNCATCHABLE_SIGNALS.includes(signal) ? "destructive" : undefined}
|
|
47
|
+
disabled={proc.protected}
|
|
48
|
+
onSelect={() => { if (!proc.protected) onSignal(proc, signal, false); }}
|
|
49
|
+
>
|
|
50
|
+
{SIGNAL_LABELS[signal]}
|
|
51
|
+
</ContextMenuItem>
|
|
52
|
+
))}
|
|
53
|
+
</ContextMenuSubContent>
|
|
54
|
+
</ContextMenuSub>
|
|
55
|
+
)}
|
|
56
|
+
<ContextMenuSeparator />
|
|
57
|
+
<ContextMenuItem
|
|
58
|
+
variant="destructive"
|
|
59
|
+
disabled={proc.protected}
|
|
60
|
+
onSelect={() => { if (!proc.protected) onKill(proc); }}
|
|
61
|
+
>
|
|
62
|
+
End process
|
|
63
|
+
</ContextMenuItem>
|
|
64
|
+
{proc.protected && (
|
|
65
|
+
<p className="px-2 py-1.5 text-[11px] text-text-subtle max-w-64">
|
|
66
|
+
PPM or OS-critical process — it cannot be ended or signalled.
|
|
67
|
+
</p>
|
|
68
|
+
)}
|
|
69
|
+
</ContextMenuContent>
|
|
70
|
+
</ContextMenu>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { X } from "@/lib/icons";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
3
|
import { formatRam } from "@/lib/format-bytes";
|
|
4
|
-
import { cpuColor, formatAge, formatDiskCell, formatGpuCell, formatNetCell, sumOptionalBps } from "./process-row-format";
|
|
4
|
+
import { cpuColor, formatAge, formatDiskCell, formatGpuCell, formatNetCell, formatSwapCell, sumOptionalBps } from "./process-row-format";
|
|
5
5
|
import { optionalCellClassName, type ProcessGridResult } from "./process-columns-grid";
|
|
6
6
|
import type { ProcessInfo } from "../../../types/system-metrics";
|
|
7
7
|
|
|
@@ -22,6 +22,7 @@ export function ProcessRow({ proc, indent, grid, onKillClick }: ProcessRowProps)
|
|
|
22
22
|
data-pid={proc.pid}
|
|
23
23
|
data-ppm={proc.ppm}
|
|
24
24
|
data-protected={proc.protected}
|
|
25
|
+
data-swap-mb={proc.swapMB}
|
|
25
26
|
data-disk-bps={sumOptionalBps(proc.diskReadBps, proc.diskWriteBps)}
|
|
26
27
|
data-gpu-pct={proc.gpuPct}
|
|
27
28
|
data-net-bps={sumOptionalBps(proc.netInBps, proc.netOutBps)}
|
|
@@ -39,6 +40,11 @@ export function ProcessRow({ proc, indent, grid, onKillClick }: ProcessRowProps)
|
|
|
39
40
|
</div>
|
|
40
41
|
<span className={cn("text-right", cpuColor(proc.cpu))}>{proc.cpu.toFixed(1)}%</span>
|
|
41
42
|
<span className="text-right text-text-secondary">{formatRam(proc.ramMB)}</span>
|
|
43
|
+
{grid.columns.swap && (
|
|
44
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "swap"))}>
|
|
45
|
+
{formatSwapCell(proc.swapMB)}
|
|
46
|
+
</span>
|
|
47
|
+
)}
|
|
42
48
|
{grid.columns.disk && (
|
|
43
49
|
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "disk"))}>
|
|
44
50
|
{formatDiskCell(proc.diskReadBps, proc.diskWriteBps)}
|
|
@@ -102,7 +102,7 @@ export function buildRows(input: BuildRowsInput): BuildRowsResult {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/** Three-state sort toggle: desc -> asc -> off, shared by every sortable column. */
|
|
105
|
-
export function toggleSort(current:
|
|
105
|
+
export function toggleSort<K extends string>(current: K | null, dir: SortDir, clicked: K): [K | null, SortDir] {
|
|
106
106
|
if (current !== clicked) return [clicked, "desc"];
|
|
107
107
|
if (dir === "desc") return [clicked, "asc"];
|
|
108
108
|
return [null, "desc"];
|
|
@@ -11,6 +11,7 @@ export interface SortableFields {
|
|
|
11
11
|
cpu: number;
|
|
12
12
|
ramMB: number;
|
|
13
13
|
name: string;
|
|
14
|
+
swapMB?: number;
|
|
14
15
|
diskReadBps?: number;
|
|
15
16
|
diskWriteBps?: number;
|
|
16
17
|
gpuPct?: number;
|
|
@@ -25,6 +26,7 @@ export interface SortableFields {
|
|
|
25
26
|
export function sortFields(m: {
|
|
26
27
|
cpu: number;
|
|
27
28
|
ramMB: number;
|
|
29
|
+
swapMB?: number;
|
|
28
30
|
diskReadBps?: number;
|
|
29
31
|
diskWriteBps?: number;
|
|
30
32
|
gpuPct?: number;
|
|
@@ -36,6 +38,7 @@ export function sortFields(m: {
|
|
|
36
38
|
cpu: m.cpu,
|
|
37
39
|
ramMB: m.ramMB,
|
|
38
40
|
name,
|
|
41
|
+
swapMB: m.swapMB,
|
|
39
42
|
diskReadBps: m.diskReadBps,
|
|
40
43
|
diskWriteBps: m.diskWriteBps,
|
|
41
44
|
gpuPct: m.gpuPct,
|
|
@@ -52,15 +55,16 @@ function sumPair(a?: number, b?: number): number | undefined {
|
|
|
52
55
|
return (a ?? 0) + (b ?? 0);
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
function optionalValueFor(key: "disk" | "gpu" | "gpuMem" | "net", f: SortableFields): number | undefined {
|
|
58
|
+
function optionalValueFor(key: "swap" | "disk" | "gpu" | "gpuMem" | "net", f: SortableFields): number | undefined {
|
|
59
|
+
if (key === "swap") return f.swapMB;
|
|
56
60
|
if (key === "disk") return sumPair(f.diskReadBps, f.diskWriteBps);
|
|
57
61
|
if (key === "net") return sumPair(f.netInBps, f.netOutBps);
|
|
58
62
|
if (key === "gpu") return f.gpuPct;
|
|
59
63
|
return f.gpuMemMB;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
function isOptionalSortKey(key: SortKey): key is "disk" | "gpu" | "gpuMem" | "net" {
|
|
63
|
-
return key === "disk" || key === "gpu" || key === "gpuMem" || key === "net";
|
|
66
|
+
function isOptionalSortKey(key: SortKey): key is "swap" | "disk" | "gpu" | "gpuMem" | "net" {
|
|
67
|
+
return key === "swap" || key === "disk" || key === "gpu" || key === "gpuMem" || key === "net";
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
export function sortByKey<T>(items: T[], key: SortKey, dir: SortDir, get: (item: T) => SortableFields): T[] {
|
|
@@ -75,7 +79,7 @@ export function sortByKey<T>(items: T[], key: SortKey, dir: SortDir, get: (item:
|
|
|
75
79
|
if (key === "cpu") return dir === "asc" ? av.cpu - bv.cpu : bv.cpu - av.cpu;
|
|
76
80
|
if (key === "ram") return dir === "asc" ? av.ramMB - bv.ramMB : bv.ramMB - av.ramMB;
|
|
77
81
|
|
|
78
|
-
// disk/gpu/gpuMem/net: optional metrics. Undefined always sorts last, in
|
|
82
|
+
// swap/disk/gpu/gpuMem/net: optional metrics. Undefined always sorts last, in
|
|
79
83
|
// EITHER direction — it means "unmeasurable", not "smallest value".
|
|
80
84
|
if (isOptionalSortKey(key)) {
|
|
81
85
|
const aVal = optionalValueFor(key, av);
|
|
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import { Search } from "@/lib/icons";
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
4
|
import { formatRam } from "@/lib/format-bytes";
|
|
5
|
-
import { cpuColor, formatDiskCell, formatGpuCell, formatNetCell } from "./process-row-format";
|
|
5
|
+
import { cpuColor, formatDiskCell, formatGpuCell, formatNetCell, formatSwapCell } from "./process-row-format";
|
|
6
6
|
import { optionalCellClassName, PROCESS_ROW_GRID_CLASS, type ProcessGridResult } from "./process-columns-grid";
|
|
7
7
|
import type { Totals } from "./process-table-totals";
|
|
8
8
|
import { SortableHeader, type ColumnResizeHandlers } from "./sortable-header";
|
|
@@ -86,7 +86,7 @@ export interface ProcessTableHeaderProps {
|
|
|
86
86
|
resize: ColumnResizeHandlers;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/** Sticky column header row, grid-aligned with the rows below it. Disk/GPU/Net
|
|
89
|
+
/** Sticky column header row, grid-aligned with the rows below it. Swap/Disk/GPU/Net
|
|
90
90
|
* headers only render when the host reported that column as measurable
|
|
91
91
|
* (`grid.columns.<x>`); below `@lg` only the one currently sorted survives. Every
|
|
92
92
|
* fixed-width column carries a drag handle on its right edge. */
|
|
@@ -103,6 +103,9 @@ export function ProcessTableHeader({ sortKey, sortDir, grid, onSort, resize }: P
|
|
|
103
103
|
<SortableHeader label="Process" field="name" {...common} resize={undefined} align="left" testId="sysmon-sort-name" />
|
|
104
104
|
<SortableHeader label="CPU" field="cpu" {...common} resizeKey="cpu" testId="sysmon-sort-cpu" />
|
|
105
105
|
<SortableHeader label="RAM" field="ram" {...common} resizeKey="ram" testId="sysmon-sort-ram" />
|
|
106
|
+
{grid.columns.swap && (
|
|
107
|
+
<SortableHeader label="Swap" field="swap" {...common} resizeKey="swap" testId="sysmon-col-swap" className={optionalCellClassName(grid, "swap")} />
|
|
108
|
+
)}
|
|
106
109
|
{grid.columns.disk && (
|
|
107
110
|
<SortableHeader label="Disk" field="disk" {...common} resizeKey="disk" testId="sysmon-col-disk" className={optionalCellClassName(grid, "disk")} />
|
|
108
111
|
)}
|
|
@@ -138,6 +141,11 @@ export function ProcessTableFooter({ totals, grid, gpuUtilPercent }: ProcessTabl
|
|
|
138
141
|
<span className="truncate">Total ({totals.count} processes)</span>
|
|
139
142
|
<span className={cn("text-right", cpuColor(totals.cpu))}>{totals.cpu.toFixed(1)}%</span>
|
|
140
143
|
<span className="text-right text-text-secondary">{formatRam(totals.ramMB)}</span>
|
|
144
|
+
{grid.columns.swap && (
|
|
145
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "swap"))}>
|
|
146
|
+
{formatSwapCell(totals.swapMB)}
|
|
147
|
+
</span>
|
|
148
|
+
)}
|
|
141
149
|
{grid.columns.disk && (
|
|
142
150
|
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "disk"))}>
|
|
143
151
|
{formatDiskCell(totals.diskReadBps, totals.diskWriteBps)}
|
|
@@ -7,6 +7,7 @@ export interface Totals {
|
|
|
7
7
|
count: number;
|
|
8
8
|
/** Sums over rows with a defined value; `undefined` when NO visible row measured
|
|
9
9
|
* that metric — mirrors the "undefined = host can't measure" rule on ProcessInfo. */
|
|
10
|
+
swapMB?: number;
|
|
10
11
|
diskReadBps?: number;
|
|
11
12
|
diskWriteBps?: number;
|
|
12
13
|
gpuMemMB?: number;
|
|
@@ -28,6 +29,7 @@ export function accumulateTotals(
|
|
|
28
29
|
item: {
|
|
29
30
|
cpu: number;
|
|
30
31
|
ramMB: number;
|
|
32
|
+
swapMB?: number;
|
|
31
33
|
diskReadBps?: number;
|
|
32
34
|
diskWriteBps?: number;
|
|
33
35
|
gpuMemMB?: number;
|
|
@@ -40,6 +42,7 @@ export function accumulateTotals(
|
|
|
40
42
|
cpu: acc.cpu + item.cpu,
|
|
41
43
|
ramMB: acc.ramMB + item.ramMB,
|
|
42
44
|
count: acc.count + countDelta,
|
|
45
|
+
swapMB: addOptional(acc.swapMB, item.swapMB),
|
|
43
46
|
diskReadBps: addOptional(acc.diskReadBps, item.diskReadBps),
|
|
44
47
|
diskWriteBps: addOptional(acc.diskWriteBps, item.diskWriteBps),
|
|
45
48
|
gpuMemMB: addOptional(acc.gpuMemMB, item.gpuMemMB),
|
|
@@ -6,10 +6,13 @@ import { buildProcessGrid, gridCssVars } from "./process-columns-grid";
|
|
|
6
6
|
import { ProcessTableToolbar, ProcessTableHeader, ProcessTableFooter } from "./process-table-toolbar";
|
|
7
7
|
import { ProcessGroupRow } from "./process-group-row";
|
|
8
8
|
import { ProcessRow } from "./process-row";
|
|
9
|
+
import { ProcessRowMenu } from "./process-row-menu";
|
|
10
|
+
import { ProcessDetailsDialog } from "./process-details-dialog";
|
|
9
11
|
import { KillConfirmDialog } from "./kill-confirm-dialog";
|
|
10
12
|
import { useProcessKill } from "./use-process-kill";
|
|
13
|
+
import { useProcessSignal } from "./use-process-signal";
|
|
11
14
|
import { useColumnWidths } from "./use-column-widths";
|
|
12
|
-
import type { MetricsSnapshot, SortDir, SortKey } from "../../../types/system-metrics";
|
|
15
|
+
import type { MetricsSnapshot, ProcessInfo, SortDir, SortKey } from "../../../types/system-metrics";
|
|
13
16
|
|
|
14
17
|
/** Older cached bundles/snapshots (mid-rollout) predate `processColumns` — default
|
|
15
18
|
* every optional column off rather than let a missing field throw. */
|
|
@@ -31,6 +34,13 @@ export function ProcessTable({ snapshot }: ProcessTableProps) {
|
|
|
31
34
|
const [expanded, setExpanded] = useState<Set<string>>(() => new Set());
|
|
32
35
|
const { pendingKill, groupProtected, requestKillProcess, requestKillGroup, confirmKill, cancelKill } =
|
|
33
36
|
useProcessKill(snapshot);
|
|
37
|
+
const { send: sendSignal } = useProcessSignal();
|
|
38
|
+
// Held as the whole row rather than a pid: the dialog needs a name to show while
|
|
39
|
+
// it is fetching, and the row can leave the table before the answer arrives.
|
|
40
|
+
const [details, setDetails] = useState<ProcessInfo | null>(null);
|
|
41
|
+
// Absent on a light-tier frame and on any host with no signal support, in which
|
|
42
|
+
// case the menu simply has no Send-signal submenu.
|
|
43
|
+
const signals = snapshot.signals ?? [];
|
|
34
44
|
const { widths, begin: onResizeStart, reset: onResizeReset } = useColumnWidths();
|
|
35
45
|
|
|
36
46
|
const { rows, totals } = useMemo(
|
|
@@ -128,7 +138,15 @@ export function ProcessTable({ snapshot }: ProcessTableProps) {
|
|
|
128
138
|
onKillClick={requestKillGroup}
|
|
129
139
|
/>
|
|
130
140
|
) : (
|
|
131
|
-
<
|
|
141
|
+
<ProcessRowMenu
|
|
142
|
+
proc={row.proc}
|
|
143
|
+
signals={signals}
|
|
144
|
+
onDetails={setDetails}
|
|
145
|
+
onKill={requestKillProcess}
|
|
146
|
+
onSignal={(proc, signal, tree) => void sendSignal(proc, signal, tree)}
|
|
147
|
+
>
|
|
148
|
+
<ProcessRow proc={row.proc} indent={row.indent} grid={grid} onKillClick={requestKillProcess} />
|
|
149
|
+
</ProcessRowMenu>
|
|
132
150
|
)}
|
|
133
151
|
</div>
|
|
134
152
|
);
|
|
@@ -141,6 +159,11 @@ export function ProcessTable({ snapshot }: ProcessTableProps) {
|
|
|
141
159
|
onConfirm={confirmKill}
|
|
142
160
|
onCancel={cancelKill}
|
|
143
161
|
/>
|
|
162
|
+
<ProcessDetailsDialog
|
|
163
|
+
pid={details?.pid ?? null}
|
|
164
|
+
name={details?.name ?? ""}
|
|
165
|
+
onClose={() => setDetails(null)}
|
|
166
|
+
/>
|
|
144
167
|
</div>
|
|
145
168
|
);
|
|
146
169
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirm before a service action that takes something away.
|
|
3
|
+
*
|
|
4
|
+
* Mission Center asks nothing and lets polkit decide. PPM asks, because its
|
|
5
|
+
* Services page is reachable from a phone on a LAN where a mis-tap on "Stop" has
|
|
6
|
+
* no undo — and because the actions that would be catastrophic are refused by the
|
|
7
|
+
* server anyway, so what is left here is exactly the consequential-but-allowed
|
|
8
|
+
* middle. Start and enable are not confirmed: they take nothing away.
|
|
9
|
+
*/
|
|
10
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
|
11
|
+
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
12
|
+
import { Button } from "@/components/ui/button";
|
|
13
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
14
|
+
import type { ServiceAction, ServiceInfo } from "../../../../types/system-services";
|
|
15
|
+
|
|
16
|
+
/** The actions worth a question. */
|
|
17
|
+
export const CONFIRMED_ACTIONS: readonly ServiceAction[] = ["stop", "restart", "disable"];
|
|
18
|
+
|
|
19
|
+
export function needsConfirm(action: ServiceAction): boolean {
|
|
20
|
+
return CONFIRMED_ACTIONS.includes(action);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const WORDING: Partial<Record<ServiceAction, { title: string; body: (unit: string) => string; cta: string }>> = {
|
|
24
|
+
stop: {
|
|
25
|
+
title: "Stop service",
|
|
26
|
+
body: (unit) => `Stop ${unit}? Anything depending on it stops too.`,
|
|
27
|
+
cta: "Stop",
|
|
28
|
+
},
|
|
29
|
+
restart: {
|
|
30
|
+
title: "Restart service",
|
|
31
|
+
body: (unit) => `Restart ${unit}? It will be briefly unavailable.`,
|
|
32
|
+
cta: "Restart",
|
|
33
|
+
},
|
|
34
|
+
disable: {
|
|
35
|
+
title: "Disable at boot",
|
|
36
|
+
body: (unit) => `${unit} will no longer start at boot. It keeps running now.`,
|
|
37
|
+
cta: "Disable",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface PendingServiceAction {
|
|
42
|
+
service: ServiceInfo;
|
|
43
|
+
action: ServiceAction;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ServiceActionConfirmProps {
|
|
47
|
+
pending: PendingServiceAction | null;
|
|
48
|
+
onConfirm: (pending: PendingServiceAction) => void;
|
|
49
|
+
onCancel: () => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function ServiceActionConfirm({ pending, onConfirm, onCancel }: ServiceActionConfirmProps) {
|
|
53
|
+
const isMobile = useIsMobile();
|
|
54
|
+
if (!pending) return null;
|
|
55
|
+
const wording = WORDING[pending.action];
|
|
56
|
+
if (!wording) return null;
|
|
57
|
+
|
|
58
|
+
const body = (
|
|
59
|
+
<div className="space-y-4" data-testid="sysmon-service-confirm" data-action={pending.action}>
|
|
60
|
+
<p className="text-sm break-words">{wording.body(pending.service.unit)}</p>
|
|
61
|
+
<p className="text-xs text-text-subtle">
|
|
62
|
+
{pending.service.scope === "system" ? "System service" : "User service"}
|
|
63
|
+
{pending.service.mainPid !== null && ` · pid ${pending.service.mainPid}`}
|
|
64
|
+
</p>
|
|
65
|
+
<div className="flex flex-col-reverse md:flex-row gap-2 md:justify-end pt-2">
|
|
66
|
+
<Button variant="outline" onClick={onCancel} className="min-h-11">Cancel</Button>
|
|
67
|
+
<Button
|
|
68
|
+
variant="destructive"
|
|
69
|
+
autoFocus={false}
|
|
70
|
+
onClick={() => onConfirm(pending)}
|
|
71
|
+
data-testid="sysmon-service-confirm-ok"
|
|
72
|
+
className="min-h-11"
|
|
73
|
+
>
|
|
74
|
+
{wording.cta}
|
|
75
|
+
</Button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (isMobile) {
|
|
81
|
+
return (
|
|
82
|
+
<BottomSheet open onClose={onCancel}>
|
|
83
|
+
<div className="px-4 pb-4">
|
|
84
|
+
<h2 className="text-base font-semibold mb-3">{wording.title}</h2>
|
|
85
|
+
{body}
|
|
86
|
+
</div>
|
|
87
|
+
</BottomSheet>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return (
|
|
91
|
+
<Dialog open onOpenChange={(open) => !open && onCancel()}>
|
|
92
|
+
<DialogContent>
|
|
93
|
+
<DialogHeader>
|
|
94
|
+
<DialogTitle>{wording.title}</DialogTitle>
|
|
95
|
+
</DialogHeader>
|
|
96
|
+
{body}
|
|
97
|
+
</DialogContent>
|
|
98
|
+
</Dialog>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Services table's columns — Mission Center's own set, in its own order:
|
|
3
|
+
* Name, PID, CPU, Memory, Swap, Drive, GPU, GPU Memory.
|
|
4
|
+
*
|
|
5
|
+
* One table drives three things that have to agree or the page silently
|
|
6
|
+
* misaligns: the header labels, each cell's visibility, and the grid template at
|
|
7
|
+
* each width. They are derived from this list rather than written out three
|
|
8
|
+
* times, because a column added to the header and forgotten in the template does
|
|
9
|
+
* not fail — it shifts every cell after it one track to the left.
|
|
10
|
+
*
|
|
11
|
+
* Widths are fixed pixels for every column but the name. They cannot be `auto`:
|
|
12
|
+
* each row is its own grid element, so an `auto` track is sized by *that row's*
|
|
13
|
+
* content and two rows with different-length numbers would not line up.
|
|
14
|
+
*
|
|
15
|
+
* Pure, React-free, relative imports only.
|
|
16
|
+
*/
|
|
17
|
+
import type { CSSProperties } from "react";
|
|
18
|
+
|
|
19
|
+
export type ServiceColumnKey = "name" | "pid" | "cpu" | "ram" | "swap" | "disk" | "gpu" | "gpuMem";
|
|
20
|
+
|
|
21
|
+
/** The container width at which a column appears. `base` is always present. */
|
|
22
|
+
export type ColumnBreakpoint = "base" | "@2xl" | "@3xl" | "@4xl";
|
|
23
|
+
|
|
24
|
+
export interface ServiceColumn {
|
|
25
|
+
key: ServiceColumnKey;
|
|
26
|
+
label: string;
|
|
27
|
+
/** Track width in px; `null` is the one flexible column (the name). */
|
|
28
|
+
width: number | null;
|
|
29
|
+
from: ColumnBreakpoint;
|
|
30
|
+
align: "left" | "right";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The ladder is by *usefulness per pixel*: CPU and Memory are the two figures
|
|
35
|
+
* worth a narrow window, PID and Swap come next, and the three widest cells
|
|
36
|
+
* (Drive carries two rates) only once there is room for them beside a readable
|
|
37
|
+
* unit name. A 60-character unit name squeezed into 90px to show a GPU column
|
|
38
|
+
* that reads 0% for almost every unit is a worse table, not a fuller one.
|
|
39
|
+
*/
|
|
40
|
+
export const SERVICE_COLUMNS: readonly ServiceColumn[] = [
|
|
41
|
+
{ key: "name", label: "Name", width: null, from: "base", align: "left" },
|
|
42
|
+
{ key: "pid", label: "PID", width: 56, from: "@3xl", align: "right" },
|
|
43
|
+
{ key: "cpu", label: "CPU", width: 56, from: "@2xl", align: "right" },
|
|
44
|
+
{ key: "ram", label: "Memory", width: 72, from: "@2xl", align: "right" },
|
|
45
|
+
{ key: "swap", label: "Swap", width: 72, from: "@3xl", align: "right" },
|
|
46
|
+
{ key: "disk", label: "Drive", width: 112, from: "@4xl", align: "right" },
|
|
47
|
+
{ key: "gpu", label: "GPU", width: 56, from: "@4xl", align: "right" },
|
|
48
|
+
{ key: "gpuMem", label: "GPU Memory", width: 80, from: "@4xl", align: "right" },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/** Narrowest first; a column appears at its own breakpoint and every wider one. */
|
|
52
|
+
export const BREAKPOINT_ORDER: readonly ColumnBreakpoint[] = ["base", "@2xl", "@3xl", "@4xl"];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Written out as literal strings, never built from `col.from` at runtime:
|
|
56
|
+
* Tailwind scans source text for class names, so a class assembled as
|
|
57
|
+
* `` `hidden ${bp}:block` `` emits no rule at all and the column would be
|
|
58
|
+
* visible at every width — the same silent failure as a colour class naming a
|
|
59
|
+
* token that does not exist.
|
|
60
|
+
*/
|
|
61
|
+
const VISIBILITY: Record<ColumnBreakpoint, string> = {
|
|
62
|
+
base: "",
|
|
63
|
+
"@2xl": "hidden @2xl:block",
|
|
64
|
+
"@3xl": "hidden @3xl:block",
|
|
65
|
+
"@4xl": "hidden @4xl:block",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export function columnVisibilityClass(column: ServiceColumn): string {
|
|
69
|
+
return VISIBILITY[column.from];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function visibleColumnsAt(breakpoint: ColumnBreakpoint): ServiceColumn[] {
|
|
73
|
+
const width = BREAKPOINT_ORDER.indexOf(breakpoint);
|
|
74
|
+
return SERVICE_COLUMNS.filter((c) => BREAKPOINT_ORDER.indexOf(c.from) <= width);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function gridTemplateAt(breakpoint: ColumnBreakpoint): string {
|
|
78
|
+
return visibleColumnsAt(breakpoint)
|
|
79
|
+
.map((c) => (c.width === null ? "minmax(0,1fr)" : `${c.width}px`))
|
|
80
|
+
.join(" ");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Static class names for the four templates; the templates themselves arrive as
|
|
85
|
+
* CSS custom properties set once on the panel and inherited by every row, which
|
|
86
|
+
* is the same arrangement the process table uses. `gap-2` rather than `gap-3`:
|
|
87
|
+
* eight columns pay seven gaps, and 28px of them is a tenth of the name column.
|
|
88
|
+
*/
|
|
89
|
+
export const SERVICE_ROW_GRID_CLASS = [
|
|
90
|
+
"grid gap-2 grid-cols-[var(--svc-cols-base)]",
|
|
91
|
+
"@2xl:grid-cols-[var(--svc-cols-2xl)]",
|
|
92
|
+
"@3xl:grid-cols-[var(--svc-cols-3xl)]",
|
|
93
|
+
"@4xl:grid-cols-[var(--svc-cols-4xl)]",
|
|
94
|
+
].join(" ");
|
|
95
|
+
|
|
96
|
+
export function serviceGridCssVars(): CSSProperties {
|
|
97
|
+
return {
|
|
98
|
+
"--svc-cols-base": gridTemplateAt("base"),
|
|
99
|
+
"--svc-cols-2xl": gridTemplateAt("@2xl"),
|
|
100
|
+
"--svc-cols-3xl": gridTemplateAt("@3xl"),
|
|
101
|
+
"--svc-cols-4xl": gridTemplateAt("@4xl"),
|
|
102
|
+
} as CSSProperties;
|
|
103
|
+
}
|