forge-openclaw-plugin 0.2.99 → 0.2.101
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/dist/assets/activity-copy-Bj4h9OcF.js +1 -0
- package/dist/assets/activity-page-CpjuNSHw.js +1 -0
- package/dist/assets/ai-surface-workspace-DEAFZruS.js +1 -0
- package/dist/assets/atlas-panel-CdVNPotj.js +1 -0
- package/dist/assets/{board-Ju0h0SeG.js → board-BkDRaMp6.js} +1 -1
- package/dist/assets/calendar-display-preferences-Cid-2RnL.js +1 -0
- package/dist/assets/calendar-page-DNNt6lfz.js +1 -0
- package/dist/assets/calendar-rules-DNJFNsxi.js +1 -0
- package/dist/assets/calendar-ui-Cy1XRwzV.js +1 -0
- package/dist/assets/calendar-week-toolbar-BbPwYeN0.js +1 -0
- package/dist/assets/charts-P7EVhIog.js +36 -0
- package/dist/assets/companion-sync-lab-page-KxEDigM6.js +1 -0
- package/dist/assets/daily-metrics-dashboard-B3cqJgDt.js +1 -0
- package/dist/assets/date-keys-Cj1G3TOn.js +1 -0
- package/dist/assets/entity-links-DwpxhW2H.js +1 -0
- package/dist/assets/entity-note-count-link-DrhjJZ4i.js +1 -0
- package/dist/assets/entity-notes-surface-CkcRsKJQ.js +1 -0
- package/dist/assets/execution-board-D07gOocB.js +1 -0
- package/dist/assets/faceted-token-search-BxRRcM3q.js +1 -0
- package/dist/assets/flagship-signal-deck-cmy82b8_.js +1 -0
- package/dist/assets/floating-action-menu-Fs_ZiUMo.js +1 -0
- package/dist/assets/forms-BFlTgZ3W.js +1 -0
- package/dist/assets/goal-detail-page-CqLiNz4f.js +1 -0
- package/dist/assets/goals-page-BTk7mg_T.js +1 -0
- package/dist/assets/graph-BZV40eAE.css +1 -0
- package/dist/assets/graph-D6JLqDbD.js +318 -0
- package/dist/assets/habits-page-BJxagdzx.js +1 -0
- package/dist/assets/health-link-options-Cpx8w7uM.js +1 -0
- package/dist/assets/index-CF4J4R9L.js +19 -0
- package/dist/assets/index-CZbuZQjw.css +1 -0
- package/dist/assets/insight-flow-dialog-8f3D0GuC.js +1 -0
- package/dist/assets/insights-page-D6rOa7uk.js +8 -0
- package/dist/assets/kanban-page-XQ7Se6dH.js +1 -0
- package/dist/assets/knowledge-graph-page-BtAg8iv3.js +1 -0
- package/dist/assets/life-force-page-Dy0JTS2G.js +1 -0
- package/dist/assets/life-force-workspace-OfyB9HJM.js +1 -0
- package/dist/assets/maps-B-YMMjus.css +1 -0
- package/dist/assets/maps-ClgJoCjz.js +803 -0
- package/dist/assets/metric-tile-DKpo-8xw.js +1 -0
- package/dist/assets/{motion-DRPJkN3a.js → motion-BeD44FeG.js} +1 -1
- package/dist/assets/movement-page-Bg_T_Stx.js +1 -0
- package/dist/assets/note-markdown-N-uxD3Xt.js +3 -0
- package/dist/assets/note-tags-input-Cdu7wiw6.js +1 -0
- package/dist/assets/notes-page-CKXnF_KU.js +1 -0
- package/dist/assets/open-in-graph-button-IXe9SGth.js +1 -0
- package/dist/assets/orbit-map-Dzi6KliQ.js +1 -0
- package/dist/assets/overview-page-1miYqaVS.js +1 -0
- package/dist/assets/page-hero-DRy5b2MU.js +1 -0
- package/dist/assets/pill-cluster-C9QczVJ2.js +1 -0
- package/dist/assets/preference-entity-handoff-button-5PzUn42S.js +1 -0
- package/dist/assets/preferences-page-DtNaF5Q3.js +1 -0
- package/dist/assets/project-collections-xPz2mlRr.js +1 -0
- package/dist/assets/project-detail-page-BXK5-4xW.js +1 -0
- package/dist/assets/project-management-hierarchy-page-DtRpMABw.js +1 -0
- package/dist/assets/project-management-section-nav-P3ixzPa-.js +1 -0
- package/dist/assets/projects-page-C5ViRuf4.js +1 -0
- package/dist/assets/psyche-behaviors-page-Dco46sC4.js +5 -0
- package/dist/assets/psyche-flashcards-page-ZcoEB8gV.js +1 -0
- package/dist/assets/psyche-goal-map-page-CLBAQOI0.js +1 -0
- package/dist/assets/psyche-graph-k4tX2tdp.js +1 -0
- package/dist/assets/psyche-metrics-page-CuR9oqEy.js +1 -0
- package/dist/assets/psyche-mode-guide-page-hIVXcCnE.js +1 -0
- package/dist/assets/psyche-modes-page-0lYtBlhO.js +1 -0
- package/dist/assets/psyche-page-VZ9k9ISp.js +1 -0
- package/dist/assets/psyche-patterns-page-gx5nmdGq.js +5 -0
- package/dist/assets/psyche-questionnaire-builder-page-Bn0TOISd.js +1 -0
- package/dist/assets/psyche-questionnaire-detail-page-CmVzSd_s.js +1 -0
- package/dist/assets/psyche-questionnaire-run-detail-page-BsMbmXCG.js +1 -0
- package/dist/assets/psyche-questionnaire-run-page-CgkRL2vi.js +1 -0
- package/dist/assets/psyche-questionnaires-page-D7V8uLXM.js +1 -0
- package/dist/assets/psyche-report-detail-page-OlFq57eL.js +3 -0
- package/dist/assets/psyche-reports-page-dVUZjna1.js +1 -0
- package/dist/assets/psyche-schemas-HFmg37Wj.js +1 -0
- package/dist/assets/psyche-schemas-beliefs-page-BCgc8FUd.js +9 -0
- package/dist/assets/psyche-screen-time-page-B_6BT_WN.js +1 -0
- package/dist/assets/psyche-self-observation-page-CEG5mluK.js +1 -0
- package/dist/assets/psyche-values-page-DRbRfEd6.js +5 -0
- package/dist/assets/query-cache-IQ8W-LNC.js +1 -0
- package/dist/assets/report-chain-fields-CALCV3V5.js +1 -0
- package/dist/assets/rewards-page-DmC4R_Ps.js +1 -0
- package/dist/assets/scheduling-rules-editor-D02s70hr.js +1 -0
- package/dist/assets/schema-badge-BZO-qNhO.js +1 -0
- package/dist/assets/schema-visuals-D6nxjbYC.js +1 -0
- package/dist/assets/select-menu-fYyreSdQ.js +1 -0
- package/dist/assets/settings-agents-page-C_v_hMJF.js +6 -0
- package/dist/assets/settings-bin-page-DY5bg81n.js +1 -0
- package/dist/assets/settings-calendar-page-D1CzE6cg.js +5 -0
- package/dist/assets/settings-data-page-CHRQFU9H.js +1 -0
- package/dist/assets/settings-logs-page-B04pUwEv.js +1 -0
- package/dist/assets/settings-mobile-page-D9kTlYDS.js +1 -0
- package/dist/assets/settings-models-page-D26270R2.js +1 -0
- package/dist/assets/settings-page-DYDTFlnv.js +1 -0
- package/dist/assets/settings-rewards-page-cl4vqqO_.js +1 -0
- package/dist/assets/settings-section-nav-DSOuht_F.js +1 -0
- package/dist/assets/settings-users-page-BU79JB_T.js +1 -0
- package/dist/assets/settings-wiki-page-DwAUlyA3.js +1 -0
- package/dist/assets/sleep-page-D8NbdhyS.js +1 -0
- package/dist/assets/sports-page-CV4Cnzwn.js +1 -0
- package/dist/assets/state-B-4sS1xO.js +1 -0
- package/dist/assets/strategies-page-C4qvXnql.js +1 -0
- package/dist/assets/strategy-detail-page-DJLo5rfy.js +1 -0
- package/dist/assets/strategy-dialog-D3AuUlVz.js +1 -0
- package/dist/assets/{table-DewbFlTh.js → table-WfAPUppN.js} +1 -1
- package/dist/assets/task-detail-page-z-9u9rF0.js +1 -0
- package/dist/assets/timebox-planning-dialog-DB6FLqmI.js +1 -0
- package/dist/assets/today-page-BKlu6gx5.js +1 -0
- package/dist/assets/training-load-page-CyJQqo_3.js +1 -0
- package/dist/assets/{ui-C2IvSrAz.js → ui-C13Nbgas.js} +4 -4
- package/dist/assets/use-psyche-focus-target-C1C_XjYG.js +1 -0
- package/dist/assets/vendor-CRS-psbw.css +1 -0
- package/dist/assets/vendor-DHkYh85p.js +1052 -0
- package/dist/assets/vitals-page-qre17Nw8.js +1 -0
- package/dist/assets/weekly-review-page-Cz4vkRcx.js +1 -0
- package/dist/assets/weight-loss-page-BQrnOI0y.js +1 -0
- package/dist/assets/wiki-article-markdown-DdiR2TJE.js +4 -0
- package/dist/assets/wiki-editor-page-DqwoqVFb.js +26 -0
- package/dist/assets/wiki-ingest-history-page--evBLbOw.js +1 -0
- package/dist/assets/wiki-ingest-modal--ohzFnj2.js +1 -0
- package/dist/assets/wiki-page-B_VJFBPA.js +1 -0
- package/dist/assets/workbench-flow-page-Du62mtJU.js +5 -0
- package/dist/assets/workbench-page-4MKr3iRm.js +1 -0
- package/dist/assets/workout-detail-page-DfUbYYw1.js +2 -0
- package/dist/index.html +148 -9
- package/dist/openclaw/tools.js +340 -0
- package/dist/server/server/migrations/065_weight_loss_nutrition_insights.sql +236 -0
- package/dist/server/server/migrations/066_watch_action_receipts.sql +20 -0
- package/dist/server/server/src/app.js +266 -13
- package/dist/server/server/src/health-weight-loss.js +1378 -0
- package/dist/server/server/src/health.js +188 -35
- package/dist/server/server/src/openapi.js +449 -0
- package/dist/server/server/src/services/context.js +6 -7
- package/dist/server/server/src/services/doctor.js +39 -4
- package/dist/server/server/src/services/gamification.js +146 -34
- package/dist/server/server/src/watch-mobile.js +576 -4
- package/dist/server/server/src/web.js +18 -5
- package/dist/server/src/components/ui/info-tooltip.js +48 -3
- package/dist/server/src/lib/api.js +131 -0
- package/dist/server/src/lib/weight-loss-types.js +1 -0
- package/openclaw.plugin.json +14 -1
- package/package.json +1 -1
- package/server/migrations/065_weight_loss_nutrition_insights.sql +236 -0
- package/server/migrations/066_watch_action_receipts.sql +20 -0
- package/skills/forge-openclaw/SKILL.md +26 -5
- package/skills/forge-openclaw/entity_conversation_playbooks.md +134 -5
- package/skills/forge-openclaw/psyche_entity_playbooks.md +45 -0
- package/dist/assets/index-Cn5Wpwau.css +0 -1
- package/dist/assets/index-CwvGs8n4.js +0 -91
- package/dist/assets/vendor-B-Lq_OG3.css +0 -1
- package/dist/assets/vendor-DL2K5ayT.js +0 -2186
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{j as e,cb as Me,df as Ee,aN as ur,bn as be,r as l,dh as pr,bF as Re,ce as mr,d6 as Pe,c2 as fr,cY as xr,c7 as vr,aV as Te}from"./vendor-DHkYh85p.js";import{j as ar,k as Q,i as Ue}from"./state-B-4sS1xO.js";import{C as Ge,dY as br,dZ as Qe,d_ as wr,d$ as yr,dj as He,e0 as Cr,F as D,j as jr,I as B,c as b,B as k,aq as Fr,n as De,Q as $e,a9 as Nr,e1 as Sr,e2 as kr,e3 as Ur,e4 as Ir,e5 as Mr,e6 as Er,e7 as Or,e8 as Ar,e9 as Lr,S as Rr,E as Ye,i as Gr,dx as Dr,b$ as _r,ea as Pr,eb as zr,ec as Tr}from"./index-CF4J4R9L.js";import{S as $r}from"./settings-section-nav-DSOuht_F.js";import{P as qr}from"./page-hero-DRy5b2MU.js";import{r as Vr,b as Kr,w as Wr}from"./calendar-display-preferences-Cid-2RnL.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./forms-BFlTgZ3W.js";import"./graph-D6JLqDbD.js";const Xe=[{title:"Before you connect anything",description:"Forge mirrors provider events into Forge. Writable providers can also publish work blocks plus owned timeboxes into one shared Forge write target, while Exchange Online stays read-only for now.",bullets:["Google uses a localhost Authorization Code + PKCE flow. Each user signs in with their own Google account on the same machine running Forge, while Forge stores that user's refresh token on the server for background sync.","Calendars On This Mac uses EventKit to access the calendars already configured in Calendar.app on the host machine, including iCloud, Google, Exchange, and other accounts the Mac is already syncing.","Apple Calendar starts from https://caldav.icloud.com and autodiscovers the real principal plus calendar collections for you.","Exchange Online uses Microsoft Graph with a guided local public-client Microsoft sign-in flow and mirrors the calendars you select into Forge.","Custom CalDAV uses one account-level base URL, then Forge discovers the writable calendars before you choose what to mirror.","Read-only .ics feeds are not enough for writable-provider flows because Forge needs write access for work blocks and task timeboxes."],icon:Me,links:[]},{title:"Calendars On This Mac setup",description:"Use this path when the Mac already has the needed accounts connected in Calendar.app and Forge should sync them through EventKit instead of reconnecting each provider manually.",bullets:["Open Forge on the same Mac whose Calendar.app already contains the accounts you want to mirror.","Choose Calendars On This Mac in Forge settings.","Grant Calendar full access when macOS prompts for it, or re-enable it later in System Settings -> Privacy & Security -> Calendars.","Let Forge discover the available host calendar sources and pick the source account you want to sync.","Choose which calendars Forge should mirror. If Forge already has a write target on another writable connection, this new connection can reuse it instead of creating another Forge calendar.","If Forge already syncs the same account through Google, Apple, CalDAV, or Microsoft, the macOS-local connection replaces the older remote one instead of keeping two visible copies."],icon:Me,links:[]},{title:"Google Calendar setup",description:"Use one Google Cloud desktop-app OAuth client for local Forge, register the exact localhost callback URI, and let Forge complete the Authorization Code + PKCE exchange on the backend.",bullets:["Open Google Cloud credentials and create or reuse one OAuth client for Forge as a Desktop app.","Enable the Calendar API for the same project.","Register Forge's exact callback URI. In local Forge, the default callback is http://127.0.0.1:4317/api/v1/calendar/oauth/google/callback.","Open Forge on localhost on the same machine that is running Forge. If Forge is opened remotely from a phone or a Tailscale route while the callback is localhost, Google will redirect to localhost on that device and the flow will fail.","The user signs in with their own Google account and grants Forge access. They do not create their own Google OAuth client during this step.","Forge will discover the calendars, let you choose which calendars to mirror, and create or reuse Forge as the write calendar."],icon:Ee,links:[{label:"Google Cloud credentials",href:"https://console.cloud.google.com/apis/credentials"},{label:"Calendar API quickstart",href:"https://developers.google.com/workspace/calendar/api/quickstart"}]},{title:"Apple Calendar setup",description:"Apple does not require you to paste raw calendar collection URLs into Forge. Start with your Apple ID email, an app-specific password, and the iCloud CalDAV base URL.",bullets:["Create an Apple app-specific password for third-party calendar access.","Open Forge settings and choose Apple Calendar.","Enter the Apple ID email and the app-specific password. Forge uses https://caldav.icloud.com for autodiscovery.","After discovery, choose which calendars Forge should mirror.","If a calendar named Forge already exists, Forge will preselect it as the write calendar. Otherwise you can ask Forge to create it for you."],icon:ur,links:[{label:"Apple app-specific passwords",href:"https://support.apple.com/en-us/102654"},{label:"Use iCloud Calendar with third-party apps",href:"https://support.apple.com/guide/icloud/set-up-calendar-mmfc0f2442/icloud"}]},{title:"Exchange Online setup",description:"Use Microsoft Graph for Microsoft 365 or Exchange Online calendars. In self-hosted local Forge, the user first saves a Microsoft public client ID, tenant, and redirect URI in Settings -> Calendar, then completes a guided local sign-in flow with PKCE. The connection is still read-only in Forge today.",bullets:["Open Microsoft Entra App registrations and create or reuse an app for this local Forge instance.","Choose a supported account type that matches your self-hosted use case. Use a broad multi-account setup when Forge should work with normal personal or organizational Microsoft sign-ins.","Enable mobile and desktop or public client flow support for that app registration.","Add Forge's callback URI to the redirect URI list. The default local callback is http://127.0.0.1:4317/api/v1/calendar/oauth/microsoft/callback.","Add delegated Graph permissions for User.Read and Calendars.Read, then grant or request consent as required by the tenant.","Open Forge Settings -> Calendar and save the Microsoft client ID, tenant value, and redirect URI in the Exchange Online setup card.","Use Test Microsoft configuration to confirm Forge can launch the local sign-in flow.","Click Sign in with Microsoft, complete the popup flow, and then choose which Exchange Online calendars Forge should mirror."],icon:Ee,links:[{label:"Microsoft Graph permissions",href:"https://learn.microsoft.com/en-us/graph/permissions-reference"},{label:"Microsoft identity platform",href:"https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow"},{label:"Microsoft Graph calendar overview",href:"https://learn.microsoft.com/en-us/graph/api/resources/calendar?view=graph-rest-1.0"}]},{title:"Custom CalDAV setup",description:"Use this path for Nextcloud, Fastmail, Baikal, DAViCal, and other CalDAV-compatible providers that expose an account-level base URL.",bullets:["Confirm the provider supports CalDAV, not just an .ics export.","Gather the account-level CalDAV server URL, username, and password or app password.","Open Forge settings and choose Custom CalDAV.","Forge discovers the available calendars from that base URL before anything is saved.","Choose which calendars to mirror and either select an existing Forge calendar or let Forge create one automatically."],icon:Me,links:[]}];function Br(t){if(!t)return Xe;const c=t==="google"?"Google Calendar setup":t==="macos_local"?"Calendars On This Mac setup":t==="apple"?"Apple Calendar setup":t==="microsoft"?"Exchange Online setup":"Custom CalDAV setup";return Xe.filter(p=>p.title==="Before you connect anything"||p.title===c)}function Qr({section:t,compact:c}){const p=t.icon;return e.jsxs(Ge,{className:c?"grid gap-3 rounded-[24px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))] p-4":"grid gap-4 rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(p,{className:c?"size-4":"size-5"})}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:c?"font-medium text-white":"font-display text-[1.15rem] text-white",children:t.title}),e.jsx("p",{className:c?"mt-1.5 text-sm leading-6 text-white/62":"mt-2 max-w-3xl text-sm leading-6 text-white/62",children:t.description})]})]}),e.jsx("div",{className:c?"grid gap-1.5":"grid gap-2",children:t.bullets.map(w=>e.jsx("div",{className:c?"rounded-[16px] bg-white/[0.04] px-3 py-2.5 text-sm leading-6 text-white/70":"rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/72",children:w},w))}),t.links.length>0?e.jsx("div",{className:"flex flex-wrap gap-2",children:t.links.map(w=>e.jsxs("a",{href:w.href,target:"_blank",rel:"noreferrer",className:"inline-flex min-h-10 items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-3 py-2 text-sm text-white/74 transition hover:bg-white/[0.08] hover:text-white",children:[e.jsx(be,{className:"size-3.5"}),w.label]},w.href))}):null]})}function Hr({provider:t,compact:c=!1}){const p=Br(t);return e.jsx("div",{className:"grid gap-4",children:p.map(w=>e.jsx(Qr,{section:w,compact:c},w.title))})}const Ze="/api/v1/calendar/oauth/microsoft/callback",Yr=/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,Je=1e3,_e={google:{label:"Primary Google",serverUrl:""},apple:{label:"Primary Apple",serverUrl:"https://caldav.icloud.com"},microsoft:{label:"Primary Exchange Online",serverUrl:""},macos_local:{label:"Calendars On This Mac",serverUrl:"forge-macos-local://eventkit/"},caldav:{label:"Primary CalDAV",serverUrl:"https://caldav.example.com"}};function ze(t){return{provider:t,label:_e[t].label,serverUrl:_e[t].serverUrl,username:"",password:"",selectedCalendarUrls:[],forgeCalendarUrl:null,createForgeCalendar:!1,sourceId:null,replaceConnectionIds:[]}}function oe(t,c){const p=c.trim();return p.length>0?p:_e[t].label}function Le(t){return{clientId:t.clientId,tenantId:t.tenantId,redirectUri:t.redirectUri}}function Ie(t){return{clientId:t.storedClientId??"",clientSecret:t.storedClientSecret??""}}function Xr(t){return t.replace(/\s*No GOOGLE_CLIENT_SECRET is used in this local PKCE flow\./gi,"").replace(/\s{2,}/g," ").trim()}function er(){return["Google OAuth credentials are not set for this Forge install.","- Save a Google desktop-app client ID and client secret below for this Forge install.","- Or rely on the packaged or environment defaults for the Forge runtime."].join(`
|
|
2
|
+
`)}function rr(t,c){return[t,"- Open Forge from a local browser on the host running Forge.",`- Use one of these local addresses: ${c.join(", ")}.`].join(`
|
|
3
|
+
`)}function nr(t){return{clientId:(t.clientId??"").trim(),clientSecret:(t.clientSecret??"").trim()}}function Zr(t,c){return t.clientId.trim()===c.clientId.trim()&&t.clientSecret.trim()===c.clientSecret.trim()}function Jr(t){const c=nr(t),p={},w=c.clientId.length>0,A=c.clientSecret.length>0;if(w!==A){const q="When overriding Google OAuth credentials, save the client ID and client secret together, or clear both to use the bundled defaults.";w||(p.clientId=q),A||(p.clientSecret=q)}return{normalized:c,issues:p,isValid:Object.keys(p).length===0}}function qe(t){return{clientId:t.clientId.trim(),tenantId:t.tenantId.trim()||"common",redirectUri:t.redirectUri.trim()}}function et(t){const c=qe(t),p={};if(c.clientId?Yr.test(c.clientId)||(p.clientId="Use the Microsoft app registration client ID GUID."):p.clientId="Microsoft client ID is required.",!c.redirectUri)p.redirectUri="Redirect URI is required.";else try{const w=new URL(c.redirectUri);w.protocol!=="http:"&&w.protocol!=="https:"?p.redirectUri="Redirect URI must use http or https.":w.pathname!==Ze&&(p.redirectUri=`Redirect URI must end with ${Ze}.`)}catch{p.redirectUri="Redirect URI must be a full URL."}return{normalized:c,issues:p,isValid:Object.keys(p).length===0}}function rt(t,c){return t.clientId.trim()===c.clientId.trim()&&t.tenantId.trim()===c.tenantId.trim()&&t.redirectUri.trim()===c.redirectUri.trim()}function Ve(t){return t==="127.0.0.1"||t==="localhost"}function tt(t){return t.endsWith(".ts.net")}function st(t){t.allowedOrigins.filter(w=>{try{return Ve(new URL(w).hostname)}catch{return!1}});const c=(()=>{try{return new URL(t.redirectUri).hostname}catch{return""}})();let p="";try{p=new URL(t.currentOrigin).hostname}catch{p=""}return tt(p)&&Ve(c)?`Google sign-in has to start from a local browser on the host running Forge. Forge is currently open through Tailscale at ${t.currentOrigin}, but Google sends the callback to localhost on the device that opens the popup. On a phone or another computer, that callback goes to that device instead of the Forge host.`:t.isLocalOnly?"Google sign-in has to start from a local browser on the host running Forge. Google sends the callback to localhost, so if Forge is opened remotely, the callback goes to the other device instead of the Forge host.":`Google sign-in is only enabled from the configured Forge host for this deployment. Open Forge on ${t.appBaseUrl}. Current browser origin: ${t.currentOrigin}.`}function at({open:t,onOpenChange:c,initialProvider:p="google",initialStepId:w,googleSetup:A,microsoftSetup:q,onCalendarSettingsChanged:H,existingConnections:ge=[],onSubmit:Y,pending:N=!1}){const we=ar(),[n,V]=l.useState(()=>ze(p)),[ye,m]=l.useState(null),[v,_]=l.useState(null),[U,ae]=l.useState("not_determined"),[C,P]=l.useState(null),[g,y]=l.useState(null),[u,X]=l.useState(null),[h,ue]=l.useState(A),[I,K]=l.useState(()=>Ie(A)),[z,le]=l.useState(()=>Ie(A)),[Oe,ne]=l.useState(!1),[Z,F]=l.useState(null),[T,pe]=l.useState(q),[S,ce]=l.useState(()=>Le(q)),[Ce,ie]=l.useState(()=>Le(q)),[me,L]=l.useState(null),M=l.useRef(null),fe=(r=[])=>{const a=new Set(r);return ge.find(i=>{var o;return a.has(i.id)?!1:typeof((o=i.config)==null?void 0:o.forgeCalendarUrl)=="string"&&i.config.forgeCalendarUrl.trim().length>0})??null},R=l.useMemo(()=>n.provider==="microsoft"?null:fe(n.replaceConnectionIds),[n.provider,n.replaceConnectionIds,ge]),E=R?R.accountLabel&&R.accountLabel.trim().length>0?`${R.label} · ${R.accountLabel}`:R.label:null,je=r=>(we.setQueryData(["forge-settings"],r),r.settings),s=()=>{y(null),M.current=null},d=()=>{X(null),M.current=null},f=r=>{_(r);const a=r.calendars.filter(o=>o.selectedByDefault).map(o=>o.url),i=r.calendars.find(o=>o.isForgeCandidate);V(o=>{const j=fe(o.replaceConnectionIds);return{...o,selectedCalendarUrls:o.selectedCalendarUrls.length>0?o.selectedCalendarUrls.filter(se=>r.calendars.some(Ne=>Ne.url===se)):a,forgeCalendarUrl:o.provider==="microsoft"||j?null:(i==null?void 0:i.url)??o.forgeCalendarUrl??null,createForgeCalendar:o.provider==="microsoft"||j?!1:o.createForgeCalendar&&!i}}),m(null)};l.useEffect(()=>{var r;if(!t){(r=M.current)==null||r.close(),M.current=null;return}m(null),_(null),V(ze(p)),s(),d(),P(null),ae("not_determined"),ne(!1),F(null),L(null)},[p,t]),l.useEffect(()=>{!t||n.provider!=="macos_local"||G.mutateAsync()},[n.provider,t]),l.useEffect(()=>{if(!t||!v||n.provider==="microsoft"||R||n.forgeCalendarUrl||n.createForgeCalendar)return;const r=v.calendars.find(a=>a.isForgeCandidate);r&&V(a=>a.provider==="microsoft"||a.forgeCalendarUrl||a.createForgeCalendar||fe(a.replaceConnectionIds)?a:{...a,forgeCalendarUrl:r.url})},[v,n.createForgeCalendar,n.forgeCalendarUrl,n.provider,t,R]),l.useEffect(()=>{if(!t)return;ue(A);const r=Ie(A);K(r),le(r),ne(!1),F(null)},[A,t]),l.useEffect(()=>{if(!t)return;pe(q);const r=Le(q);ce(r),ie(r),L(null)},[q,t]),l.useEffect(()=>{if(!t||!g||g.status!=="pending")return;const r=new URL(h.redirectUri).origin;let a=!1;const i=()=>{a||(a=!0,cr(g.sessionId).finally(()=>{a=!1}))},o=he=>{var Se,ke;he.origin===r&&(((Se=he.data)==null?void 0:Se.type)!=="forge:google-calendar-auth"||((ke=he.data)==null?void 0:ke.sessionId)!==g.sessionId||i())},j=()=>{i()},se=()=>{document.visibilityState==="visible"&&i()},Ne=window.setInterval(i,Je);return window.addEventListener("message",o),window.addEventListener("focus",j),document.addEventListener("visibilitychange",se),()=>{window.removeEventListener("message",o),window.removeEventListener("focus",j),document.removeEventListener("visibilitychange",se),window.clearInterval(Ne)}},[h.redirectUri,g,t]),l.useEffect(()=>{if(!t||!u||u.status!=="pending")return;const r=new URL(T.redirectUri).origin;let a=!1;const i=()=>{a||(a=!0,dr(u.sessionId).finally(()=>{a=!1}))},o=he=>{var Se,ke;he.origin===r&&(((Se=he.data)==null?void 0:Se.type)!=="forge:microsoft-calendar-auth"||((ke=he.data)==null?void 0:ke.sessionId)!==u.sessionId||i())},j=()=>{i()},se=()=>{document.visibilityState==="visible"&&i()},Ne=window.setInterval(i,Je);return window.addEventListener("message",o),window.addEventListener("focus",j),document.addEventListener("visibilitychange",se),()=>{window.removeEventListener("message",o),window.removeEventListener("focus",j),document.removeEventListener("visibilitychange",se),window.clearInterval(Ne)}},[T.redirectUri,u,t]);const x=Q({mutationFn:()=>n.provider==="macos_local"?br().then(({discovery:r})=>{P(r),ae(r.status);const a=r.sources.find(i=>i.sourceId===n.sourceId)??r.sources[0]??null;return a&&(f({provider:"macos_local",accountLabel:a.accountLabel,serverUrl:n.serverUrl,principalUrl:null,homeUrl:null,calendars:a.calendars}),V(i=>({...i,sourceId:a.sourceId}))),{discovery:null}}):n.provider==="apple"?Qe({provider:"apple",username:n.username,password:n.password}):Qe({provider:"caldav",serverUrl:n.serverUrl,username:n.username,password:n.password}),onSuccess:({discovery:r})=>{r&&f(r)},onError:r=>{_(null),m(r instanceof Error?r.message:"Forge could not discover calendars with these credentials.")}}),G=Q({mutationFn:wr,onSuccess:({status:r})=>{ae(r),r!=="full_access"&&(P(null),_(null))}}),J=Q({mutationFn:yr,onSuccess:({granted:r,status:a,message:i})=>{if(ae(a),r){m(null);return}m(i??"Forge could not obtain Calendar access from macOS yet. Open System Settings > Privacy & Security > Calendars, allow Forge, then return here and click Check access.")},onError:r=>{m(r instanceof Error?r.message:"Forge could not request Calendar access from macOS.")}});l.useEffect(()=>{!t||n.provider!=="macos_local"||U!=="full_access"||C!==null||x.isPending||x.mutateAsync()},[x,n.provider,C,U,t]);const ee=Q({mutationFn:async r=>{const a=qe(r),i=await He({calendarProviders:{microsoft:a}});return{normalized:a,settings:je(i)}},onSuccess:async({settings:r})=>{pe(r.calendarProviders.microsoft);const a=Le(r.calendarProviders.microsoft);ie(a),ce(a),L("Microsoft settings saved. Start the guided Microsoft sign-in when you are ready."),H==null||H()},onError:r=>{L(r instanceof Error?r.message:"Forge could not save the Microsoft settings.")}}),$=Q({mutationFn:async r=>{const a=nr(r),i=await He({calendarProviders:{google:a}});return{normalized:a,settings:je(i)}},onSuccess:async({normalized:r,settings:a})=>{ue(a.calendarProviders.google);const i=Ie(a.calendarProviders.google);le(i),K(i),ne(!1),F(r.clientId||r.clientSecret?"Google OAuth credentials saved on the Forge server for this install.":"Google OAuth override cleared. Forge will use the packaged or environment default again."),H==null||H()},onError:r=>{F(r instanceof Error?r.message:"Forge could not save the Google OAuth credentials.")}}),re=Q({mutationFn:r=>{const a=qe(r);return Cr(a)},onSuccess:({result:r})=>{L(r.message)},onError:r=>{L(r instanceof Error?r.message:"Forge could not validate the Microsoft configuration.")}}),O=l.useMemo(()=>et(S),[S]),W=l.useMemo(()=>Jr(I),[I]),te=!Zr(I,z),xe=!rt(S,Ce),de=typeof window>"u"?"":window.location.origin,Ke=l.useMemo(()=>{try{return new URL(h.redirectUri).origin}catch{return""}},[h.redirectUri]),Ae=de.length>0&&h.allowedOrigins.includes(de)&&(!h.isLocalOnly||Ve(new URL(de).hostname)),Fe=de&&!Ae?st({currentOrigin:de,appBaseUrl:h.appBaseUrl,redirectUri:h.redirectUri,allowedOrigins:h.allowedOrigins,isLocalOnly:h.isLocalOnly}):null,ir=h.isReadyForPairing?null:Xr(h.setupMessage)||er(),or=Fe?rr(Fe,h.allowedOrigins):null,lr=r=>{if(ye)return ye;if(n.provider==="google"&&(r==="credentials"||r==="discovery")){if(te)return"Save the Google OAuth credential change before starting sign-in.";const a=[or,ir].filter(i=>!!i);if(a.length>0)return a.join(`
|
|
4
|
+
|
|
5
|
+
`)}if(n.provider==="microsoft"&&r==="credentials"){if(xe)return"Save these Microsoft settings before starting sign-in.";if(!xe&&!Ce.clientId&&!me)return T.setupMessage}if(n.provider==="macos_local"&&(r==="credentials"||r==="discovery")&&U!=="full_access")return U==="unavailable"?"This provider is only available on macOS, because Forge uses EventKit to access the host machine's calendar store.":"Grant Calendar full access for Forge on this Mac before discovering host calendars."},cr=async(r,a)=>{try{const{session:i}=await Ur(r);if(y(i),i.status==="authorized"&&i.discovery){f(i.discovery),m(null);return}if(i.status==="error"||i.status==="expired"){m(i.error??"Google sign-in did not complete. Start the guided sign-in again.");return}a!=null&&a.afterPopupClose}catch(i){m(i instanceof Error?i.message:"Forge could not confirm the Google sign-in session.")}},dr=async(r,a)=>{try{const{session:i}=await Ir(r);if(X(i),i.status==="authorized"&&i.discovery){f(i.discovery),m(null);return}if(i.status==="error"||i.status==="expired"){m(i.error??"Microsoft sign-in did not complete. Start the guided sign-in again.");return}a!=null&&a.afterPopupClose}catch(i){m(i instanceof Error?i.message:"Forge could not confirm the Microsoft sign-in session.")}},We=async()=>{var r;try{if(Fe)throw new Error(rr(Fe,h.allowedOrigins));if(!h.isReadyForPairing)throw new Error(er());m(null),_(null);const{session:a}=await Sr({label:oe("google",n.label),browserOrigin:de||void 0});if(!a.authUrl)throw new Error("Forge could not prepare the Google sign-in URL.");if(y(a),(r=M.current)==null||r.close(),M.current=window.open(a.authUrl,"forge-google-calendar-auth","popup=yes,width=520,height=720,resizable=yes,scrollbars=yes"),!M.current)throw new Error("The Google sign-in popup was blocked. Allow popups for Forge and try again.");M.current.focus()}catch(a){s(),m(a instanceof Error?a.message:"Forge could not start the Google sign-in flow.")}},Be=async()=>{var r;try{if(!O.isValid)throw new Error("Enter a valid Microsoft client ID and redirect URI before starting sign-in.");if(xe)throw new Error("Save the Microsoft settings in this guided flow before starting sign-in.");if(ee.isPending)throw new Error("Wait for Forge to finish saving the Microsoft settings before starting sign-in.");m(null),L(null),_(null);const{session:a}=await kr({label:oe("microsoft",n.label)});if(!a.authUrl)throw new Error("Forge could not prepare the Microsoft sign-in URL.");if(X(a),(r=M.current)==null||r.close(),M.current=window.open(a.authUrl,"forge-microsoft-calendar-auth","popup=yes,width=520,height=720,resizable=yes,scrollbars=yes"),!M.current)throw new Error("The Microsoft sign-in popup was blocked. Allow popups for Forge and try again.");M.current.focus()}catch(a){d(),m(a instanceof Error?a.message:"Forge could not start the Microsoft sign-in flow.")}},hr=l.useMemo(()=>[{id:"provider",eyebrow:"Connection",title:"Choose the calendar provider Forge should connect to",description:"macOS local uses EventKit to access the calendars already configured on this Mac, Apple uses autodiscovery from caldav.icloud.com, Google uses a localhost Authorization Code + PKCE flow, Exchange Online uses guided Microsoft sign-in in read-only mode, and custom CalDAV stays available for everything else.",render:(r,a)=>e.jsxs("div",{className:"grid gap-5",children:[e.jsx(D,{label:"Provider",description:"Each setup path is guided. Forge discovers calendars before anything is saved.",children:e.jsx(jr,{value:r.provider,onChange:i=>{_(null),P(null),m(null),L(null),s(),d(),a(ze(i))},options:[{value:"google",label:"Google Calendar",description:"Use Google sign-in with Authorization Code + PKCE, let Forge exchange the code on the backend, and store a per-user refresh token server-side."},{value:"apple",label:"Apple Calendar",description:"Start from https://caldav.icloud.com and autodiscover calendars with your app password."},{value:"microsoft",label:"Exchange Online",description:"Save the Microsoft app registration fields in Settings, then sign in with Microsoft and mirror selected Exchange Online calendars in read-only mode."},{value:"macos_local",label:"Calendars On This Mac",description:"Use EventKit to access the calendars already configured in Calendar.app on this host machine and avoid reconnecting those same accounts manually."},{value:"caldav",label:"Custom CalDAV",description:"Use a CalDAV base URL for Nextcloud, Fastmail, Baikal, and other compatible providers."}]})}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex items-center gap-3 text-white",children:[e.jsx(pr,{className:"size-4 text-[var(--primary)]"}),e.jsx("div",{className:"font-medium",children:"Dedicated write calendar"})]}),e.jsx("p",{className:"mt-3 text-sm leading-6 text-white/60",children:r.provider==="microsoft"?"Exchange Online is read-only for now. Forge mirrors selected calendars into Forge, but it does not publish work blocks or owned timeboxes back to Microsoft.":e.jsxs(e.Fragment,{children:["Forge writes work blocks and owned timeboxes into a dedicated calendar named"," ",e.jsx("span",{className:"font-medium text-white",children:"Forge"}),"."]})})]}),e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex items-center gap-3 text-white",children:[e.jsx(Ee,{className:"size-4 text-[var(--primary)]"}),e.jsx("div",{className:"font-medium",children:"Discovery first"})]}),e.jsx("p",{className:"mt-3 text-sm leading-6 text-white/60",children:r.provider==="google"?"Forge opens a Google sign-in popup, exchanges the authorization code on the backend, stores a per-user refresh token, and then discovers the writable calendars for that account.":r.provider==="macos_local"?"Forge asks macOS for Calendar access, discovers the host calendars grouped by account source, and replaces overlapping remote connections instead of keeping two copies.":r.provider==="microsoft"?"Forge starts a Microsoft sign-in popup, then discovers the calendars available to that account before you choose what to mirror.":"Forge discovers the actual calendar collections before you choose which ones to mirror and which one should receive owned timeboxes."})]})]}),e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.03] p-4",children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/42",children:"Setup guide"}),e.jsx("p",{className:"mt-2 text-sm leading-6 text-white/60",children:"These are the exact setup steps for the selected provider. They stay inside this guided flow so Settings can stay focused on connection health and actions."}),e.jsx("div",{className:"mt-4",children:e.jsx(Hr,{provider:r.provider,compact:!0})})]})]})},{id:"credentials",eyebrow:"Credentials",title:n.provider==="google"?"Sign in with Google":n.provider==="macos_local"?"Use the calendars already configured on this Mac":n.provider==="apple"?"Provide the Apple account email and app-specific password":n.provider==="microsoft"?"Sign in with Microsoft":"Provide the custom CalDAV base URL and credentials",description:n.provider==="google"?"Review the Google desktop OAuth client, save a local override only if you need one, then start the popup and let Forge finish the PKCE exchange on the backend.":n.provider==="macos_local"?"Forge requests Calendar access through EventKit, discovers sources from Calendar.app, then lets you choose which host calendars to mirror and where Forge should write.":n.provider==="apple"?"Apple discovery starts from https://caldav.icloud.com, so you only need the Apple ID email and app password here.":n.provider==="microsoft"?"Forge uses the Microsoft client ID, tenant, and redirect URI saved in Settings -> Calendar, then runs a guided popup sign-in.":"Forge stores the secrets securely, then discovers the available calendars before anything is saved.",render:(r,a)=>{var i;return e.jsxs("div",{className:"grid gap-4",children:[e.jsx(D,{label:"Connection label",description:"This is the readable label Forge shows in settings and the calendar health cards.",children:e.jsx(B,{value:r.label,onChange:o=>a({label:o.target.value}),placeholder:_e[r.provider].label})}),r.provider==="macos_local"?e.jsx("div",{className:"grid gap-4",children:e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-[linear-gradient(180deg,rgba(20,32,48,0.98),rgba(11,18,30,0.98))] p-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"macOS Calendar access"}),e.jsx("p",{className:"mt-2 max-w-2xl text-sm leading-6 text-white/60",children:"Forge uses EventKit to read and write the calendars already configured in Calendar.app on this Mac. Grant Calendar full access, then discover the available account sources."})]}),e.jsx(b,{className:U==="full_access"?"bg-emerald-500/16 text-emerald-100":"bg-white/[0.08] text-white/72",children:U==="full_access"?"Full access":U.replaceAll("_"," ")})]}),e.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-3",children:[e.jsxs(k,{type:"button",onClick:()=>void J.mutateAsync(),pending:J.isPending,pendingLabel:"Waiting for macOS",children:[e.jsx(Ee,{className:"size-4"}),"Request Calendar access"]}),e.jsxs(k,{type:"button",variant:"secondary",onClick:()=>void G.mutateAsync(),pending:G.isPending,pendingLabel:"Checking",children:[e.jsx(Re,{className:"size-4"}),"Check access"]}),e.jsxs(k,{type:"button",onClick:()=>void x.mutateAsync(),disabled:U!=="full_access",pending:x.isPending,pendingLabel:"Discovering",children:[e.jsx(Re,{className:"size-4"}),"Discover host calendars"]})]}),(i=C==null?void 0:C.sources)!=null&&i.length?e.jsxs("div",{className:"mt-5 grid gap-3",children:[e.jsx("div",{className:"text-sm font-medium text-white",children:"Host calendar sources"}),C.sources.map(o=>{const j=r.sourceId===o.sourceId;return e.jsxs("button",{type:"button",className:`rounded-[20px] border px-4 py-3 text-left transition ${j?"border-[var(--primary)]/40 bg-[var(--primary)]/12 text-white":"border-white/8 bg-white/[0.04] text-white/72 hover:bg-white/[0.07]"}`,onClick:()=>{a({sourceId:o.sourceId}),f({provider:"macos_local",accountLabel:o.accountLabel,serverUrl:r.serverUrl,principalUrl:null,homeUrl:null,calendars:o.calendars})},children:[e.jsx("div",{className:"font-medium",children:o.accountLabel||o.sourceTitle}),e.jsxs("div",{className:"mt-1 text-sm text-white/56",children:[o.sourceType," · ",o.calendars.length," ","calendars"]})]},o.sourceId)})]}):null]})}):r.provider==="google"?e.jsx("div",{className:"grid gap-4",children:e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-[linear-gradient(180deg,rgba(20,32,48,0.98),rgba(11,18,30,0.98))] p-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"How Google sign-in works"}),e.jsx("p",{className:"mt-2 max-w-2xl text-sm leading-6 text-white/60",children:"Start the popup from the host running Forge. Google returns to Forge on localhost, Forge completes the PKCE exchange on the backend, then Forge discovers the calendars for that account."})]}),e.jsx(b,{className:"bg-emerald-500/16 text-emerald-100",children:"Auth code + PKCE"})]}),e.jsxs("div",{className:"mt-4 rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/68",children:[e.jsxs("div",{children:["Forge runtime:"," ",e.jsx("span",{className:"font-medium text-white",children:h.appBaseUrl})]}),e.jsxs("div",{className:"break-all",children:["Redirect URI:"," ",e.jsx("span",{className:"font-medium text-white",children:h.redirectUri})]}),e.jsxs("div",{className:"break-all",children:["Redirect origin:"," ",e.jsx("span",{className:"font-medium text-white",children:Ke||"Unavailable"})]}),e.jsxs("div",{children:["Allowed local browser origins:"," ",e.jsx("span",{className:"font-medium text-white",children:h.allowedOrigins.join(", ")})]}),e.jsxs("div",{className:"break-all",children:["Detected browser origin:"," ",e.jsx("span",{className:"font-medium text-white",children:de||"Unavailable"})]})]}),e.jsx("div",{className:"mt-4 rounded-[18px] bg-white/[0.04] p-4",children:Oe?e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Google OAuth override"}),e.jsx("p",{className:"mt-2 max-w-2xl text-sm leading-6 text-white/60",children:"Save both the client ID and client secret only when this Forge install should use a different Google desktop OAuth app than the packaged default."})]}),e.jsx("button",{type:"button","aria-label":"Done editing Google OAuth client",className:"inline-flex size-9 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.06] text-white/72 transition hover:bg-white/[0.12] hover:text-white",onClick:()=>{F(null);const o=Ie(h);K(o),ne(!1)},children:e.jsx(Pe,{className:"size-4"})})]}),e.jsxs(D,{label:"Client ID",description:"Override the packaged Google desktop-app client ID for this Forge install.",children:[e.jsx(B,{"aria-label":"Client ID",value:I.clientId,onChange:o=>{F(null),K({...I,clientId:o.target.value})},placeholder:"1234567890-abcdef.apps.googleusercontent.com"}),W.issues.clientId?e.jsx("p",{className:"mt-2 text-sm text-rose-200",children:W.issues.clientId}):null]}),e.jsxs(D,{label:"Client secret",description:"Override the packaged Google desktop-app client secret for this Forge install.",children:[e.jsx(B,{"aria-label":"Client secret",value:I.clientSecret,onChange:o=>{F(null),K({...I,clientSecret:o.target.value})},placeholder:"GOCSPX-..."}),W.issues.clientSecret?e.jsx("p",{className:"mt-2 text-sm text-rose-200",children:W.issues.clientSecret}):null]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx(k,{type:"button",onClick:()=>void $.mutateAsync(I),disabled:!te||!W.isValid,pending:$.isPending,pendingLabel:"Saving",children:"Save Google OAuth override"}),e.jsx(k,{type:"button",variant:"secondary",onClick:()=>{F(null),K({clientId:"",clientSecret:""})},disabled:$.isPending||!z.clientId&&!z.clientSecret&&I.clientId.length===0&&I.clientSecret.length===0,children:z.clientId||z.clientSecret?"Clear override":"Use packaged default"})]})]}):e.jsxs("div",{className:"grid gap-3",children:[e.jsx("div",{className:"grid min-w-0 gap-3",children:e.jsxs("div",{className:"flex min-w-0 items-center justify-between gap-3",children:[e.jsx("div",{className:"min-w-0 flex-1",children:e.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[e.jsx("span",{className:"truncate font-medium text-white",children:"Google OAuth client"}),e.jsx(b,{className:h.storedClientId||h.storedClientSecret?"bg-emerald-500/16 text-emerald-100":"bg-white/[0.08] text-white/72",children:h.storedClientId||h.storedClientSecret?"Stored on server":"Using packaged default"}),e.jsx(Fr,{content:"Forge ships with a packaged Google desktop OAuth client by default. Save both fields only when this Forge install should use a different client ID and client secret pair.",label:"Explain Google OAuth client",className:"shrink-0"})]})}),e.jsx("button",{type:"button","aria-label":"Edit Google OAuth client",className:"inline-flex size-9 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.06] text-white/72 transition hover:bg-white/[0.12] hover:text-white",onClick:()=>{F(null),ne(!0)},children:e.jsx(mr,{className:"size-4"})})]})}),e.jsx(D,{label:"Effective client ID",description:"This is the Google desktop-app client ID Forge will use right now.",children:e.jsx("div",{className:"flex min-h-11 min-w-0 items-center overflow-hidden rounded-[18px] border border-white/8 bg-black/20 px-4 text-sm text-white/38",children:e.jsx("span",{className:"block min-w-0 truncate",title:h.clientId,children:h.clientId})})}),e.jsx(D,{label:"Effective client secret",description:"Forge uses this value on the local backend when exchanging and refreshing Google tokens.",children:e.jsx("div",{className:"flex min-h-11 min-w-0 items-center overflow-hidden rounded-[18px] border border-white/8 bg-black/20 px-4 text-sm text-white/38",children:e.jsx("span",{className:"block min-w-0 truncate",title:h.clientSecret||"",children:h.clientSecret||""})})})]})}),Z?e.jsx("div",{className:"mt-4 rounded-[18px] border border-white/10 bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/72",children:Z}):null,e.jsx("div",{className:"mt-4 rounded-[18px] border border-sky-400/20 bg-sky-400/10 px-4 py-3 text-sm leading-6 text-sky-50",children:"If you open Forge on a phone or another remote route, Google redirects to localhost on that other device instead of back to Forge."}),e.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-3",children:[e.jsxs(k,{type:"button",onClick:()=>void We(),disabled:!h.isReadyForPairing||!Ae||te||$.isPending,pending:(g==null?void 0:g.status)==="pending",pendingLabel:"Waiting for Google",children:[e.jsx(be,{className:"size-4"}),(g==null?void 0:g.status)==="authorized"?"Sign in again":"Sign in with Google"]}),g!=null&&g.accountLabel?e.jsxs(b,{className:"bg-emerald-500/16 text-emerald-100",children:[e.jsx(Pe,{className:"mr-1 size-3.5"}),g.accountLabel]}):null]})]})}):r.provider==="microsoft"?e.jsx("div",{className:"grid gap-4",children:e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-[linear-gradient(180deg,rgba(20,32,48,0.98),rgba(11,18,30,0.98))] p-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Guided Microsoft setup"}),e.jsx("p",{className:"mt-2 max-w-2xl text-sm leading-6 text-white/60",children:"Save the Microsoft app registration details for this Forge instance here, optionally test them, then continue into the Microsoft sign-in popup. Exchange Online stays read-only for now."})]}),e.jsx(b,{className:"bg-sky-400/12 text-sky-100",children:"Read only"})]}),e.jsxs("div",{className:"mt-4 grid gap-4 md:grid-cols-2",children:[e.jsxs(D,{label:"Microsoft client ID",description:"Use the Application (client) ID from the Microsoft Entra app registration for this Forge instance.",children:[e.jsx(B,{value:S.clientId,onChange:o=>{L(null),ce(j=>({...j,clientId:o.target.value}))},placeholder:"00000000-0000-0000-0000-000000000000"}),O.issues.clientId?e.jsx("div",{className:"text-sm text-rose-300",children:O.issues.clientId}):null]}),e.jsx(D,{label:"Tenant / authority",description:"Use common unless you need a tenant-specific authority.",children:e.jsx(B,{value:S.tenantId,onChange:o=>{L(null),ce(j=>({...j,tenantId:o.target.value}))},placeholder:"common"})})]}),e.jsxs(D,{label:"Redirect URI",description:"Register this exact Forge callback URI in the Microsoft app registration.",children:[e.jsx(B,{value:S.redirectUri,onChange:o=>{L(null),ce(j=>({...j,redirectUri:o.target.value}))},placeholder:"http://127.0.0.1:4317/api/v1/calendar/oauth/microsoft/callback"}),O.issues.redirectUri?e.jsx("div",{className:"text-sm text-rose-300",children:O.issues.redirectUri}):null]}),e.jsx("div",{className:"mt-4 rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/68",children:"Forge saves the client ID, tenant, and redirect URI for this local instance, then handles Microsoft sign-in in a popup."}),e.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-3",children:[e.jsx(k,{type:"button",onClick:()=>void ee.mutateAsync(S),disabled:!O.isValid,pending:ee.isPending,pendingLabel:"Saving",children:"Save Microsoft settings"}),e.jsx(k,{type:"button",variant:"secondary",onClick:()=>void re.mutateAsync(S),disabled:!O.isValid,pending:re.isPending,pendingLabel:"Testing",children:"Test Microsoft configuration"}),e.jsxs(k,{type:"button",onClick:()=>void Be(),disabled:!O.isValid||xe||ee.isPending,pending:(u==null?void 0:u.status)==="pending",pendingLabel:"Waiting for Microsoft",children:[e.jsx(be,{className:"size-4"}),(u==null?void 0:u.status)==="authorized"?"Sign in again":"Sign in with Microsoft"]}),u!=null&&u.accountLabel?e.jsxs(b,{className:"bg-emerald-500/16 text-emerald-100",children:[e.jsx(Pe,{className:"mr-1 size-3.5"}),u.accountLabel]}):null]}),e.jsxs("div",{className:"mt-4 grid gap-3 md:grid-cols-2",children:[e.jsx("div",{className:"rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/68",children:"Save before sign-in. The Microsoft popup always uses the latest saved client ID, tenant, and redirect URI."}),e.jsx("div",{className:"rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/68",children:"After sign-in, Forge will let you choose which Exchange Online calendars to mirror into the Calendar page."})]}),me?e.jsx("div",{className:"mt-4 rounded-[18px] border border-white/10 bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/72",children:me}):null]})}):e.jsxs(e.Fragment,{children:[r.provider==="caldav"?e.jsx(D,{label:"CalDAV base URL",description:"Use the account-level CalDAV server URL, not an individual calendar collection URL.",children:e.jsx(B,{value:r.serverUrl,onChange:o=>a({serverUrl:o.target.value}),placeholder:"https://caldav.example.com"})}):null,r.provider==="apple"?e.jsx(D,{label:"Apple CalDAV base URL",children:e.jsx(B,{value:"https://caldav.icloud.com",disabled:!0})}):null,e.jsx(D,{label:"Account email or username",children:e.jsx(B,{value:r.username,onChange:o=>a({username:o.target.value}),placeholder:"operator@example.com"})}),e.jsx(D,{label:r.provider==="apple"?"App-specific password":"Password or app password",children:e.jsx(B,{type:"password",value:r.password,onChange:o=>a({password:o.target.value}),placeholder:"Password"})})]})]})}},{id:"discovery",eyebrow:"Discovery",title:"Discover the calendars and choose what Forge should sync",description:n.provider==="microsoft"?"Select the Exchange Online calendars Forge should mirror into the Calendar page. This connection stays read-only for now.":n.provider==="macos_local"?E?`Select the host-machine calendars Forge should mirror into the Calendar page. Forge already writes work blocks and timeboxes through ${E}.`:"Select the host-machine calendars Forge should mirror into the Calendar page, then choose the host calendar Forge should write into for work blocks and timeboxes.":E?`Select the calendars Forge should mirror into the Calendar page. Forge already writes work blocks and timeboxes through ${E}.`:"Select the calendars Forge should mirror into the Calendar page, then choose the calendar Forge should write into for work blocks and timeboxes.",render:(r,a)=>e.jsxs("div",{className:"grid gap-4",children:[r.provider==="google"?e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(k,{type:"button",onClick:()=>void We(),disabled:!h.isReadyForPairing||!Ae,pending:(g==null?void 0:g.status)==="pending",pendingLabel:"Waiting for Google",children:[e.jsx(be,{className:"size-4"}),(g==null?void 0:g.status)==="authorized"?"Reconnect Google":"Sign in with Google"]}),v?e.jsxs(b,{className:"bg-white/[0.08] text-white/74",children:[v.calendars.length," discovered"]}):null]}):r.provider==="microsoft"?e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(k,{type:"button",onClick:()=>void Be(),disabled:!O.isValid||xe||ee.isPending,pending:(u==null?void 0:u.status)==="pending",pendingLabel:"Waiting for Microsoft",children:[e.jsx(be,{className:"size-4"}),(u==null?void 0:u.status)==="authorized"?"Reconnect Microsoft":"Sign in with Microsoft"]}),v?e.jsxs(b,{className:"bg-white/[0.08] text-white/74",children:[v.calendars.length," discovered"]}):null]}):e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(k,{pending:x.isPending,pendingLabel:"Discovering",onClick:()=>void x.mutateAsync(),disabled:r.provider==="macos_local"&&U!=="full_access",children:[e.jsx(Re,{className:"size-4"}),r.provider==="macos_local"?"Discover host calendars":"Discover calendars"]}),v?e.jsxs(b,{className:"bg-white/[0.08] text-white/74",children:[v.calendars.length," discovered"]}):null]}),v?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.04] p-4 text-sm leading-6 text-white/64",children:[r.provider==="macos_local"?"Discovered through the host calendar store":"Discovered through"," ",e.jsx("span",{className:"font-medium text-white",children:v.serverUrl}),v.homeUrl?e.jsxs(e.Fragment,{children:[" ","· home set"," ",e.jsx("span",{className:"font-medium text-white",children:v.homeUrl})]}):null]}),r.provider!=="microsoft"&&E?e.jsxs("div",{className:"rounded-[24px] border border-emerald-400/20 bg-emerald-400/10 p-4 text-sm leading-6 text-emerald-50",children:["Forge already writes work blocks and owned timeboxes through"," ",e.jsx("span",{className:"font-medium text-white",children:E}),". This connection only needs a mirror selection."]}):null,e.jsx("div",{className:"grid gap-3",children:v.calendars.map(i=>{const o=r.selectedCalendarUrls.includes(i.url),j=r.forgeCalendarUrl===i.url;return e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:De(i)}),e.jsxs("div",{className:"mt-1 text-sm text-white/56",children:[i.timezone||"No timezone exposed"," ·"," ",i.url]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[i.isForgeCandidate?e.jsx(b,{className:"bg-[var(--primary)]/14 text-[var(--primary)]",children:"Forge match"}):null,i.isPrimary?e.jsx(b,{className:"bg-white/[0.08] text-white/74",children:"Primary"}):null]})]}),e.jsxs("div",{className:"mt-4 flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:()=>a({selectedCalendarUrls:o?r.selectedCalendarUrls.filter(se=>se!==i.url):[...r.selectedCalendarUrls,i.url]}),className:`rounded-full px-3 py-2 text-sm transition ${o?"bg-[var(--primary)]/18 text-[var(--primary)] shadow-[inset_0_0_0_1px_rgba(192,193,255,0.24)]":"bg-white/[0.05] text-white/62 hover:bg-white/[0.08]"}`,children:o?"Mirrored":"Mirror into Forge"}),r.provider!=="microsoft"&&!E?e.jsx("button",{type:"button",onClick:()=>a({forgeCalendarUrl:i.url,createForgeCalendar:!1}),className:`rounded-full px-3 py-2 text-sm transition ${j?"bg-emerald-500/18 text-emerald-100 shadow-[inset_0_0_0_1px_rgba(16,185,129,0.28)]":"bg-white/[0.05] text-white/62 hover:bg-white/[0.08]"}`,children:j?"Forge writes here":"Use for Forge writes"}):e.jsx(b,{className:r.provider==="microsoft"?"bg-sky-400/12 text-sky-100":"bg-white/[0.08] text-white/74",children:r.provider==="microsoft"?"Read only":"Shared target elsewhere"})]})]},i.url)})}),r.provider!=="microsoft"&&!E?e.jsxs("div",{className:"rounded-[24px] border border-dashed border-white/10 bg-white/[0.03] p-4",children:[e.jsx("div",{className:"font-medium text-white",children:"No Forge calendar yet?"}),e.jsxs("p",{className:"mt-2 text-sm leading-6 text-white/60",children:["If none of the discovered calendars should receive Forge-owned work blocks and timeboxes, let Forge create a dedicated calendar named"," ",e.jsx("span",{className:"font-medium text-white",children:"Forge"}),"."]}),e.jsx("div",{className:"mt-4",children:e.jsx("button",{type:"button",onClick:()=>a({forgeCalendarUrl:null,createForgeCalendar:!r.createForgeCalendar}),className:`rounded-full px-3 py-2 text-sm transition ${r.createForgeCalendar?"bg-emerald-500/18 text-emerald-100 shadow-[inset_0_0_0_1px_rgba(16,185,129,0.28)]":"bg-white/[0.05] text-white/62 hover:bg-white/[0.08]"}`,children:r.createForgeCalendar?"Forge will create one":"Create a new Forge calendar"})})]}):r.provider==="microsoft"?e.jsx("div",{className:"rounded-[24px] border border-sky-400/20 bg-sky-400/10 p-4 text-sm leading-6 text-sky-50",children:"Exchange Online is connected through Microsoft Graph in read-only mode. Forge will mirror the calendars you select here, but it will keep work blocks and owned timeboxes local or publish them through another writable provider."}):e.jsxs("div",{className:"rounded-[24px] border border-dashed border-white/10 bg-white/[0.03] p-4 text-sm leading-6 text-white/60",children:["Forge will keep"," ",e.jsx("span",{className:"font-medium text-white",children:E})," ","as the canonical write target instead of creating another Forge calendar on this connection."]})]}):e.jsx("div",{className:"rounded-[24px] border border-dashed border-white/10 bg-white/[0.03] px-4 py-6 text-sm leading-6 text-white/58",children:r.provider==="google"?e.jsx(e.Fragment,{children:"Start the guided Google sign-in first. Forge will bring the discovered Google calendars back here as soon as the popup completes."}):r.provider==="microsoft"?e.jsx(e.Fragment,{children:"Start the guided Microsoft sign-in first. Forge will bring the discovered Exchange Online calendars back here as soon as the popup completes."}):e.jsx(e.Fragment,{children:r.provider==="macos_local"?"Grant macOS Calendar access and discover the host calendars first. If Calendar.app already aggregates Google, Exchange, or iCloud for this Mac, Forge will pick them up here without reconnecting those accounts.":e.jsxs(e.Fragment,{children:["Discover calendars after entering the credentials. For Apple, Forge starts from"," ",e.jsx("span",{className:"font-medium text-white",children:"https://caldav.icloud.com"})," ","and resolves the principal plus calendar home automatically."]})})})]})},{id:"review",eyebrow:"Review",title:"Confirm what Forge will mirror and where it will write",description:"This keeps the sync model explicit before the provider connection is saved.",render:r=>{var a,i;return e.jsxs("div",{className:"grid gap-4",children:[r.provider==="macos_local"&&r.sourceId?e.jsxs("div",{className:"rounded-[20px] border border-white/8 bg-white/[0.04] px-4 py-3 text-sm leading-6 text-white/70",children:["Selected host source:"," ",e.jsx("span",{className:"font-medium text-white",children:((a=C==null?void 0:C.sources.find(o=>o.sourceId===r.sourceId))==null?void 0:a.accountLabel)??((i=C==null?void 0:C.sources.find(o=>o.sourceId===r.sourceId))==null?void 0:i.sourceTitle)??r.sourceId})]}):null,e.jsxs("div",{className:"rounded-[26px] border border-white/8 bg-[linear-gradient(180deg,rgba(21,31,42,0.96),rgba(10,16,26,0.96))] p-5",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(Me,{className:"size-4"})}),e.jsxs("div",{children:[e.jsx("div",{className:"font-display text-xl text-white",children:oe(r.provider,r.label)}),e.jsx("div",{className:"mt-1 text-sm text-white/58",children:r.provider==="google"?"Google Calendar":r.provider==="macos_local"?"Calendars On This Mac":r.provider==="apple"?"Apple Calendar":r.provider==="microsoft"?"Exchange Online":"Custom CalDAV"})]})]}),e.jsxs("div",{className:"mt-4 grid gap-3 md:grid-cols-2",children:[e.jsxs("div",{className:"rounded-[20px] bg-white/[0.04] px-4 py-3 text-sm text-white/72",children:["Mirrored calendars:"," ",e.jsx("span",{className:"font-medium text-white",children:r.selectedCalendarUrls.length})]}),e.jsxs("div",{className:"rounded-[20px] bg-white/[0.04] px-4 py-3 text-sm text-white/72",children:["Forge writes:"," ",e.jsx("span",{className:"font-medium text-white",children:r.provider==="microsoft"?"read only":r.forgeCalendarUrl?"existing calendar":r.createForgeCalendar?"new Forge calendar":E?`shared target via ${E}`:"not selected"})]})]}),r.replaceConnectionIds.length>0?e.jsxs("div",{className:"mt-4 rounded-[20px] border border-amber-400/20 bg-amber-400/10 px-4 py-3 text-sm leading-6 text-amber-50",children:["Forge will replace ",r.replaceConnectionIds.length," older overlapping connection",r.replaceConnectionIds.length===1?"":"s"," for this same calendar account so only one visible copy remains.",ge.filter(o=>r.replaceConnectionIds.includes(o.id)).map(o=>o.label).join(", ")?` ${ge.filter(o=>r.replaceConnectionIds.includes(o.id)).map(o=>o.label).join(", ")}.`:""]}):null]})]})}}],[v,x.isPending,n.provider,Oe,I,g,h.clientId,Z,h.allowedOrigins,h.appBaseUrl,h.isLocalOnly,h.isReadyForPairing,h.redirectUri,Ke,te,Ae,Fe,xe,S,T.setupMessage,me,O,$.isPending,ee.isPending,Ce,re.isPending,T.isReadyForSignIn,T.redirectUri,C,u,R,E]),gr=n.provider==="macos_local"&&n.replaceConnectionIds.length>0?"Replace and connect":"Connect provider";return e.jsx($e,{open:t,onOpenChange:c,eyebrow:"Calendar settings",title:"Connect a calendar provider",description:"Discover provider calendars first, choose which calendars Forge should mirror, and only choose a Forge write target when the runtime does not already have one.",value:n,onChange:r=>{V(r),v&&r.provider!==v.provider&&_(null),r.provider!=="macos_local"&&P(null)},draftPersistenceKey:"calendar.connection.new",steps:hr,submitLabel:gr,pending:N,pendingLabel:"Connecting",error:ye,resolveError:lr,initialStepId:w,onSubmit:async()=>{try{if(m(null),!v){m("Discover the available calendars before saving the connection.");return}if(n.selectedCalendarUrls.length===0){m("Select at least one calendar to mirror into Forge.");return}if(n.provider!=="microsoft"&&!n.forgeCalendarUrl&&!n.createForgeCalendar&&!R){m("Choose the calendar Forge should write into, ask Forge to create one, or keep using the existing shared Forge write target.");return}if(n.provider==="google"){if(!(g!=null&&g.sessionId)||g.status!=="authorized"){m("Complete the Google sign-in flow before saving this connection.");return}await Y({provider:"google",label:oe("google",n.label),authSessionId:g.sessionId,selectedCalendarUrls:n.selectedCalendarUrls,forgeCalendarUrl:n.forgeCalendarUrl,createForgeCalendar:n.createForgeCalendar})}else if(n.provider==="apple")await Y({provider:"apple",label:oe("apple",n.label),username:n.username.trim(),password:n.password.trim(),selectedCalendarUrls:n.selectedCalendarUrls,forgeCalendarUrl:n.forgeCalendarUrl,createForgeCalendar:n.createForgeCalendar});else if(n.provider==="microsoft"){if(!(u!=null&&u.sessionId)||u.status!=="authorized"){m("Complete the Microsoft sign-in flow before saving this connection.");return}await Y({provider:"microsoft",label:oe("microsoft",n.label),authSessionId:u.sessionId,selectedCalendarUrls:n.selectedCalendarUrls})}else if(n.provider==="macos_local"){if(!n.sourceId){m("Choose which host calendar source Forge should connect before saving.");return}await Y({provider:"macos_local",label:oe("macos_local",n.label),sourceId:n.sourceId,selectedCalendarUrls:n.selectedCalendarUrls,forgeCalendarUrl:n.forgeCalendarUrl,createForgeCalendar:n.createForgeCalendar,replaceConnectionIds:n.replaceConnectionIds})}else await Y({provider:"caldav",label:oe("caldav",n.label),serverUrl:n.serverUrl.trim(),username:n.username.trim(),password:n.password.trim(),selectedCalendarUrls:n.selectedCalendarUrls,forgeCalendarUrl:n.forgeCalendarUrl,createForgeCalendar:n.createForgeCalendar});c(!1)}catch(r){if(r instanceof Nr&&r.code==="calendar_connection_overlap"){const a=r.response,i=Array.isArray(a==null?void 0:a.overlappingConnectionIds)?a==null?void 0:a.overlappingConnectionIds.filter(o=>typeof o=="string"):[];V(o=>({...o,replaceConnectionIds:i})),m(`${r.message} Submit again to replace the older overlapping connection${i.length===1?"":"s"}.`);return}m(r instanceof Error?r.message:"Forge could not create this calendar connection.")}}})}function ve(t){try{const c=new URL(t);return c.pathname.endsWith("/")||(c.pathname=`${c.pathname}/`),c.toString()}catch{return t}}function tr(t){switch(t){case"google":return"Google Calendar";case"apple":return"Apple Calendar";case"microsoft":return"Exchange Online";case"macos_local":return"Calendars On This Mac";case"caldav":default:return"Custom CalDAV"}}function nt(t){switch(t){case"google":return"Open Google guided flow";case"microsoft":return"Open Microsoft guided flow";case"macos_local":return"Open Mac calendar flow";default:return"Open guided setup"}}function it(t){switch(t){case"google":case"microsoft":return Ee;case"macos_local":return Te;case"apple":return Te;case"caldav":default:return Me}}function ot(t){switch(t){case"microsoft":return"Read only";case"macos_local":return"Read + write";default:return"Read + write"}}function lt(t){switch(t){case"google":return"Local PKCE";case"microsoft":return"Guided sign-in";case"macos_local":return"Host machine";case"apple":return"App password";case"caldav":default:return"CalDAV credentials"}}function ct(t){switch(t){case"google":return"Sign in from the same machine running Forge. After connection, Forge can mirror the calendars you choose and reuse the current shared Forge write target, creating one only when the runtime does not already have one.";case"apple":return"Use your Apple ID email and app-specific password. Forge discovers your iCloud calendars before you choose what to mirror.";case"microsoft":return"Use the guided Microsoft sign-in flow. Forge mirrors the Exchange calendars you choose and keeps this provider read only.";case"macos_local":return"Use the calendars already configured in Calendar.app on this Mac. Forge requests Calendar access through macOS, discovers host calendars by account source, and replaces overlapping remote account connections instead of duplicating them.";case"caldav":default:return"Enter a CalDAV server URL and account credentials. Forge discovers the calendars on that account before you choose what to mirror."}}function sr(t){return`${t} connection${t===1?"":"s"}`}function yt(){var M,fe,R,E,je;const t=ar(),[c,p]=fr(),[w,A]=l.useState(!1),[q,H]=l.useState("google"),[ge,Y]=l.useState(void 0),[N,we]=l.useState(null),[n,V]=l.useState([]),[ye,m]=l.useState(!1),[v,_]=l.useState(null),[U,ae]=l.useState(()=>Vr()),C=Ue({queryKey:["forge-operator-session"],queryFn:Dr}),P=C.isSuccess,g=Ue({queryKey:["forge-settings"],queryFn:_r,enabled:P}),y=Ue({queryKey:["forge-calendar-connections"],queryFn:Pr,enabled:P}),u=Ue({queryKey:["forge-calendar-resources"],queryFn:zr,enabled:P}),X=async()=>{await Promise.all([t.invalidateQueries({queryKey:["forge-settings"]}),t.invalidateQueries({queryKey:["forge-calendar-connections"]}),t.invalidateQueries({queryKey:["forge-calendar-resources"]}),t.invalidateQueries({queryKey:["forge-calendar-overview"]}),Gr(t)])},h=Q({mutationFn:Mr,onSuccess:X}),ue=Q({mutationFn:s=>Er(s),onSuccess:X}),I=Q({mutationFn:({connectionId:s,patch:d})=>Or(s,d),onSuccess:X}),K=Q({mutationFn:s=>Ar(s),onSuccess:X});l.useEffect(()=>{if(!P)return;const s=c.get("intent"),d=c.get("provider");if(s!=="connect")return;H(d==="apple"||d==="caldav"||d==="google"||d==="microsoft"||d==="macos_local"?d:"google"),Y(d==="microsoft"?"credentials":void 0),A(!0);const f=new URLSearchParams(c);f.delete("intent"),f.delete("provider"),p(f,{replace:!0})},[P,c,p]);const z=l.useMemo(()=>{var s,d;return Lr(((s=u.data)==null?void 0:s.calendars)??[],((d=y.data)==null?void 0:d.connections)??[])},[(M=u.data)==null?void 0:M.calendars,(fe=y.data)==null?void 0:fe.connections]),le=l.useMemo(()=>{const s=new Map;for(const d of z){const f=s.get(d.connectionId)??[];f.push(d),s.set(d.connectionId,f)}return s},[z]),Oe=l.useMemo(()=>{var d;const s={};for(const f of((d=y.data)==null?void 0:d.connections)??[])s[f.provider]=(s[f.provider]??0)+1;return s},[(R=y.data)==null?void 0:R.connections]),ne=l.useMemo(()=>Kr(z,U.calendarColors),[z,U.calendarColors]),Z=l.useMemo(()=>{var s;return(((s=y.data)==null?void 0:s.connections)??[]).find(d=>{var f;return typeof((f=d.config)==null?void 0:f.forgeCalendarUrl)=="string"&&d.config.forgeCalendarUrl.trim().length>0})??null},[(E=y.data)==null?void 0:E.connections]),F=l.useMemo(()=>{var s;return((s=y.data)==null?void 0:s.connections.find(d=>d.id===N))??null},[y.data,N]),T=l.useMemo(()=>{var s;return((s=y.data)==null?void 0:s.connections.find(d=>d.id===v))??null},[y.data,v]),pe=l.useMemo(()=>N?le.get(N)??[]:[],[le,N]),S=Ue({queryKey:["forge-calendar-connection-discovery",N],queryFn:()=>Tr(N),enabled:P&&N!==null});l.useEffect(()=>{if(!N){V([]),m(!1);return}const s=pe.filter(d=>d.selectedForSync).map(d=>ve(d.remoteId));V(s),m(!0)},[N,pe]),l.useEffect(()=>{Wr(U)},[U]);const ce=l.useMemo(()=>[{id:"mirrors",eyebrow:"Mirroring",title:"Choose which calendars Forge should mirror",description:"Unselected calendars stop showing up in Forge’s mirrored calendar views. The Forge write calendar stays available for work blocks and timeboxes.",render:(s,d)=>{var J,ee;if(S.isLoading)return e.jsx("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.03] px-4 py-6 text-sm leading-6 text-white/58",children:"Rediscovering calendars for this connection."});if(S.isError||!((J=S.data)!=null&&J.discovery))return e.jsx("div",{className:"rounded-[24px] border border-rose-400/20 bg-rose-400/10 px-4 py-6 text-sm leading-6 text-rose-100",children:S.error instanceof Error?S.error.message:"Forge could not rediscover calendars for this connection."});const f=S.data.discovery,x=(F==null?void 0:F.provider)==="microsoft",G=typeof((ee=F==null?void 0:F.config)==null?void 0:ee.forgeCalendarUrl)=="string"?ve(F.config.forgeCalendarUrl):null;return e.jsx("div",{className:"grid gap-3",children:f.calendars.map($=>{const re=ve($.url),O=ye?s.selectedCalendarUrls.includes(re):pe.some(te=>te.selectedForSync&&ve(te.remoteId)===re),W=G===re;return e.jsxs("div",{className:"rounded-[24px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:De($)}),e.jsxs("div",{className:"mt-1 text-sm text-white/56",children:[$.timezone||"No timezone exposed"," ·"," ",$.url]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[W&&!x?e.jsx(b,{className:"bg-[var(--primary)]/14 text-[var(--primary)]",children:"Forge writes here"}):null,x?e.jsx(b,{className:"bg-sky-400/12 text-sky-100",children:"Read only"}):null,$.isPrimary?e.jsx(b,{className:"bg-white/[0.08] text-white/74",children:"Primary"}):null]})]}),e.jsx("div",{className:"mt-4 flex flex-wrap gap-2",children:e.jsx("button",{type:"button",disabled:W&&!x,onClick:()=>d({selectedCalendarUrls:O?s.selectedCalendarUrls.filter(te=>te!==re):[...s.selectedCalendarUrls,re]}),className:`rounded-full px-3 py-2 text-sm transition ${W&&!x?"cursor-not-allowed bg-white/[0.05] text-white/35":O?"bg-emerald-500/18 text-emerald-100 shadow-[inset_0_0_0_1px_rgba(16,185,129,0.28)]":"bg-white/[0.05] text-white/62 hover:bg-white/[0.08]"}`,children:W&&!x?"Always available for Forge writes":O?"Mirrored into Forge":"Do not mirror"})})]},$.url)})})}}],[F,S]);if(C.isLoading||g.isLoading||y.isLoading||u.isLoading)return e.jsx(Rr,{eyebrow:"Settings · Calendar",title:"Loading calendar settings",description:"Checking the operator session and loading provider connections.",columns:2,blocks:6});if(C.isError)return e.jsx(Ye,{eyebrow:"Settings · Calendar",error:C.error,onRetry:()=>void C.refetch()});if(g.isError||y.isError||u.isError||!((je=g.data)!=null&&je.settings)||!y.data||!u.data)return e.jsx(Ye,{eyebrow:"Settings · Calendar",error:g.error??y.error??u.error??new Error("Calendar settings are unavailable."),onRetry:()=>{g.refetch(),y.refetch(),u.refetch()}});const{providers:Ce,connections:ie}=y.data,me=g.data.settings.calendarProviders.google,L=g.data.settings.calendarProviders.microsoft;return e.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[e.jsx(qr,{title:"Calendar settings",description:"Manage provider connections, review the shared Forge write target, and open guided setup only when you need to connect or reconfigure a provider.",badge:`${ie.length} connection${ie.length===1?"":"s"}`}),e.jsx($r,{}),e.jsxs("div",{className:"grid gap-5",children:[e.jsxs(Ge,{className:"surface-section-panel grid gap-5 rounded-[30px] border",children:[e.jsxs("div",{className:"max-w-3xl",children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Provider connections"}),e.jsxs("p",{className:"mt-2 text-sm leading-6 text-white/60",children:["Connect a provider here, then choose which calendars Forge should mirror. Writable providers publish work blocks and owned timeboxes through one shared"," ",e.jsx("span",{className:"font-medium text-white",children:"Forge"})," write target, creating it only when the runtime does not already have one."]})]}),e.jsx("div",{className:"grid gap-4 lg:grid-cols-2",children:Ce.map(s=>{const d=it(s.provider),f=Oe[s.provider]??0,x=f>0;return e.jsxs("div",{className:`flex min-h-[248px] flex-col rounded-[26px] border p-5 shadow-[inset_0_1px_0_var(--ui-border-subtle)] ${x?"border-emerald-400/24 bg-[linear-gradient(180deg,color-mix(in_srgb,#10b981_18%,var(--surface-panel)_82%),var(--ui-surface-2))]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)]"}`,children:[e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:`rounded-[18px] p-3 ${x?"bg-emerald-400/16 text-emerald-100":"bg-[var(--primary)]/14 text-[var(--primary)]"}`,children:e.jsx(d,{className:"size-4"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:s.label}),x?e.jsxs(e.Fragment,{children:[e.jsx(b,{className:"bg-emerald-400/16 text-emerald-50",children:"Connected"}),e.jsx(b,{className:"bg-white/[0.08] text-white/82",children:sr(f)})]}):null]}),e.jsx("p",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:ct(s.provider)}),x?e.jsxs("div",{className:"mt-3 text-sm text-emerald-100/88",children:["Forge already has"," ",sr(f)," for this provider. Open the guided flow again to add another account or reconfigure one."]}):null]})]}),e.jsxs("div",{className:"mt-5 flex flex-wrap gap-2",children:[e.jsx(b,{tone:"signal",className:"bg-[var(--primary)]/14 text-white/86",children:lt(s.provider)}),e.jsx(b,{className:s.supportsDedicatedForgeCalendar?"bg-emerald-500/16 text-emerald-100":"bg-sky-400/14 text-sky-100",children:ot(s.provider)})]}),e.jsx("div",{className:"mt-auto pt-5",children:e.jsxs(k,{variant:"secondary",className:"w-full justify-center",onClick:()=>{H(s.provider),Y(s.provider==="google"||s.provider==="microsoft"?"credentials":void 0),A(!0)},children:[e.jsx(be,{className:"size-4"}),nt(s.provider)]})})]},s.provider)})})]}),e.jsxs(Ge,{className:"surface-section-panel grid gap-4 rounded-[30px] border",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Calendar colors"}),e.jsx("p",{className:"mt-2 max-w-3xl text-sm leading-6 text-white/60",children:"Calendar colors are on by default so each mirrored calendar stays legible in the week view. Adjust any display color here without changing the provider itself."})]}),e.jsx("button",{type:"button",onClick:()=>ae(s=>({...s,useCalendarColors:!s.useCalendarColors})),className:`rounded-full px-4 py-2 text-sm transition ${U.useCalendarColors?"bg-[var(--ui-accent-soft)] text-[var(--primary)] shadow-[inset_0_0_0_1px_rgba(192,193,255,0.2)]":"border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] text-[var(--ui-ink-soft)] hover:bg-[var(--ui-surface-hover)]"}`,children:U.useCalendarColors?"Colors on":"Colors off"})]}),z.length>0?e.jsx("div",{className:"grid gap-3",children:z.map(s=>{const d=De(s);return e.jsxs("div",{className:"grid gap-3 rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4 md:grid-cols-[minmax(0,1fr)_auto]",children:[e.jsx("div",{className:"min-w-0",children:e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx("span",{"aria-hidden":"true",className:"size-3 shrink-0 rounded-full",style:{backgroundColor:ne[s.id]}}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate font-medium text-[var(--ui-ink-strong)]",children:d}),e.jsxs("div",{className:"mt-1 text-sm text-[var(--ui-ink-soft)]",children:[s.canWrite?"Writable":"Read only"," ·"," ",s.timezone]})]})]})}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{"aria-label":`Choose display color for ${d}`,type:"color",value:ne[s.id],onChange:f=>ae(x=>({...x,calendarColors:{...x.calendarColors,[s.id]:f.target.value}})),className:"h-10 w-12 cursor-pointer rounded-[14px] border border-[var(--ui-border-subtle)] bg-transparent p-1"}),e.jsx(k,{size:"sm",variant:"secondary",onClick:()=>ae(f=>{const x={...f.calendarColors};return delete x[s.id],{...f,calendarColors:x}}),children:"Reset palette"})]})]},s.id)})}):e.jsx("div",{className:"rounded-[24px] border border-dashed border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-5 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Connect a provider first, then Forge will let you tune the display color of each mirrored calendar here."})]}),e.jsxs(Ge,{className:"surface-section-panel grid gap-4 rounded-[30px] border",children:[e.jsx("div",{className:"flex items-center justify-between gap-3",children:e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Connected providers"}),e.jsx("p",{className:"mt-2 text-sm leading-6 text-white/60",children:"Review connection health, confirm which provider calendars Forge can read or mirror, and see which connection currently owns the shared Forge write target."})]})}),ie.length>0?e.jsx("div",{className:"grid gap-3",children:ie.map(s=>{var x;const d=le.get(s.id)??[],f=s.provider!=="microsoft"&&Z!==null&&Z.id!==s.id;return e.jsxs("div",{className:"rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:s.label}),e.jsxs("div",{className:"mt-1 text-sm text-[var(--ui-ink-soft)]",children:[tr(s.provider)," ·"," ",s.accountLabel||"No account label yet"]}),s.lastSyncedAt?e.jsxs("div",{className:"mt-2 text-sm text-[var(--ui-ink-faint)]",children:["Last synced"," ",new Date(s.lastSyncedAt).toLocaleString()]}):null,s.lastSyncError?e.jsx("div",{className:"mt-2 text-sm text-rose-200",children:s.lastSyncError}):null,f?e.jsxs("div",{className:"mt-2 text-sm text-[var(--ui-ink-soft)]",children:["Forge writes through"," ",e.jsx("span",{className:"font-medium text-[var(--ui-ink-strong)]",children:Z.label}),Z.accountLabel?` · ${Z.accountLabel}`:"","."]}):null]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(b,{className:"bg-white/[0.08] text-white/74",children:s.status}),((x=s.config)==null?void 0:x.readOnly)===!0?e.jsx(b,{className:"bg-sky-400/12 text-sky-100",children:"Read only"}):null,e.jsxs(k,{size:"sm",variant:"secondary",pending:ue.isPending&&ue.variables===s.id,pendingLabel:"Syncing",onClick:()=>void ue.mutateAsync(s.id),children:[e.jsx(Re,{className:"size-4"}),"Sync"]}),e.jsxs(k,{size:"sm",variant:"secondary",onClick:()=>{const G=(le.get(s.id)??[]).filter(J=>J.selectedForSync).map(J=>ve(J.remoteId));V(G),m(!0),we(s.id)},children:[e.jsx(xr,{className:"size-4"}),"Manage mirrored calendars"]}),e.jsxs(k,{size:"sm",variant:"secondary",onClick:()=>_(s.id),children:[e.jsx(vr,{className:"size-4"}),"Remove"]})]})]}),e.jsx("div",{className:"mt-4 grid gap-2",children:d.map(G=>e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[18px] bg-white/[0.04] px-4 py-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate text-sm font-medium text-[var(--ui-ink-strong)]",children:De(G)}),e.jsxs("div",{className:"mt-1 text-xs uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:[G.canWrite?"Writable":"Read only"," ·"," ",G.timezone]})]}),G.forgeManaged?e.jsx(b,{className:"bg-[var(--primary)]/14 text-[var(--primary)]",children:"Forge"}):e.jsxs(b,{className:"bg-white/[0.08] text-white/74",children:[e.jsx(Te,{className:"mr-1 size-3.5"}),"Mirrored"]})]},G.id))})]},s.id)})}):e.jsxs("div",{className:"rounded-[26px] border border-dashed border-white/10 bg-white/[0.03] px-5 py-6 text-sm leading-6 text-white/60",children:["No provider is connected yet. Open a guided setup flow above when you are ready. Forge will reuse one shared"," ",e.jsx("span",{className:"font-medium text-white",children:"Forge"})," write target across writable providers when it already exists, create one only when none exists yet, and mirror selected calendars in read-only mode for providers like Exchange Online."]})]})]}),e.jsx(at,{open:w,onOpenChange:s=>{A(s),s||Y(void 0)},initialProvider:q,initialStepId:ge,googleSetup:me,microsoftSetup:L,existingConnections:ie.map(s=>({id:s.id,label:s.label,provider:s.provider,status:s.status,accountLabel:s.accountLabel,forgeCalendarId:s.forgeCalendarId,config:s.config})),onCalendarSettingsChanged:X,pending:h.isPending,onSubmit:async s=>{await h.mutateAsync(s)}}),e.jsx($e,{open:N!==null,onOpenChange:s=>{s||we(null)},eyebrow:"Calendar settings",title:"Manage mirrored calendars",description:"Choose which calendars this connection should mirror into Forge.",value:{selectedCalendarUrls:n},onChange:s=>V(s.selectedCalendarUrls),draftPersistenceKey:N?`settings.calendar.manage.${N}`:"settings.calendar.manage",steps:ce,pending:I.isPending,pendingLabel:"Saving",submitLabel:"Save mirror selection",error:I.error instanceof Error?I.error.message:null,onSubmit:async()=>{N&&(await I.mutateAsync({connectionId:N,patch:{selectedCalendarUrls:n.map(ve)}}),m(!1),we(null))}}),e.jsx($e,{open:v!==null,onOpenChange:s=>{s||_(null)},eyebrow:"Calendar settings",title:"Remove calendar connection",description:"This removes the provider connection, stops syncing its calendars, removes mirrored external events from Forge, and keeps Forge-native events local.",value:{acknowledgement:!1},onChange:()=>{},draftPersistenceKey:v?`settings.calendar.remove.${v}`:"settings.calendar.remove",steps:[{id:"confirm",eyebrow:"Disconnect",title:T?`Remove ${T.label}?`:"Remove this connection?",description:"Use this when you want to disconnect the account entirely. You can reconnect later with the guided setup flow.",render:()=>e.jsx("div",{className:"rounded-[24px] border border-rose-400/20 bg-rose-400/10 p-4 text-sm leading-6 text-rose-100",children:T?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"font-medium text-white",children:[tr(T.provider)," ·"," ",T.accountLabel||"No account label"]}),e.jsx("div",{className:"mt-2",children:"Mirrored provider calendars and external mirrored events from this connection will be removed. Forge-owned events, work blocks, and timeboxes remain in Forge."})]}):"This connection will be removed from Forge."})}],pending:K.isPending,pendingLabel:"Removing",submitLabel:"Remove connection",error:K.error instanceof Error?K.error.message:null,onSubmit:async()=>{v&&(await K.mutateAsync(v),_(null))}})]})}export{yt as SettingsCalendarPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as o,j as e,db as V,dc as Y,cr as me,dd as Z,aQ as J,de as xe,aD as ge,cg as he}from"./vendor-DHkYh85p.js";import{j as pe,i as X,k}from"./state-B-4sS1xO.js";import{dA as be,dB as fe,dC as ve,dD as je,dE as ke,dF as ye,j as we,F as Ne,I as ee,c as u,S as Fe,E as ae,B as x,C as y,Z as T,Q as te,f as Se,dx as Re,dG as De}from"./index-CF4J4R9L.js";import{S as Ce}from"./settings-section-nav-DSOuht_F.js";import{P as Be}from"./page-hero-DRy5b2MU.js";import{M as g}from"./metric-tile-DKpo-8xw.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./forms-BFlTgZ3W.js";import"./graph-D6JLqDbD.js";function E(t){if(!Number.isFinite(t)||t<=0)return"0 B";const l=["B","KB","MB","GB","TB"];let n=t,m=0;for(;n>=1024&&m<l.length-1;)n/=1024,m+=1;return`${n.toFixed(n>=100?0:n>=10?1:2)} ${l[m]}`}function Me(t,l){const n=URL.createObjectURL(t),m=document.createElement("a");m.href=n,m.download=l,m.click(),URL.revokeObjectURL(n)}function Ae(t){return t?t===1?"Every hour":t===24?"Every day":t===168?"Every week":`Every ${t} hours`:"Off"}function se(t){switch(t){case"manual":return"Manual";case"automatic":return"Automatic";case"pre_restore":return"Safety backup before restore";case"pre_switch_root":return"Safety backup before folder change";default:return t}}function w(t,l="Unknown time"){if(!t)return l;const n=new Date(t);return Number.isNaN(n.getTime())?l:Se(t)}function Ee({tone:t,message:l}){return e.jsx("div",{className:T("rounded-[20px] border px-4 py-3 text-sm leading-6",t==="success"?"border-emerald-400/20 bg-emerald-500/[0.08] text-emerald-100/88":t==="warning"?"border-amber-400/20 bg-amber-500/[0.08] text-amber-100/88":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)]"),children:l})}function z({label:t,value:l,icon:n}){return e.jsxs("div",{className:"rounded-[24px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 text-[11px] uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:[e.jsx(n,{className:"size-4"}),t]}),e.jsx("div",{className:"mt-3 break-all text-sm leading-6 text-[var(--ui-ink-soft)]",children:l})]})}function Ie(){var G,W;const t=pe(),[l,n]=o.useState(""),[m,$]=o.useState(""),[L,q]=o.useState(""),[O,U]=o.useState(!0),[f,re]=o.useState([]),[P,v]=o.useState(null),[ie,N]=o.useState(!1),[c,F]=o.useState({mode:"migrate_current",targetDataRoot:"",createSafetyBackup:!0}),[ne,j]=o.useState(null),[i,_]=o.useState(null),[K,H]=o.useState({createSafetyBackup:!0}),[oe,R]=o.useState(null),p=X({queryKey:["forge-operator-session"],queryFn:Re}),le=p.isSuccess,S=X({queryKey:["forge-data-management"],queryFn:De,enabled:le}),D=async()=>{await Promise.all([t.invalidateQueries({queryKey:["forge-operator-session"]}),t.invalidateQueries({queryKey:["forge-data-management"]})])},I=k({mutationFn:()=>be({backupDirectory:l,backupFrequencyHours:m==="off"?null:Number(m||"24"),backupRetentionDays:L==="forever"?null:Number(L||"30"),autoRepairEnabled:O}),onSuccess:async()=>{v({tone:"success",message:"Backup settings saved."}),await D()}}),C=k({mutationFn:()=>fe("Manual backup from Settings → Data"),onSuccess:async()=>{v({tone:"success",message:"Backup created."}),await D()}}),B=k({mutationFn:ve,onSuccess:({candidates:a})=>{re(a),v({tone:a.some(d=>d.newerThanCurrent)?"warning":"neutral",message:a.length>0?`Found ${a.length} Forge ${a.length===1?"copy":"copies"} on disk.`:"No other Forge data copies were found in the scanned folders."})}}),M=k({mutationFn:a=>je({targetDataRoot:a.targetDataRoot,mode:a.mode,createSafetyBackup:a.createSafetyBackup}),onSuccess:async()=>{v({tone:"success",message:"Forge is now using the selected data folder."}),N(!1),await D()}}),A=k({mutationFn:({backupId:a,createSafetyBackup:d})=>ke(a,d),onSuccess:async()=>{v({tone:"success",message:"Backup restored. Forge is now running from that restored state."}),_(null),await D()}}),Q=k({mutationFn:async a=>{const d=await ye(a);return Me(d.blob,d.fileName??`forge-export.${a}`),a},onSuccess:a=>{v({tone:"neutral",message:`Started download for ${a}.`})}}),s=(G=S.data)==null?void 0:G.data;o.useEffect(()=>{s&&(n(a=>a||s.settings.backupDirectory),$(a=>a||(s.settings.backupFrequencyHours?String(s.settings.backupFrequencyHours):"off")),U(s.settings.autoRepairEnabled),q(a=>a||(s.settings.backupRetentionDays?String(s.settings.backupRetentionDays):"forever")),F(a=>({...a,targetDataRoot:a.targetDataRoot||s.current.dataRoot})))},[s]);const de=o.useMemo(()=>f.find(a=>a.newerThanCurrent),[f]),h=o.useMemo(()=>f.find(a=>a.dataRoot===c.targetDataRoot.trim()),[c.targetDataRoot,f]),ce=[{id:"mode",eyebrow:"Step 1",title:"What do you want Forge to do?",description:"Choose whether Forge should move the current data into a new folder or switch to a folder that already contains the right Forge data.",render:(a,d)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(we,{value:a.mode,onChange:b=>d({mode:b}),options:[{value:"migrate_current",label:"Move the current data",description:"Copy the live database and local secrets key into a new folder, then switch Forge to it."},{value:"adopt_existing",label:"Use an existing data folder",description:"Keep the target folder as it is and point Forge at that existing database directly."}]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:b=>d({createSafetyBackup:b.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup first."})]})]})},{id:"folder",eyebrow:"Step 2",title:c.mode==="migrate_current"?"Choose the new data folder":"Choose the data folder to use",description:c.mode==="migrate_current"?"Pick an empty folder for the moved Forge data.":"Pick the folder that already contains the Forge data you trust.",render:(a,d)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(Ne,{label:"Data folder",description:"Forge will place or read the database and backups from here.",children:e.jsx(ee,{value:a.targetDataRoot,onChange:b=>d({targetDataRoot:b.target.value}),placeholder:"/absolute/path/to/forge-data"})}),h?e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Found on this machine"}),e.jsx("div",{className:"mt-2 break-all",children:h.databasePath}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:h.sourceHint}),e.jsxs(u,{className:"bg-white/[0.08] text-white/78",children:[h.counts.notes," notes"]}),e.jsxs(u,{className:"bg-white/[0.08] text-white/78",children:[h.counts.tasks," tasks"]}),h.newerThanCurrent?e.jsx(u,{className:"bg-amber-500/16 text-amber-100",children:"Newer than the current copy"}):null]})]}):e.jsx("div",{className:"rounded-[22px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:c.mode==="migrate_current"?"Forge will copy the current data into this folder and then switch over.":"If this folder already holds a Forge database, Forge will start using it after you confirm."})]})}],ue=[{id:"review",eyebrow:"Step 1",title:"Review the backup you want to restore",description:"Restoring replaces the current database with the selected backup.",render:(a,d)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:i?w(i.createdAt):"Selected backup"}),e.jsx("div",{className:"mt-2",children:(i==null?void 0:i.note)||"Forge backup archive"}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:i?se(i.mode):"Backup"}),e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:i?E(i.sizeBytes):"0 B"}),i!=null&&i.includesWiki?e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:"Includes wiki"}):null]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:a.createSafetyBackup,onChange:b=>d({createSafetyBackup:b.target.checked})}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Create one safety backup of the current state first."})]})]})},{id:"confirm",eyebrow:"Step 2",title:"Confirm the restore",description:"Use this only when you are confident this backup is the state you want back.",render:()=>e.jsx("div",{className:"rounded-[22px] border border-amber-400/20 bg-amber-500/[0.08] p-4 text-sm leading-6 text-amber-100/88",children:"Forge will replace the live database with this backup, then reopen the restored copy."})}];if(p.isLoading||S.isLoading)return e.jsx(Fe,{eyebrow:"Data",title:"Loading data controls",description:"Checking the live data folder, backup plan, and recovery tools.",columns:3,blocks:6});if(p.isError)return e.jsx(ae,{eyebrow:"Data",error:p.error,onRetry:()=>void p.refetch()});if(S.isError||!s)return e.jsx(ae,{eyebrow:"Data",error:S.error??new Error("Forge returned an empty data payload."),onRetry:()=>void S.refetch()});const r=s.current;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mx-auto grid w-full max-w-[1480px] gap-5",children:[e.jsx(Be,{eyebrow:"Data, backups, recovery",title:"Data",description:"See where Forge is saving the live data, keep it protected with backups, look for a newer copy on disk if something goes wrong, and download the database or its structure when you need it.",badge:`${r.integrityOk?"Healthy":"Needs attention"} · ${E(r.databaseSizeBytes)}`,actions:e.jsxs(e.Fragment,{children:[e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(V,{className:"size-4"}),"Look for other Forge copies"]}),e.jsxs(x,{pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:[e.jsx(Y,{className:"size-4"}),"Create backup now"]})]})}),e.jsx(Ce,{}),(W=p.data)!=null&&W.session?e.jsxs("div",{className:"rounded-[20px] border border-emerald-400/20 bg-emerald-500/[0.08] px-4 py-3 text-sm text-emerald-100/88",children:["You are managing Forge data as"," ",e.jsx("span",{className:"font-medium text-white",children:p.data.session.actorLabel}),"."]}):null,P?e.jsx(Ee,{tone:P.tone,message:P.message}):null,e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,0.85fr)]",children:[e.jsxs(y,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Live data folder"}),e.jsx("div",{className:"mt-2 text-xl font-semibold text-[var(--ui-ink-strong)]",children:r.dataRoot}),e.jsx("div",{className:"mt-2 max-w-3xl text-sm leading-6 text-[var(--ui-ink-soft)]",children:"This is the folder Forge is reading and writing right now."})]}),e.jsx(u,{className:T(r.integrityOk?"bg-emerald-500/14 text-emerald-100":"bg-amber-500/14 text-amber-100"),children:r.integrityMessage})]}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(z,{label:"Database file",value:r.databasePath,icon:me}),e.jsx(z,{label:"Folder layout",value:r.layout,icon:Z}),e.jsx(z,{label:"Last database change",value:r.databaseLastModifiedAt?w(r.databaseLastModifiedAt):"Unknown",icon:J})]}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-3 xl:grid-cols-6",children:[e.jsx(g,{label:"Notes",value:r.counts.notes}),e.jsx(g,{label:"Goals",value:r.counts.goals}),e.jsx(g,{label:"Projects",value:r.counts.projects}),e.jsx(g,{label:"Tasks",value:r.counts.tasks}),e.jsx(g,{label:"Runs",value:r.counts.taskRuns}),e.jsx(g,{label:"Tags",value:r.counts.tags})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"flex size-11 items-center justify-center rounded-2xl border border-emerald-400/20 bg-emerald-500/[0.12]",children:e.jsx(xe,{className:"size-5 text-emerald-200"})}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:"Protection plan"}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Choose where backups go, how often Forge creates them, and whether scans should call out newer copies found elsewhere on disk."})]})]}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-3",children:[e.jsx(g,{label:"Automatic backup",value:Ae(s.settings.backupFrequencyHours),detail:s.settings.lastAutoBackupAt?`Last run ${w(s.settings.lastAutoBackupAt)}`:"No automatic backup recorded yet"}),e.jsx(g,{label:"Manual backup",value:s.settings.lastManualBackupAt?w(s.settings.lastManualBackupAt):"None yet",detail:`${s.backups.length} backup${s.backups.length===1?"":"s"} saved`}),e.jsx(g,{label:"Retention",value:s.settings.backupRetentionDays?`${s.settings.backupRetentionDays} days`:"Keep forever",detail:"Automatic backups only"})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Backup folder"}),e.jsx(ee,{value:l,onChange:a=>n(a.target.value)})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Automatic backup"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:m||"24",onChange:a=>$(a.target.value),children:[e.jsx("option",{value:"off",children:"Off"}),e.jsx("option",{value:"1",children:"Every hour"}),e.jsx("option",{value:"6",children:"Every 6 hours"}),e.jsx("option",{value:"24",children:"Every day"}),e.jsx("option",{value:"168",children:"Every week"})]})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-[var(--ui-ink-soft)]",children:"Keep automatic backups"}),e.jsxs("select",{className:"h-11 rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-3 text-sm text-[var(--ui-ink-strong)] outline-none transition focus:border-[var(--primary)]",value:L||"30",onChange:a=>q(a.target.value),children:[e.jsx("option",{value:"7",children:"7 days"}),e.jsx("option",{value:"14",children:"14 days"}),e.jsx("option",{value:"30",children:"30 days"}),e.jsx("option",{value:"90",children:"90 days"}),e.jsx("option",{value:"365",children:"1 year"}),e.jsx("option",{value:"forever",children:"Keep forever"})]})]}),e.jsxs("label",{className:"flex items-start gap-3 rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-4 py-3",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:O,onChange:a=>U(a.target.checked)}),e.jsx("span",{className:"text-sm leading-6 text-[var(--ui-ink-soft)]",children:"When I scan, point out Forge copies that look newer than the one I am using now."})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(x,{pending:I.isPending,pendingLabel:"Saving",onClick:()=>void I.mutateAsync(),children:"Save backup settings"}),e.jsx(x,{variant:"secondary",pending:C.isPending,pendingLabel:"Creating backup",onClick:()=>void C.mutateAsync(),children:"Create backup now"})]})]})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Change data folder"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Move today’s Forge data into a new folder, or switch to another folder that already contains the right Forge database."})]}),e.jsxs("div",{className:"rounded-[22px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4 text-sm leading-6 text-[var(--ui-ink-soft)]",children:[e.jsx("div",{className:"font-medium text-[var(--ui-ink-strong)]",children:"Current folder"}),e.jsx("div",{className:"mt-2 break-all",children:r.dataRoot}),h?e.jsxs("div",{className:"mt-3 text-sm text-[var(--ui-ink-soft)]",children:["Selected scanned copy: ",h.dataRoot]}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(x,{onClick:()=>{F(a=>({...a,mode:"migrate_current",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(Z,{className:"size-4"}),"Move current data"]}),e.jsxs(x,{variant:"secondary",onClick:()=>{F(a=>({...a,mode:"adopt_existing",targetDataRoot:a.targetDataRoot||r.dataRoot})),j(null),N(!0)},children:[e.jsx(J,{className:"size-4"}),"Use existing data folder"]})]})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Downloads"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Download the live database itself, or export a structure and table snapshot in other formats."})]}),e.jsx(ge,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.exportOptions.map(a=>e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.label}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.description})]}),e.jsx(x,{variant:"secondary",pending:Q.isPending,pendingLabel:"Preparing",onClick:()=>void Q.mutateAsync(a.format),children:"Download"})]},a.format))})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]",children:[e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Backup history"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Go back to an older saved state if you need to undo a bad change."})]}),e.jsx(Y,{className:"size-5 text-[var(--ui-ink-faint)]"})]}),e.jsx("div",{className:"grid gap-3",children:s.backups.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No backups yet. Create one now so you have a safe restore point."}):s.backups.map(a=>e.jsxs("div",{className:"rounded-[20px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:w(a.createdAt)}),e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:se(a.mode)})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:a.note||"Forge backup archive"})]}),e.jsx(x,{variant:"secondary",onClick:()=>{H({createSafetyBackup:!0}),R(null),_(a)},children:"Restore"})]}),e.jsxs("div",{className:"mt-3 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-2",children:[e.jsx("div",{className:"break-all",children:a.archivePath}),e.jsx("div",{children:E(a.sizeBytes)})]})]},a.id))})]}),e.jsxs(y,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Find other Forge copies"}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-[var(--ui-ink-soft)]",children:"Search common folders on this machine for other Forge databases. Use this when Forge opened the wrong copy or when you think a newer copy exists somewhere else."})]}),e.jsxs(x,{variant:"secondary",pending:B.isPending,pendingLabel:"Scanning",onClick:()=>void B.mutateAsync(),children:[e.jsx(V,{className:"size-4"}),"Scan now"]})]}),e.jsx("div",{className:"grid gap-3",children:f.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-[var(--ui-border-subtle)] px-4 py-6 text-sm text-[var(--ui-ink-soft)]",children:"No scan results yet. Run a scan to compare the live data folder with other Forge copies on disk."}):f.map(a=>e.jsxs("div",{className:T("rounded-[22px] border p-4",a.sameAsCurrent?"border-emerald-400/18 bg-emerald-500/[0.08]":a.newerThanCurrent?"border-amber-400/20 bg-amber-500/[0.08]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)]"),children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm font-semibold text-[var(--ui-ink-strong)]",children:a.dataRoot}),e.jsx(u,{className:"bg-white/[0.08] text-white/78",children:a.sourceHint}),a.newerThanCurrent?e.jsx(u,{className:"bg-amber-500/16 text-amber-100",children:"Newer than current"}):null,a.sameAsCurrent?e.jsx(u,{className:"bg-emerald-500/16 text-emerald-100",children:"Current copy"}):null]}),e.jsx("div",{className:"mt-2 break-all text-sm text-[var(--ui-ink-soft)]",children:a.databasePath})]}),a.sameAsCurrent?null:e.jsx(x,{variant:"secondary",onClick:()=>{F({mode:"adopt_existing",targetDataRoot:a.dataRoot,createSafetyBackup:!0}),j(null),N(!0)},children:"Use this folder"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 text-xs text-[var(--ui-ink-faint)] md:grid-cols-5",children:[e.jsx("div",{children:a.integrityMessage}),e.jsx("div",{children:w(a.databaseLastModifiedAt??new Date().toISOString())}),e.jsx("div",{children:E(a.databaseSizeBytes)}),e.jsxs("div",{children:[a.counts.notes," notes"]}),e.jsxs("div",{children:[a.counts.tasks," tasks"]})]})]},a.id))}),de?e.jsxs("div",{className:"flex items-start gap-3 rounded-[20px] border border-amber-400/20 bg-amber-500/[0.08] px-4 py-3 text-sm text-amber-100/88",children:[e.jsx(he,{className:"mt-0.5 size-4 shrink-0"}),e.jsx("div",{children:"Forge found a copy on disk that looks newer than the one you are using now. Review it carefully before switching."})]}):null]})]})]}),e.jsx(te,{open:ie,onOpenChange:a=>{N(a),a||j(null)},eyebrow:"Data folder",title:c.mode==="migrate_current"?"Move Forge data":"Use an existing Forge data folder",description:"This guided flow keeps the folder change explicit and gives you a safety backup option first.",value:c,onChange:F,draftPersistenceKey:`settings.data.root.${c.mode}`,steps:ce,pending:M.isPending,pendingLabel:c.mode==="migrate_current"?"Moving data":"Switching folder",submitLabel:c.mode==="migrate_current"?"Move and switch":"Use this folder",error:ne??(M.error instanceof Error?M.error.message:null),onSubmit:async()=>{if(!c.targetDataRoot.trim()){j("Choose a data folder first.");return}j(null),await M.mutateAsync(c)}}),e.jsx(te,{open:i!==null,onOpenChange:a=>{a||(_(null),R(null))},eyebrow:"Restore backup",title:"Restore Forge backup",description:"This flow replaces the live data with an older saved state.",value:K,onChange:H,draftPersistenceKey:i?`settings.data.restore.${i.id}`:"settings.data.restore",steps:ue,pending:A.isPending,pendingLabel:"Restoring",submitLabel:"Restore this backup",error:oe??(A.error instanceof Error?A.error.message:null),onSubmit:async()=>{if(!i){R("Choose a backup first.");return}R(null),await A.mutateAsync({backupId:i.id,createSafetyBackup:K.createSafetyBackup})}})]})}export{Ie as SettingsDataPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c2 as _,r as c,j as n,cs as q,aK as U,b3 as H,o as V}from"./vendor-DHkYh85p.js";import{x as Q}from"./state-B-4sS1xO.js";import{c as A,S as G,E as J,C as D,B as P,I as W,Z as B,en as Z,eo as X,b as Y,ep as ee}from"./index-CF4J4R9L.js";import{P as te}from"./page-hero-DRy5b2MU.js";import{S as se}from"./settings-section-nav-DSOuht_F.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./forms-BFlTgZ3W.js";import"./graph-D6JLqDbD.js";const ne=["error","warning","info","debug"],re=["server","ui","system","agent","openclaw"],ie=60;function E(t){return t.trim().toLowerCase()}function $(t){return Array.from(new Set(t.map(r=>(r==null?void 0:r.trim())??"").filter(Boolean)))}function S(t,r){const s=$(t.getAll(r));if(s.length>0)return s;const a=t.get(r);return a!=null&&a.trim()?[a.trim()]:[]}function ae(t){return new Intl.DateTimeFormat(void 0,{dateStyle:"medium",timeStyle:"medium"}).format(new Date(t))}function K(t){return t==="error"?"border-rose-400/20 bg-rose-500/[0.08] text-rose-100":t==="warning"?"border-amber-400/20 bg-amber-500/[0.08] text-amber-100":t==="info"?"border-sky-400/20 bg-sky-500/[0.08] text-sky-100":"border-white/10 bg-white/[0.04] text-white/68"}function R(t){return t==="error"?"Errors":t==="warning"?"Warnings":t==="info"?"Info":"Debug"}function F(t){return t==="openclaw"?"OpenClaw":t.charAt(0).toUpperCase()+t.slice(1)}function oe(t){return[t.scope?`scope: ${t.scope}`:null,t.eventKey?`event: ${t.eventKey}`:null,t.route?`route: ${t.route}`:null,t.functionName?`function: ${t.functionName}`:null,t.jobId?`job: ${t.jobId}`:null,t.entityType&&t.entityId?`entity: ${t.entityType}:${t.entityId}`:null,t.requestId?`request: ${t.requestId}`:null].filter(r=>!!r)}function le(t){return E([t.message,t.scope,t.eventKey,t.route,t.functionName,t.requestId,t.entityType,t.entityId,t.jobId,JSON.stringify(t.details)].filter(Boolean).join(" "))}function j(t,r){return n.jsx(A,{size:"sm",className:B("bg-white/[0.08] text-white/74",r),children:t})}function z(t,r){return X(t)?n.jsx(Y,{kind:t,label:r,compact:!0,gradient:!1}):j(r,"bg-[rgba(192,193,255,0.12)] text-white/84")}function k({label:t,placeholder:r,options:s,selectedIds:a,onChange:h,emptyMessage:u="No matches yet."}){const[y,d]=c.useState(!1),[f,b]=c.useState(""),[T,w]=c.useState(0),I=c.useRef(null),L=c.useRef(null),M=Z(I,y,{offset:8,preferredMaxHeight:320,minHeight:160}),C=c.useMemo(()=>a.map(i=>s.find(o=>o.id===i)??null).filter(i=>i!==null),[s,a]),p=E(f),x=c.useMemo(()=>{const i=s.filter(o=>!a.includes(o.id));return p?i.filter(o=>E(`${o.label} ${o.description??""} ${o.searchText??""}`).includes(p)).slice(0,10):i.slice(0,10)},[p,s,a]),v=i=>{a.includes(i)||(h([...a,i]),b(""),w(0),d(!1))},O=i=>{h(a.filter(o=>o!==i))};return c.useEffect(()=>{if(!y)return;const i=e=>{var m,g;const l=e.target;(m=I.current)!=null&&m.contains(l)||(g=L.current)!=null&&g.contains(l)||d(!1)},o=e=>{e.key==="Escape"&&d(!1)};return document.addEventListener("pointerdown",i),document.addEventListener("keydown",o),()=>{document.removeEventListener("pointerdown",i),document.removeEventListener("keydown",o)}},[y]),n.jsxs("label",{className:"grid gap-2",children:[n.jsx("span",{className:"text-[11px] font-medium uppercase tracking-[0.18em] text-white/45",children:t}),n.jsxs("div",{ref:I,className:"relative rounded-[20px] border border-white/8 bg-white/[0.04] px-3 py-2.5",children:[C.length>0?n.jsx("div",{className:"mb-2 flex flex-wrap gap-1.5",children:C.map(i=>n.jsxs("span",{className:"inline-flex items-center gap-1.5 rounded-full border border-white/8 bg-white/[0.05] px-1.5 py-1",children:[i.badge,n.jsx("button",{type:"button",className:"rounded-full p-0.5 text-white/46 transition hover:text-white",onClick:()=>O(i.id),"aria-label":`Remove ${i.label}`,children:n.jsx(U,{className:"size-3"})})]},i.id))}):null,n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(H,{className:"size-3.5 text-white/34"}),n.jsx("input",{value:f,onChange:i=>{b(i.target.value),w(0),d(!0)},onFocus:()=>d(!0),onKeyDown:i=>{if(i.key==="Backspace"&&!f&&a.length>0){O(a[a.length-1]);return}if(i.key==="ArrowDown"){i.preventDefault(),d(!0),w(o=>x.length===0?0:Math.min(x.length-1,o+1));return}if(i.key==="ArrowUp"){i.preventDefault(),w(o=>Math.max(0,o-1));return}if(i.key==="Escape"){d(!1);return}i.key==="Enter"&&x[T]&&(i.preventDefault(),v(x[T].id))},placeholder:r,className:"min-w-0 flex-1 bg-transparent text-sm text-white placeholder:text-white/34 focus:outline-none"})]}),y&&M&&typeof document<"u"?V.createPortal(n.jsx("div",{ref:L,role:"listbox","aria-multiselectable":"true",className:"z-[80] overflow-y-auto overscroll-contain rounded-[20px] border border-white/8 bg-[rgba(8,13,24,0.96)] p-2 shadow-[0_26px_60px_rgba(4,8,18,0.32)] backdrop-blur-xl [webkit-overflow-scrolling:touch]",style:M,children:x.length>0?x.map((i,o)=>n.jsx("button",{type:"button",role:"option","aria-selected":!1,className:B("flex w-full items-start justify-between gap-3 rounded-[16px] px-3 py-2 text-left transition",o===T?"bg-white/[0.1] text-white":"text-white/70 hover:bg-white/[0.06] hover:text-white"),onMouseEnter:()=>w(o),onMouseDown:e=>e.preventDefault(),onClick:()=>v(i.id),children:n.jsxs("div",{className:"min-w-0",children:[n.jsx("div",{className:"truncate text-sm font-medium",children:i.menuBadge??i.badge}),i.description?n.jsx("div",{className:"mt-1 text-xs leading-5 text-white/46",children:i.description}):null]})},i.id)):n.jsx("div",{className:"px-3 py-2 text-sm text-white/42",children:u})}),document.body):null]})]})}function ce(t,r){const s=`${r.entityType}:${r.entityId}`;t.has(s)||t.set(s,{id:s,label:r.label,description:r.description,searchText:r.searchText,badge:r.badge,menuBadge:r.menuBadge})}function de(t){const r=new Map;for(const s of t){if(!s.entityType||!s.entityId)continue;const a=`${s.entityType}:${s.entityId}`;if(r.has(a))continue;const h=s.entityType==="wiki_ingest_job"?`Ingest ${s.entityId}`:`${s.entityType} ${s.entityId}`;ce(r,{entityType:s.entityType,entityId:s.entityId,label:h,description:"Seen in diagnostics logs",searchText:E(`${h} ${s.scope} ${s.message} ${s.eventKey}`),badge:z(s.entityType,h),menuBadge:z(s.entityType,h)})}return Array.from(r.values()).sort((s,a)=>s.label.localeCompare(a.label))}const ue=c.memo(function({entry:r}){const[s,a]=c.useState(!1),h=c.useMemo(()=>s&&Object.keys(r.details).length>0?JSON.stringify(r.details,null,2):"",[s,r.details]);return n.jsxs(D,{className:"grid gap-4",children:[n.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[n.jsxs("div",{className:"grid gap-3",children:[n.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[n.jsx("span",{className:B("rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em]",K(r.level)),children:r.level}),n.jsx("span",{className:"rounded-full border border-white/10 bg-white/[0.04] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] text-white/60",children:r.source}),n.jsx("span",{className:"rounded-full border border-white/10 bg-white/[0.04] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] text-white/60",children:r.scope}),r.eventKey?n.jsx("span",{className:"rounded-full border border-white/10 bg-white/[0.04] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] text-white/46",children:r.eventKey}):null]}),n.jsx("div",{className:"text-base font-medium text-white",children:r.message}),n.jsx("div",{className:"flex flex-wrap gap-3 text-xs text-white/45",children:oe(r).map(u=>n.jsx("span",{children:u},u))})]}),n.jsxs("div",{className:"shrink-0 text-right text-xs text-white/40",children:[n.jsx("div",{children:ae(r.createdAt)}),n.jsx("div",{className:"mt-1 font-mono text-[11px]",children:r.id})]})]}),Object.keys(r.details).length>0?n.jsxs("details",{className:"rounded-[18px] border border-white/8 bg-[rgba(7,11,21,0.72)] px-4 py-3",onToggle:u=>a(u.currentTarget.open),children:[n.jsx("summary",{className:"cursor-pointer text-sm text-white/70",children:"View structured details"}),s?n.jsx("pre",{className:"mt-3 overflow-x-auto whitespace-pre-wrap text-xs leading-6 text-white/58",children:h}):null]}):null]})});function ve(){const[t,r]=_(),s=c.useMemo(()=>{var g,N;const e=((g=t.get("entityType"))==null?void 0:g.trim())||"",l=((N=t.get("entityId"))==null?void 0:N.trim())||"",m=S(t,"entity");return m.length===0&&e&&l&&m.push(`${e}:${l}`),{search:t.get("search")||"",levels:S(t,"level"),sources:S(t,"source"),scopes:S(t,"scope"),routes:S(t,"route"),jobs:S(t,"jobId"),entities:$(m)}},[t]),a=Q({queryKey:["forge-diagnostic-logs","settings-filters"],initialPageParam:null,queryFn:({pageParam:e})=>ee({limit:ie,beforeCreatedAt:e==null?void 0:e.beforeCreatedAt,beforeId:e==null?void 0:e.beforeId}),getNextPageParam:e=>e.nextCursor,retry:!1,refetchOnWindowFocus:!1}),h=(e,l)=>{const m=new URLSearchParams(t);l.trim()?m.set(e,l.trim()):m.delete(e),r(m,{replace:!0})},u=(e,l,m=[])=>{const g=new URLSearchParams(t);g.delete(e);for(const N of m)g.delete(N);for(const N of $(l))g.append(e,N);r(g,{replace:!0})},y=()=>{const e=new URLSearchParams(t);["search","level","source","scope","route","jobId","entity","entityType","entityId"].forEach(l=>e.delete(l)),r(e,{replace:!0})},d=c.useMemo(()=>{var e;return((e=a.data)==null?void 0:e.pages.flatMap(l=>l.logs))??[]},[a.data]),f=E(s.search),b=c.useRef(null),T=c.useMemo(()=>ne.map(e=>({id:e,label:R(e),searchText:`${e} ${R(e)}`,badge:n.jsx(A,{size:"sm",className:K(e),children:R(e)})})),[]),w=c.useMemo(()=>re.map(e=>({id:e,label:F(e),searchText:`${e} ${F(e)}`,badge:j(F(e))})),[]),I=c.useMemo(()=>$(d.map(e=>e.scope)).map(e=>({id:e,label:e,searchText:e,badge:j(e)})),[d]),L=c.useMemo(()=>$(d.map(e=>e.route)).map(e=>({id:e,label:e,description:"Filter logs to one or more exact routes.",searchText:e,badge:j(e,"max-w-[16rem]"),menuBadge:j(e)})),[d]),M=c.useMemo(()=>$(d.map(e=>e.jobId)).map(e=>({id:e,label:e,description:"Background job or ingest run id.",searchText:e,badge:j(e,"max-w-[14rem]"),menuBadge:j(e)})),[d]),C=c.useMemo(()=>de(d),[d]),p=c.useMemo(()=>d.filter(e=>{if(f&&!le(e).includes(f)||s.levels.length>0&&!s.levels.includes(e.level)||s.sources.length>0&&!s.sources.includes(e.source)||s.scopes.length>0&&!s.scopes.includes(e.scope)||s.routes.length>0&&!s.routes.includes(e.route??"")||s.jobs.length>0&&!s.jobs.includes(e.jobId??""))return!1;if(s.entities.length>0){const l=e.entityType&&e.entityId?`${e.entityType}:${e.entityId}`:"";if(!l||!s.entities.includes(l))return!1}return!0}),[s,f,d]),x=[s.search,s.levels.join("|"),s.sources.join("|"),s.scopes.join("|"),s.routes.join("|"),s.jobs.join("|"),s.entities.join("|")].join("::");c.useEffect(()=>{var e;(e=b.current)==null||e.scrollTo({top:0})},[x]);const v=q({count:p.length,getScrollElement:()=>b.current,estimateSize:()=>260,overscan:8}),O=v.getVirtualItems(),i=()=>{const e=b.current;if(!e||!a.hasNextPage||a.isFetchingNextPage)return;e.scrollHeight-e.scrollTop-e.clientHeight<=800&&a.fetchNextPage()},o=s.levels.length+s.sources.length+s.scopes.length+s.routes.length+s.jobs.length+s.entities.length+(s.search.trim()?1:0);return a.isPending?n.jsx(G,{eyebrow:"Settings",title:"Loading diagnostics",description:"Collecting the latest frontend, backend, and runtime traces.",columns:1,blocks:6}):a.isError?n.jsx(J,{eyebrow:"Settings",error:a.error,onRetry:()=>void a.refetch()}):n.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[n.jsx(te,{title:"Logs",description:"Inspect shared diagnostics from the UI, backend routes, background jobs, and LLM flows.",badge:`${p.length} matching${p.length!==d.length?` · ${d.length} loaded`:""}${a.hasNextPage?" · more available":""}`}),n.jsx(se,{}),n.jsxs(D,{className:"grid gap-4",children:[n.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[n.jsxs("div",{children:[n.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Filters"}),n.jsx("div",{className:"mt-2 max-w-3xl text-sm leading-6 text-white/58",children:"Use token filters with OR-style badge selections for levels, sources, routes, jobs, scopes, and linked entities. Search still matches the message body and structured details."})]}),n.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[o>0?n.jsxs(P,{variant:"ghost",size:"sm",onClick:y,children:["Clear ",o]}):null,n.jsx(P,{variant:"secondary",size:"sm",onClick:()=>void a.refetch(),pending:a.isRefetching&&!a.isFetchingNextPage,pendingLabel:"Refreshing",children:"Refresh"})]})]}),n.jsxs("label",{className:"grid gap-2",children:[n.jsx("span",{className:"text-[11px] font-medium uppercase tracking-[0.18em] text-white/45",children:"Search message or details"}),n.jsx(W,{value:s.search,onChange:e=>h("search",e.target.value),placeholder:"LLM compilation failed, wiki_ingest, request_failed…",className:"h-11 rounded-[20px]"})]}),n.jsxs("div",{className:"grid gap-3 xl:grid-cols-2",children:[n.jsx(k,{label:"Levels",placeholder:"Add one or more levels",options:T,selectedIds:s.levels,onChange:e=>u("level",e),emptyMessage:"No additional log levels."}),n.jsx(k,{label:"Sources",placeholder:"Add one or more sources",options:w,selectedIds:s.sources,onChange:e=>u("source",e),emptyMessage:"No additional log sources."}),n.jsx(k,{label:"Scopes",placeholder:"Search scopes",options:I,selectedIds:s.scopes,onChange:e=>u("scope",e),emptyMessage:"No scopes match the current logs."}),n.jsx(k,{label:"Routes",placeholder:"Search exact routes",options:L,selectedIds:s.routes,onChange:e=>u("route",e),emptyMessage:"No routes match the current logs."}),n.jsx(k,{label:"Jobs",placeholder:"Search job ids",options:M,selectedIds:s.jobs,onChange:e=>u("jobId",e),emptyMessage:"No job ids match the current logs."}),n.jsx(k,{label:"Entities",placeholder:"Search Forge entities or logged ids",options:C,selectedIds:s.entities,onChange:e=>u("entity",e,["entityType","entityId"]),emptyMessage:"No logged entities match yet."})]})]}),n.jsx("div",{className:"grid gap-3",children:p.length===0?n.jsx(D,{className:"text-sm text-white/58",children:"No diagnostic entries match the current filters yet."}):n.jsx(D,{className:"p-0",children:n.jsxs("div",{ref:b,onScroll:i,className:"h-[72vh] overflow-y-auto px-3 py-3",children:[n.jsx("div",{className:"relative",style:{height:`${v.getTotalSize()}px`},children:O.map(e=>{const l=p[e.index];return l?n.jsx("div",{"data-index":e.index,ref:v.measureElement,className:"absolute left-0 top-0 w-full pb-3",style:{transform:`translateY(${e.start}px)`},children:n.jsx(ue,{entry:l})},l.id):null})}),n.jsx("div",{className:"border-t border-white/6 px-1 py-3 text-center text-xs text-white/46",children:a.isFetchingNextPage?"Loading older logs…":a.hasNextPage?"Scroll to load older logs.":`Showing all ${d.length} loaded logs.`})]})})})]})}export{ve as SettingsLogsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as m,di as J,j as e,dj as V,dk as X,cw as q,cx as M,dh as Y,dl as O,dm as Z,bl as H,bF as U,dn as ee,dp as D,aC as C,cb as R,dq as se}from"./vendor-DHkYh85p.js";import{j as te,i as ie,k as f}from"./state-B-4sS1xO.js";import{u as ae,s as ne,ed as re,ee as le,ef as de,eg as oe,S as ce,E as xe,C as A,B as o,c as a,dy as he}from"./index-CF4J4R9L.js";import{S as me}from"./settings-section-nav-DSOuht_F.js";import{P as pe}from"./page-hero-DRy5b2MU.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./forms-BFlTgZ3W.js";import"./graph-D6JLqDbD.js";function ge(t){return t.replaceAll("."," ")}function ue(t){const l=typeof t.sleepNights=="number"?t.sleepNights:typeof t.sleepSessions=="number"?t.sleepSessions:0,p=typeof t.sleepSegments=="number"?t.sleepSegments:0,N=typeof t.sleepRawRecords=="number"?t.sleepRawRecords:0,u=typeof t.sleepSessions=="number"?t.sleepSessions:0,v=typeof t.workouts=="number"?t.workouts:0,c=t.vitals&&typeof t.vitals=="object"&&!Array.isArray(t.vitals)&&typeof t.vitals.metricEntries=="number"?t.vitals.metricEntries:0;return`${l||u} nights · ${p} segments · ${N} raw records · ${v} workouts · ${c} vitals`}function G(t){return t?"signal":"meta"}function ve(t){return t.replaceAll("_"," ")}function we(t){return t?new Date(t).toLocaleString():"Waiting for device update"}function je(t,l){return t?l?"signal":"default":"meta"}function fe(t){return t.transportMode==="iroh"?"Iroh":"Manual HTTP"}function Ne(t){return t.transportMode==="iroh"?"signal":"meta"}function Le(){const t=ae(),l=te(),p=Array.isArray(t.selectedUserIds)?t.selectedUserIds:[],N=ne(p),[u,v]=m.useState(null),[c,b]=m.useState(!1),[y,w]=m.useState(!1),[z,k]=m.useState(!1),[n,$]=m.useState(null),x=ie({queryKey:["forge-companion-overview",...p],queryFn:async()=>(await he(p)).overview}),d=f({mutationFn:async(s="iroh")=>re({userId:N??null,transportMode:s}),onSuccess:async s=>{$({qrPayload:s.qrPayload}),b(!0),await l.invalidateQueries({queryKey:["forge-companion-overview"]})}}),S=f({mutationFn:async s=>le(s),onSuccess:async()=>{await l.invalidateQueries({queryKey:["forge-companion-overview"]})}}),E=f({mutationFn:async()=>de({userIds:p,includeRevoked:!1}),onSuccess:async()=>{await l.invalidateQueries({queryKey:["forge-companion-overview"]})}}),j=f({mutationFn:async s=>oe(s.pairingSessionId,s.source,s.desiredEnabled),onSuccess:async()=>{await l.invalidateQueries({queryKey:["forge-companion-overview"]})}});if(m.useEffect(()=>{if(!n){v(null);return}J.toDataURL(JSON.stringify(n.qrPayload),{width:320,margin:1}).then(v)},[n]),m.useEffect(()=>{w(!1),k(!1)},[n]),x.isLoading)return e.jsx(ce,{eyebrow:"Companion",title:"Loading mobile companion",description:"Checking pairing state and recent sync status.",columns:2,blocks:5});if(x.isError||!x.data)return e.jsx(xe,{eyebrow:"Companion",error:x.error??new Error("Companion overview unavailable"),onRetry:()=>void x.refetch()});const i=x.data,g=i.pairings.filter(s=>s.status!=="revoked"),L=i.pairings.length-g.length,P=n?JSON.stringify(n.qrPayload,null,2):"",K=async()=>{if(n&&c){b(!1);return}if(n&&!c){b(!0);return}await d.mutateAsync("iroh")},_=async()=>{await d.mutateAsync("manual-http")},B=async()=>{if(P){if(!navigator.clipboard){w(!0);return}try{await navigator.clipboard.writeText(P),k(!0),window.setTimeout(()=>k(!1),1800)}catch{w(!0)}}};return e.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5 pb-24 lg:pb-0",children:[e.jsx(pe,{title:"Mobile companion",description:"Pair the native iPhone companion, sync Apple Health, and keep the bridge open for watch and location signals.",badge:i.healthState.replaceAll("_"," ")}),e.jsx(me,{}),e.jsxs("section",{className:"grid gap-4",children:[null,e.jsxs(A,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Pair iPhone"}),e.jsx("div",{className:"mt-2 text-lg text-white",children:"Pair your iPhone privately"}),e.jsx("div",{className:"mt-2 max-w-3xl text-sm leading-6 text-white/58",children:"Forge uses its own Iroh/QUIC companion route by default. Scan once from the iPhone app; manual HTTP stays as the advanced LAN or Tailscale path."})]}),e.jsxs("div",{className:"flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:justify-end",children:[e.jsxs(o,{variant:"secondary",className:"w-full sm:w-auto",onClick:()=>void _(),pending:d.isPending&&d.variables==="manual-http",pendingLabel:"Generating",children:[e.jsx(V,{className:"size-4"}),"Advanced HTTP"]}),e.jsxs(o,{className:"w-full sm:w-auto",onClick:()=>void K(),pending:d.isPending&&d.variables!=="manual-http",pendingLabel:"Generating",children:[e.jsx(X,{className:"size-4"}),n?c?"Hide QR":"Show QR":"Generate Forge QR",n?c?e.jsx(q,{className:"size-4"}):e.jsx(M,{className:"size-4"}):null]})]})]}),c?e.jsxs("div",{className:"grid gap-4 rounded-[24px] border border-white/8 bg-white/[0.03] p-4 sm:p-5",children:[e.jsxs("div",{className:"grid gap-4 lg:grid-cols-[minmax(260px,360px)_1fr]",children:[u?e.jsxs("div",{className:"grid justify-items-center gap-4 rounded-[24px] bg-white px-6 py-6 text-slate-950",children:[e.jsx("img",{src:u,alt:"Forge Companion pairing QR code",className:"w-full max-w-[320px]"}),e.jsx("div",{className:"max-w-[320px] text-center text-sm text-slate-600",children:"Scan this code from Forge Companion on iPhone."})]}):e.jsx("div",{className:"rounded-[24px] border border-dashed border-white/10 bg-white/[0.03] px-5 py-8 text-center text-sm text-white/55",children:"Generating the QR code now."}),e.jsxs("div",{className:"grid content-start gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[n?e.jsxs(a,{tone:Ne(n.qrPayload),children:[e.jsx(Y,{className:"size-3"}),fe(n.qrPayload)]}):null,e.jsxs(a,{tone:"meta",children:[e.jsx(O,{className:"size-3"}),"One-time token"]})]}),e.jsxs("div",{className:"grid gap-3 text-sm leading-6 text-white/66",children:[e.jsxs("div",{className:"flex gap-3",children:[e.jsx(Z,{className:"mt-1 size-4 shrink-0 text-white/45"}),e.jsx("span",{children:"Open Forge Companion and choose Scan Forge QR."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(O,{className:"mt-1 size-4 shrink-0 text-white/45"}),e.jsx("span",{children:"The iPhone receives the desktop node, relay hint, and pairing token for the Forge Iroh route."})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(H,{className:"mt-1 size-4 shrink-0 text-white/45"}),e.jsx("span",{children:"After verification, the app moves straight into native permissions and first sync."})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/62",children:n?e.jsxs("span",{children:["Expires"," ",new Date(n.qrPayload.expiresAt).toLocaleString(),"."]}):"Generate the one-time QR and scan it from the iPhone app."}),n?e.jsxs(o,{variant:"secondary",pending:d.isPending,pendingLabel:"Generating",onClick:()=>void d.mutateAsync("iroh"),children:[e.jsx(U,{className:"size-4"}),"Regenerate QR"]}):null]})]})]}),n?e.jsxs("div",{className:"grid gap-3 rounded-[18px] bg-white/[0.04] p-4 text-sm text-white/62",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"max-w-2xl",children:[e.jsx("div",{className:"text-white/78",children:"Fallback pairing payload"}),e.jsx("div",{className:"mt-1 text-xs leading-5 text-white/45",children:"Use this only when the iPhone camera cannot scan the QR. The payload contains the same Forge Iroh connection recipe."})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(o,{variant:"secondary",onClick:()=>void B(),children:[z?e.jsx(H,{className:"size-4"}):e.jsx(ee,{className:"size-4"}),z?"Copied":"Copy payload"]}),e.jsxs(o,{variant:"secondary",onClick:()=>w(s=>!s),children:[y?"Hide payload":"Show payload",y?e.jsx(q,{className:"size-4"}):e.jsx(M,{className:"size-4"})]})]})]}),y?e.jsx("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap break-words rounded-[16px] bg-slate-950/60 p-3 font-mono text-[11px] leading-5 text-white/70",children:P}):null]}):null]}):e.jsx("div",{className:"rounded-[24px] border border-dashed border-white/10 bg-white/[0.03] px-5 py-6 text-sm leading-6 text-white/55",children:"Generate a one-time Forge QR when the iPhone is in your hand. The code expires automatically and can be regenerated anytime."})]}),e.jsxs(A,{className:"grid gap-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Companion state"}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-3",children:[e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Pairings"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:g.length}),L>0?e.jsxs("div",{className:"mt-2 text-xs text-white/42",children:[L," revoked hidden"]}):null]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Sleep sessions"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.sleepSessions})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Raw sleep records"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.sleepRawRecords})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.workouts})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Vitals days"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.vitalsDaySummaries??0})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Vital entries"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.vitalsMetricEntries??0})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Reflected sleep"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.reflectiveSleepSessions})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Linked workouts"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.linkedWorkouts})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Habit-generated"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.habitGeneratedWorkouts})]}),e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Reconciled"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:i.counts.reconciledWorkouts})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(a,{children:i.healthState.replaceAll("_"," ")}),i.lastSyncAt?e.jsxs(a,{tone:"meta",children:["Last sync ",new Date(i.lastSyncAt).toLocaleString()]}):null,e.jsxs(a,{tone:G(i.permissions.healthKitAuthorized),children:["HealthKit ",i.permissions.healthKitAuthorized?"ready":"needed"]}),e.jsxs(a,{tone:G(i.permissions.backgroundRefreshEnabled),children:["Background refresh"," ",i.permissions.backgroundRefreshEnabled?"ready":"not yet"]}),e.jsxs(a,{tone:"meta",children:["Location ",i.permissions.locationReady?"ready":"later"]}),e.jsxs(a,{tone:"meta",children:["Motion ",i.permissions.motionReady?"ready":"later"]})]}),e.jsxs("div",{className:"grid gap-3 rounded-[18px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Pairing path"}),e.jsxs("div",{className:"grid gap-2 text-sm text-white/62",children:[e.jsx("div",{children:"1. Generate the Forge QR from this page."}),e.jsx("div",{children:"2. Scan it in Forge Companion to pass the desktop node and pairing token."}),e.jsx("div",{children:"3. Approve Health access on iPhone, then run the first sync."}),e.jsx("div",{children:"4. Use Advanced HTTP only for a local, Tailscale, or direct TCP route."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[g.length>0?e.jsx("div",{className:"flex justify-end",children:e.jsxs(o,{variant:"secondary",pending:E.isPending,pendingLabel:"Revoking all",onClick:()=>void E.mutateAsync(),children:[e.jsx(D,{className:"size-4"}),"Revoke all"]})}):null,g.map(s=>e.jsxs("div",{className:"grid gap-3 rounded-[18px] bg-white/[0.04] px-4 py-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-base text-white",children:s.deviceName??s.label}),e.jsxs("div",{className:"mt-1 text-sm text-white/56",children:[s.platform??"ios"," · ",s.status]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(a,{tone:s.status==="healthy"?"signal":"meta",children:s.status.replaceAll("_"," ")}),s.lastSyncAt?e.jsxs(a,{tone:"meta",children:["Synced ",new Date(s.lastSyncAt).toLocaleString()]}):null]})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:s.capabilities.map(h=>e.jsx(a,{tone:"meta",size:"sm",wrap:!0,children:ge(h)},h))}),e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 text-sm text-white/55",children:[e.jsxs("div",{className:"grid gap-1",children:[e.jsx("div",{children:s.apiBaseUrl}),e.jsxs("div",{children:["Expires ",new Date(s.expiresAt).toLocaleString()]}),s.lastSyncError?e.jsx("div",{className:"text-rose-200/80",children:s.lastSyncError}):null]}),e.jsxs(o,{variant:"secondary",pending:S.isPending&&S.variables===s.id,pendingLabel:"Revoking",disabled:s.status==="revoked",onClick:()=>void S.mutateAsync(s.id),children:[e.jsx(D,{className:"size-4"}),s.status==="revoked"?"Revoked":"Revoke"]})]}),e.jsxs("div",{className:"grid gap-3 rounded-[16px] border border-white/8 bg-white/[0.03] p-3",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Device sync sources"}),[["health","Health"],["movement","Movement"],["screenTime","Screen Time"]].map(([h,Q])=>{var F,I;const r=s.sourceStates[h],W=r.desiredEnabled!==r.appliedEnabled,T=j.isPending&&((F=j.variables)==null?void 0:F.pairingSessionId)===s.id&&((I=j.variables)==null?void 0:I.source)===h;return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[14px] border border-white/6 bg-white/[0.03] px-3 py-3",children:[e.jsxs("div",{className:"grid gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"text-sm text-white",children:Q}),e.jsx(a,{tone:je(r.desiredEnabled,r.syncEligible),size:"sm",children:r.desiredEnabled?"Enabled":"Off"}),W?e.jsx(a,{tone:"meta",size:"sm",children:"Pending on phone"}):e.jsx(a,{tone:"meta",size:"sm",children:"Applied"})]}),e.jsxs("div",{className:"text-xs text-white/55",children:["Authorization ",ve(r.authorizationStatus)," · ","Last seen ",we(r.lastObservedAt)]})]}),e.jsx("button",{type:"button",role:"switch","aria-checked":r.desiredEnabled,"aria-label":`${Q} sync source`,disabled:T,onClick:()=>void j.mutateAsync({pairingSessionId:s.id,source:h,desiredEnabled:!r.desiredEnabled}),className:`relative inline-flex h-7 w-12 items-center rounded-full border transition ${r.desiredEnabled?"border-[rgba(171,232,255,0.4)] bg-[rgba(111,133,232,0.36)]":"border-white/10 bg-white/[0.06]"} ${T?"opacity-60":""}`,children:e.jsx("span",{className:`inline-block size-5 rounded-full bg-white shadow transition ${r.desiredEnabled?"translate-x-6":"translate-x-1"}`})})]},h)})]})]},s.id)),g.length===0?e.jsx("div",{className:"rounded-[18px] bg-white/[0.04] px-4 py-6 text-sm text-white/55",children:"No companion paired yet. Generate a QR code, then open the iOS companion and scan it."}):null]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(o,{variant:"secondary",onClick:()=>void x.refetch(),children:[e.jsx(U,{className:"size-4"}),"Refresh status"]}),e.jsxs(C,{to:"/sleep",className:"inline-flex min-h-11 items-center gap-2 rounded-[16px] border border-white/8 bg-white/[0.03] px-4 py-3 text-sm text-white/72 transition hover:bg-white/[0.06] hover:text-white",children:[e.jsx(R,{className:"size-4"}),"Open sleep view"]}),e.jsxs(C,{to:"/sports",className:"inline-flex min-h-11 items-center gap-2 rounded-[16px] border border-white/8 bg-white/[0.03] px-4 py-3 text-sm text-white/72 transition hover:bg-white/[0.06] hover:text-white",children:[e.jsx(R,{className:"size-4"}),"Open sports view"]}),e.jsxs(C,{to:"/vitals",className:"inline-flex min-h-11 items-center gap-2 rounded-[16px] border border-white/8 bg-white/[0.03] px-4 py-3 text-sm text-white/72 transition hover:bg-white/[0.06] hover:text-white",children:[e.jsx(R,{className:"size-4"}),"Open vitals view"]})]})]})]}),e.jsxs(A,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Sync history"}),e.jsx("div",{className:"mt-2 text-lg text-white",children:"Recent HealthKit import runs"})]}),e.jsxs(a,{tone:"meta",children:[i.importRuns.length," recent runs"]})]}),e.jsxs("div",{className:"grid gap-3",children:[i.importRuns.map(s=>e.jsxs("div",{className:"grid gap-3 rounded-[18px] bg-white/[0.04] px-4 py-4 lg:grid-cols-[minmax(0,1fr)_auto]",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(se,{className:"size-4 text-white/55"}),e.jsxs("div",{className:"text-base text-white",children:[s.sourceDevice||"iPhone"," import"]}),e.jsx(a,{tone:s.status==="completed"?"signal":"meta",children:s.status})]}),e.jsxs("div",{className:"text-sm text-white/60",children:[new Date(s.importedAt).toLocaleString()," ·"," ",ue(s.payloadSummary)]}),e.jsxs("div",{className:"flex flex-wrap gap-2 text-sm text-white/60",children:[e.jsxs(a,{tone:"meta",children:["Imported ",s.importedCount]}),e.jsxs(a,{tone:"meta",children:["Created ",s.createdCount]}),e.jsxs(a,{tone:"meta",children:["Updated ",s.updatedCount]}),e.jsxs(a,{tone:"meta",children:["Merged ",s.mergedCount]})]}),s.errorMessage?e.jsx("div",{className:"text-sm text-rose-200/80",children:s.errorMessage}):null]}),s.pairingSessionId?e.jsxs("div",{className:"text-sm text-white/45 lg:text-right",children:["Pairing ",s.pairingSessionId]}):null]},s.id)),i.importRuns.length===0?e.jsx("div",{className:"rounded-[18px] bg-white/[0.04] px-4 py-6 text-sm text-white/55",children:"No sync runs yet. Pair the iPhone companion and run the first HealthKit import."}):null]})]})]})}export{Le as SettingsMobilePage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as o,j as e,b2 as $,dr as _,aG as D,bn as G,df as H,c7 as Z}from"./vendor-DHkYh85p.js";import{j as J,i as Q,k as x}from"./state-B-4sS1xO.js";import{S as V}from"./settings-section-nav-DSOuht_F.js";import{P as X}from"./page-hero-DRy5b2MU.js";import{dj as Y,eh as ee,ei as te,ej as ae,ek as se,el as ie,L as ne,E as oe,C as j,B as l,c as p,b$ as de,em as re}from"./index-CF4J4R9L.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./forms-BFlTgZ3W.js";import"./graph-D6JLqDbD.js";function f(s="openai-api"){return{label:s==="openai-codex"?"OpenAI Codex":s==="openai-compatible"?"Local compatible endpoint":s==="mock"?"Workbench mock runtime":"OpenAI API",provider:s,baseUrl:s==="openai-codex"?"https://chatgpt.com/backend-api":s==="openai-compatible"?"http://127.0.0.1:11434/v1":s==="mock"?"mock://workbench":"https://api.openai.com/v1",model:s==="mock"?"mock-echo":"gpt-5.4-mini",apiKey:""}}function le(s){return{id:s.id,label:s.label,provider:s.provider,baseUrl:s.baseUrl,model:s.model,apiKey:""}}function je(){var z,B,q;const s=J(),[a,c]=o.useState(()=>f()),[y,N]=o.useState(""),[C,k]=o.useState("gpt-5.4-mini"),[A,S]=o.useState(""),[O,I]=o.useState("gpt-5.4-mini"),[v,u]=o.useState(""),[d,b]=o.useState(null),[M,m]=o.useState(null),r=Q({queryKey:["forge-settings"],queryFn:de}),R=Q({queryKey:["forge-openai-codex-oauth",d],queryFn:async()=>{if(!d)throw new Error("Missing OAuth session id");return await re(d)},enabled:!!d,refetchInterval:t=>{var W;const n=(W=t.state.data)==null?void 0:W.session.status;return n&&["authorized","error","consumed","expired"].includes(n)?!1:1500}}),w=async()=>{await s.invalidateQueries({queryKey:["forge-settings"]}),await s.invalidateQueries({queryKey:["forge-openai-codex-oauth",d]})},L=x({mutationFn:()=>Y({modelSettings:{forgeAgent:{basicChat:{connectionId:y||null,model:C},wiki:{connectionId:A||null,model:O}}}}),onSuccess:w}),F=x({mutationFn:()=>ee({id:a.id,label:a.label,provider:a.provider,authMode:a.provider==="openai-codex"?"oauth":"api_key",baseUrl:a.baseUrl,model:a.model,apiKey:a.provider==="openai-codex"?void 0:a.apiKey||void 0,oauthSessionId:a.provider==="openai-codex"?d??void 0:void 0}),onSuccess:async()=>{m("Connection saved."),a.provider==="openai-codex"&&(b(null),u("")),c(f(a.provider)),await w()}}),P=x({mutationFn:te,onSuccess:w}),K=x({mutationFn:async()=>ae({connectionId:a.id,provider:a.provider,baseUrl:a.baseUrl,model:a.model,apiKey:a.provider==="openai-codex"?void 0:a.apiKey||void 0}),onSuccess:({result:t})=>{m(`Connection test succeeded: ${t.outputPreview}`)},onError:t=>{m(t instanceof Error?t.message:"Connection test failed.")}}),E=x({mutationFn:se,onSuccess:({session:t})=>{b(t.id),m("OpenAI Codex OAuth started."),t.authUrl&&window.open(t.authUrl,"_blank","noopener,noreferrer")}}),U=x({mutationFn:async()=>{if(!d)throw new Error("No OAuth session started yet.");return await ie(d,v)},onSuccess:({session:t})=>{m(t.status==="authorized"?"OpenAI Codex OAuth authorized.":"Manual OAuth code submitted.")}});o.useEffect(()=>{var n;const t=(n=r.data)==null?void 0:n.settings;t&&(N(t.modelSettings.forgeAgent.basicChat.connectionId??""),k(t.modelSettings.forgeAgent.basicChat.model),S(t.modelSettings.forgeAgent.wiki.connectionId??""),I(t.modelSettings.forgeAgent.wiki.model))},[r.data]);const h=((z=r.data)==null?void 0:z.settings.modelSettings.connections)??[],i=((B=R.data)==null?void 0:B.session)??null,T=o.useMemo(()=>!a.label.trim()||!a.model.trim()?!1:a.provider==="openai-codex"?!!(a.id||(i==null?void 0:i.status)==="authorized"):a.provider==="mock"?!0:a.apiKey.trim().length>0||!!a.id,[a,i==null?void 0:i.status]);if(r.isLoading)return e.jsx(ne,{eyebrow:"Models",title:"Loading model settings",description:"Fetching Forge agent defaults and configured AI connections."});if(r.isError||!((q=r.data)!=null&&q.settings))return e.jsx(oe,{eyebrow:"Models",error:r.error??new Error("Forge returned an empty model settings payload."),onRetry:()=>void r.refetch()});const g=r.data.settings;return e.jsxs("div",{className:"mx-auto grid w-full max-w-[1440px] gap-5",children:[e.jsx(X,{eyebrow:"AI runtime",title:"Model Settings",description:"Manage Forge Agent defaults, OpenAI OAuth/API connections, and local OpenAI-compatible endpoints as first-class chat agents.",badge:`${h.length} model connection${h.length===1?"":"s"}`}),e.jsx(V,{}),e.jsxs(j,{className:"grid gap-5",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx($,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm text-white",children:"Forge Agent defaults"}),e.jsx("div",{className:"text-xs leading-5 text-white/52",children:"Forge Agent stays the default system agent. Choose which model connection powers basic chat and the managed wiki workflow."})]})]}),e.jsxs("div",{className:"grid gap-4 lg:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2 rounded-[20px] bg-white/[0.04] p-4",children:[e.jsx("span",{className:"text-sm text-white/72",children:"Basic chat connection"}),e.jsxs("select",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:y,onChange:t=>N(t.target.value),children:[e.jsx("option",{value:"",children:"No external connection"}),h.map(t=>e.jsxs("option",{value:t.id,children:[t.label," (",t.agentLabel,")"]},t.id))]}),e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:C,onChange:t=>k(t.target.value),placeholder:"Model"})]}),e.jsxs("label",{className:"grid gap-2 rounded-[20px] bg-white/[0.04] p-4",children:[e.jsx("span",{className:"text-sm text-white/72",children:"KarpaWiki model connection"}),e.jsxs("select",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:A,onChange:t=>S(t.target.value),children:[e.jsx("option",{value:"",children:"No external connection"}),h.map(t=>e.jsxs("option",{value:t.id,children:[t.label," (",t.agentLabel,")"]},t.id))]}),e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:O,onChange:t=>I(t.target.value),placeholder:"Model"})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(l,{pending:L.isPending,pendingLabel:"Saving defaults",onClick:()=>void L.mutateAsync(),children:"Save Forge Agent defaults"}),e.jsxs(p,{className:"bg-white/[0.06] text-white/78",children:["Forge Agent",g.modelSettings.forgeAgent.basicChat.connectionLabel?` basic chat: ${g.modelSettings.forgeAgent.basicChat.connectionLabel}`:" basic chat stays local"]}),e.jsx(p,{className:"bg-white/[0.06] text-white/78",children:g.modelSettings.forgeAgent.wiki.connectionLabel?`KarpaWiki: ${g.modelSettings.forgeAgent.wiki.connectionLabel}`:"KarpaWiki: no external model selected"})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]",children:[e.jsxs(j,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(_,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm text-white",children:"Connection editor"}),e.jsx("div",{className:"text-xs leading-5 text-white/52",children:"Every saved connection becomes a first-class agent layered on top of Forge Agent."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/42",children:"Provider"}),e.jsx("div",{className:"grid gap-2 md:grid-cols-3",children:[["openai-api","OpenAI API"],["openai-codex","OpenAI Codex OAuth"],["openai-compatible","OpenAI-compatible"]].map(([t,n])=>e.jsx("button",{type:"button",className:`rounded-[18px] px-4 py-3 text-left text-sm transition ${a.provider===t?"bg-[var(--primary)]/[0.18] text-white":"bg-white/[0.04] text-white/62 hover:bg-white/[0.08]"}`,onClick:()=>{c(f(t)),b(null),u("")},children:n},t))})]}),e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:a.label,onChange:t=>c(n=>({...n,label:t.target.value})),placeholder:"Connection label"}),e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:a.model,onChange:t=>c(n=>({...n,model:t.target.value})),placeholder:"Model"}),a.provider==="mock"?e.jsxs("div",{className:"grid gap-3 rounded-[20px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"text-sm text-white",children:"The Workbench mock runtime is only meant for local development and test workflows."}),e.jsxs("div",{className:"text-xs leading-5 text-white/52",children:["Use mock models like ",e.jsx("code",{children:"mock-echo"}),", ",e.jsx("code",{children:"mock-json"}),",",e.jsx("code",{children:"mock-tool-search"}),", ",e.jsx("code",{children:"mock-tool-note"}),", or",e.jsx("code",{children:"mock-chat-memory"})," to exercise deterministic flow behavior without a real external model."]})]}):a.provider!=="openai-codex"?e.jsxs(e.Fragment,{children:[e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:a.baseUrl,onChange:t=>c(n=>({...n,baseUrl:t.target.value})),placeholder:"Base URL"}),e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:a.apiKey,onChange:t=>c(n=>({...n,apiKey:t.target.value})),placeholder:a.id?"Leave blank to keep the stored key":"API key",type:"password"})]}):e.jsxs("div",{className:"grid gap-3 rounded-[20px] bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"text-sm text-white",children:["OpenAI Codex uses the documented PKCE flow with the local callback at ",g.modelSettings.oauth.openAiCodex.callbackUrl,"."]}),e.jsx("div",{className:"text-xs leading-5 text-white/52",children:"Start OAuth, finish the browser sign-in, then save the resulting connection as a chat agent backed by the ChatGPT Codex runtime."}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs(l,{variant:"secondary",pending:E.isPending,pendingLabel:"Starting OAuth",onClick:()=>void E.mutateAsync(),children:[e.jsx(D,{className:"size-4"}),"Start OAuth"]}),i!=null&&i.authUrl?e.jsxs(l,{variant:"secondary",onClick:()=>window.open(i.authUrl??"","_blank","noopener,noreferrer"),children:["Open sign-in",e.jsx(G,{className:"size-4"})]}):null]}),i?e.jsxs("div",{className:"grid gap-2 rounded-[18px] bg-black/20 p-3 text-sm text-white/72",children:[e.jsxs("div",{children:["Status: ",i.status]}),i.accountLabel?e.jsxs("div",{children:["Account: ",i.accountLabel]}):null,i.error?e.jsx("div",{className:"text-rose-200",children:i.error}):null]}):null,e.jsxs("div",{className:"grid gap-2",children:[e.jsx("input",{className:"rounded-[16px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white",value:v,onChange:t=>u(t.target.value),placeholder:"Paste the authorization code or full redirect URL"}),e.jsx(l,{variant:"secondary",disabled:!v.trim()||!d,pending:U.isPending,pendingLabel:"Submitting",onClick:()=>void U.mutateAsync(),children:"Submit manual code"})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(l,{pending:F.isPending,pendingLabel:"Saving connection",disabled:!T,onClick:()=>void F.mutateAsync(),children:"Save connection"}),e.jsxs(l,{variant:"secondary",pending:K.isPending,pendingLabel:"Testing",disabled:a.provider==="openai-codex"?!a.id:a.provider==="mock"?!1:!a.id&&!a.apiKey.trim(),onClick:()=>void K.mutateAsync(),children:[e.jsx(H,{className:"size-4"}),"Test connection"]})]}),M?e.jsx("div",{className:"rounded-[18px] bg-white/[0.04] px-4 py-3 text-sm text-white/72",children:M}):null]})]}),e.jsxs(j,{className:"grid gap-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx($,{className:"size-4 text-[var(--secondary)]"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm text-white",children:"Connected agents"}),e.jsx("div",{className:"text-xs leading-5 text-white/52",children:"Each connection registers its own chat-facing agent identity."})]})]}),e.jsxs("div",{className:"grid gap-3",children:[h.length===0?e.jsx("div",{className:"rounded-[20px] border border-dashed border-white/10 bg-white/[0.02] px-4 py-5 text-sm leading-6 text-white/58",children:"No external model connection yet. Add one with OAuth or API credentials and Forge will expose it as a first-class agent."}):null,h.map(t=>e.jsxs("div",{className:"grid gap-3 rounded-[20px] bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-white",children:t.label}),e.jsxs("div",{className:"mt-1 text-xs text-white/46",children:[t.agentLabel," · ",t.provider," ·"," ",t.model]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(l,{variant:"secondary",onClick:()=>{c(le(t)),b(null),u("")},children:"Edit"}),e.jsx(l,{variant:"secondary",pending:P.isPending,pendingLabel:"Deleting",onClick:()=>void P.mutateAsync(t.id),children:e.jsx(Z,{className:"size-4"})})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(p,{className:"bg-white/[0.06] text-white/78",children:t.authMode==="oauth"?"OAuth":"API key"}),e.jsx(p,{className:"bg-white/[0.06] text-white/78",children:t.status}),e.jsx(p,{className:"bg-white/[0.06] text-white/78",children:t.baseUrl}),t.accountLabel?e.jsx(p,{className:"bg-white/[0.06] text-white/78",children:t.accountLabel}):null]})]},t.id))]})]})]})]})}export{je as SettingsModelsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as j,j as e,aD as pe,d9 as xe,aC as ue,aG as ge,bl as he,da as be,aQ as fe}from"./vendor-DHkYh85p.js";import{j as ye,i as _,k as $}from"./state-B-4sS1xO.js";import{u as ve}from"./forms-BFlTgZ3W.js";import{Q as we,de as Y,F as L,I as F,j as je,df as Ne,T as ke,dg as D,B as N,dh as ee,P as Se,aF as Ce,di as Fe,dj as I,dk as Te,dl as Pe,dm as De,dn as Ae,dp as X,S as Ee,E as Z,C as T,dq as _e,dr as $e,ds as Ie,dt as Le,du as Me,dv as Qe,dw as Re,dx as qe,b$ as ze,dy as Je,dz as Ke}from"./index-CF4J4R9L.js";import{S as Oe}from"./settings-section-nav-DSOuht_F.js";import{P as Ge}from"./page-hero-DRy5b2MU.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./motion-BeD44FeG.js";import"./graph-D6JLqDbD.js";function R({theme:s,title:l,description:n}){return e.jsx("div",{className:"overflow-hidden rounded-[24px] border border-white/10",style:{background:`linear-gradient(180deg, ${s.panelHigh}, ${s.panelLow})`,color:s.ink},children:e.jsxs("div",{className:"px-4 py-4",style:{background:`radial-gradient(circle at top left, ${s.primary}33, transparent 42%), radial-gradient(circle at top right, ${s.secondary}2a, transparent 36%), linear-gradient(180deg, ${s.panel}, ${s.canvas})`},children:[e.jsx("div",{className:"text-xs uppercase tracking-[0.2em] opacity-60",children:"Preview"}),e.jsx("div",{className:"mt-2 font-display text-xl",children:l}),e.jsx("div",{className:"mt-2 text-sm leading-6 opacity-72",children:n}),e.jsx("div",{className:"mt-5 flex gap-2",children:[s.primary,s.secondary,s.tertiary,s.panelHigh].map(i=>e.jsx("div",{className:"h-9 flex-1 rounded-[14px] border border-black/10",style:{background:i}},i))})]})})}function w({label:s,value:l,onChange:n,description:i}){return e.jsx(L,{label:s,description:i,children:e.jsxs("div",{className:"grid gap-3 sm:grid-cols-[5.5rem_minmax(0,1fr)]",children:[e.jsx("input",{type:"color",value:l,onChange:d=>n(d.target.value),className:"h-12 w-full cursor-pointer rounded-[18px] border border-white/10 bg-transparent p-1"}),e.jsx(F,{value:l,onChange:d=>n(d.target.value),placeholder:"#7cc7ff"})]})})}function He({open:s,onOpenChange:l,value:n,onSave:i}){const[d,p]=j.useState(n),[u,m]=j.useState(""),[y,f]=j.useState(null),k=j.useRef(null),c=a=>{const r=Y.parse(JSON.parse(a));p(r),m(JSON.stringify(r,null,2)),f(null)},g=a=>{const r=ee(a);p({...r,label:d.label.trim().length>0?d.label:`${r.label} Custom`})},S=async a=>{var o;const r=(o=a.target.files)==null?void 0:o[0];if(r)try{c(await r.text())}catch(C){f(C instanceof Error?C.message:"Forge could not parse that JSON theme.")}finally{a.target.value=""}},A=[{id:"identity",eyebrow:"Custom theme",title:"Name the mood and choose a starting point",description:"Start from a Forge preset, then tune the accents and surfaces in the next steps.",render:(a,r)=>e.jsxs("div",{className:"grid gap-5",children:[e.jsx(L,{label:"Theme label",description:"This label appears in Settings when the custom theme is active.",children:e.jsx(F,{value:a.label,onChange:o=>r({label:o.target.value}),placeholder:"Midnight Circuit"})}),e.jsx(L,{label:"Starter preset",children:e.jsx(je,{value:"",onChange:o=>g(o),options:Object.entries(Ne).map(([o,C])=>({value:o,label:C.label,description:C.description})),columns:2})}),e.jsx(R,{theme:a,title:a.label,description:"Live preview of the current custom theme draft."})]})},{id:"accents",eyebrow:"Custom theme",title:"Set the accent colors",description:"These colors drive buttons, highlights, charts, and the ambient shell lighting.",render:(a,r)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(w,{label:"Primary",description:"Main emphasis color for actions and active state.",value:a.primary,onChange:o=>r({primary:o})}),e.jsx(w,{label:"Secondary",description:"Support accent for positive or secondary emphasis.",value:a.secondary,onChange:o=>r({secondary:o})}),e.jsx(w,{label:"Tertiary",description:"Warm contrast color for warnings, highlights, and supporting metrics.",value:a.tertiary,onChange:o=>r({tertiary:o})})]})},{id:"surfaces",eyebrow:"Custom theme",title:"Tune the shell surfaces",description:"Forge currently assumes a dark shell, so these should remain fairly deep colors for legibility.",render:(a,r)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(w,{label:"Canvas",description:"Primary app background.",value:a.canvas,onChange:o=>r({canvas:o})}),e.jsx(w,{label:"Panel",description:"Default card and rail background.",value:a.panel,onChange:o=>r({panel:o})}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsx(w,{label:"Panel high",description:"Raised highlights and stronger sections.",value:a.panelHigh,onChange:o=>r({panelHigh:o})}),e.jsx(w,{label:"Panel low",description:"Lower contrast and deeper card areas.",value:a.panelLow,onChange:o=>r({panelLow:o})})]}),e.jsx(w,{label:"Ink",description:"Main text and readable foreground color.",value:a.ink,onChange:o=>r({ink:o})}),e.jsx(R,{theme:a,title:a.label,description:"Live preview after the current surface edits."})]})},{id:"import",eyebrow:"Custom theme",title:"Import or paste JSON directly",description:"You can skip the picker workflow entirely by uploading a JSON file or pasting a valid theme object.",render:a=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(L,{label:"Direct JSON",description:"Paste a full custom theme object, then click Apply JSON.",children:e.jsx(ke,{value:u,onChange:r=>m(r.target.value),className:"min-h-52 font-mono text-[13px] leading-6",placeholder:JSON.stringify(D,null,2)})}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(N,{type:"button",variant:"secondary",onClick:()=>{try{c(u)}catch(r){f(r instanceof Error?r.message:"Forge could not parse that JSON theme.")}},children:"Apply JSON"}),e.jsx(N,{type:"button",variant:"ghost",onClick:()=>{var r;return(r=k.current)==null?void 0:r.click()},children:"Upload JSON file"}),e.jsx("input",{ref:k,type:"file",accept:"application/json,.json",className:"hidden",onChange:S})]}),e.jsx(R,{theme:a,title:a.label,description:"Preview of the theme that will be saved if you submit now."})]})}];return e.jsx(we,{open:s,onOpenChange:a=>{a&&(p(n),m(""),f(null)),l(a)},eyebrow:"Settings",title:"Forge custom theme",description:"Build a dark Forge palette visually, or import one directly as JSON.",value:d,onChange:a=>{p(a),f(null)},draftPersistenceKey:"settings.theme-customizer",steps:A,error:y,onSubmit:async()=>{try{const a=Y.parse(d);i(a),l(!1)}catch(a){f(a instanceof Error?a.message:"Forge could not save that custom theme.")}},submitLabel:"Save custom theme",contentClassName:"lg:w-[min(62rem,calc(100vw-1.5rem))]"})}function Ue({theme:s}){return e.jsx("div",{className:"mt-3 grid grid-cols-4 gap-2",children:[s.primary,s.secondary,s.tertiary,s.panelHigh].map(l=>e.jsx("div",{className:"h-6 rounded-[10px] border border-black/10",style:{background:l}},l))})}function Be({selected:s,theme:l}){return e.jsxs("div",{className:"relative min-h-[138px] overflow-hidden rounded-[18px] border border-white/10 bg-[radial-gradient(circle_at_24%_10%,rgba(255,199,104,0.22),transparent_30%),radial-gradient(circle_at_88%_12%,rgba(84,191,255,0.16),transparent_32%),linear-gradient(145deg,rgba(255,255,255,0.08),rgba(255,255,255,0.025))]",children:[e.jsx("div",{className:"absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-black/42 to-transparent"}),e.jsx("img",{src:Me(l),alt:`${l} neutral Forge Smith mascot preview`,className:"absolute bottom-1 left-1/2 h-[124px] w-[124px] -translate-x-1/2 object-contain drop-shadow-[0_18px_30px_rgba(0,0,0,0.34)]"}),e.jsxs("div",{className:"absolute left-3 top-3 flex items-center gap-2 rounded-full border border-white/10 bg-black/28 px-2.5 py-1 text-[9px] font-semibold uppercase tracking-[0.14em] text-white/78 backdrop-blur-md",children:[e.jsx(ge,{className:"size-3 text-amber-200"}),"Live rewards"]}),e.jsx("div",{className:"absolute bottom-3 left-3 flex items-center gap-1.5",children:Qe.map(n=>e.jsx("span",{className:"grid size-11 place-items-center overflow-hidden rounded-[12px] border border-white/12 bg-black/26 p-1 shadow-[0_12px_22px_rgba(0,0,0,0.22)] backdrop-blur-md",children:e.jsx("img",{src:Re(l,n),alt:`${l} reward thumbnail`,className:"size-full object-contain"})},n))}),e.jsx("span",{className:`absolute right-3 top-3 grid size-7 place-items-center rounded-full border ${s?"border-emerald-200/55 bg-emerald-300/18 text-emerald-100":"border-white/15 bg-black/20 text-white/40"}`,children:s?e.jsx(he,{className:"size-4"}):null})]})}function V({healthy:s}){return e.jsx(T,{className:"p-4",children:e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Mobile companion"}),e.jsx("div",{className:"mt-1 text-base font-medium text-white",children:s?"iPhone bridge is syncing":"Connect the iPhone bridge"}),e.jsx("div",{className:"mt-1 max-w-3xl text-sm leading-6 text-white/58",children:s?"Review HealthKit, movement, and background sync permissions.":"Pair or refresh the native companion before relying on HealthKit, movement, or watch signals."})]}),e.jsx(ue,{to:"/settings/mobile",className:"inline-flex min-h-10 items-center rounded-[14px] bg-white/[0.08] px-3 py-2 text-sm text-white transition hover:bg-white/[0.12]",children:"Open mobile settings"})]})})}function M(s){return new Date(s).toLocaleString()}function te({integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i}){return i?[i.integrity.headline,i.integrity.topIssues.length>0?i.integrity.topIssues[0].summary:"No active Doctor warnings are holding back integrity.",`Storage mode: ${l}. Latest Doctor run: ${M(i.integrity.lastCheckedAt)}.`]:s>=100?["All currently reported settings and storage checks passed.",`Latest audit: ${M(n)}.`]:[`Forge is holding back ${Math.max(0,100-s)}% because the latest settings and storage audit reported a consistency warning.`,"The current audit only exposes the aggregate score, so per-check details are not available yet.",`Storage mode: ${l}. Latest audit: ${M(n)}.`]}function se({integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i}){const d=(i==null?void 0:i.integrity.score)??s,p=te({integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i});return e.jsxs("details",{className:"group relative inline-flex",children:[e.jsxs("summary",{className:"inline-flex cursor-pointer list-none items-center gap-1 rounded-full border border-white/10 bg-white/[0.05] px-2.5 py-1 text-[11px] font-medium normal-case tracking-normal text-white/72 transition marker:hidden hover:border-white/18 hover:bg-white/[0.08] hover:text-white/88 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgba(192,193,255,0.35)] [&::-webkit-details-marker]:hidden",onKeyDown:u=>{var m;u.key==="Escape"&&((m=u.currentTarget.parentElement)==null||m.removeAttribute("open"))},children:[e.jsx(xe,{className:"size-3.5","aria-hidden":"true"}),d,"% integrity"]}),e.jsxs("span",{role:"tooltip",className:"absolute right-0 top-[calc(100%+0.55rem)] z-50 hidden w-[min(19rem,calc(100vw-2rem))] rounded-[16px] border border-white/10 bg-[rgba(10,15,27,0.98)] px-3 py-2.5 text-left text-xs leading-5 tracking-normal text-white/70 normal-case shadow-[0_18px_48px_rgba(3,8,18,0.46)] group-open:block",children:[e.jsx("span",{className:"block font-medium text-white/88",children:d>=100?"Integrity is complete":`Why this is ${d}%`}),p.map(u=>e.jsx("span",{className:"mt-1 block",children:u},u))]})]})}function We({integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i,doctorLoading:d,onRefreshDoctor:p,onApplyFix:u,applyingFixId:m}){const y=(i==null?void 0:i.integrity.score)??s,f=(i==null?void 0:i.integrity.lastCheckedAt)??n,k=(i==null?void 0:i.issues.filter(g=>g.severity!=="info").slice(0,4))??[],[c]=te({integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i});return e.jsxs(T,{className:"p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Security posture"}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-white/58",children:"Local-first means Forge stores its runtime data on this machine. Integrity is the latest internal consistency score from settings and data checks."}),e.jsx("div",{className:"mt-2 text-xs leading-5 text-white/50",children:c})]}),e.jsx(se,{integrityScore:s,storageMode:l,lastAuditAt:n,doctor:i})]}),e.jsxs("div",{className:"mt-3 grid gap-2 md:grid-cols-2",children:[e.jsxs("div",{className:"rounded-[14px] bg-white/[0.04] px-3 py-3",children:[e.jsx("div",{className:"text-xs text-white/54",children:"Storage mode"}),e.jsx("div",{className:"mt-1 text-base font-medium text-white",children:l})]}),e.jsxs("div",{className:"rounded-[14px] bg-white/[0.04] px-3 py-3",children:[e.jsx("div",{className:"text-xs text-white/54",children:"Last Doctor run"}),e.jsx("div",{className:"mt-1 text-base font-medium text-white",children:M(f)})]})]}),e.jsxs("div",{className:"mt-3 rounded-[14px] border border-white/8 bg-white/[0.035] p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm font-medium text-white",children:[e.jsx(be,{className:"size-4 text-cyan-200"}),"Forge Doctor"]}),e.jsxs(N,{type:"button",variant:"secondary",pending:d,onClick:p,children:[e.jsx(fe,{className:"size-4"}),"Run"]})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/58",children:i?`${y}% integrity. ${i.integrity.headline}`:"Run Doctor to check settings, storage, entities, rewards, and runtime consistency."}),k.length>0?e.jsx("div",{className:"mt-3 grid gap-2",children:k.map(g=>{var S;return e.jsx(Ye,{issue:g,applying:m===((S=g.fix)==null?void 0:S.id),onApplyFix:u},g.id)})}):i?e.jsx("div",{className:"mt-3 rounded-[12px] border border-emerald-200/12 bg-emerald-300/8 px-3 py-2 text-sm text-emerald-100",children:"No active consistency warnings."}):null]})]})}function Ye({issue:s,applying:l,onApplyFix:n}){var i;return e.jsx("div",{className:"rounded-[12px] border border-white/8 bg-black/12 px-3 py-2",children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-2",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"text-xs uppercase tracking-[0.14em] text-white/42",children:[s.group," / ",s.severity]}),e.jsx("div",{className:"mt-1 text-sm text-white/78",children:s.summary})]}),((i=s.fix)==null?void 0:i.kind)==="safe_auto_fix"?e.jsx(N,{type:"button",variant:"secondary",pending:l,onClick:()=>n(s.fix.id),children:"Apply fix"}):null]})})}function lt(){var G,H,U,B,W;const{t:s}=Se(),l=Ce(),n=ye(),[i,d]=j.useState(!1),p=_({queryKey:["forge-operator-session"],queryFn:qe}),u=p.isSuccess,m=_({queryKey:["forge-settings"],queryFn:ze,enabled:u}),y=Fe(void 0,{skip:!u}),f=_({queryKey:["forge-companion-overview"],queryFn:async()=>(await Je()).overview,enabled:u,staleTime:3e4}),k=_({queryKey:["forge-gamification-assets"],queryFn:Ke,enabled:u,staleTime:3e4}),c=ve({defaultValues:{profile:{operatorName:"",operatorEmail:"",operatorTitle:""},notifications:{goalDriftAlerts:!0,dailyQuestReminders:!0,achievementCelebrations:!0},execution:{maxActiveTasks:2,timeAccountingMode:"split"},themePreference:"obsidian",gamificationTheme:"dramatic-smithie",customTheme:D,localePreference:"en"}}),g=async()=>{await Promise.all([n.invalidateQueries({queryKey:["forge-operator-session"]}),n.invalidateQueries({queryKey:["forge-settings"]})])},S=$({mutationFn:t=>I(t),onSuccess:g}),A=$({mutationFn:t=>I(t),onSuccess:async t=>{n.setQueryData(["forge-settings"],t),await g()}}),a=$({mutationFn:t=>I(t),onSuccess:async t=>{n.setQueryData(["forge-settings"],t),await g()}}),r=$({mutationFn:async t=>(await Te(t),I({gamificationTheme:t})),onSuccess:async t=>{n.setQueryData(["forge-settings"],t),await Promise.all([n.invalidateQueries({queryKey:["forge-settings"]}),n.invalidateQueries({queryKey:["forge-gamification-assets"]})])}}),[o,C]=Pe(),[ae,ie]=De(),[re,q]=j.useState(),ne=async()=>{await o().unwrap(),l(Ie([])),l(Le.util.resetApiState()),n.removeQueries({predicate:t=>{const[b]=t.queryKey;return typeof b=="string"&&b.startsWith("forge-")}}),await Promise.all([g(),p.refetch()])};j.useEffect(()=>{var t;(t=m.data)!=null&&t.settings&&c.reset(Ae.parse(m.data.settings))},[m.data,c]);const x=(G=m.data)==null?void 0:G.settings,le=(H=y.data)==null?void 0:H.doctor,P=c.watch("themePreference"),z=c.watch("gamificationTheme"),J=((U=k.data)==null?void 0:U.assets.styles)??[],Q=J.find(t=>t.id===z),v=c.watch("customTheme")??D,K=((B=f.data)==null?void 0:B.healthState)==="healthy_sync",oe=async t=>{if(window.confirm("Apply this Forge Doctor fix? Forge will only run the selected safe repair.")){q(t);try{await ae({fixIds:[t]}).unwrap(),await Promise.all([m.refetch(),y.refetch()])}finally{q(void 0)}}},O=async(t,b=v)=>{c.setValue("themePreference",t,{shouldDirty:!0}),c.setValue("customTheme",b??D,{shouldDirty:!0}),await A.mutateAsync({themePreference:t,customTheme:b??D})},ce=async t=>{c.setValue("gamificationTheme",t,{shouldDirty:!0}),await a.mutateAsync({gamificationTheme:t})};return j.useEffect(()=>{if(x)return X(P,v),()=>{X(x.themePreference,x.customTheme??null)}},[v,P,x,x==null?void 0:x.customTheme,x==null?void 0:x.themePreference]),p.isLoading||m.isLoading?e.jsx(Ee,{eyebrow:"Settings",title:"Loading settings",description:"Establishing the operator session and fetching current configuration.",columns:2,blocks:6}):p.isError?e.jsx(Z,{eyebrow:"Settings",error:p.error,onRetry:()=>void p.refetch()}):m.isError||!x?e.jsx(Z,{eyebrow:"Settings",error:m.error??new Error("Forge returned an empty settings payload."),onRetry:()=>void m.refetch()}):e.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[e.jsx(Ge,{title:"Settings",description:"Tune execution policy, timer behaviour, and personal preferences.",badge:e.jsx(se,{integrityScore:x.security.integrityScore,storageMode:x.security.storageMode,lastAuditAt:x.security.lastAuditAt})}),null,e.jsx(Oe,{}),(W=p.data)!=null&&W.session?e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-[18px] border border-emerald-400/20 bg-emerald-500/[0.08] px-4 py-3 text-sm text-emerald-100/88",children:[e.jsxs("div",{children:["Operator session active as"," ",e.jsx("span",{className:"font-medium text-white",children:p.data.session.actorLabel}),"."]}),e.jsx(N,{variant:"secondary",size:"sm",pending:C.isLoading,pendingLabel:"Resetting session",onClick:()=>void ne(),children:"Reset operator session"})]}):null,e.jsxs("div",{className:"grid gap-4",children:[K?null:e.jsx(V,{healthy:!1}),e.jsxs("form",{className:"grid gap-4",onSubmit:c.handleSubmit(async t=>{await S.mutateAsync(t)}),children:[e.jsxs(T,{className:"p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Operator profile"}),e.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Name"}),e.jsx(F,{...c.register("profile.operatorName")})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Email"}),e.jsx(F,{...c.register("profile.operatorEmail")})]})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Title"}),e.jsx(F,{...c.register("profile.operatorTitle")})]}),e.jsx("div",{className:"mt-2 font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Execution policy"}),e.jsxs("div",{className:"grid gap-3 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)]",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Maximum active tasks"}),e.jsx(F,{type:"number",min:1,max:8,...c.register("execution.maxActiveTasks",{valueAsNumber:!0})})]}),e.jsxs("div",{className:"grid gap-3",children:[e.jsx("div",{className:"text-sm text-white/58",children:"Time accounting mode"}),e.jsx("div",{className:"grid gap-2 md:grid-cols-3",children:[{value:"split",label:"Split",description:"Multitasking divides credited time across active tasks."},{value:"parallel",label:"Parallel",description:"Every active task receives full credited wall time."},{value:"primary_only",label:"Primary only",description:"Only the highlighted task earns credited time during overlap."}].map(t=>e.jsxs("label",{className:"grid gap-2 rounded-[16px] bg-white/[0.04] px-3 py-3",children:[e.jsxs("span",{className:"flex items-center gap-3",children:[e.jsx("input",{type:"radio",value:t.value,...c.register("execution.timeAccountingMode")}),e.jsx("span",{className:"text-white/82",children:t.label})]}),e.jsx("span",{className:"text-xs leading-5 text-white/56",children:t.description})]},t.value))})]})]}),e.jsx("div",{className:"mt-2 font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Notification rules"}),e.jsxs("label",{className:"flex items-center justify-between rounded-[16px] bg-white/[0.04] px-3 py-2.5",children:[e.jsx("span",{className:"text-white/72",children:"Goal drift alerts"}),e.jsx("input",{type:"checkbox",...c.register("notifications.goalDriftAlerts")})]}),e.jsxs("label",{className:"flex items-center justify-between rounded-[16px] bg-white/[0.04] px-3 py-2.5",children:[e.jsx("span",{className:"text-white/72",children:"Daily quest reminders"}),e.jsx("input",{type:"checkbox",...c.register("notifications.dailyQuestReminders")})]}),e.jsxs("label",{className:"flex items-center justify-between rounded-[16px] bg-white/[0.04] px-3 py-2.5",children:[e.jsx("span",{className:"text-white/72",children:"Achievement celebrations"}),e.jsx("input",{type:"checkbox",...c.register("notifications.achievementCelebrations")})]})]}),e.jsxs(T,{className:"p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Theme calibration"}),e.jsx("p",{className:"text-sm text-white/58",children:"Switch between Forge dark and light presets, follow the system palette, or save your own shell theme."}),e.jsx("div",{className:"grid gap-2 xl:grid-cols-3",children:_e.map(t=>{const b=ee(t.value,v),h=P===t.value;return e.jsxs("button",{type:"button",onClick:()=>void O(t.value,(t.value==="custom",v)),className:`rounded-[18px] border px-3 py-3 text-left transition ${h?"border-[rgba(192,193,255,0.28)] bg-[rgba(192,193,255,0.14)] shadow-[0_18px_36px_rgba(5,12,24,0.24)]":"border-white/8 bg-white/[0.04] hover:bg-white/[0.07]"}`,children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-white",children:t.value==="custom"?v.label:t.label}),e.jsx("div",{className:"mt-1 line-clamp-2 text-xs leading-5 text-white/58",children:t.description})]}),e.jsx("div",{className:`mt-1 size-4 rounded-full border ${h?"border-[rgba(192,193,255,0.65)] bg-[var(--primary)]":"border-white/25"}`})]}),e.jsx(Ue,{theme:b})]},t.value)})}),e.jsxs("div",{className:"mt-3 flex flex-wrap items-center justify-between gap-3 rounded-[16px] bg-white/[0.04] px-3 py-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium text-white",children:"Custom theme editor"}),e.jsx("div",{className:"mt-1 text-sm leading-6 text-white/58",children:"Save a custom Forge palette through a guided modal, or paste and upload JSON directly."})]}),e.jsx(N,{type:"button",variant:P==="custom"?"secondary":"ghost",onClick:()=>d(!0),pending:A.isPending,children:P==="custom"?"Edit custom theme":"Create custom theme"})]})]}),e.jsxs(T,{className:"p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Gamification style"}),e.jsx("p",{className:"text-sm text-white/58",children:"Choose the reward art style and download its optional trophy, unlock, and mascot sprites."})]}),Q!=null&&Q.installed?e.jsx("span",{className:"inline-flex rounded-full border border-emerald-200/18 bg-emerald-300/10 px-3 py-1 text-xs font-medium text-emerald-100",children:"Selected style downloaded"}):e.jsx("span",{className:"inline-flex rounded-full border border-amber-200/18 bg-amber-300/10 px-3 py-1 text-xs font-medium text-amber-100",children:"Selected style not downloaded"})]}),e.jsx("div",{className:"mt-3 grid gap-2 xl:grid-cols-3",children:$e.map(t=>{const b=z===t.value,h=J.find(me=>me.id===t.value),E=(h==null?void 0:h.installed)??!1,de=r.isPending&&r.variables===t.value;return e.jsxs("div",{className:`grid gap-2 rounded-[18px] border p-2.5 text-left transition ${b?"border-amber-200/28 bg-amber-300/[0.09] shadow-[0_18px_42px_rgba(0,0,0,0.26)]":"border-white/8 bg-white/[0.035] hover:border-white/16 hover:bg-white/[0.065]"}`,children:[e.jsx("button",{type:"button",onClick:()=>void ce(t.value),className:"grid gap-2 text-left","aria-label":`Select ${t.label}`,"aria-pressed":b,children:e.jsx(Be,{selected:b,theme:t.value})}),e.jsxs("span",{className:"grid gap-1 px-1 pb-1",children:[e.jsx("span",{className:"text-sm font-semibold text-white",children:t.label}),e.jsx("span",{className:"line-clamp-2 text-xs leading-5 text-white/58",children:t.description}),e.jsx("span",{className:"mt-1 text-[11px] uppercase tracking-[0.14em] text-white/42",children:E?`Downloaded ${(h==null?void 0:h.spriteCount)??0}/${(h==null?void 0:h.expectedSpriteCount)??0}`:"Not downloaded"}),e.jsxs(N,{type:"button",variant:E?"secondary":"primary",pending:de,disabled:E||r.isPending,onClick:()=>r.mutate(t.value),children:[e.jsx(pe,{className:"size-4"}),E?"Downloaded":"Download"]})]})]},t.value)})}),a.isPending?e.jsx("div",{className:"text-sm text-white/48",children:"Saving reward style…"}):null,r.isError?e.jsx("div",{className:"mt-3 rounded-[14px] border border-red-300/20 bg-red-500/10 px-3 py-2 text-sm text-red-100",children:r.error instanceof Error?r.error.message:"Could not download the selected reward art."}):null]}),e.jsxs(T,{className:"p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:s("common.settings.localeLabel")}),e.jsx("p",{className:"text-sm text-white/58",children:s("common.settings.localeDescription")}),e.jsx("div",{className:"grid gap-3 md:grid-cols-2",children:[{value:"en",label:s("common.settings.localeEnglish")},{value:"fr",label:s("common.settings.localeFrench")}].map(t=>e.jsxs("label",{className:"flex items-center gap-3 rounded-[16px] bg-white/[0.04] px-3 py-3",children:[e.jsx("input",{type:"radio",value:t.value,...c.register("localePreference")}),e.jsx("span",{className:"text-white/72",children:t.label})]},t.value))}),e.jsx(N,{type:"submit",pending:S.isPending,pendingLabel:"Saving settings",children:"Save settings"})]})]}),K?e.jsx(V,{healthy:!0}):null,e.jsx(We,{integrityScore:x.security.integrityScore,storageMode:x.security.storageMode,lastAuditAt:x.security.lastAuditAt,doctor:le,doctorLoading:y.isFetching||ie.isLoading,onRefreshDoctor:()=>void y.refetch(),onApplyFix:t=>void oe(t),applyingFixId:re})]}),e.jsx(He,{open:i,onOpenChange:d,value:v,onSave:t=>void O("custom",t)})]})}export{lt as SettingsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as e,r as w}from"./vendor-DHkYh85p.js";import{j as $,i as v,k as K}from"./state-B-4sS1xO.js";import{u as D}from"./forms-BFlTgZ3W.js";import{S as H}from"./settings-section-nav-DSOuht_F.js";import{c as u,Z as S,W as B,f as z,u as U,eq as Y,er as ee,S as se,E as te,C as ae,I as P,T as E,B as V,dx as re,cZ as ie,es as le,et as ne,ad as de}from"./index-CF4J4R9L.js";import{m as G}from"./motion-BeD44FeG.js";import{P as ce}from"./page-hero-DRy5b2MU.js";import{M as W}from"./metric-tile-DKpo-8xw.js";import"./board-BkDRaMp6.js";import"./ui-C13Nbgas.js";import"./graph-D6JLqDbD.js";function oe(a){switch(a){case"platinum":return"text-cyan-200";case"gold":return"text-amber-200";case"silver":return"text-slate-200";default:return"text-orange-200"}}function me(a){switch(a){case"surging":return"from-[rgba(192,193,255,0.3)] via-[rgba(78,222,163,0.22)] to-[rgba(255,185,95,0.22)]";case"steady":return"from-[rgba(192,193,255,0.24)] via-[rgba(192,193,255,0.14)] to-[rgba(78,222,163,0.18)]";default:return"from-[rgba(255,185,95,0.2)] via-[rgba(255,185,95,0.12)] to-[rgba(192,193,255,0.16)]"}}function xe({profile:a,achievements:o,milestoneRewards:n,momentumPulse:m,recentLedger:R=[],className:j,tone:k="core"}){const y=o.filter(r=>r.unlocked),h=(y.length>0?y:o).slice(0,3),X=n.slice(0,3),L=R.slice(0,3),I=Math.min(100,Math.round(a.currentLevelXp/a.nextLevelXp*100));return e.jsxs("section",{className:S("min-w-0 overflow-hidden rounded-[30px] border border-white/6 bg-[linear-gradient(180deg,rgba(18,24,40,0.96),rgba(11,16,28,0.94))] shadow-[0_24px_70px_rgba(4,8,18,0.3)]",k==="psyche"&&"bg-[linear-gradient(180deg,rgba(18,27,35,0.96),rgba(12,20,26,0.94))]",j),children:[e.jsx("div",{className:S("bg-gradient-to-r px-5 py-5",me(m.status)),children:e.jsxs("div",{className:"flex min-w-0 flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.2em] text-white/55",children:"Weekly progress"}),e.jsx("h2",{className:"mt-3 font-display text-3xl leading-none text-white lg:text-4xl",children:m.headline}),e.jsx("p",{className:"mt-3 max-w-3xl text-sm leading-7 text-white/68",children:m.detail})]}),e.jsxs("div",{className:"flex min-w-0 flex-wrap gap-2",children:[e.jsxs(u,{wrap:!0,className:"bg-black/20 text-white/84",children:["Level ",a.level]}),e.jsxs(u,{wrap:!0,className:"bg-black/20 text-white/84",children:[a.streakDays," day streak"]}),e.jsxs(u,{wrap:!0,className:"bg-black/20 text-white/84",children:[a.weeklyXp," weekly XP"]})]})]})}),e.jsxs("div",{className:"grid gap-5 px-5 py-5 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]",children:[e.jsxs("div",{className:"grid gap-5",children:[e.jsxs(G.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.24,ease:"easeOut"},className:"overflow-hidden rounded-[24px] bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-medium text-white",children:"Next reward"}),e.jsx("div",{className:"mt-2 text-sm text-white/60",children:m.nextMilestoneLabel})]}),e.jsx(u,{wrap:!0,className:"max-w-[12rem] shrink-0 self-start text-[var(--tertiary)]",children:m.celebrationLabel})]}),e.jsx("div",{className:"mt-5",children:e.jsx(B,{value:I})}),e.jsxs("div",{className:"mt-3 flex items-center justify-between gap-3 text-xs uppercase tracking-[0.16em] text-white/38",children:[e.jsxs("span",{children:[a.currentLevelXp,"/",a.nextLevelXp," XP"]}),e.jsxs("span",{children:[a.comboMultiplier.toFixed(2),"x combo"]})]})]}),e.jsx("div",{className:"grid gap-3 md:grid-cols-3",children:h.map((r,d)=>e.jsxs(G.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},transition:{duration:.24,delay:.04*d,ease:"easeOut"},className:"overflow-hidden rounded-[22px] bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-3",children:[e.jsx("div",{className:"min-w-0 flex-1 font-medium text-white",children:r.title}),e.jsx(u,{wrap:!0,className:S("max-w-[8rem] shrink-0 self-start",oe(r.tier)),children:r.tier})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/58",children:r.summary}),e.jsx("div",{className:"mt-4 text-xs uppercase tracking-[0.16em] text-white/40",children:r.progressLabel})]},r.id))})]}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"overflow-hidden rounded-[24px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Rewards in progress"}),e.jsx("div",{className:"mt-4 grid gap-3",children:X.map(r=>{const d=Math.min(100,Math.round(r.current/r.target*100));return e.jsxs("div",{className:"overflow-hidden rounded-[18px] bg-[rgba(8,13,28,0.68)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-3",children:[e.jsx("div",{className:"min-w-0 flex-1 font-medium text-white",children:r.title}),e.jsx(u,{wrap:!0,className:S("max-w-[10.5rem] shrink-0 self-start",r.completed?"text-emerald-300":"text-white/68"),children:r.rewardLabel})]}),e.jsx("div",{className:"mt-2 text-sm text-white/58",children:r.summary}),e.jsx("div",{className:"mt-4",children:e.jsx(B,{value:d})}),e.jsx("div",{className:"mt-3 text-xs uppercase tracking-[0.16em] text-white/38",children:r.progressLabel})]},r.id)})})]}),L.length>0?e.jsxs("div",{className:"overflow-hidden rounded-[24px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Recent XP changes"}),e.jsx("div",{className:"mt-4 grid gap-3",children:L.map(r=>e.jsxs("div",{className:"overflow-hidden rounded-[18px] bg-[rgba(8,13,28,0.68)] p-4",children:[e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-3",children:[e.jsx("div",{className:"min-w-0 flex-1 font-medium text-white",children:r.reasonTitle}),e.jsxs(u,{wrap:!0,className:S("max-w-[8rem] shrink-0 self-start",r.deltaXp>=0?"text-emerald-300":"text-amber-300"),children:[r.deltaXp>0?"+":"",r.deltaXp," XP"]})]}),e.jsx("div",{className:"mt-2 text-sm text-white/58",children:r.reasonSummary}),e.jsx("div",{className:"mt-3 text-xs uppercase tracking-[0.16em] text-white/38",children:z(r.createdAt)})]},r.id))})]}):null]})]})]})}function pe(a){return JSON.stringify(a,null,2)}function Z(a){const o=a.trim();if(!o)return{};const n=JSON.parse(o);if(!n||typeof n!="object"||Array.isArray(n))throw new Error("Expected a JSON object.");return n}function ke(){var F,_,A;const a=U(),o=$(),[n,m]=w.useState(""),[R,j]=w.useState(null),[k,y]=w.useState(null),h=v({queryKey:["forge-operator-session"],queryFn:re}),X=h.isSuccess,L=v({queryKey:["forge-xp-metrics"],queryFn:ie}),I=v({queryKey:["forge-reward-rules"],queryFn:le,enabled:X}),r=v({queryKey:["forge-reward-ledger"],queryFn:()=>ne(30),enabled:X}),d=v({queryKey:["forge-psyche-overview"],queryFn:async()=>(await de()).overview}),g=D({defaultValues:{title:"",description:"",active:!0,configJson:"{}"}}),l=D({defaultValues:{entityType:"task",entityId:"",deltaXp:15,reasonTitle:"Operator bonus",reasonSummary:"Manual boost for a meaningful action captured with good provenance.",metadataJson:"{}"}}),q=async()=>{await Promise.all([o.invalidateQueries({queryKey:["forge-xp-metrics"]}),o.invalidateQueries({queryKey:["forge-reward-rules"]}),o.invalidateQueries({queryKey:["forge-reward-ledger"]})])},O=K({mutationFn:s=>Y(s.ruleId,{title:s.title,description:s.description,active:s.active,config:s.config}),onSuccess:q}),b=K({mutationFn:ee,onSuccess:q}),x=((F=I.data)==null?void 0:F.rules)??[],M=w.useMemo(()=>{var s,i,f,N,T,C,Q;return{system:[{id:"operator_manual_reward",label:"Operator reward ledger"}],goal:a.snapshot.goals.map(t=>({id:t.id,label:t.title})),project:a.snapshot.dashboard.projects.map(t=>({id:t.id,label:t.title})),task:a.snapshot.tasks.map(t=>({id:t.id,label:t.title})),habit:a.snapshot.habits.map(t=>({id:t.id,label:t.title})),tag:a.snapshot.tags.map(t=>({id:t.id,label:t.name})),note:[],insight:[],psyche_value:(((s=d.data)==null?void 0:s.values)??[]).map(t=>({id:t.id,label:t.title})),behavior_pattern:(((i=d.data)==null?void 0:i.patterns)??[]).map(t=>({id:t.id,label:t.title})),behavior:(((f=d.data)==null?void 0:f.behaviors)??[]).map(t=>({id:t.id,label:t.title})),belief_entry:(((N=d.data)==null?void 0:N.beliefs)??[]).map(t=>({id:t.id,label:t.statement})),mode_profile:(((T=d.data)==null?void 0:T.modes)??[]).map(t=>({id:t.id,label:t.title})),flashcard:(((C=d.data)==null?void 0:C.flashcards)??[]).map(t=>({id:t.id,label:t.title||t.message})),trigger_report:(((Q=d.data)==null?void 0:Q.reports)??[]).map(t=>({id:t.id,label:t.title}))}},[d.data,a.snapshot.dashboard.projects,a.snapshot.goals,a.snapshot.habits,a.snapshot.tags,a.snapshot.tasks]);w.useEffect(()=>{var N;const s=l.getValues("entityType"),i=l.getValues("entityId"),f=M[s]??[];i&&f.some(T=>T.id===i)||l.setValue("entityId",((N=f[0])==null?void 0:N.id)??"")},[l,M]),w.useEffect(()=>{x.length&&(!n||!x.some(s=>s.id===n))&&m(x[0].id)},[x,n]);const p=x.find(s=>s.id===n)??x[0]??null;w.useEffect(()=>{p&&(g.reset({title:p.title,description:p.description,active:p.active,configJson:pe(p.config)}),j(null))},[p,g]);const c=(_=L.data)==null?void 0:_.metrics,J=(((A=r.data)==null?void 0:A.ledger)??[]).filter(s=>s.metadata.manual===!0).slice(0,8);return h.isLoading?e.jsx(se,{eyebrow:"Settings · Rewards",title:"Loading reward controls",description:"Establishing the operator session and fetching reward configuration.",columns:2,blocks:6}):h.isError?e.jsx(te,{eyebrow:"Settings · Rewards",error:h.error,onRetry:()=>void h.refetch()}):e.jsxs("div",{className:"mx-auto grid w-full max-w-[1220px] gap-5",children:[e.jsx(ce,{title:"Rewards",description:"XP command deck, reward rule editor, manual bonus grants, and ledger history."}),e.jsx(H,{}),e.jsx("div",{className:"grid gap-5",children:e.jsxs(ae,{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Reward operations"}),e.jsxs("div",{className:"mt-4 grid gap-4",children:[c?e.jsx(xe,{profile:c.profile,achievements:c.achievements,milestoneRewards:c.milestoneRewards,momentumPulse:c.momentumPulse,recentLedger:c.recentLedger}):null,c?e.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[e.jsx(W,{label:"Total XP",value:c.profile.totalXp,tone:"core"}),e.jsx(W,{label:"Daily ambient",value:`${c.dailyAmbientXp} / ${c.dailyAmbientCap}`,tone:"core"})]}):null,e.jsxs("div",{className:"grid gap-4 xl:grid-cols-2",children:[e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-medium text-white",children:"Reward rule editor"}),x.length>0?e.jsxs("form",{className:"mt-4 grid gap-4",onSubmit:g.handleSubmit(async s=>{try{j(null);const i=Z(s.configJson);if(!p)return;await O.mutateAsync({ruleId:p.id,title:s.title,description:s.description,active:s.active,config:i})}catch(i){j(i instanceof Error?i.message:"Invalid reward rule config.")}}),children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Rule"}),e.jsx("select",{className:"rounded-[14px] bg-white/[0.06] px-3 py-3 text-white",value:n,onChange:s=>m(s.target.value),children:x.map(s=>e.jsx("option",{value:s.id,children:s.title},s.id))})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Title"}),e.jsx(P,{...g.register("title")})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Description"}),e.jsx(E,{className:"min-h-24",...g.register("description")})]}),e.jsxs("label",{className:"flex items-center justify-between rounded-[18px] bg-[rgba(8,13,28,0.68)] px-4 py-3",children:[e.jsx("span",{className:"text-white/72",children:"Rule is active"}),e.jsx("input",{type:"checkbox",...g.register("active")})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Config JSON"}),e.jsx(E,{className:"min-h-28 font-mono text-xs",...g.register("configJson")})]}),R?e.jsx("div",{className:"text-sm text-amber-300",children:R}):null,e.jsx(V,{type:"submit",pending:O.isPending,pendingLabel:"Saving rule",children:"Save reward rule"})]}):e.jsx("div",{className:"mt-4 text-sm text-white/58",children:"Loading reward rules…"})]}),e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-medium text-white",children:"Manual bonus XP"}),e.jsxs("form",{className:"mt-4 grid gap-4",onSubmit:l.handleSubmit(async s=>{try{y(null);const i=Z(s.metadataJson);await b.mutateAsync({entityType:s.entityType,entityId:s.entityId,deltaXp:s.deltaXp,reasonTitle:s.reasonTitle,reasonSummary:s.reasonSummary,metadata:i}),l.reset({...s,entityId:"",reasonTitle:"Operator bonus",reasonSummary:"Manual boost for a meaningful action captured with good provenance.",metadataJson:"{}"})}catch(i){y(i instanceof Error?i.message:"Invalid metadata payload.")}}),children:[e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Entity type"}),e.jsx("select",{className:"rounded-[14px] bg-white/[0.06] px-3 py-3 text-white",...l.register("entityType"),children:Object.keys(M).map(s=>e.jsx("option",{value:s,children:s.replaceAll("_"," ")},s))})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Entity id"}),e.jsx("select",{className:"rounded-[14px] bg-white/[0.06] px-3 py-3 text-white",...l.register("entityId"),children:(M[l.watch("entityType")]??[]).map(s=>e.jsx("option",{value:s.id,children:s.label},s.id))})]})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Delta XP"}),e.jsx(P,{type:"number",...l.register("deltaXp",{valueAsNumber:!0})})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Reason title"}),e.jsx(P,{...l.register("reasonTitle")})]})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Reason summary"}),e.jsx(E,{className:"min-h-24",...l.register("reasonSummary")})]}),e.jsxs("label",{className:"grid gap-2",children:[e.jsx("span",{className:"text-sm text-white/58",children:"Metadata JSON"}),e.jsx(E,{className:"min-h-24 font-mono text-xs",...l.register("metadataJson")})]}),k?e.jsx("div",{className:"text-sm text-amber-300",children:k}):null,e.jsx(V,{type:"submit",pending:b.isPending,pendingLabel:"Issuing bonus",children:"Issue bonus XP"})]}),b.data?e.jsxs("div",{className:"mt-4 rounded-[18px] bg-[rgba(192,193,255,0.12)] p-4 text-sm text-white",children:["Granted ",b.data.reward.deltaXp>0?"+":"",b.data.reward.deltaXp," XP for ",e.jsx("strong",{children:b.data.reward.reasonTitle}),"."]}):null]})]}),e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] p-4",children:[e.jsx("div",{className:"font-medium text-white",children:"Manual bonus history"}),e.jsx("div",{className:"mt-4 grid gap-3",children:J.length===0?e.jsx("div",{className:"rounded-[18px] bg-[rgba(8,13,28,0.68)] p-4 text-sm text-white/58",children:"No manual bonus grants yet."}):J.map(s=>e.jsxs("div",{className:"rounded-[18px] bg-[rgba(8,13,28,0.68)] p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("div",{className:"font-medium text-white",children:s.reasonTitle}),e.jsxs(u,{className:s.deltaXp>=0?"text-emerald-300":"text-amber-300",children:[s.deltaXp>0?"+":"",s.deltaXp," XP"]})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/58",children:s.reasonSummary||"No summary supplied."}),e.jsxs("div",{className:"mt-2 text-xs uppercase tracking-[0.16em] text-white/38",children:[s.entityType," · ",s.entityId," · ",new Date(s.createdAt).toLocaleString()]})]},s.id))})]})]})]})})]})}export{ke as SettingsRewardsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{aJ as b,r as d,cm as v,cr as f,bO as g,aV as h,cZ as y,c_ as j,b2 as k,ba as N,c$ as w,aF as S,d0 as C,j as e,bz as x,o as z,aK as E}from"./vendor-DHkYh85p.js";import{C as T,Z as i}from"./index-CF4J4R9L.js";const o=[{to:"/settings",label:"General",icon:v},{to:"/settings/data",label:"Data",icon:f},{to:"/settings/users",label:"Users",icon:g},{to:"/settings/calendar",label:"Calendar",icon:h},{to:"/settings/mobile",label:"Mobile",icon:y},{to:"/settings/models",label:"Models",icon:j},{to:"/settings/agents",label:"Agents",icon:k},{to:"/settings/wiki",label:"KarpaWiki",icon:N},{to:"/settings/logs",label:"Logs",icon:w},{to:"/settings/rewards",label:"Rewards",icon:S},{to:"/settings/bin",label:"Bin",icon:C}];function m(t,a){return a==="/settings"?t==="/settings":t===a||t.startsWith(`${a}/`)}function O({className:t}){const a=b(),[l,n]=d.useState(!1),c=d.useMemo(()=>[...o].sort((r,s)=>s.to.length-r.to.length).find(r=>m(a.pathname,r.to))??o[0],[a.pathname]);return d.useEffect(()=>{if(!l)return;const r=document.body.style.overflow,s=document.body.style.touchAction,u=p=>{p.key==="Escape"&&n(!1)};return document.body.style.overflow="hidden",document.body.style.touchAction="none",window.addEventListener("keydown",u),()=>{document.body.style.overflow=r,document.body.style.touchAction=s,window.removeEventListener("keydown",u)}},[l]),e.jsxs(e.Fragment,{children:[e.jsxs(T,{className:i("surface-shell-panel overflow-hidden p-2",t),children:[e.jsx("div",{className:"hidden items-center gap-3 lg:flex",children:e.jsx("div",{className:"flex flex-wrap gap-2",children:o.map(r=>e.jsxs(x,{to:r.to,end:r.to==="/settings",className:({isActive:s})=>i("inline-flex items-center gap-2 whitespace-nowrap rounded-full px-3 py-1.5 text-[11px] font-semibold uppercase tracking-[0.14em] transition",s||m(a.pathname,r.to)?"border border-[var(--primary)]/14 bg-[var(--ui-accent-soft)] text-[var(--primary)]":"border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)] hover:border-[var(--ui-border-strong)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]"),children:[e.jsx(r.icon,{className:"size-3.5"}),e.jsx("span",{children:r.label})]},r.to))})}),e.jsx("div",{className:"flex items-center justify-between gap-3 lg:hidden",children:e.jsxs("button",{type:"button",className:"surface-shell-panel inline-flex min-w-0 flex-1 items-center justify-between gap-3 rounded-[22px] border px-3.5 py-2.5 text-left transition hover:border-[var(--ui-border-strong)] hover:bg-[var(--ui-surface-hover)]",onClick:()=>n(!0),children:[e.jsxs("span",{className:"flex min-w-0 items-center gap-3",children:[e.jsx("span",{className:"flex size-9 shrink-0 items-center justify-center rounded-2xl border border-[var(--primary)]/20 bg-[var(--primary)]/12",children:e.jsx(c.icon,{className:"size-4 text-[var(--primary)]"})}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-[10px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]",children:"Settings section"}),e.jsx("span",{className:"mt-0.5 block truncate text-sm font-medium text-[var(--ui-ink-strong)]",children:c.label})]})]}),e.jsx("span",{className:"rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] px-2.5 py-1 text-[10px] uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:"Browse"})]})})]}),l&&typeof document<"u"?z.createPortal(e.jsxs("div",{className:"lg:hidden",children:[e.jsx("div",{className:"surface-overlay fixed inset-0 z-50 backdrop-blur-xl"}),e.jsx("button",{type:"button","aria-label":"Close settings sections",className:"fixed inset-0 z-[51]",onClick:()=>n(!1)}),e.jsx("div",{className:"pointer-events-none fixed inset-0 z-[52] flex items-end justify-center px-3 pt-3 sm:px-4 sm:pt-4",style:{paddingLeft:"max(0.75rem, calc(var(--forge-safe-area-left) + 0.75rem))",paddingRight:"max(0.75rem, calc(var(--forge-safe-area-right) + 0.75rem))",paddingTop:"max(0.75rem, calc(env(safe-area-inset-top) + 0.75rem))",paddingBottom:"calc(var(--forge-mobile-nav-clearance) - 0.25rem)"},children:e.jsxs("div",{role:"dialog","aria-modal":"true","aria-label":"Settings sections",className:"surface-modal-panel pointer-events-auto flex max-h-[min(34rem,calc(100dvh-var(--forge-mobile-nav-clearance)-1rem))] w-full max-w-xl min-h-0 flex-col overflow-hidden rounded-[30px] border",children:[e.jsx("div",{className:"shrink-0 border-b border-[var(--ui-border-subtle)] px-4 pb-3 pt-4 sm:px-5",children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-label text-[10px] uppercase tracking-[0.22em] text-[var(--ui-ink-faint)]",children:"Settings"}),e.jsxs("div",{className:"mt-1 flex min-w-0 flex-wrap items-center gap-2",children:[e.jsx("div",{className:"truncate text-base font-semibold text-[var(--ui-ink-strong)]",children:"Tune Forge"}),e.jsx("span",{className:"rounded-full border border-[var(--primary)]/20 bg-[var(--primary)]/12 px-2.5 py-1 text-[10px] uppercase tracking-[0.16em] text-[var(--primary)]",children:c.label})]}),e.jsx("div",{className:"mt-1 text-xs leading-5 text-[var(--ui-ink-soft)]",children:"Jump between users, calendar, models, rewards, and more."})]}),e.jsx("button",{type:"button","aria-label":"Close settings sections",className:"inline-flex size-10 shrink-0 items-center justify-center rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)] transition hover:border-[var(--ui-border-strong)] hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]",onClick:()=>n(!1),children:e.jsx(E,{className:"size-4"})})]})}),e.jsx("div",{className:"min-h-0 overflow-y-auto p-3 overscroll-contain sm:p-4",children:e.jsx("div",{className:"grid gap-2",children:o.map(r=>{const s=m(a.pathname,r.to);return e.jsxs(x,{to:r.to,end:r.to==="/settings",onClick:()=>n(!1),className:i("group flex items-center justify-between gap-3 rounded-[22px] border px-3.5 py-3 transition-[transform,border-color,background-color,color] duration-150 hover:-translate-y-[1px] hover:text-white",s?"border-[var(--primary)]/18 bg-[var(--ui-accent-soft)] text-[var(--ui-ink-strong)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-medium)] hover:border-[var(--ui-border-strong)] hover:bg-[var(--ui-surface-hover)]"),children:[e.jsxs("span",{className:"flex min-w-0 items-center gap-3",children:[e.jsx("span",{className:i("flex size-10 shrink-0 items-center justify-center rounded-2xl border transition",s?"border-[var(--primary)]/18 bg-[var(--primary)]/14 text-[var(--primary)]":"border-[var(--ui-border-subtle)] bg-[var(--ui-surface-1)] text-[var(--ui-ink-soft)] group-hover:border-[var(--ui-border-strong)] group-hover:text-[var(--ui-ink-strong)]"),children:e.jsx(r.icon,{className:"size-4"})}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block truncate text-sm font-semibold text-[var(--ui-ink-strong)]",children:r.label}),e.jsx("span",{className:"mt-0.5 block text-[10px] uppercase tracking-[0.16em] text-[var(--ui-ink-faint)]",children:"Forge settings"})]})]}),e.jsx("span",{className:i("rounded-full px-2.5 py-1 text-[10px] uppercase tracking-[0.16em]",s?"bg-[var(--primary)]/16 text-[var(--primary)]":"bg-[var(--ui-surface-1)] text-[var(--ui-ink-faint)]"),children:s?"Current":"Open"})]},r.to)})})})]})})]}),document.body):null]})}export{O as S};
|