@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,12 +1,11 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
2
|
-
import { X, Bug as BugIcon, Cloud, FolderTree, MonitorSmartphone } from "lucide-react";
|
|
2
|
+
import { X, Bug as BugIcon, Cloud, FolderTree, MonitorSmartphone, Settings } from "lucide-react";
|
|
3
3
|
import { useShallow } from "zustand/react/shallow";
|
|
4
4
|
import { useProjectStore } from "@/stores/project-store";
|
|
5
5
|
import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
|
|
6
6
|
import { useExtensionStore } from "@/stores/extension-store";
|
|
7
7
|
import { FileTree } from "@/components/explorer/file-tree";
|
|
8
8
|
import { GitStatusPanel } from "@/components/git/git-status-panel";
|
|
9
|
-
import { SettingsTab } from "@/components/settings/settings-tab";
|
|
10
9
|
import { DatabaseSidebar } from "@/components/database/database-sidebar";
|
|
11
10
|
import { JiraPanel } from "@/components/jira/jira-panel";
|
|
12
11
|
import { AiResourcesPanel } from "@/components/ai-resources/ai-resources-panel";
|
|
@@ -25,6 +24,7 @@ import { isMobileDevice } from "@/hooks/use-is-mobile";
|
|
|
25
24
|
import { openExplorer } from "@/components/os-explorer/open-explorer";
|
|
26
25
|
import { useOpenRemoteDesktop } from "@/components/remote-desktop/open-remote-desktop";
|
|
27
26
|
import { useRemoteDesktopAvailable } from "@/components/remote-desktop/use-remote-desktop-available";
|
|
27
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
28
28
|
import { FeatureBadge } from "@/components/ui/feature-badge";
|
|
29
29
|
import type { FeatureBadgeId } from "@/lib/feature-badges";
|
|
30
30
|
import { cn } from "@/lib/utils";
|
|
@@ -32,7 +32,7 @@ import { cn } from "@/lib/utils";
|
|
|
32
32
|
// Tab ids the mobile drawer can render content for. `search` is desktop-only for now;
|
|
33
33
|
// ext views are supported via the `ext:` prefix.
|
|
34
34
|
const MOBILE_SUPPORTED = new Set<string>([
|
|
35
|
-
"history", "teams", "explorer", "git", "database", "tunnels", "ai-resources", "
|
|
35
|
+
"history", "teams", "explorer", "git", "database", "tunnels", "ai-resources", "jira",
|
|
36
36
|
]);
|
|
37
37
|
const isMobileSupported = (id: SidebarActiveTab) => MOBILE_SUPPORTED.has(id) || id.startsWith("ext:");
|
|
38
38
|
|
|
@@ -148,7 +148,6 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
|
|
|
148
148
|
{activeTab === "tunnels" && <TunnelManagerTab />}
|
|
149
149
|
{activeTab === "jira" && <JiraPanel />}
|
|
150
150
|
{activeTab === "ai-resources" && <AiResourcesPanel />}
|
|
151
|
-
{activeTab === "settings" && <SettingsTab />}
|
|
152
151
|
{activeTab.startsWith("ext:") && <ExtensionTreeView viewId={activeTab.slice(4)} className="h-full" />}
|
|
153
152
|
</div>
|
|
154
153
|
|
|
@@ -171,6 +170,8 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
|
|
|
171
170
|
<FooterTile icon={MonitorSmartphone} label="Remote" badge="remote-desktop" onClick={() => { onClose(); openRemoteDesktop(); }} />
|
|
172
171
|
)}
|
|
173
172
|
<FooterTile icon={Cloud} label="Cloud" onClick={() => setCloudOpen(true)} />
|
|
173
|
+
{/* Also not a sidebar tab — settings open as their own tab here, window on desktop. */}
|
|
174
|
+
<FooterTile icon={Settings} label="Settings" onClick={() => { onClose(); openSettings(); }} />
|
|
174
175
|
<FooterTile icon={BugIcon} label="Bug" onClick={handleReportBug} />
|
|
175
176
|
</div>
|
|
176
177
|
{/* Version / upgrade pinned at the very bottom, under a divider. */}
|
|
@@ -261,7 +261,11 @@ export function MobileNav({ onMenuPress, onProjectsPress }: MobileNavProps) {
|
|
|
261
261
|
<div className="flex items-center h-12">
|
|
262
262
|
{/* Fixed cluster: Menu | Project | Terminal | + */}
|
|
263
263
|
<div className="flex items-center shrink-0 border-r border-border">
|
|
264
|
-
<button
|
|
264
|
+
<button
|
|
265
|
+
onClick={onMenuPress}
|
|
266
|
+
aria-label="Open menu"
|
|
267
|
+
className="flex items-center justify-center size-12 shrink-0 text-text-secondary"
|
|
268
|
+
>
|
|
265
269
|
<Menu className="size-5" />
|
|
266
270
|
</button>
|
|
267
271
|
|
|
@@ -4,6 +4,7 @@ import { Settings, Bug, Cloud, FolderTree, MonitorSmartphone } from "lucide-reac
|
|
|
4
4
|
import { openExplorer } from "@/components/os-explorer/open-explorer";
|
|
5
5
|
import { useOpenRemoteDesktop } from "@/components/remote-desktop/open-remote-desktop";
|
|
6
6
|
import { useRemoteDesktopAvailable } from "@/components/remote-desktop/use-remote-desktop-available";
|
|
7
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
7
8
|
import { FeatureBadge } from "@/components/ui/feature-badge";
|
|
8
9
|
import type { FeatureBadgeId } from "@/lib/feature-badges";
|
|
9
10
|
import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
|
|
@@ -220,7 +221,7 @@ export const NavSectionRail = memo(function NavSectionRail({ className }: { clas
|
|
|
220
221
|
<FooterUtil icon={MonitorSmartphone} label="Remote Desktop" featureBadge="remote-desktop" onClick={openRemoteDesktop} />
|
|
221
222
|
)}
|
|
222
223
|
<FooterUtil icon={Bug} label="Report Bug" onClick={handleReportBug} />
|
|
223
|
-
<FooterUtil icon={Settings} label="Settings"
|
|
224
|
+
<FooterUtil icon={Settings} label="Settings" onClick={() => openSettings()} />
|
|
224
225
|
</div>
|
|
225
226
|
</div>
|
|
226
227
|
);
|
|
@@ -12,6 +12,7 @@ import { formatRelativeDate } from "@/lib/format-date";
|
|
|
12
12
|
import { cn } from "@/lib/utils";
|
|
13
13
|
import { copyToClipboard } from "@/lib/clipboard";
|
|
14
14
|
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
15
|
+
import { openSettings } from "@/components/settings/open-settings";
|
|
15
16
|
|
|
16
17
|
interface ProjectBottomSheetProps {
|
|
17
18
|
isOpen: boolean;
|
|
@@ -96,15 +97,8 @@ export function ProjectBottomSheet({ isOpen, onClose }: ProjectBottomSheetProps)
|
|
|
96
97
|
|
|
97
98
|
function handleSettings() {
|
|
98
99
|
handleClose();
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
window.dispatchEvent(new Event("open-mobile-settings"));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// Desktop: open sidebar settings tab
|
|
105
|
-
const { sidebarCollapsed, toggleSidebar, setSidebarActiveTab } = useSettingsStore.getState();
|
|
106
|
-
if (sidebarCollapsed) toggleSidebar();
|
|
107
|
-
setSidebarActiveTab("settings");
|
|
100
|
+
// No viewport branch here: the hook routes to a window or a tab on its own.
|
|
101
|
+
openSettings();
|
|
108
102
|
}
|
|
109
103
|
|
|
110
104
|
async function handleRename() {
|
|
@@ -5,7 +5,6 @@ import { useProjectStore } from "@/stores/project-store";
|
|
|
5
5
|
import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
|
|
6
6
|
import { FileTree } from "@/components/explorer/file-tree";
|
|
7
7
|
import { GitStatusPanel } from "@/components/git/git-status-panel";
|
|
8
|
-
import { SettingsTab } from "@/components/settings/settings-tab";
|
|
9
8
|
import { DatabaseSidebar } from "@/components/database/database-sidebar";
|
|
10
9
|
import { SearchPanel } from "@/components/explorer/search-panel";
|
|
11
10
|
import { ExtensionTreeView } from "@/components/extensions/extension-tree-view";
|
|
@@ -137,7 +136,6 @@ export const Sidebar = memo(function Sidebar() {
|
|
|
137
136
|
{sidebarActiveTab === "tunnels" && <TunnelManagerTab />}
|
|
138
137
|
{sidebarActiveTab === "jira" && <JiraPanel />}
|
|
139
138
|
{sidebarActiveTab === "ai-resources" && <AiResourcesPanel />}
|
|
140
|
-
{sidebarActiveTab === "settings" && <SettingsTab />}
|
|
141
139
|
{typeof sidebarActiveTab === "string" && sidebarActiveTab.startsWith("ext:") && (
|
|
142
140
|
<ExtensionTreeView viewId={sidebarActiveTab.slice(4)} className="h-full" />
|
|
143
141
|
)}
|
|
@@ -15,6 +15,7 @@ import { isDocumentPipSupported } from "@/components/floating-window/pip/pip-sup
|
|
|
15
15
|
import { ContextMenuItem, ContextMenuSeparator } from "@/components/ui/context-menu";
|
|
16
16
|
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
17
17
|
import { usePanelStore } from "@/stores/panel-store";
|
|
18
|
+
import { NON_POPPABLE_TAB_TYPES } from "@/stores/panel-utils";
|
|
18
19
|
import type { Tab } from "@/stores/tab-store";
|
|
19
20
|
|
|
20
21
|
interface TabPopOutMenuItemProps {
|
|
@@ -25,9 +26,9 @@ interface TabPopOutMenuItemProps {
|
|
|
25
26
|
|
|
26
27
|
export function TabPopOutMenuItem({ tab, panelId }: TabPopOutMenuItemProps) {
|
|
27
28
|
const isMobile = useIsMobile();
|
|
28
|
-
//
|
|
29
|
+
// Some tabs already have a window kind of their own; detaching one would open a second,
|
|
29
30
|
// duplicate presentation of the same data.
|
|
30
|
-
if (isMobile || tab.type
|
|
31
|
+
if (isMobile || NON_POPPABLE_TAB_TYPES.has(tab.type)) return null;
|
|
31
32
|
|
|
32
33
|
return (
|
|
33
34
|
<>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Input } from "@/components/ui/input";
|
|
5
|
+
import { Label } from "@/components/ui/label";
|
|
6
|
+
import { Loader2 } from "lucide-react";
|
|
7
|
+
import { addAccount, getOAuthUrl, exchangeOAuthCode } from "../../../lib/api-settings";
|
|
8
|
+
|
|
9
|
+
// ── Add Account Dialog ─────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
interface AddAccountDialogProps {
|
|
12
|
+
open: boolean;
|
|
13
|
+
onOpenChange: (open: boolean) => void;
|
|
14
|
+
onSuccess: (msg?: string) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function AddAccountDialog({ open, onOpenChange, onSuccess }: AddAccountDialogProps) {
|
|
18
|
+
const [newToken, setNewToken] = useState("");
|
|
19
|
+
const [newLabel, setNewLabel] = useState("");
|
|
20
|
+
const [adding, setAdding] = useState(false);
|
|
21
|
+
const [addError, setAddError] = useState<string | null>(null);
|
|
22
|
+
const [oauthState, setOauthState] = useState<string | null>(null);
|
|
23
|
+
const [oauthCode, setOauthCode] = useState("");
|
|
24
|
+
const [oauthLoading, setOauthLoading] = useState(false);
|
|
25
|
+
const [oauthStep, setOauthStep] = useState<"idle" | "waiting">("idle");
|
|
26
|
+
|
|
27
|
+
function resetOAuth() {
|
|
28
|
+
setOauthState(null);
|
|
29
|
+
setOauthCode("");
|
|
30
|
+
setOauthStep("idle");
|
|
31
|
+
setAddError(null);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function handleClose() {
|
|
35
|
+
onOpenChange(false);
|
|
36
|
+
resetOAuth();
|
|
37
|
+
setNewToken("");
|
|
38
|
+
setNewLabel("");
|
|
39
|
+
setAddError(null);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function handleOAuthLogin() {
|
|
43
|
+
setOauthLoading(true);
|
|
44
|
+
setAddError(null);
|
|
45
|
+
try {
|
|
46
|
+
const { url, state } = await getOAuthUrl();
|
|
47
|
+
setOauthState(state);
|
|
48
|
+
setOauthStep("waiting");
|
|
49
|
+
window.open(url, "_blank");
|
|
50
|
+
} catch (e) {
|
|
51
|
+
setAddError((e as Error).message);
|
|
52
|
+
}
|
|
53
|
+
setOauthLoading(false);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function handleOAuthExchange() {
|
|
57
|
+
if (!oauthCode.trim() || !oauthState) return;
|
|
58
|
+
setOauthLoading(true);
|
|
59
|
+
setAddError(null);
|
|
60
|
+
try {
|
|
61
|
+
let code = oauthCode.trim();
|
|
62
|
+
if (code.includes("#")) code = code.split("#")[0] ?? code;
|
|
63
|
+
const acc = await exchangeOAuthCode(code, oauthState);
|
|
64
|
+
handleClose();
|
|
65
|
+
// Signing in again on an account this machine parked carries the token in but
|
|
66
|
+
// deliberately leaves it out of the rotation. A flat success over a toggle that is
|
|
67
|
+
// still off reads as a bug, and this is the only place the user finds out otherwise.
|
|
68
|
+
onSuccess(acc?.status === "disabled"
|
|
69
|
+
? "Signed in. This account is still disabled — enable it to use it."
|
|
70
|
+
: "Account connected via OAuth!");
|
|
71
|
+
} catch (e) {
|
|
72
|
+
setAddError((e as Error).message);
|
|
73
|
+
}
|
|
74
|
+
setOauthLoading(false);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function handleAddToken() {
|
|
78
|
+
if (!newToken.trim()) return;
|
|
79
|
+
setAdding(true);
|
|
80
|
+
setAddError(null);
|
|
81
|
+
try {
|
|
82
|
+
const acc = await addAccount({ apiKey: newToken.trim(), label: newLabel.trim() || undefined });
|
|
83
|
+
handleClose();
|
|
84
|
+
onSuccess(acc?.status === "disabled"
|
|
85
|
+
? "Token updated. This account is still disabled — enable it to use it."
|
|
86
|
+
: "Account added!");
|
|
87
|
+
} catch (e) {
|
|
88
|
+
setAddError((e as Error).message);
|
|
89
|
+
}
|
|
90
|
+
setAdding(false);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const tokenHint = newToken.trim()
|
|
94
|
+
? newToken.trim().startsWith("sk-ant-oat") ? "OAuth token (Claude Max/Pro)"
|
|
95
|
+
: newToken.trim().startsWith("sk-ant-api") ? "API key"
|
|
96
|
+
: "Unknown format"
|
|
97
|
+
: "";
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Dialog open={open} onOpenChange={(v) => { if (!v) handleClose(); }}>
|
|
101
|
+
<DialogContent className="sm:max-w-md">
|
|
102
|
+
<DialogHeader>
|
|
103
|
+
<DialogTitle className="text-sm">Add Claude Account</DialogTitle>
|
|
104
|
+
<DialogDescription className="text-xs leading-relaxed">
|
|
105
|
+
Connect via OAuth (recommended) or paste a token manually.
|
|
106
|
+
</DialogDescription>
|
|
107
|
+
</DialogHeader>
|
|
108
|
+
<div className="space-y-3">
|
|
109
|
+
{/* OAuth login */}
|
|
110
|
+
<div className="rounded-md border p-3 space-y-2">
|
|
111
|
+
<p className="text-[11px] font-medium">Recommended: Login with Claude</p>
|
|
112
|
+
{oauthStep === "idle" ? (
|
|
113
|
+
<Button size="sm" className="w-full h-8 text-xs" onClick={handleOAuthLogin} disabled={oauthLoading}>
|
|
114
|
+
{oauthLoading ? <><Loader2 className="size-3 animate-spin mr-1" /> Opening...</> : "Login with Claude"}
|
|
115
|
+
</Button>
|
|
116
|
+
) : (
|
|
117
|
+
<div className="space-y-2">
|
|
118
|
+
<p className="text-[10px] text-muted-foreground">Authorize in the opened tab, then paste the code:</p>
|
|
119
|
+
<Input placeholder="Paste code here..." value={oauthCode} onChange={(e) => setOauthCode(e.target.value)} className="text-xs h-8 font-mono" autoFocus />
|
|
120
|
+
<div className="flex gap-1.5">
|
|
121
|
+
<Button size="sm" className="flex-1 h-7 text-xs" onClick={handleOAuthExchange} disabled={!oauthCode.trim() || oauthLoading}>
|
|
122
|
+
{oauthLoading ? <><Loader2 className="size-3 animate-spin mr-1" /> Connecting...</> : "Connect"}
|
|
123
|
+
</Button>
|
|
124
|
+
<Button size="sm" variant="ghost" className="h-7 text-xs" onClick={resetOAuth}>Cancel</Button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
<div className="flex items-center gap-2">
|
|
130
|
+
<div className="flex-1 border-t" />
|
|
131
|
+
<span className="text-[10px] text-muted-foreground">or paste token</span>
|
|
132
|
+
<div className="flex-1 border-t" />
|
|
133
|
+
</div>
|
|
134
|
+
{/* Manual token */}
|
|
135
|
+
<div className="space-y-1.5">
|
|
136
|
+
<Label htmlFor="add-token" className="text-xs">Token</Label>
|
|
137
|
+
<Input id="add-token" type="password" placeholder="sk-ant-..." value={newToken} onChange={(e) => setNewToken(e.target.value)} className="text-xs h-8 font-mono" />
|
|
138
|
+
{tokenHint && <p className="text-[10px] text-muted-foreground">Detected: {tokenHint}</p>}
|
|
139
|
+
</div>
|
|
140
|
+
<div className="space-y-1.5">
|
|
141
|
+
<Label htmlFor="add-label" className="text-xs">Label (optional)</Label>
|
|
142
|
+
<Input id="add-label" placeholder="e.g. Personal, Work" value={newLabel} onChange={(e) => setNewLabel(e.target.value)} className="text-xs h-8" />
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
{addError && <div className="text-[11px] p-2 rounded bg-error/10 text-error">{addError}</div>}
|
|
146
|
+
<DialogFooter>
|
|
147
|
+
<Button size="sm" variant="outline" className="text-xs h-7" onClick={handleClose}>Cancel</Button>
|
|
148
|
+
<Button size="sm" className="text-xs h-7" onClick={handleAddToken} disabled={!newToken.trim() || adding}>
|
|
149
|
+
{adding ? "Adding..." : "Add Token"}
|
|
150
|
+
</Button>
|
|
151
|
+
</DialogFooter>
|
|
152
|
+
</DialogContent>
|
|
153
|
+
</Dialog>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared bits of the encrypted account-backup format.
|
|
3
|
+
*
|
|
4
|
+
* The password default is part of the format, not a UI nicety: an export written with it
|
|
5
|
+
* must import with it, so export and import have to read the same constant.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Used when the user leaves the password field empty on either side of the round trip. */
|
|
9
|
+
export const DEFAULT_PASSWORD = "ppm-hienlh";
|
|
10
|
+
|
|
11
|
+
/** Save the backup text as a file — the fallback when the clipboard is unavailable. */
|
|
12
|
+
export function downloadBackup(text: string): void {
|
|
13
|
+
const blob = new Blob([text], { type: "application/json" });
|
|
14
|
+
const a = document.createElement("a");
|
|
15
|
+
a.href = URL.createObjectURL(blob);
|
|
16
|
+
a.download = "ppm-accounts-backup.json";
|
|
17
|
+
a.click();
|
|
18
|
+
URL.revokeObjectURL(a.href);
|
|
19
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The usage bar, and the rate-limit-bucket adapter over it.
|
|
3
|
+
*
|
|
4
|
+
* Two callers with different data: a Claude bucket knows its reset time and window, a Codex
|
|
5
|
+
* usage figure is a bare percentage. `AccountUsageBar` is the shared visual so both read the
|
|
6
|
+
* same; the bucket adapter adds what only a bucket has. Fabricating a reset time to force
|
|
7
|
+
* Codex through the bucket shape would have put invented data on screen.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { LimitBucket } from "../../../../types/chat";
|
|
11
|
+
import { barColor, formatResetTime, pctColor } from "./account-usage-format";
|
|
12
|
+
|
|
13
|
+
export function AccountUsageBar({ label, pct, reset }: {
|
|
14
|
+
label: string;
|
|
15
|
+
/** 0-100. Null renders the row with an em dash instead of a bar. */
|
|
16
|
+
pct: number | null;
|
|
17
|
+
/** "Resets in" text, when the source knows it. */
|
|
18
|
+
reset?: string | null;
|
|
19
|
+
}) {
|
|
20
|
+
return (
|
|
21
|
+
<div className="space-y-1" data-testid="account-usage-bar">
|
|
22
|
+
<div className="flex items-center justify-between">
|
|
23
|
+
<span className="text-xs font-medium text-text-primary">{label}</span>
|
|
24
|
+
{reset && (
|
|
25
|
+
<span className="text-[10px] text-text-subtle" title="Resets in">↻ {reset}</span>
|
|
26
|
+
)}
|
|
27
|
+
</div>
|
|
28
|
+
<div className="flex items-center gap-2">
|
|
29
|
+
<div className="flex-1 h-2 rounded-full bg-border overflow-hidden">
|
|
30
|
+
{pct != null && (
|
|
31
|
+
<div
|
|
32
|
+
className={`h-full rounded-full transition-all ${barColor(pct)}`}
|
|
33
|
+
style={{ width: `${Math.min(pct, 100)}%` }}
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
<span className={`text-xs font-medium tabular-nums w-10 text-right ${pct != null ? pctColor(pct) : "text-text-subtle"}`}>
|
|
38
|
+
{pct != null ? `${pct}%` : "—"}
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A Claude rate-limit bucket as a usage bar. Renders nothing when the bucket is absent. */
|
|
46
|
+
export function AccountBucketRow({ label, bucket }: { label: string; bucket?: LimitBucket }) {
|
|
47
|
+
if (!bucket) return null;
|
|
48
|
+
return (
|
|
49
|
+
<AccountUsageBar
|
|
50
|
+
label={label}
|
|
51
|
+
pct={Math.round(bucket.utilization * 100)}
|
|
52
|
+
reset={formatResetTime(bucket)}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One account: name, badges, per-account controls, its rate-limit buckets, and a footer of
|
|
3
|
+
* token facts.
|
|
4
|
+
*
|
|
5
|
+
* Three layouts, because the two callers want opposite things. Settings manages accounts one
|
|
6
|
+
* at a time, so `list` gives each card the full width. The chat panel is for comparing them
|
|
7
|
+
* at a glance, so `strip` makes fixed-width cards that scroll sideways and `grid` fills a
|
|
8
|
+
* cell of the fullscreen view — stacked vertically, comparing two accounts meant scrolling
|
|
9
|
+
* past the one above.
|
|
10
|
+
*
|
|
11
|
+
* An expired account (past `expiresAt` AND no refresh token) is dimmed and loses every
|
|
12
|
+
* control except delete — toggling or exporting a token the server can no longer renew only
|
|
13
|
+
* produces confusing failures.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Download, Eye, Trash2 } from "lucide-react";
|
|
17
|
+
import { Switch } from "@/components/ui/switch";
|
|
18
|
+
import type { AccountInfo, AccountUsageEntry, OAuthProfileData } from "../../../lib/api-settings";
|
|
19
|
+
import { AccountBucketRow } from "./account-bucket-row";
|
|
20
|
+
import { AccountCardShell } from "./accounts-pane-header";
|
|
21
|
+
import { formatExpiry, formatLastUpdated, tokenStatus } from "./account-usage-format";
|
|
22
|
+
|
|
23
|
+
export interface AccountCardProps {
|
|
24
|
+
entry: AccountUsageEntry;
|
|
25
|
+
isActive: boolean;
|
|
26
|
+
accountInfo?: AccountInfo;
|
|
27
|
+
onToggle?: (id: string, status: string) => void;
|
|
28
|
+
toggling?: boolean;
|
|
29
|
+
onDelete?: (id: string, display: string) => void;
|
|
30
|
+
onExport?: (id: string) => void;
|
|
31
|
+
onViewProfile?: (profile: OAuthProfileData, accountId: string) => void;
|
|
32
|
+
/** Brief highlight when this account's usage numbers just changed. */
|
|
33
|
+
flash?: boolean;
|
|
34
|
+
/** `list` fills the width, `strip` is a fixed-width card in a sideways scroller, `grid`
|
|
35
|
+
* fills a cell of the fullscreen grid. */
|
|
36
|
+
layout?: "list" | "strip" | "grid";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fixed widths so a row scrolls instead of squeezing. Two of them: a read-only card holds a
|
|
40
|
+
// name and its bars, but a card that also carries view/export/toggle/delete needs room for
|
|
41
|
+
// four controls beside the name, and at the read-only width that header wraps.
|
|
42
|
+
const STRIP_WIDTH = { readOnly: "min-w-[220px]", withActions: "min-w-[300px]" } as const;
|
|
43
|
+
|
|
44
|
+
export function AccountCard({
|
|
45
|
+
entry, isActive, accountInfo, onToggle, toggling, onDelete, onExport, onViewProfile, flash,
|
|
46
|
+
layout = "list",
|
|
47
|
+
}: AccountCardProps) {
|
|
48
|
+
const { usage } = entry;
|
|
49
|
+
const hasBuckets = usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet;
|
|
50
|
+
const status = accountInfo?.status ?? entry.accountStatus;
|
|
51
|
+
const isExpired = !!(
|
|
52
|
+
accountInfo && !accountInfo.hasRefreshToken && accountInfo.expiresAt
|
|
53
|
+
&& accountInfo.expiresAt < Math.floor(Date.now() / 1000)
|
|
54
|
+
);
|
|
55
|
+
const ts = tokenStatus(accountInfo);
|
|
56
|
+
const hasActions = Boolean(onToggle || onDelete || onExport || onViewProfile);
|
|
57
|
+
|
|
58
|
+
const layoutClass = layout === "list"
|
|
59
|
+
? ""
|
|
60
|
+
: layout === "grid"
|
|
61
|
+
// The cell owns the height, so the card spreads its rows into it.
|
|
62
|
+
? "flex flex-col justify-evenly overflow-hidden min-h-0"
|
|
63
|
+
: `shrink-0 snap-start ${hasActions ? STRIP_WIDTH.withActions : STRIP_WIDTH.readOnly}`;
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<AccountCardShell
|
|
67
|
+
active={isActive}
|
|
68
|
+
flash={flash}
|
|
69
|
+
dense={layout !== "list"}
|
|
70
|
+
className={[layoutClass, isExpired ? "opacity-50" : ""].filter(Boolean).join(" ") || undefined}
|
|
71
|
+
data-testid="account-card"
|
|
72
|
+
data-account-id={entry.accountId}
|
|
73
|
+
>
|
|
74
|
+
<div className="flex items-center gap-2">
|
|
75
|
+
<span className="text-sm font-medium truncate flex-1 min-w-0">
|
|
76
|
+
{entry.accountLabel ?? entry.accountId.slice(0, 8)}
|
|
77
|
+
</span>
|
|
78
|
+
{isActive && <span className="text-[10px] text-primary shrink-0 font-medium">Active</span>}
|
|
79
|
+
{isExpired && <span className="text-[10px] text-error shrink-0 font-medium">Expired</span>}
|
|
80
|
+
{!entry.isOAuth && !isExpired && (
|
|
81
|
+
<span className="text-[10px] text-text-subtle shrink-0">API key</span>
|
|
82
|
+
)}
|
|
83
|
+
|
|
84
|
+
<div className="flex items-center gap-0.5 shrink-0">
|
|
85
|
+
{!isExpired && onViewProfile && accountInfo?.profileData && (
|
|
86
|
+
<button
|
|
87
|
+
className="p-2 rounded cursor-pointer text-text-subtle hover:text-foreground hover:bg-surface-elevated transition-colors"
|
|
88
|
+
onClick={() => onViewProfile(accountInfo.profileData!, entry.accountId)}
|
|
89
|
+
title="View profile"
|
|
90
|
+
aria-label="View profile"
|
|
91
|
+
>
|
|
92
|
+
<Eye className="size-4" />
|
|
93
|
+
</button>
|
|
94
|
+
)}
|
|
95
|
+
{!isExpired && onExport && entry.isOAuth && (
|
|
96
|
+
<button
|
|
97
|
+
className="p-2 rounded cursor-pointer text-text-subtle hover:text-primary hover:bg-surface-elevated transition-colors"
|
|
98
|
+
onClick={() => onExport(entry.accountId)}
|
|
99
|
+
title="Export this account"
|
|
100
|
+
aria-label="Export this account"
|
|
101
|
+
>
|
|
102
|
+
<Download className="size-4" />
|
|
103
|
+
</button>
|
|
104
|
+
)}
|
|
105
|
+
{!isExpired && onToggle && (
|
|
106
|
+
<Switch
|
|
107
|
+
checked={status !== "disabled"}
|
|
108
|
+
onCheckedChange={() => onToggle(entry.accountId, status)}
|
|
109
|
+
disabled={toggling || status === "cooldown"}
|
|
110
|
+
aria-label={status === "disabled" ? "Enable account" : "Disable account"}
|
|
111
|
+
className="cursor-pointer"
|
|
112
|
+
/>
|
|
113
|
+
)}
|
|
114
|
+
{onDelete && (
|
|
115
|
+
<button
|
|
116
|
+
className="p-2 rounded cursor-pointer text-text-subtle hover:text-error hover:bg-surface-elevated transition-colors"
|
|
117
|
+
onClick={() => onDelete(entry.accountId, entry.accountLabel ?? entry.accountId.slice(0, 8))}
|
|
118
|
+
title="Remove account"
|
|
119
|
+
aria-label="Remove account"
|
|
120
|
+
>
|
|
121
|
+
<Trash2 className="size-4" />
|
|
122
|
+
</button>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{hasBuckets ? (
|
|
128
|
+
<div className="space-y-2">
|
|
129
|
+
<AccountBucketRow label="5-Hour Session" bucket={usage.session} />
|
|
130
|
+
<AccountBucketRow label="Weekly" bucket={usage.weekly} />
|
|
131
|
+
<AccountBucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
|
|
132
|
+
<AccountBucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
|
|
133
|
+
</div>
|
|
134
|
+
) : (
|
|
135
|
+
<p className="text-xs text-text-subtle">
|
|
136
|
+
{entry.isOAuth ? "No usage data yet" : "Usage tracking not available for API keys"}
|
|
137
|
+
</p>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
<div className="flex items-center gap-2 text-[10px] text-text-subtle flex-wrap">
|
|
141
|
+
{usage.lastFetchedAt && (
|
|
142
|
+
<span title="Last usage data update">↻ {formatLastUpdated(new Date(usage.lastFetchedAt).getTime())}</span>
|
|
143
|
+
)}
|
|
144
|
+
{accountInfo?.expiresAt && accountInfo.expiresAt * 1000 > Date.now() && (
|
|
145
|
+
<span title="Token expires in">⏱ {formatExpiry(accountInfo.expiresAt * 1000)}</span>
|
|
146
|
+
)}
|
|
147
|
+
<span className={ts.color} title={ts.tip}>© {ts.label}</span>
|
|
148
|
+
</div>
|
|
149
|
+
</AccountCardShell>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirmation before removing an account.
|
|
3
|
+
*
|
|
4
|
+
* Bottom sheet below `md`, centered dialog above — the same adaptive shell the process-kill
|
|
5
|
+
* confirmation uses. Removal is destructive and not undoable, so the destructive button is
|
|
6
|
+
* never the focused default and both Escape and the backdrop cancel.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
|
10
|
+
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
11
|
+
import { Button } from "@/components/ui/button";
|
|
12
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
13
|
+
|
|
14
|
+
export function AccountDeleteConfirm({ display, onConfirm, onCancel }: {
|
|
15
|
+
/** Label shown to the user — never the raw token or id. */
|
|
16
|
+
display: string;
|
|
17
|
+
onConfirm: () => void;
|
|
18
|
+
onCancel: () => void;
|
|
19
|
+
}) {
|
|
20
|
+
const isMobile = useIsMobile();
|
|
21
|
+
|
|
22
|
+
const body = (
|
|
23
|
+
<div className="space-y-4" data-testid="account-delete-confirm">
|
|
24
|
+
<p className="text-sm">
|
|
25
|
+
Remove <span className="font-medium">{display}</span>?
|
|
26
|
+
</p>
|
|
27
|
+
<p className="text-xs text-text-subtle">
|
|
28
|
+
The stored token is deleted from this machine. Any export you already made keeps working.
|
|
29
|
+
</p>
|
|
30
|
+
<div className="flex flex-col-reverse md:flex-row gap-2 md:justify-end pt-2">
|
|
31
|
+
<Button variant="outline" onClick={onCancel} className="min-h-11">
|
|
32
|
+
Cancel
|
|
33
|
+
</Button>
|
|
34
|
+
<Button variant="destructive" autoFocus={false} onClick={onConfirm} className="min-h-11">
|
|
35
|
+
Remove account
|
|
36
|
+
</Button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (isMobile) {
|
|
42
|
+
return (
|
|
43
|
+
<BottomSheet open onClose={onCancel}>
|
|
44
|
+
<div className="px-4 pb-4">
|
|
45
|
+
<h2 className="text-base font-semibold mb-3">Remove account</h2>
|
|
46
|
+
{body}
|
|
47
|
+
</div>
|
|
48
|
+
</BottomSheet>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Dialog open onOpenChange={(v) => { if (!v) onCancel(); }}>
|
|
54
|
+
<DialogContent className="sm:max-w-sm">
|
|
55
|
+
<DialogHeader>
|
|
56
|
+
<DialogTitle className="text-sm">Remove account</DialogTitle>
|
|
57
|
+
</DialogHeader>
|
|
58
|
+
{body}
|
|
59
|
+
</DialogContent>
|
|
60
|
+
</Dialog>
|
|
61
|
+
);
|
|
62
|
+
}
|