@hienlh/ppm 0.19.2 → 0.19.4
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 +27 -0
- package/CLAUDE.md +1 -0
- 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 +3 -2
- package/dist/web/assets/accounts-settings-section-CCFQV-RB.js +1 -0
- package/dist/web/assets/ai-resource-editor-BTWds-aC.js +1 -0
- package/dist/web/assets/ai-settings-section-CmoBsSpY.js +1 -0
- package/dist/web/assets/ai-settings-section-DjbYj4wK.js +1 -0
- package/dist/web/assets/{angular-html-BlcrLjUx.js → angular-html-BuHNQIbQ.js} +1 -1
- package/dist/web/assets/{angular-ts-BUjtceAJ.js → angular-ts-DHRWoLc-.js} +1 -1
- package/dist/web/assets/api-client-BogqsFna.js +1 -0
- package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
- package/dist/web/assets/{api-themes-YsZgf6Xj.js → api-themes-Cknp3Q-P.js} +1 -1
- package/dist/web/assets/{apl-B3g0v1pk.js → apl-C1VSWVei.js} +1 -1
- package/dist/web/assets/appearance-settings-section-vLmakLtA.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-Ca5IpdzP.js +1 -0
- package/dist/web/assets/arrow-left-CyFcsyzD.js +1 -0
- package/dist/web/assets/{astro-FRnyn7cH.js → astro-RX-rChsZ.js} +1 -1
- package/dist/web/assets/{audio-preview-DWTRm4HC.js → audio-preview-CCd1jdje.js} +1 -1
- package/dist/web/assets/{blade-NLdOqUKw.js → blade-CZ6bxMbK.js} +1 -1
- package/dist/web/assets/{pencil-BlIIg6RH.js → brain-KDa9jFRq.js} +1 -1
- package/dist/web/assets/{bsl-CenHZfaU.js → bsl-BhgCXLWk.js} +1 -1
- package/dist/web/assets/{button-Cq8yixjf.js → button-BZtEJcUv.js} +1 -1
- package/dist/web/assets/{cairo-B_WR0aiQ.js → cairo-BrwygPkn.js} +1 -1
- package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
- package/dist/web/assets/chat-tab-CLRlS8Jc.js +15 -0
- package/dist/web/assets/check-DN75Ucvz.js +1 -0
- package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
- package/dist/web/assets/{cobol-DOynhWYj.js → cobol-C5TGW1Ir.js} +1 -1
- package/dist/web/assets/code-editor-CCwVu5F5.js +7 -0
- package/dist/web/assets/{coffee-Bn6dbw4P.js → coffee-CFgKlmgI.js} +1 -1
- package/dist/web/assets/{conflict-editor-Cgb-z12D.js → conflict-editor-CvWYcbwD.js} +1 -1
- package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
- package/dist/web/assets/{cpp-CoZR9t8r.js → cpp-BhG5q3-d.js} +1 -1
- package/dist/web/assets/{crystal-BSheONSg.js → crystal-DvuI7_tY.js} +1 -1
- package/dist/web/assets/{csv-preview-BZMHfFH3.js → csv-preview-DzuDuyE_.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-gwPoVSCU.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
- package/dist/web/assets/database-viewer-D4XGEDHm.js +1 -0
- package/dist/web/assets/diff-viewer-B5N1X61R.js +4 -0
- package/dist/web/assets/{docx-preview-DqVDOMmv.js → docx-preview-CWIDVNZn.js} +1 -1
- package/dist/web/assets/{edge-DTtoslQu.js → edge-BSIEsmlI.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-CXSbSUBX.js → edit-diff-preview-DeHb85DN.js} +1 -1
- package/dist/web/assets/{elixir-CIBCZ3Zi.js → elixir-BF-lrGXM.js} +1 -1
- package/dist/web/assets/{elm-BLmb7K1H.js → elm-8mCsJOeN.js} +1 -1
- package/dist/web/assets/{erb-BBY8ApRd.js → erb-Dw5PUVKa.js} +1 -1
- package/dist/web/assets/{erlang-D5Zb5_P0.js → erlang-BvjBIA6O.js} +1 -1
- package/dist/web/assets/{esm-6F8v1jLL.js → esm-Bt9OwSnU.js} +1 -1
- package/dist/web/assets/explorer-body-BxLLjthF.js +2 -0
- package/dist/web/assets/explorer-window-content-CL1Cipj3.js +1 -0
- package/dist/web/assets/extension-manager-section-BpyGq15A.js +1 -0
- package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-BM8FXhuN.js} +1 -1
- package/dist/web/assets/{plus-BR0qewJI.js → eye-gWwaF4Lg.js} +1 -1
- package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
- package/dist/web/assets/files-settings-section-B0_aR1nL.js +1 -0
- package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CBdwkEUJ.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
- package/dist/web/assets/{fsharp-AT4XdVYH.js → fsharp-CjUIHIHp.js} +1 -1
- package/dist/web/assets/{gdresource-D852fWBR.js → gdresource-x_NUQFrZ.js} +1 -1
- package/dist/web/assets/general-settings-section-C1EJzjhU.js +1 -0
- package/dist/web/assets/{git-commit-DWfWAyxy.js → git-commit-BOpxSbns.js} +1 -1
- package/dist/web/assets/git-log-panel-D1yGTUE_.js +1 -0
- package/dist/web/assets/{git-rebase-C6opk8gr.js → git-rebase-BW4xlK7k.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
- package/dist/web/assets/{glide-data-grid-CICFjJon.js → glide-data-grid-Cu0STKML.js} +12 -12
- package/dist/web/assets/{glimmer-js-DLi5mWYO.js → glimmer-js-CT9jrmFj.js} +1 -1
- package/dist/web/assets/{glimmer-ts-D-scFX30.js → glimmer-ts-CjQT1lxK.js} +1 -1
- package/dist/web/assets/{glsl-dbQzF4iA.js → glsl-DsFJvtg5.js} +1 -1
- package/dist/web/assets/{graphql-D1m5Wen2.js → graphql-Dhlnmkn_.js} +1 -1
- package/dist/web/assets/group-chat-tab-BfcvkRX5.js +1 -0
- package/dist/web/assets/{hack-CqYmpO7u.js → hack-BKHbsJ7u.js} +1 -1
- package/dist/web/assets/{haml-BXzKWEag.js → haml-C1Ih25Y2.js} +1 -1
- package/dist/web/assets/{handlebars-DXnrtHtq.js → handlebars-CaFitvmC.js} +1 -1
- package/dist/web/assets/{html-DhgQJ-xL.js → html-BwpKIE6V.js} +1 -1
- package/dist/web/assets/{html-derivative-xZRft-YE.js → html-derivative-uuTEquZU.js} +1 -1
- package/dist/web/assets/{http-B53mSj14.js → http-Cv4Pg5cR.js} +1 -1
- package/dist/web/assets/{hurl-CsomVy04.js → hurl-DubkI6TG.js} +1 -1
- package/dist/web/assets/{hxml-LffjWwKA.js → hxml-B9OVZFAB.js} +1 -1
- package/dist/web/assets/{image-preview-CNA6XMNS.js → image-preview-DRbZ0FA2.js} +1 -1
- package/dist/web/assets/index-B1bzKRjJ.js +52 -0
- package/dist/web/assets/index-nP3uxXvR.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
- package/dist/web/assets/{jinja-CCHURl7V.js → jinja-BHb1jyl6.js} +1 -1
- package/dist/web/assets/jira-watcher-section-DZh-Z2MK.js +1 -0
- package/dist/web/assets/{jison-7qBd8dnR.js → jison-CtpfXDzp.js} +1 -1
- package/dist/web/assets/{julia-BY9pnTcy.js → julia-TYjgpazU.js} +1 -1
- package/dist/web/assets/{just-D7wRSNRr.js → just-D27bzZuW.js} +1 -1
- package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
- package/dist/web/assets/keybindings-store-CFwgcnpZ.js +1 -0
- package/dist/web/assets/keyboard-shortcuts-section-JBtcJGM3.js +1 -0
- package/dist/web/assets/{latex-RgsCae55.js → latex-D_MzopTn.js} +1 -1
- package/dist/web/assets/{liquid-CnDFzvOZ.js → liquid-BG_FG0Pe.js} +1 -1
- package/dist/web/assets/{lua-0lj5W8sm.js → lua-Bl29oC2L.js} +1 -1
- package/dist/web/assets/{markdown-renderer-dbLIvU2M.js → markdown-renderer-Bo8GgGXl.js} +3 -3
- package/dist/web/assets/markdown-renderer-DY60UZNW.js +1 -0
- package/dist/web/assets/{marko-CQgqAhbV.js → marko-D-HI7dbm.js} +1 -1
- package/dist/web/assets/{mdc-BkIcTiIy.js → mdc-y444JQTQ.js} +1 -1
- package/dist/web/assets/{media-url-DDciwvLU.js → media-url-VzecHk9g.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-pjcHKorA.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-C59rPw7Z.js +1 -0
- package/dist/web/assets/{nextflow-DvIW68DS.js → nextflow-C5sKcldC.js} +1 -1
- package/dist/web/assets/{nginx-O-hft0gG.js → nginx-bXnEC3wm.js} +1 -1
- package/dist/web/assets/{nim-BxrR4HwQ.js → nim-pevhf4WD.js} +1 -1
- package/dist/web/assets/notification-store-Bd6L0K_Q.js +1 -0
- package/dist/web/assets/notifications-settings-section-ARQlF-6E.js +1 -0
- package/dist/web/assets/{number-overlay-editor-BoLRYuZT.js → number-overlay-editor-B7WINIW4.js} +1 -1
- package/dist/web/assets/{overview-panel-l3g1gT5e.js → overview-panel-mhN0qw6Q.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-D_BoHr_M.js +1 -0
- package/dist/web/assets/panel-store-BRrnDO_i.js +1 -0
- package/dist/web/assets/pdf-preview-CRShdbBS.js +1 -0
- package/dist/web/assets/{perl-Da-uNqmL.js → perl-B1KUtMnW.js} +1 -1
- package/dist/web/assets/{php-JMu45mEx.js → php-BGmVZBAJ.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
- package/dist/web/assets/{postgres-viewer-DstZwUai.js → postgres-viewer-BNT-4yYl.js} +3 -3
- package/dist/web/assets/power-CriQkeK5.js +1 -0
- package/dist/web/assets/ppmbot-settings-section-Bq4YAcFW.js +1 -0
- package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-CjiXW0rg.js} +1 -1
- package/dist/web/assets/{project-store-DTUCS65m.js → project-store-BuY7rxn_.js} +1 -1
- package/dist/web/assets/proxy-settings-section-wRbiyQiA.js +3 -0
- package/dist/web/assets/{pug-CLzyQhia.js → pug-BfN8CpEH.js} +1 -1
- package/dist/web/assets/{qml-BHXfGB1l.js → qml-D6fRdLZt.js} +1 -1
- package/dist/web/assets/query-audit-section-C5RmhRSu.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
- package/dist/web/assets/{razor-BqetJLN3.js → razor-fg-9AScR.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-BF-75_03.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-C9KR9I9G.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BnKJicB2.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-awXsNw_R.js +1 -0
- package/dist/web/assets/{rst-iQdJZ0BP.js → rst-BZgx076b.js} +1 -1
- package/dist/web/assets/{ruby-CNwzZGdH.js → ruby-iUkWDcLo.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CBXmVGWa.js → run-in-terminal-bKRwuO2z.js} +1 -1
- package/dist/web/assets/{sas-BpBIT2eR.js → sas-CLXO0lZ6.js} +1 -1
- package/dist/web/assets/schedules-settings-section-BOecKJzl.js +1 -0
- package/dist/web/assets/{scss-D1MotuEp.js → scss-DQqteGaG.js} +1 -1
- package/dist/web/assets/send-Bb0jtcR6.js +1 -0
- package/dist/web/assets/{send-to-chat-DJAdlvJ8.js → send-to-chat-S8LCNX7V.js} +1 -1
- package/dist/web/assets/separator-DqGg3f9c.js +1 -0
- package/dist/web/assets/settings-body-DGi5DXY6.js +2 -0
- package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
- package/dist/web/assets/settings-tab-GM9zTRul.js +1 -0
- package/dist/web/assets/settings-window-content-Dvhxo4_H.js +1 -0
- package/dist/web/assets/{shaderlab-BNqmcPQi.js → shaderlab-CeMTqagR.js} +1 -1
- package/dist/web/assets/{shellsession-BBLOVOO-.js → shellsession-BAkquZAV.js} +1 -1
- package/dist/web/assets/{soy-BpTGo9uy.js → soy-Bxm9Ez55.js} +1 -1
- package/dist/web/assets/{sparql-D7A3yKob.js → sparql-C1phwdLc.js} +1 -1
- package/dist/web/assets/sql-query-editor-BmkGFzcL.js +1 -0
- package/dist/web/assets/sqlite-viewer-DbziVQXQ.js +1 -0
- package/dist/web/assets/{stata-B7N56ptS.js → stata-DGNMQdEb.js} +1 -1
- package/dist/web/assets/{surrealql-CTmnD-lv.js → surrealql-ByVrV320.js} +1 -1
- package/dist/web/assets/{svelte-BppwY9TR.js → svelte-CNWjIMhl.js} +1 -1
- package/dist/web/assets/system-monitor-body-CbHW5aYm.js +2 -0
- package/dist/web/assets/system-monitor-tab-C7EZLMIo.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-C_w4w81e.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-BSP1SEXS.js} +1 -1
- package/dist/web/assets/{tab-store-DzYSsw5a.js → tab-store-PZsP5ZwG.js} +1 -1
- package/dist/web/assets/team-member-sheet-C9N0iA1-.js +2 -0
- package/dist/web/assets/team-member-window-content-CM2QFv-s.js +1 -0
- package/dist/web/assets/{templ-CvTMKKra.js → templ-Cf0gQL4I.js} +1 -1
- package/dist/web/assets/{terminal-tab-B9I_HlES.js → terminal-tab-jWYELm8y.js} +3 -3
- package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
- package/dist/web/assets/tool-cards-jefdOWVJ.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
- package/dist/web/assets/{ts-tags--kx7D-Hw.js → ts-tags-B8dN_Yf6.js} +1 -1
- package/dist/web/assets/{twig-UG9uMHGd.js → twig-BgemonbJ.js} +1 -1
- package/dist/web/assets/use-accounts-data-MhMl0Y4Z.js +1 -0
- package/dist/web/assets/{use-blob-url-Bdxopwwc.js → use-blob-url-Gfi69PtP.js} +1 -1
- package/dist/web/assets/use-monaco-theme-BbAd7DXr.js +1 -0
- package/dist/web/assets/{use-open-team-member-D9EOB8-i.js → use-open-team-member-CruUTqzD.js} +1 -1
- package/dist/web/assets/use-remote-desktop-display-choice-DlfMIWq3.js +1 -0
- package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-Bq8X_SUI.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
- package/dist/web/assets/video-preview-BGh3B0Lu.js +1 -0
- package/dist/web/assets/{vue-jjTomlbt.js → vue-D3D4lbXz.js} +1 -1
- package/dist/web/assets/{vue-html-8KEW6-I9.js → vue-html-DYEQFAiK.js} +1 -1
- package/dist/web/assets/{vue-vine-C5tohCkU.js → vue-vine-D0OPNscN.js} +1 -1
- package/dist/web/assets/{window-pip-registry-FdZdGF7h.js → window-pip-registry-BEN0QNSW.js} +1 -1
- package/dist/web/assets/window-store-DGKf9rPG.js +1 -0
- package/dist/web/assets/ws-auth-Dawx17PM.js +1 -0
- package/dist/web/assets/{xml-ByFFosqL.js → xml-DHaWgpya.js} +1 -1
- package/dist/web/assets/{xsl-CZUwiLkj.js → xsl-DVRN8JsA.js} +1 -1
- package/dist/web/index.html +32 -55
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +9 -5
- package/docs/lessons-learned.md +11 -0
- package/package.json +2 -2
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- package/src/providers/codex-app-server/codex-event-mapper.ts +70 -5
- package/src/providers/codex-app-server/codex-history.ts +24 -0
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +39 -2
- package/src/providers/codex-app-server/codex-protocol.ts +24 -0
- package/src/providers/codex-app-server/codex-provider.ts +159 -17
- package/src/providers/codex-app-server/codex-rollout-items.ts +149 -0
- package/src/providers/codex-app-server/codex-skill-parser.ts +63 -0
- package/src/providers/codex-app-server/codex-usage-fetch.ts +22 -20
- package/src/providers/codex-app-server/codex-usage-source.ts +37 -0
- package/src/server/routes/chat.ts +67 -9
- package/src/server/routes/codex-accounts.ts +9 -5
- package/src/server/ws/chat.ts +46 -1
- package/src/services/claude-usage-source.ts +40 -0
- package/src/services/claude-usage.service.ts +77 -146
- package/src/services/codex-account-login.ts +123 -55
- package/src/services/codex-account.service.ts +27 -4
- package/src/services/db.service.ts +161 -20
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-credential-path-guard.ts +35 -8
- package/src/services/fs-path-guard.service.ts +1 -0
- package/src/services/postgres.service.ts +144 -72
- package/src/services/provider-usage/index.ts +63 -0
- package/src/services/provider-usage/register-usage-sources.ts +18 -0
- package/src/services/provider-usage/usage-memory-cache.ts +71 -0
- package/src/services/provider-usage/usage-registry.ts +157 -0
- package/src/services/provider-usage/usage-scheduler.ts +117 -0
- package/src/services/provider-usage/usage-snapshot-store.ts +126 -0
- package/src/services/provider-usage/usage-source.ts +82 -0
- package/src/services/proxy-agent-anthropic-bridge.ts +93 -0
- package/src/services/proxy-agent-bridge.ts +100 -0
- package/src/services/proxy-agent-turn.ts +161 -0
- package/src/services/proxy-anthropic-format.ts +157 -0
- package/src/services/proxy-openai-format.ts +148 -0
- package/src/services/slash-discovery/builtin-commands.ts +13 -0
- package/src/services/slash-discovery/codex-skill-items.ts +57 -0
- package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
- package/src/services/slash-discovery/types.ts +19 -0
- package/src/services/windows-process-tree.ts +351 -351
- package/src/types/chat.ts +7 -1
- package/src/web/app.tsx +1 -7
- package/src/web/components/chat/chat-history-bar.tsx +10 -1
- package/src/web/components/chat/chat-tab.tsx +17 -1
- package/src/web/components/chat/message-input.tsx +11 -4
- package/src/web/components/chat/message-list.tsx +14 -0
- package/src/web/components/chat/slash-command-picker.tsx +22 -3
- package/src/web/components/chat/tool-cards.tsx +47 -4
- package/src/web/components/chat/usage-badge.tsx +59 -426
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/layout/command-palette.tsx +2 -2
- package/src/web/components/layout/mobile-drawer.tsx +5 -4
- package/src/web/components/layout/mobile-nav.tsx +5 -1
- package/src/web/components/layout/nav-section-rail.tsx +2 -1
- package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
- package/src/web/components/layout/sidebar.tsx +0 -2
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
- package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
- package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
- package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
- package/src/web/components/settings/accounts/account-card.tsx +151 -0
- package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
- package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
- package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
- package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
- package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
- package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
- package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
- package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
- package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
- package/src/web/components/settings/accounts/accounts-pane-header.tsx +113 -0
- package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
- package/src/web/components/settings/accounts/claude-accounts-section.tsx +169 -0
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +144 -0
- package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
- package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
- package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
- package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
- package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
- package/src/web/components/settings/ai-settings-section.tsx +14 -4
- package/src/web/components/settings/appearance-settings-section.tsx +125 -0
- package/src/web/components/settings/general-settings-section.tsx +87 -0
- package/src/web/components/settings/jira-watcher-section.tsx +34 -0
- package/src/web/components/settings/notifications-settings-section.tsx +37 -0
- package/src/web/components/settings/open-settings.ts +42 -0
- package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
- package/src/web/components/settings/settings-body.tsx +110 -0
- package/src/web/components/settings/settings-categories.ts +102 -0
- package/src/web/components/settings/settings-category-list.tsx +56 -0
- package/src/web/components/settings/settings-category-rail.tsx +62 -0
- package/src/web/components/settings/settings-section-content.tsx +43 -0
- package/src/web/components/settings/settings-tab.tsx +15 -329
- package/src/web/components/settings/settings-window-content.tsx +24 -0
- package/src/web/hooks/use-chat.ts +38 -1
- package/src/web/hooks/use-global-keybindings.ts +3 -4
- package/src/web/hooks/use-url-sync.ts +30 -0
- package/src/web/hooks/use-usage.ts +23 -11
- package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
- package/src/web/lib/slash-items-cache.ts +27 -7
- package/src/web/stores/panel-utils.ts +11 -0
- package/src/web/stores/settings-store.ts +4 -2
- package/src/web/stores/window-panel-actions.ts +1 -3
- package/src/web/stores/window-panel-persistence.ts +9 -4
- package/dist/web/assets/adaptive-context-menu-BbuRVTLn.js +0 -1
- package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
- package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
- package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
- package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
- package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
- package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
- package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
- package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
- package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
- package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
- package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
- package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
- package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
- package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
- package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
- package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
- package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
- package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
- package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
- package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
- package/dist/web/assets/index-DTqbMiVc.js +0 -52
- package/dist/web/assets/index-SFFv2-VM.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
- package/dist/web/assets/input-D0ol5jW0.js +0 -1
- package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
- package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
- package/dist/web/assets/lock-CNxUGpTk.js +0 -1
- package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
- package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
- package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
- package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
- package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
- package/dist/web/assets/play-DpEEBJTT.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
- package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
- package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
- package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
- package/dist/web/assets/send-C_sLFt56.js +0 -1
- package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
- package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
- package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
- package/dist/web/assets/shallow-CmPMAPte.js +0 -1
- package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
- package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
- package/dist/web/assets/switch-BmjKoIpR.js +0 -1
- package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
- package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
- package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
- package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
- package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
- package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
- package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
- package/dist/web/assets/upload-BNlX8D07.js +0 -1
- package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
- package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
- package/dist/web/assets/window-store-D0x_fxr0.js +0 -1
- package/src/web/components/chat/account-dialogs.tsx +0 -384
- package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
- package/src/web/components/settings/codex-accounts-section.tsx +0 -198
- package/src/web/components/settings/telegram-settings-section.tsx +0 -113
- /package/dist/web/assets/{abap-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
- /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
- /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
- /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
- /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
- /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
- /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
- /package/dist/web/assets/{applescript-CD-Cw8bt.js → applescript-Dx6GGbay.js} +0 -0
- /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
- /package/dist/web/assets/{ara-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
- /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
- /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
- /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
- /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
- /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
- /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
- /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
- /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
- /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
- /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
- /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
- /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
- /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
- /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
- /package/dist/web/assets/{cadence-BFcD-LyM.js → cadence-CvgF6ehN.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
- /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
- /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
- /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
- /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
- /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
- /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
- /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
- /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
- /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
- /package/dist/web/assets/{csv-DViLbHxI.js → csv-Bh9_WD_h.js} +0 -0
- /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
- /package/dist/web/assets/{cue-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
- /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
- /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
- /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
- /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
- /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
- /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
- /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
- /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
- /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
- /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
- /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
- /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
- /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
- /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
- /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
- /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
- /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
- /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
- /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
- /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
- /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
- /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
- /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
- /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
- /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
- /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
- /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
- /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
- /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
- /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
- /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
- /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
- /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
- /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
- /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
- /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
- /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
- /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
- /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
- /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
- /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
- /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
- /package/dist/web/assets/{hy-DcsmE-Nm.js → hy-XzuL55dw.js} +0 -0
- /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
- /package/dist/web/assets/{imba-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
- /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
- /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
- /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
- /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
- /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
- /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
- /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
- /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
- /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
- /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
- /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
- /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
- /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
- /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
- /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
- /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
- /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
- /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
- /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
- /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
- /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
- /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
- /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
- /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
- /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
- /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
- /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
- /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
- /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
- /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
- /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
- /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
- /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
- /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
- /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
- /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
- /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
- /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
- /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
- /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
- /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
- /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
- /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
- /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
- /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
- /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
- /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
- /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
- /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
- /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
- /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
- /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
- /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
- /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
- /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
- /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
- /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
- /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
- /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
- /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
- /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
- /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
- /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
- /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
- /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
- /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
- /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
- /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
- /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
- /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
- /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
- /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
- /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
- /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
- /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
- /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
- /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
- /package/dist/web/assets/{rel-CR6WJDRD.js → rel-bNsb1-3L.js} +0 -0
- /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
- /package/dist/web/assets/{riscv-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
- /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
- /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
- /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
- /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
- /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
- /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
- /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
- /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
- /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
- /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
- /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
- /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
- /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
- /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
- /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
- /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
- /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
- /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
- /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
- /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
- /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
- /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
- /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
- /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
- /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
- /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
- /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
- /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
- /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
- /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
- /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
- /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
- /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
- /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
- /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
- /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
- /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
- /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
- /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
- /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
- /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
- /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
- /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
- /package/dist/web/assets/{vb-C7DGSldd.js → vb-DxI86znh.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
- /package/dist/web/assets/{verilog-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
- /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
- /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
- /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
- /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
- /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
- /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
- /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
- /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
- /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
- /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
- /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
- /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
- /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
- /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
- /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
- /package/dist/web/assets/{zig-9x4qXYLg.js → zig-F0vvImTJ.js} +0 -0
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
1
|
+
/**
|
|
2
|
+
* The chat header's usage chip and the panel it opens.
|
|
3
|
+
*
|
|
4
|
+
* Display only. Adding, removing, enabling, exporting and rotating accounts all live in
|
|
5
|
+
* Settings → Accounts; this panel links there instead of carrying its own copy of those
|
|
6
|
+
* controls, which is what let the two drift apart. The account cards are the same component
|
|
7
|
+
* the Settings pane renders — passing no action callbacks is what makes them read-only, so
|
|
8
|
+
* there is one card implementation rather than a display twin.
|
|
9
|
+
*
|
|
10
|
+
* Accounts sit in a row that scrolls sideways, not a vertical stack: this panel exists to
|
|
11
|
+
* compare them, and stacked in a 350px strip that meant scrolling past one account to see
|
|
12
|
+
* the next. Fullscreen lays the same cards out as a grid when there are too many to fit.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { useState } from "react";
|
|
16
|
+
import { Activity, ExternalLink, Maximize2, Minimize2, RefreshCw, X } from "lucide-react";
|
|
17
|
+
import type { UsageInfo } from "../../../types/chat";
|
|
18
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
19
|
+
import { AccountCard } from "@/components/settings/accounts/account-card";
|
|
20
|
+
import { AccountBucketRow } from "@/components/settings/accounts/account-bucket-row";
|
|
21
|
+
import { useAccountsData } from "@/components/settings/accounts/use-accounts-data";
|
|
22
|
+
import { formatLastUpdated, pctColor } from "@/components/settings/accounts/account-usage-format";
|
|
18
23
|
|
|
19
24
|
interface UsageBadgeProps {
|
|
20
25
|
usage: UsageInfo;
|
|
@@ -22,18 +27,6 @@ interface UsageBadgeProps {
|
|
|
22
27
|
onClick?: () => void;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
function pctColor(pct: number): string {
|
|
26
|
-
if (pct >= 90) return "text-error";
|
|
27
|
-
if (pct >= 70) return "text-warning";
|
|
28
|
-
return "text-success";
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function barColor(pct: number): string {
|
|
32
|
-
if (pct >= 90) return "bg-error";
|
|
33
|
-
if (pct >= 70) return "bg-warning";
|
|
34
|
-
return "bg-success";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
30
|
export function UsageBadge({ usage, loading, onClick }: UsageBadgeProps) {
|
|
38
31
|
const fiveHourPct = usage.fiveHour != null ? Math.round(usage.fiveHour * 100) : null;
|
|
39
32
|
const sevenDayPct = usage.sevenDay != null ? Math.round(usage.sevenDay * 100) : null;
|
|
@@ -69,350 +62,63 @@ interface UsageDetailPanelProps {
|
|
|
69
62
|
lastFetchedAt?: string | null;
|
|
70
63
|
}
|
|
71
64
|
|
|
72
|
-
function formatResetTime(bucket?: LimitBucket): string | null {
|
|
73
|
-
if (!bucket) return null;
|
|
74
|
-
let totalMins: number | null = null;
|
|
75
|
-
if (bucket.resetsInMinutes != null) {
|
|
76
|
-
totalMins = bucket.resetsInMinutes;
|
|
77
|
-
} else if (bucket.resetsInHours != null) {
|
|
78
|
-
totalMins = Math.round(bucket.resetsInHours * 60);
|
|
79
|
-
} else if (bucket.resetsAt) {
|
|
80
|
-
const diff = new Date(bucket.resetsAt).getTime() - Date.now();
|
|
81
|
-
totalMins = diff > 0 ? Math.ceil(diff / 60_000) : 0;
|
|
82
|
-
}
|
|
83
|
-
if (totalMins == null) return null;
|
|
84
|
-
if (totalMins <= 0) return "now";
|
|
85
|
-
const d = Math.floor(totalMins / 1440);
|
|
86
|
-
const h = Math.floor((totalMins % 1440) / 60);
|
|
87
|
-
const m = totalMins % 60;
|
|
88
|
-
if (d > 0) return m > 0 ? `${d}d ${h}h ${m}m` : h > 0 ? `${d}d ${h}h` : `${d}d`;
|
|
89
|
-
if (h > 0) return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
90
|
-
return `${m}m`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function BucketRow({ label, bucket }: { label: string; bucket?: LimitBucket }) {
|
|
94
|
-
if (!bucket) return null;
|
|
95
|
-
const pct = Math.round(bucket.utilization * 100);
|
|
96
|
-
const reset = formatResetTime(bucket);
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<div className="space-y-1">
|
|
100
|
-
<div className="flex items-center justify-between">
|
|
101
|
-
<span className="text-xs font-medium text-text-primary">{label}</span>
|
|
102
|
-
{reset && (
|
|
103
|
-
<span className="text-[10px] text-text-subtle" title="Resets in">↻ {reset}</span>
|
|
104
|
-
)}
|
|
105
|
-
</div>
|
|
106
|
-
<div className="flex items-center gap-2">
|
|
107
|
-
<div className="flex-1 h-2 rounded-full bg-border overflow-hidden">
|
|
108
|
-
<div
|
|
109
|
-
className={`h-full rounded-full transition-all ${barColor(pct)}`}
|
|
110
|
-
style={{ width: `${Math.min(pct, 100)}%` }}
|
|
111
|
-
/>
|
|
112
|
-
</div>
|
|
113
|
-
<span className={`text-xs font-medium tabular-nums w-10 text-right ${pctColor(pct)}`}>
|
|
114
|
-
{pct}%
|
|
115
|
-
</span>
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function formatExpiry(expiresAt: number): string {
|
|
122
|
-
const diff = expiresAt - Date.now();
|
|
123
|
-
if (diff <= 0) return "expired";
|
|
124
|
-
const mins = Math.ceil(diff / 60_000);
|
|
125
|
-
const h = Math.floor(mins / 60);
|
|
126
|
-
const d = Math.floor(h / 24);
|
|
127
|
-
if (d > 0) return `${d}d ${h % 24}h`;
|
|
128
|
-
if (h > 0) return `${h}h ${mins % 60}m`;
|
|
129
|
-
return `${mins}m`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** Derive a human-readable token status from account info */
|
|
133
|
-
function tokenStatus(info?: AccountInfo): { label: string; tip: string; color: string } {
|
|
134
|
-
if (!info) return { label: "unknown", tip: "No account info available", color: "text-text-subtle" };
|
|
135
|
-
if (!info.expiresAt) return { label: "key", tip: "API key (no expiry)", color: "text-text-subtle" };
|
|
136
|
-
const expired = info.expiresAt * 1000 < Date.now(); // expiresAt is seconds
|
|
137
|
-
if (expired && info.hasRefreshToken) return { label: "expired", tip: "Token expired but has refresh token — will auto-renew", color: "text-warning" };
|
|
138
|
-
if (expired) return { label: "expired", tip: "Token expired, no refresh token", color: "text-error" };
|
|
139
|
-
if (info.hasRefreshToken) return { label: "long-lived", tip: "OAuth token with refresh — long-lived", color: "text-success" };
|
|
140
|
-
return { label: "temp", tip: "Temporary token without refresh — will expire", color: "text-warning" };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function formatLastUpdated(ts: number | null | undefined): string | null {
|
|
144
|
-
if (!ts) return null;
|
|
145
|
-
const secs = Math.round((Date.now() - ts) / 1000);
|
|
146
|
-
if (secs < 5) return "just now";
|
|
147
|
-
if (secs < 60) return `${secs}s ago`;
|
|
148
|
-
const mins = Math.floor(secs / 60);
|
|
149
|
-
if (mins < 60) return `${mins}m ago`;
|
|
150
|
-
const hrs = Math.floor(mins / 60);
|
|
151
|
-
const remainMins = mins % 60;
|
|
152
|
-
if (hrs < 24) return remainMins > 0 ? `${hrs}h ${remainMins}m ago` : `${hrs}h ago`;
|
|
153
|
-
const days = Math.floor(hrs / 24);
|
|
154
|
-
return `${days}d ago`;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function AccountUsageCard({ entry, isActive, accountInfo, onToggle, toggling, onDelete, onExport, onViewProfile, flash, fullscreen }: {
|
|
158
|
-
entry: AccountUsageEntry;
|
|
159
|
-
isActive: boolean;
|
|
160
|
-
accountInfo?: AccountInfo;
|
|
161
|
-
onToggle?: (id: string, status: string) => void;
|
|
162
|
-
toggling?: boolean;
|
|
163
|
-
onDelete?: (id: string, display: string) => void;
|
|
164
|
-
onExport?: (id: string) => void;
|
|
165
|
-
onViewProfile?: (profile: OAuthProfileData, accountId: string) => void;
|
|
166
|
-
flash?: boolean;
|
|
167
|
-
fullscreen?: boolean;
|
|
168
|
-
}) {
|
|
169
|
-
const { usage } = entry;
|
|
170
|
-
const hasBuckets = usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet;
|
|
171
|
-
const status = accountInfo?.status ?? entry.accountStatus;
|
|
172
|
-
// Expired: has expiresAt in the past AND no refresh token to auto-renew
|
|
173
|
-
const isExpired = !!(accountInfo && !accountInfo.hasRefreshToken && accountInfo.expiresAt && accountInfo.expiresAt < Math.floor(Date.now() / 1000));
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<div className={`rounded-md border p-2 transition-colors duration-500 ${fullscreen ? "flex flex-col gap-1.5 overflow-hidden" : "space-y-1.5 min-w-[200px] shrink-0 snap-start"} ${isExpired ? "opacity-50" : ""} ${flash ? "bg-primary/10 border-primary/40" : ""} ${isActive ? "border-primary/30 bg-primary/5" : "border-border/50"}`}>
|
|
177
|
-
<div className="flex items-center gap-1.5">
|
|
178
|
-
<span className="text-xs font-medium truncate flex-1 min-w-0">
|
|
179
|
-
{entry.accountLabel ?? entry.accountId.slice(0, 8)}
|
|
180
|
-
</span>
|
|
181
|
-
{isExpired && (
|
|
182
|
-
<span className="text-[9px] text-error shrink-0 font-medium">Expired</span>
|
|
183
|
-
)}
|
|
184
|
-
{!entry.isOAuth && !isExpired && (
|
|
185
|
-
<span className="text-[9px] text-text-subtle shrink-0">API key</span>
|
|
186
|
-
)}
|
|
187
|
-
{/* Account controls */}
|
|
188
|
-
<div className="flex items-center gap-0.5 shrink-0">
|
|
189
|
-
{!isExpired && onViewProfile && accountInfo?.profileData && (
|
|
190
|
-
<button
|
|
191
|
-
className="p-1 rounded cursor-pointer text-text-subtle hover:text-foreground hover:bg-surface-elevated transition-colors"
|
|
192
|
-
onClick={() => onViewProfile(accountInfo.profileData!, entry.accountId)}
|
|
193
|
-
title="View profile"
|
|
194
|
-
>
|
|
195
|
-
<Eye className="size-3" />
|
|
196
|
-
</button>
|
|
197
|
-
)}
|
|
198
|
-
{!isExpired && onExport && entry.isOAuth && (
|
|
199
|
-
<button
|
|
200
|
-
className="p-1 rounded cursor-pointer text-text-subtle hover:text-primary hover:bg-surface-elevated transition-colors"
|
|
201
|
-
onClick={() => onExport(entry.accountId)}
|
|
202
|
-
title="Export this account"
|
|
203
|
-
>
|
|
204
|
-
<Download className="size-3" />
|
|
205
|
-
</button>
|
|
206
|
-
)}
|
|
207
|
-
{!isExpired && onToggle && (
|
|
208
|
-
<Switch
|
|
209
|
-
checked={status !== "disabled"}
|
|
210
|
-
onCheckedChange={() => onToggle(entry.accountId, status)}
|
|
211
|
-
disabled={toggling || status === "cooldown"}
|
|
212
|
-
className="scale-[0.6] cursor-pointer"
|
|
213
|
-
/>
|
|
214
|
-
)}
|
|
215
|
-
{onDelete && (
|
|
216
|
-
<button
|
|
217
|
-
className="p-1 rounded cursor-pointer text-text-subtle hover:text-error hover:bg-surface-elevated transition-colors"
|
|
218
|
-
onClick={() => onDelete(entry.accountId, entry.accountLabel ?? entry.accountId.slice(0, 8))}
|
|
219
|
-
title="Remove account"
|
|
220
|
-
>
|
|
221
|
-
<Trash2 className="size-3" />
|
|
222
|
-
</button>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
{hasBuckets ? (
|
|
227
|
-
<div className={fullscreen ? "flex-1 flex flex-col justify-evenly min-h-0" : "space-y-1.5"}>
|
|
228
|
-
<BucketRow label="5-Hour Session" bucket={usage.session} />
|
|
229
|
-
<BucketRow label="Weekly" bucket={usage.weekly} />
|
|
230
|
-
<BucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
|
|
231
|
-
<BucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
|
|
232
|
-
</div>
|
|
233
|
-
) : (
|
|
234
|
-
<p className="text-[10px] text-text-subtle">
|
|
235
|
-
{entry.isOAuth ? "No usage data yet" : "Usage tracking not available for API keys"}
|
|
236
|
-
</p>
|
|
237
|
-
)}
|
|
238
|
-
{/* Footer: updated · expires · type */}
|
|
239
|
-
{(() => {
|
|
240
|
-
const ts = tokenStatus(accountInfo);
|
|
241
|
-
return (
|
|
242
|
-
<div className="flex items-center gap-1.5 text-[9px] text-text-subtle flex-wrap">
|
|
243
|
-
{usage.lastFetchedAt && (
|
|
244
|
-
<span title="Last usage data update">↻ {formatLastUpdated(new Date(usage.lastFetchedAt).getTime())}</span>
|
|
245
|
-
)}
|
|
246
|
-
{accountInfo?.expiresAt && accountInfo.expiresAt * 1000 > Date.now() && (
|
|
247
|
-
<span title="Token expires in">⏱ {formatExpiry(accountInfo.expiresAt * 1000)}</span>
|
|
248
|
-
)}
|
|
249
|
-
<span className={ts.color} title={ts.tip}>© {ts.label}</span>
|
|
250
|
-
</div>
|
|
251
|
-
);
|
|
252
|
-
})()}
|
|
253
|
-
</div>
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
65
|
export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, lastFetchedAt }: UsageDetailPanelProps) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
const [initialLoading, setInitialLoading] = useState(true);
|
|
262
|
-
const [refreshing, setRefreshing] = useState(false);
|
|
263
|
-
const [flashIds, setFlashIds] = useState<Set<string>>(new Set());
|
|
264
|
-
const [profileView, setProfileView] = useState<{ profile: OAuthProfileData; accountId: string } | null>(null);
|
|
265
|
-
const [showAddDialog, setShowAddDialog] = useState(false);
|
|
266
|
-
const [showExportDialog, setShowExportDialog] = useState(false);
|
|
267
|
-
const [showImportDialog, setShowImportDialog] = useState(false);
|
|
268
|
-
const [showRotationSettings, setShowRotationSettings] = useState(false);
|
|
269
|
-
const [deleteTarget, setDeleteTarget] = useState<{ id: string; display: string } | null>(null);
|
|
270
|
-
const [exportPreselect, setExportPreselect] = useState<string | null>(null);
|
|
66
|
+
// Fetching is gated on visibility: the panel is collapsed most of the time, and its
|
|
67
|
+
// usage endpoint is the expensive one.
|
|
68
|
+
const { usages, accounts, activeAccountId, initialLoading, refreshing, flashIds, reload } = useAccountsData(visible);
|
|
271
69
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
272
|
-
const [message, setMessage] = useState<string | null>(null);
|
|
273
|
-
const [togglingId, setTogglingId] = useState<string | null>(null);
|
|
274
|
-
const msgTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
275
|
-
const prevUsagesRef = useRef<AccountUsageEntry[]>([]);
|
|
276
|
-
|
|
277
|
-
function showMessage(msg: string) {
|
|
278
|
-
if (msgTimer.current) clearTimeout(msgTimer.current);
|
|
279
|
-
setMessage(msg);
|
|
280
|
-
msgTimer.current = setTimeout(() => setMessage(null), 4000);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function handleSuccess(msg?: string) {
|
|
284
|
-
loadAll();
|
|
285
|
-
if (msg) showMessage(msg);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
async function loadAll() {
|
|
289
|
-
const isRefresh = allUsages.length > 0;
|
|
290
|
-
if (isRefresh) setRefreshing(true); else setInitialLoading(true);
|
|
291
|
-
|
|
292
|
-
const [usages, accs, active] = await Promise.allSettled([
|
|
293
|
-
getAllAccountUsages(), getAccounts(), getActiveAccount(),
|
|
294
|
-
]);
|
|
295
|
-
|
|
296
|
-
if (usages.status === "fulfilled") {
|
|
297
|
-
const newUsages = usages.value;
|
|
298
|
-
// Detect which accounts changed usage values
|
|
299
|
-
if (isRefresh && prevUsagesRef.current.length > 0) {
|
|
300
|
-
const changed = new Set<string>();
|
|
301
|
-
const prevMap = new Map(prevUsagesRef.current.map(u => [u.accountId, u]));
|
|
302
|
-
for (const nu of newUsages) {
|
|
303
|
-
const prev = prevMap.get(nu.accountId);
|
|
304
|
-
if (!prev) { changed.add(nu.accountId); continue; }
|
|
305
|
-
const pu = prev.usage, cu = nu.usage;
|
|
306
|
-
if (pu.session?.utilization !== cu.session?.utilization
|
|
307
|
-
|| pu.weekly?.utilization !== cu.weekly?.utilization
|
|
308
|
-
|| pu.weeklyOpus?.utilization !== cu.weeklyOpus?.utilization
|
|
309
|
-
|| pu.weeklySonnet?.utilization !== cu.weeklySonnet?.utilization) {
|
|
310
|
-
changed.add(nu.accountId);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
if (changed.size > 0) {
|
|
314
|
-
setFlashIds(changed);
|
|
315
|
-
setTimeout(() => setFlashIds(new Set()), 1500);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
prevUsagesRef.current = newUsages;
|
|
319
|
-
setAllUsages(newUsages);
|
|
320
|
-
}
|
|
321
|
-
if (accs.status === "fulfilled") setAccounts(accs.value);
|
|
322
|
-
if (active.status === "fulfilled") setActiveAccountId(active.value?.id ?? null);
|
|
323
|
-
setInitialLoading(false);
|
|
324
|
-
setRefreshing(false);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
useEffect(() => {
|
|
328
|
-
if (!visible) return;
|
|
329
|
-
loadAll();
|
|
330
|
-
}, [visible]);
|
|
331
|
-
|
|
332
|
-
// Re-fetch account usages after parent refreshes from Anthropic API
|
|
333
|
-
useEffect(() => {
|
|
334
|
-
if (!visible || !lastFetchedAt) return;
|
|
335
|
-
loadAll();
|
|
336
|
-
}, [lastFetchedAt]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
337
70
|
|
|
338
71
|
if (!visible) return null;
|
|
339
72
|
|
|
340
73
|
const accountMap = new Map(accounts.map((a) => [a.id, a]));
|
|
341
74
|
const hasCost = usage.queryCostUsd != null || usage.totalCostUsd != null;
|
|
342
|
-
const
|
|
75
|
+
const hasPerAccountUsage = usages.length > 0;
|
|
343
76
|
|
|
344
|
-
//
|
|
345
|
-
const fsCount =
|
|
77
|
+
// Roughly square, so the cards fill the viewport instead of leaving a long empty column.
|
|
78
|
+
const fsCount = usages.length || 1;
|
|
346
79
|
const fsCols = Math.ceil(Math.sqrt(fsCount));
|
|
347
80
|
const fsRows = Math.ceil(fsCount / fsCols);
|
|
348
81
|
|
|
349
|
-
async function handleToggle(id: string, status: string) {
|
|
350
|
-
// Enabling a parked account proves its token server-side first, which is a network
|
|
351
|
-
// round trip that can come back 400 — and patchAccount throws on that. Without the
|
|
352
|
-
// catch the message the server takes care to write reaches nobody: unhandled
|
|
353
|
-
// rejection, no toast, no reload, and the Switch silently snaps back. The pending
|
|
354
|
-
// flag is because that round trip can take most of a minute in the worst case.
|
|
355
|
-
setTogglingId(id);
|
|
356
|
-
try {
|
|
357
|
-
await patchAccount(id, { status: status === "disabled" ? "active" : "disabled" });
|
|
358
|
-
} catch (e) {
|
|
359
|
-
showMessage((e as Error).message);
|
|
360
|
-
}
|
|
361
|
-
setTogglingId(null);
|
|
362
|
-
loadAll();
|
|
363
|
-
onReload?.();
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
async function confirmDeleteAccount() {
|
|
367
|
-
if (!deleteTarget) return;
|
|
368
|
-
try {
|
|
369
|
-
await deleteAccount(deleteTarget.id);
|
|
370
|
-
showMessage(`Account "${deleteTarget.display}" removed.`);
|
|
371
|
-
loadAll();
|
|
372
|
-
onReload?.();
|
|
373
|
-
} catch (e) {
|
|
374
|
-
showMessage(`Failed to remove: ${(e as Error).message}`);
|
|
375
|
-
}
|
|
376
|
-
setDeleteTarget(null);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function openExportAll() {
|
|
380
|
-
setExportPreselect(null);
|
|
381
|
-
setShowExportDialog(true);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
82
|
return (
|
|
385
|
-
<div
|
|
83
|
+
<div
|
|
84
|
+
className={`relative border-b border-border bg-surface px-3 py-2.5 ${
|
|
85
|
+
isFullscreen
|
|
86
|
+
? "fixed inset-0 z-50 flex flex-col gap-2.5 overflow-hidden"
|
|
87
|
+
: "space-y-2.5 max-h-[350px] overflow-y-auto"
|
|
88
|
+
}`}
|
|
89
|
+
>
|
|
386
90
|
<div className="flex items-center justify-between shrink-0">
|
|
387
91
|
<div className="flex items-center gap-2">
|
|
388
|
-
<span className="text-xs font-semibold text-text-primary">Usage
|
|
92
|
+
<span className="text-xs font-semibold text-text-primary">Usage</span>
|
|
389
93
|
{lastFetchedAt && (
|
|
390
94
|
<span className="text-[10px] text-text-subtle">{formatLastUpdated(new Date(lastFetchedAt).getTime())}</span>
|
|
391
95
|
)}
|
|
392
96
|
</div>
|
|
393
97
|
<div className="flex items-center gap-1">
|
|
394
98
|
<button
|
|
395
|
-
onClick={() =>
|
|
396
|
-
className="text-
|
|
397
|
-
title="
|
|
99
|
+
onClick={() => openSettings("accounts")}
|
|
100
|
+
className="flex items-center gap-1 text-[10px] text-text-subtle hover:text-text-primary px-1 cursor-pointer"
|
|
101
|
+
title="Add, remove or rotate accounts"
|
|
398
102
|
>
|
|
399
|
-
<
|
|
103
|
+
Manage accounts <ExternalLink className="size-3" />
|
|
400
104
|
</button>
|
|
401
|
-
{
|
|
105
|
+
{hasPerAccountUsage && (
|
|
402
106
|
<button
|
|
403
107
|
onClick={() => setIsFullscreen((v) => !v)}
|
|
404
108
|
className="text-xs text-text-subtle hover:text-text-primary px-1 cursor-pointer"
|
|
405
109
|
title={isFullscreen ? "Exit fullscreen" : "Fullscreen view"}
|
|
110
|
+
aria-label={isFullscreen ? "Exit fullscreen" : "Fullscreen view"}
|
|
406
111
|
>
|
|
407
112
|
{isFullscreen ? <Minimize2 className="size-3" /> : <Maximize2 className="size-3" />}
|
|
408
113
|
</button>
|
|
409
114
|
)}
|
|
410
115
|
{onReload && (
|
|
411
116
|
<button
|
|
412
|
-
onClick={() => { onReload();
|
|
117
|
+
onClick={() => { onReload(); void reload(); }}
|
|
413
118
|
disabled={loading || refreshing}
|
|
414
119
|
className="text-xs text-text-subtle hover:text-text-primary px-1 disabled:opacity-50 cursor-pointer"
|
|
415
120
|
title="Refresh"
|
|
121
|
+
aria-label="Refresh usage"
|
|
416
122
|
>
|
|
417
123
|
<RefreshCw className={`size-3 ${(loading || refreshing) ? "animate-spin" : ""}`} />
|
|
418
124
|
</button>
|
|
@@ -420,24 +126,19 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
420
126
|
<button
|
|
421
127
|
onClick={() => { setIsFullscreen(false); onClose(); }}
|
|
422
128
|
className="text-xs text-text-subtle hover:text-text-primary px-1 cursor-pointer"
|
|
129
|
+
aria-label="Close usage panel"
|
|
423
130
|
>
|
|
424
131
|
<X className="size-3" />
|
|
425
132
|
</button>
|
|
426
133
|
</div>
|
|
427
134
|
</div>
|
|
428
135
|
|
|
429
|
-
{
|
|
430
|
-
<div className="text-[11px] p-1.5 rounded bg-success/10 text-success text-center animate-in fade-in duration-200">
|
|
431
|
-
{message}
|
|
432
|
-
</div>
|
|
433
|
-
)}
|
|
434
|
-
|
|
435
|
-
{(hasMultipleAccounts || initialLoading) ? (
|
|
136
|
+
{hasPerAccountUsage || initialLoading ? (
|
|
436
137
|
<div
|
|
437
138
|
className={isFullscreen
|
|
438
139
|
? "flex-1 min-h-0 grid gap-2 overflow-hidden"
|
|
439
|
-
|
|
440
|
-
|
|
140
|
+
// Same classes as AccountCardRow, with the panel's wider padding to clear.
|
|
141
|
+
: "flex gap-2 overflow-x-auto pb-1 -mx-3 px-3 snap-x snap-mandatory scrollbar-thin"}
|
|
441
142
|
style={isFullscreen ? {
|
|
442
143
|
gridTemplateColumns: `repeat(${fsCols}, minmax(0, 1fr))`,
|
|
443
144
|
gridTemplateRows: `repeat(${fsRows}, minmax(0, 1fr))`,
|
|
@@ -446,36 +147,27 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
446
147
|
{initialLoading ? (
|
|
447
148
|
<p className="text-[10px] text-text-subtle">Loading...</p>
|
|
448
149
|
) : (
|
|
449
|
-
|
|
450
|
-
<
|
|
150
|
+
usages.map((entry) => (
|
|
151
|
+
<AccountCard
|
|
451
152
|
key={entry.accountId}
|
|
452
153
|
entry={entry}
|
|
453
154
|
isActive={entry.accountId === (activeAccountId ?? usage.activeAccountId)}
|
|
454
155
|
accountInfo={accountMap.get(entry.accountId)}
|
|
455
|
-
onToggle={handleToggle}
|
|
456
|
-
toggling={togglingId === entry.accountId}
|
|
457
|
-
onDelete={(id, display) => setDeleteTarget({ id, display })}
|
|
458
|
-
onExport={(id) => { setExportPreselect(id); setShowExportDialog(true); }}
|
|
459
|
-
onViewProfile={(profile, accountId) => setProfileView({ profile, accountId })}
|
|
460
156
|
flash={flashIds.has(entry.accountId)}
|
|
461
|
-
|
|
157
|
+
layout={isFullscreen ? "grid" : "strip"}
|
|
462
158
|
/>
|
|
463
159
|
))
|
|
464
160
|
)}
|
|
465
161
|
</div>
|
|
162
|
+
) : usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet ? (
|
|
163
|
+
<div className="space-y-2.5">
|
|
164
|
+
<AccountBucketRow label="5-Hour Session" bucket={usage.session} />
|
|
165
|
+
<AccountBucketRow label="Weekly" bucket={usage.weekly} />
|
|
166
|
+
<AccountBucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
|
|
167
|
+
<AccountBucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
|
|
168
|
+
</div>
|
|
466
169
|
) : (
|
|
467
|
-
|
|
468
|
-
{usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet ? (
|
|
469
|
-
<div className="space-y-2.5">
|
|
470
|
-
<BucketRow label="5-Hour Session" bucket={usage.session} />
|
|
471
|
-
<BucketRow label="Weekly" bucket={usage.weekly} />
|
|
472
|
-
<BucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
|
|
473
|
-
<BucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
|
|
474
|
-
</div>
|
|
475
|
-
) : (
|
|
476
|
-
<p className="text-xs text-text-subtle">No usage data available</p>
|
|
477
|
-
)}
|
|
478
|
-
</>
|
|
170
|
+
<p className="text-xs text-text-subtle">No usage data available</p>
|
|
479
171
|
)}
|
|
480
172
|
|
|
481
173
|
{hasCost && (
|
|
@@ -498,65 +190,6 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
498
190
|
)}
|
|
499
191
|
</div>
|
|
500
192
|
)}
|
|
501
|
-
|
|
502
|
-
{/* Inline profile popup */}
|
|
503
|
-
{profileView && (
|
|
504
|
-
<div className="border-t border-border pt-2">
|
|
505
|
-
<div className="flex items-center justify-between mb-1">
|
|
506
|
-
<span className="text-[10px] font-medium text-text-subtle">Profile</span>
|
|
507
|
-
<button className="text-text-subtle hover:text-foreground cursor-pointer" onClick={() => setProfileView(null)}>
|
|
508
|
-
<X className="size-3" />
|
|
509
|
-
</button>
|
|
510
|
-
</div>
|
|
511
|
-
<div className="grid grid-cols-[70px_1fr] gap-x-2 gap-y-0.5 text-[10px]">
|
|
512
|
-
{profileView.profile.account?.display_name && <><span className="text-text-subtle">Name</span><span>{profileView.profile.account.display_name}</span></>}
|
|
513
|
-
{profileView.profile.account?.email && <><span className="text-text-subtle">Email</span><span>{profileView.profile.account.email}</span></>}
|
|
514
|
-
{profileView.profile.organization?.name && <><span className="text-text-subtle">Org</span><span>{profileView.profile.organization.name}</span></>}
|
|
515
|
-
{profileView.profile.organization?.organization_type && <><span className="text-text-subtle">Type</span><span>{profileView.profile.organization.organization_type}</span></>}
|
|
516
|
-
{profileView.profile.organization?.rate_limit_tier && <><span className="text-text-subtle">Tier</span><span>{profileView.profile.organization.rate_limit_tier}</span></>}
|
|
517
|
-
{profileView.profile.organization?.subscription_status && <><span className="text-text-subtle">Status</span><span>{profileView.profile.organization.subscription_status}</span></>}
|
|
518
|
-
</div>
|
|
519
|
-
<UsagePatternChart accountId={profileView.accountId} />
|
|
520
|
-
</div>
|
|
521
|
-
)}
|
|
522
|
-
|
|
523
|
-
{/* Action buttons */}
|
|
524
|
-
<div className="border-t border-border pt-2 flex gap-1.5 shrink-0">
|
|
525
|
-
<button onClick={() => setShowAddDialog(true)} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
|
|
526
|
-
<Plus className="size-3" /> Add
|
|
527
|
-
</button>
|
|
528
|
-
<button onClick={openExportAll} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
|
|
529
|
-
<Download className="size-3" /> Export
|
|
530
|
-
</button>
|
|
531
|
-
<button onClick={() => setShowImportDialog(true)} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
|
|
532
|
-
<Upload className="size-3" /> Import
|
|
533
|
-
</button>
|
|
534
|
-
</div>
|
|
535
|
-
|
|
536
|
-
{/* Delete confirmation overlay */}
|
|
537
|
-
{deleteTarget && (
|
|
538
|
-
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80 backdrop-blur-sm rounded-md">
|
|
539
|
-
<div className="bg-surface border border-border rounded-lg shadow-lg p-4 mx-4 max-w-[280px] w-full space-y-3">
|
|
540
|
-
<p className="text-xs text-text-primary text-center">
|
|
541
|
-
Remove <strong className="text-foreground">{deleteTarget.display}</strong>?
|
|
542
|
-
</p>
|
|
543
|
-
<div className="flex gap-2">
|
|
544
|
-
<button onClick={() => setDeleteTarget(null)} className="flex-1 px-3 py-1.5 rounded-md text-xs border border-border text-text-secondary hover:bg-surface-hover cursor-pointer transition-colors">
|
|
545
|
-
Cancel
|
|
546
|
-
</button>
|
|
547
|
-
<button onClick={confirmDeleteAccount} className="flex-1 px-3 py-1.5 rounded-md text-xs bg-error text-white hover:bg-error/80 cursor-pointer transition-colors">
|
|
548
|
-
Remove
|
|
549
|
-
</button>
|
|
550
|
-
</div>
|
|
551
|
-
</div>
|
|
552
|
-
</div>
|
|
553
|
-
)}
|
|
554
|
-
|
|
555
|
-
{/* Account dialogs */}
|
|
556
|
-
<AddAccountDialog open={showAddDialog} onOpenChange={setShowAddDialog} onSuccess={handleSuccess} />
|
|
557
|
-
<ExportAccountsDialog open={showExportDialog} onOpenChange={(v) => { setShowExportDialog(v); if (!v) setExportPreselect(null); }} accounts={accounts} preselectId={exportPreselect} onMessage={showMessage} />
|
|
558
|
-
<ImportAccountsDialog open={showImportDialog} onOpenChange={setShowImportDialog} onSuccess={handleSuccess} />
|
|
559
|
-
<AccountRotationSettings open={showRotationSettings} onOpenChange={setShowRotationSettings} />
|
|
560
193
|
</div>
|
|
561
194
|
);
|
|
562
195
|
}
|
|
@@ -23,6 +23,7 @@ export const WINDOW_CONTENT: Record<WindowKind, LazyExoticComponent<ComponentTyp
|
|
|
23
23
|
"system-monitor": lazy(() => import("@/components/system/system-monitor-window-content")),
|
|
24
24
|
"tab-host": lazy(() => import("./tab-host-window-content")),
|
|
25
25
|
"remote-desktop": lazy(() => import("@/components/remote-desktop/remote-desktop-window-content")),
|
|
26
|
+
settings: lazy(() => import("@/components/settings/settings-window-content")),
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
/** Titlebar text for a window. Falls back to the kind's generic name. */
|
|
@@ -35,6 +36,7 @@ export function windowTitle(kind: WindowKind, payload?: Record<string, unknown>)
|
|
|
35
36
|
}
|
|
36
37
|
if (kind === "system-monitor") return "System Monitor";
|
|
37
38
|
if (kind === "remote-desktop") return "Remote Desktop";
|
|
39
|
+
if (kind === "settings") return "Settings";
|
|
38
40
|
// A detached tab carries its title in the payload; the generic name only shows for a
|
|
39
41
|
// window whose tab has not been resolved yet (restore before the layout is loaded).
|
|
40
42
|
if (kind === "tab-host") return "Tab";
|
|
@@ -7,7 +7,7 @@ import type { Rect } from "./window-geometry";
|
|
|
7
7
|
* Single source of truth: the persistence layer filters this list instead of repeating it,
|
|
8
8
|
* so a new kind can never be silently dropped on reload.
|
|
9
9
|
*/
|
|
10
|
-
export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host", "remote-desktop"] as const;
|
|
10
|
+
export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host", "remote-desktop", "settings"] as const;
|
|
11
11
|
|
|
12
12
|
export type WindowKind = (typeof WINDOW_KINDS)[number];
|
|
13
13
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
AppWindow,
|
|
22
22
|
} from "lucide-react";
|
|
23
23
|
import { openExplorer } from "@/components/os-explorer/open-explorer";
|
|
24
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
24
25
|
import { useTabStore, type TabType } from "@/stores/tab-store";
|
|
25
26
|
import { useProjectStore } from "@/stores/project-store";
|
|
26
27
|
import { useSettingsStore } from "@/stores/settings-store";
|
|
@@ -226,8 +227,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
|
|
|
226
227
|
{
|
|
227
228
|
id: "settings", label: "Settings", icon: Settings,
|
|
228
229
|
action: () => {
|
|
229
|
-
|
|
230
|
-
setSidebarActiveTab("settings");
|
|
230
|
+
openSettings();
|
|
231
231
|
onClose();
|
|
232
232
|
},
|
|
233
233
|
keywords: "config preferences theme",
|