@harperfast/harper 5.1.25 → 5.1.26

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.
Files changed (39) hide show
  1. package/dist/server/http.js +29 -13
  2. package/dist/server/http.js.map +1 -1
  3. package/dist/server/threads/threadServer.js +13 -6
  4. package/dist/server/threads/threadServer.js.map +1 -1
  5. package/npm-shrinkwrap.json +2 -2
  6. package/package.json +1 -1
  7. package/server/http.ts +28 -12
  8. package/server/threads/threadServer.js +13 -6
  9. package/studio/web/assets/{Chat-CV1Obhoj.js → Chat-CGZ3at6i.js} +2 -2
  10. package/studio/web/assets/{Chat-CV1Obhoj.js.map → Chat-CGZ3at6i.js.map} +1 -1
  11. package/studio/web/assets/{FloatingChat-M68nsbT2.js → FloatingChat-BiS_7m6l.js} +4 -4
  12. package/studio/web/assets/{FloatingChat-M68nsbT2.js.map → FloatingChat-BiS_7m6l.js.map} +1 -1
  13. package/studio/web/assets/{apiToken-BAdWiIoL.js → apiToken-CvatmjsL.js} +2 -2
  14. package/studio/web/assets/{apiToken-BAdWiIoL.js.map → apiToken-CvatmjsL.js.map} +1 -1
  15. package/studio/web/assets/{applications-Bfn86W9Z.js → applications-DLjwpVqO.js} +2 -2
  16. package/studio/web/assets/{applications-Bfn86W9Z.js.map → applications-DLjwpVqO.js.map} +1 -1
  17. package/studio/web/assets/{index-CyNVanoD.js → index-DfGv-6tB.js} +6 -6
  18. package/studio/web/assets/{index-CyNVanoD.js.map → index-DfGv-6tB.js.map} +1 -1
  19. package/studio/web/assets/{index.lazy-BUqvTFi9.js → index.lazy-CjUGzXtz.js} +4 -4
  20. package/studio/web/assets/{index.lazy-BUqvTFi9.js.map → index.lazy-CjUGzXtz.js.map} +1 -1
  21. package/studio/web/assets/{notifications-BAXHQUOi.js → notifications-Cj5wCp6-.js} +2 -2
  22. package/studio/web/assets/{notifications-BAXHQUOi.js.map → notifications-Cj5wCp6-.js.map} +1 -1
  23. package/studio/web/assets/{notifications-XVakNKhZ.js → notifications-bG86ov79.js} +2 -2
  24. package/studio/web/assets/{notifications-XVakNKhZ.js.map → notifications-bG86ov79.js.map} +1 -1
  25. package/studio/web/assets/{profile-Bc0AYPPO.js → profile-Ca4u59r1.js} +2 -2
  26. package/studio/web/assets/{profile-Bc0AYPPO.js.map → profile-Ca4u59r1.js.map} +1 -1
  27. package/studio/web/assets/{setComponentFile-CYhJWz5K.js → setComponentFile-stXkgaau.js} +2 -2
  28. package/studio/web/assets/{setComponentFile-CYhJWz5K.js.map → setComponentFile-stXkgaau.js.map} +1 -1
  29. package/studio/web/assets/{setup-BXAhGv4k.js → setup-ib2S3aBG.js} +2 -2
  30. package/studio/web/assets/{setup-BXAhGv4k.js.map → setup-ib2S3aBG.js.map} +1 -1
  31. package/studio/web/assets/{status-DkYyA55m.js → status-BC2TKO4Y.js} +2 -2
  32. package/studio/web/assets/{status-DkYyA55m.js.map → status-BC2TKO4Y.js.map} +1 -1
  33. package/studio/web/assets/{swagger-ui-react-lz-L24Bx.js → swagger-ui-react-CrjEz1Mu.js} +2 -2
  34. package/studio/web/assets/{swagger-ui-react-lz-L24Bx.js.map → swagger-ui-react-CrjEz1Mu.js.map} +1 -1
  35. package/studio/web/assets/{tsMode-DdZzwRmA.js → tsMode-CKrkTaDh.js} +2 -2
  36. package/studio/web/assets/{tsMode-DdZzwRmA.js.map → tsMode-CKrkTaDh.js.map} +1 -1
  37. package/studio/web/assets/{useEntityRestURL-BzCS-OhW.js → useEntityRestURL-dq2ZFURw.js} +2 -2
  38. package/studio/web/assets/{useEntityRestURL-BzCS-OhW.js.map → useEntityRestURL-dq2ZFURw.js.map} +1 -1
  39. package/studio/web/index.html +1 -1
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/swagger-ui-react-lz-L24Bx.js","assets/rolldown-runtime-CNC7AqOf.js","assets/vendor-datadog-DyjkTkvg.js","assets/vendor-react-DeL8Gtgl.js","assets/vendor-ui-Bj22lHGK.js","assets/vendor-core-xUefYpUO.js","assets/index-CyNVanoD.js","assets/authStore-CNoNfv0F.js","assets/button-oQgW4t1x.js","assets/vendor-tanstack-0SjDjtT0.js","assets/useAuth-DvlnspkA.js","assets/card-BHplR9Xd.js","assets/createLucideIcon-BDx8noBh.js","assets/select-y6NKMkG_.js","assets/x-C3uc0qMD.js","assets/setLocalStorage-CD_L8p_D.js","assets/useLocalStorage-hkNSGGg8.js","assets/getRegistrationInfo-BOLlgqXr.js","assets/textarea-DhLMZ3PA.js","assets/errorText-NpBmvk9I.js","assets/queryClient-CbA8wM7J.js","assets/pollUnlessForbidden-HHdQZW1N.js","assets/editor.api-OBQnf1nL.js","assets/editor-jjEx9u7D.css","assets/tokenization-uOBOyHAS.js","assets/index-C8Mv9kHV.css","assets/react-redux-Co6ou4E8.js"])))=>i.map(i=>d[i]);
2
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{t}from"./button-oQgW4t1x.js";import{C as n,N as r,h as i,j as a}from"./vendor-tanstack-0SjDjtT0.js";import{a as o,i as s}from"./vendor-datadog-DyjkTkvg.js";import{r as c}from"./vendor-react-DeL8Gtgl.js";import{i as l,t as u}from"./getRegistrationInfo-BOLlgqXr.js";import{o as d}from"./pollUnlessForbidden-HHdQZW1N.js";import{$n as f,ft as p,kn as m,lt as h,zn as g}from"./index-CyNVanoD.js";import{t as _}from"./useEntityRestURL-BzCS-OhW.js";var v=[{fn:{requestSnippetGenerator_fetch:e=>{let t=new URL(e.get(`url`)),n=!1,r=e.get(`headers`);r&&r.size&&r.map((e,t)=>{n||=/^content-type$/i.test(t)&&/^multipart\/form-data$/i.test(e)});let i=e.get(`body`),a=e.get(`method`);if(i){if(n&&[`POST`,`PUT`,`PATCH`].includes(a))return`throw new Error("Currently unsupported content-type: /^multipart\\/form-data$/i");`;typeof i!=`string`&&(i=JSON.stringify(i,null,` `))}else!i&&a===`POST`&&(i=``);let o="`"+(i||``).replace(/\\n/g,`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/swagger-ui-react-CrjEz1Mu.js","assets/rolldown-runtime-CNC7AqOf.js","assets/vendor-datadog-DyjkTkvg.js","assets/vendor-react-DeL8Gtgl.js","assets/vendor-ui-Bj22lHGK.js","assets/vendor-core-xUefYpUO.js","assets/index-DfGv-6tB.js","assets/authStore-CNoNfv0F.js","assets/button-oQgW4t1x.js","assets/vendor-tanstack-0SjDjtT0.js","assets/useAuth-DvlnspkA.js","assets/card-BHplR9Xd.js","assets/createLucideIcon-BDx8noBh.js","assets/select-y6NKMkG_.js","assets/x-C3uc0qMD.js","assets/setLocalStorage-CD_L8p_D.js","assets/useLocalStorage-hkNSGGg8.js","assets/getRegistrationInfo-BOLlgqXr.js","assets/textarea-DhLMZ3PA.js","assets/errorText-NpBmvk9I.js","assets/queryClient-CbA8wM7J.js","assets/pollUnlessForbidden-HHdQZW1N.js","assets/editor.api-OBQnf1nL.js","assets/editor-jjEx9u7D.css","assets/tokenization-uOBOyHAS.js","assets/index-C8Mv9kHV.css","assets/react-redux-Co6ou4E8.js"])))=>i.map(i=>d[i]);
2
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{t}from"./button-oQgW4t1x.js";import{C as n,N as r,h as i,j as a}from"./vendor-tanstack-0SjDjtT0.js";import{a as o,i as s}from"./vendor-datadog-DyjkTkvg.js";import{r as c}from"./vendor-react-DeL8Gtgl.js";import{i as l,t as u}from"./getRegistrationInfo-BOLlgqXr.js";import{o as d}from"./pollUnlessForbidden-HHdQZW1N.js";import{$n as f,ft as p,kn as m,lt as h,zn as g}from"./index-DfGv-6tB.js";import{t as _}from"./useEntityRestURL-dq2ZFURw.js";var v=[{fn:{requestSnippetGenerator_fetch:e=>{let t=new URL(e.get(`url`)),n=!1,r=e.get(`headers`);r&&r.size&&r.map((e,t)=>{n||=/^content-type$/i.test(t)&&/^multipart\/form-data$/i.test(e)});let i=e.get(`body`),a=e.get(`method`);if(i){if(n&&[`POST`,`PUT`,`PATCH`].includes(a))return`throw new Error("Currently unsupported content-type: /^multipart\\/form-data$/i");`;typeof i!=`string`&&(i=JSON.stringify(i,null,` `))}else!i&&a===`POST`&&(i=``);let o="`"+(i||``).replace(/\\n/g,`
3
3
  `).replace(/`/g,"\\`")+"`";return`const response = await fetch("${t.toString()}", {
4
4
  \tmethod: "${e.get(`method`)}",${r&&r.size?`
5
5
  \theaders: {
@@ -10,5 +10,5 @@ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{t}from"./button-oQgW4t
10
10
  });
11
11
  const data = await response.json();
12
12
  console.log(data);
13
- `}}}],y={generators:{fetch:{title:`Fetch`,syntax:`javascript`}}};function b({entityId:e,instanceClient:t}){return a({queryKey:[`OpenAPI`,e],queryFn:async()=>{let{data:e}=await t.get(`/api/openapi/rest`);return e}})}var x=e(o(),1),S=c(),C=(0,x.lazy)(()=>s(()=>import(`./swagger-ui-react-lz-L24Bx.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])));function w(){let{instanceId:e,clusterId:i}=n({strict:!1}),a=d(),{data:o,isLoading:s}=r(h(a)),{data:c,isLoading:w}=r(u(a)),T=_(),{data:E,isLoading:D,error:O}=r(b(a));E?.servers?.length&&(E.servers[0].url=T);let k=o?.http,A=``,j=k?.cors===!1,M=k?.corsAccessList?.length!==void 0&&!k.corsAccessList.includes(`*`)&&!k.corsAccessList.includes(`null`)&&!k.corsAccessList.includes(window.location.origin);j?A=`This ${i&&!e?`cluster`:`instance`} has CORS disabled currently, so you won't be able to execute API requests from the browser.`:M&&(A=`This ${i&&!e?`cluster`:`instance`} has CORS enabled, but ${window.location.origin} is not allowed, so you won't be able to execute API requests from the browser.`);let{onConfigUpdate:N,isPending:P}=p(),F=(0,x.useCallback)(()=>{N({...j?{http_cors:!0}:{},...M?{http_corsAccessList:[...k?.corsAccessList??[],window.location.origin]}:{}})},[j,k?.corsAccessList,M,N]);if(s||w||D)return(0,S.jsx)(m,{centered:!0,text:`Looking up your instance configuration, one moment.`});if(O){let e;return e=c?.version&&!l(`4.7.0-beta.7`,c?.version)?`API Docs are only available starting in version '4.7.0-beta.7' of Harper, please update your version ${c.version}!`:`We weren't able to look up your docs. Please check the Network tab of your developer tools to see why the docs were not accessible to Studio.`,(0,S.jsx)(g,{title:`API Docs Unavailable`,error:{message:e},showReturnToHome:!1})}return(0,S.jsxs)(`div`,{className:`pt-6`,children:[A&&(0,S.jsx)(g,{title:`CORS Disabled: HTTP API Not Accessible`,className:`mt-0 mx-4 mb-4 border-yellow text-yellow`,error:{message:A},showReturnToHome:!1,children:(0,S.jsxs)(t,{type:`button`,disabled:P,variant:`warning`,onClick:F,children:[(0,S.jsx)(f,{}),P?`Enabling CORS...`:`Enable CORS for ${window.location.origin}`]})}),(0,S.jsx)(x.Suspense,{fallback:(0,S.jsx)(m,{centered:!0,text:`Loading API documentation...`}),children:(0,S.jsx)(C,{spec:E,persistAuthorization:!0,withCredentials:!0,requestSnippetsEnabled:!0,defaultModelRendering:`model`,requestSnippets:y,plugins:v,tryItOutEnabled:!0})})]})}var T=i(`/apis`)({component:w});export{T as route};
14
- //# sourceMappingURL=index.lazy-BUqvTFi9.js.map
13
+ `}}}],y={generators:{fetch:{title:`Fetch`,syntax:`javascript`}}};function b({entityId:e,instanceClient:t}){return a({queryKey:[`OpenAPI`,e],queryFn:async()=>{let{data:e}=await t.get(`/api/openapi/rest`);return e}})}var x=e(o(),1),S=c(),C=(0,x.lazy)(()=>s(()=>import(`./swagger-ui-react-CrjEz1Mu.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])));function w(){let{instanceId:e,clusterId:i}=n({strict:!1}),a=d(),{data:o,isLoading:s}=r(h(a)),{data:c,isLoading:w}=r(u(a)),T=_(),{data:E,isLoading:D,error:O}=r(b(a));E?.servers?.length&&(E.servers[0].url=T);let k=o?.http,A=``,j=k?.cors===!1,M=k?.corsAccessList?.length!==void 0&&!k.corsAccessList.includes(`*`)&&!k.corsAccessList.includes(`null`)&&!k.corsAccessList.includes(window.location.origin);j?A=`This ${i&&!e?`cluster`:`instance`} has CORS disabled currently, so you won't be able to execute API requests from the browser.`:M&&(A=`This ${i&&!e?`cluster`:`instance`} has CORS enabled, but ${window.location.origin} is not allowed, so you won't be able to execute API requests from the browser.`);let{onConfigUpdate:N,isPending:P}=p(),F=(0,x.useCallback)(()=>{N({...j?{http_cors:!0}:{},...M?{http_corsAccessList:[...k?.corsAccessList??[],window.location.origin]}:{}})},[j,k?.corsAccessList,M,N]);if(s||w||D)return(0,S.jsx)(m,{centered:!0,text:`Looking up your instance configuration, one moment.`});if(O){let e;return e=c?.version&&!l(`4.7.0-beta.7`,c?.version)?`API Docs are only available starting in version '4.7.0-beta.7' of Harper, please update your version ${c.version}!`:`We weren't able to look up your docs. Please check the Network tab of your developer tools to see why the docs were not accessible to Studio.`,(0,S.jsx)(g,{title:`API Docs Unavailable`,error:{message:e},showReturnToHome:!1})}return(0,S.jsxs)(`div`,{className:`pt-6`,children:[A&&(0,S.jsx)(g,{title:`CORS Disabled: HTTP API Not Accessible`,className:`mt-0 mx-4 mb-4 border-yellow text-yellow`,error:{message:A},showReturnToHome:!1,children:(0,S.jsxs)(t,{type:`button`,disabled:P,variant:`warning`,onClick:F,children:[(0,S.jsx)(f,{}),P?`Enabling CORS...`:`Enable CORS for ${window.location.origin}`]})}),(0,S.jsx)(x.Suspense,{fallback:(0,S.jsx)(m,{centered:!0,text:`Loading API documentation...`}),children:(0,S.jsx)(C,{spec:E,persistAuthorization:!0,withCredentials:!0,requestSnippetsEnabled:!0,defaultModelRendering:`model`,requestSnippets:y,plugins:v,tryItOutEnabled:!0})})]})}var T=i(`/apis`)({component:w});export{T as route};
14
+ //# sourceMappingURL=index.lazy-CjUGzXtz.js.map
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../src/features/instance/apis/plugins.ts","../../src/features/instance/apis/requestSnippets.ts","../../src/integrations/api/instance/status/getOpenAPI.ts","../../src/features/instance/apis/APIDocs.tsx","../../src/features/instance/apis/index.lazy.tsx"],"sourcesContent":["export const SnippedGeneratorNodeJsPlugin = {\n\tfn: {\n\t\trequestSnippetGenerator_fetch: (request: { get: (key: string) => unknown }) => {\n\t\t\tconst url = new URL(request.get('url') as string);\n\t\t\tlet isMultipartFormDataRequest = false;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tconst headers = request.get('headers') as any;\n\t\t\tif (headers && headers.size) {\n\t\t\t\theaders.map((val: string, key: string) => {\n\t\t\t\t\tisMultipartFormDataRequest = isMultipartFormDataRequest\n\t\t\t\t\t\t|| /^content-type$/i.test(key) && /^multipart\\/form-data$/i.test(val);\n\t\t\t\t});\n\t\t\t}\n\t\t\tlet reqBody = request.get('body') as string | object;\n\t\t\tconst reqMethod = request.get('method') as string;\n\t\t\tif (reqBody) {\n\t\t\t\tif (isMultipartFormDataRequest && ['POST', 'PUT', 'PATCH'].includes(reqMethod)) {\n\t\t\t\t\treturn 'throw new Error(\"Currently unsupported content-type: /^multipart\\\\/form-data$/i\");';\n\t\t\t\t} else {\n\t\t\t\t\tif (typeof reqBody !== 'string') {\n\t\t\t\t\t\treqBody = JSON.stringify(reqBody, null, '\\t');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (!reqBody && reqMethod === 'POST') {\n\t\t\t\treqBody = '';\n\t\t\t}\n\n\t\t\tconst stringBody = '`' + (reqBody || '')\n\t\t\t\t.replace(/\\\\n/g, '\\n')\n\t\t\t\t.replace(/`/g, '\\\\`')\n\t\t\t\t+ '`';\n\n\t\t\treturn `const response = await fetch(\"${url.toString()}\", {\n\\tmethod: \"${request.get('method')}\",${\n\t\t\t\theaders && headers.size\n\t\t\t\t\t? `\n\\theaders: {\n\\t\\t${headers.map((val: string, key: string) => `\"${key}\": \"${val}\"`).valueSeq().join(',\\n\\t\\t')}\n\\t},`\n\t\t\t\t\t: ''\n\t\t\t}${\n\t\t\t\treqBody\n\t\t\t\t\t? `\n\\tbody: ${stringBody},`\n\t\t\t\t\t: ''\n\t\t\t}\n});\nconst data = await response.json();\nconsole.log(data);\n`;\n\t\t},\n\t},\n};\n\nexport const plugins = [\n\tSnippedGeneratorNodeJsPlugin,\n];\n","export const requestSnippets = {\n\tgenerators: {\n\t\tfetch: {\n\t\t\ttitle: 'Fetch',\n\t\t\tsyntax: 'javascript',\n\t\t},\n\t},\n};\n","import { InstanceClientIdConfig } from '@/config/instanceClientConfig';\nimport { queryOptions } from '@tanstack/react-query';\n\nexport function getOpenAPIQueryOptions({ entityId, instanceClient }: InstanceClientIdConfig) {\n\treturn queryOptions({\n\t\tqueryKey: ['OpenAPI', entityId] as const,\n\t\tqueryFn: async () => {\n\t\t\tconst { data } = await instanceClient.get('/api/openapi/rest');\n\t\t\treturn data;\n\t\t},\n\t});\n}\n","import { ErrorComponent } from '@/components/ErrorComponent';\nimport { Loading } from '@/components/Loading';\nimport { Button } from '@/components/ui/button';\nimport { useEntityRestURL } from '@/config/useEntityRestURL';\nimport { useInstanceClientIdParams } from '@/config/useInstanceClient';\nimport { plugins } from '@/features/instance/apis/plugins';\nimport { requestSnippets } from '@/features/instance/apis/requestSnippets';\nimport { useRollingConfigUpdate } from '@/hooks/useRollingConfigUpdate';\nimport { getConfigurationQueryOptions } from '@/integrations/api/instance/status/getConfiguration';\nimport { getOpenAPIQueryOptions } from '@/integrations/api/instance/status/getOpenAPI';\nimport { getRegistrationInfoQueryOptions } from '@/integrations/api/instance/status/getRegistrationInfo';\nimport { wasAReleasedBeforeB } from '@/lib/string/wasAReleasedBeforeB';\nimport { useQuery } from '@tanstack/react-query';\nimport { useParams } from '@tanstack/react-router';\nimport { Plus } from 'lucide-react';\nimport { lazy, Suspense, useCallback } from 'react';\n\nconst SwaggerUI = lazy(() => import('swagger-ui-react'));\nimport 'swagger-ui-react/swagger-ui.css';\nimport './swagger.css';\n\nexport function APIDocs() {\n\tconst { instanceId, clusterId }: { instanceId?: string; clusterId?: string } = useParams({ strict: false });\n\tconst operationsParams = useInstanceClientIdParams();\n\tconst {\n\t\tdata: configurationInfo,\n\t\tisLoading: isLoadingConfiguration,\n\t} = useQuery(getConfigurationQueryOptions(operationsParams));\n\tconst { data: registrationInfo, isLoading: isLoadingRegistration } = useQuery(\n\t\tgetRegistrationInfoQueryOptions(operationsParams),\n\t);\n\tconst baseURL = useEntityRestURL();\n\tconst {\n\t\tdata: spec,\n\t\tisLoading: isLoadingDocs,\n\t\terror,\n\t} = useQuery(getOpenAPIQueryOptions(operationsParams));\n\tif (spec?.servers?.length) {\n\t\tspec.servers[0].url = baseURL;\n\t}\n\tconst http = configurationInfo?.http;\n\n\tlet apiInaccessibleWarning: string = '';\n\n\tconst corsDisabled = http?.cors === false;\n\tconst missingFromCORSList = http?.corsAccessList?.length !== undefined\n\t\t&& !http.corsAccessList.includes('*')\n\t\t&& !http.corsAccessList.includes('null')\n\t\t&& !http.corsAccessList.includes(window.location.origin);\n\tif (corsDisabled) {\n\t\tapiInaccessibleWarning = `This ${\n\t\t\tclusterId && !instanceId ? 'cluster' : 'instance'\n\t\t} has CORS disabled currently, so you won't be able to execute API requests from the browser.`;\n\t} else if (missingFromCORSList) {\n\t\tapiInaccessibleWarning = `This ${\n\t\t\tclusterId && !instanceId ? 'cluster' : 'instance'\n\t\t} has CORS enabled, but ${window.location.origin} is not allowed, so you won't be able to execute API requests from the browser.`;\n\t}\n\n\tconst { onConfigUpdate, isPending: isSettingConfiguration } = useRollingConfigUpdate();\n\tconst enableCORS = useCallback(() => {\n\t\tonConfigUpdate({\n\t\t\t...(corsDisabled\n\t\t\t\t? {\n\t\t\t\t\t'http_cors': true,\n\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(missingFromCORSList\n\t\t\t\t? {\n\t\t\t\t\t'http_corsAccessList': [\n\t\t\t\t\t\t...(http?.corsAccessList ?? []),\n\t\t\t\t\t\twindow.location.origin,\n\t\t\t\t\t],\n\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}, [corsDisabled, http?.corsAccessList, missingFromCORSList, onConfigUpdate]);\n\n\tif (isLoadingConfiguration || isLoadingRegistration || isLoadingDocs) {\n\t\treturn <Loading centered={true} text=\"Looking up your instance configuration, one moment.\" />;\n\t}\n\n\tif (error) {\n\t\tlet message: string;\n\t\tif (registrationInfo?.version && !wasAReleasedBeforeB('4.7.0-beta.7', registrationInfo?.version)) {\n\t\t\tmessage =\n\t\t\t\t`API Docs are only available starting in version '4.7.0-beta.7' of Harper, please update your version ${registrationInfo.version}!`;\n\t\t} else {\n\t\t\tmessage =\n\t\t\t\t`We weren't able to look up your docs. Please check the Network tab of your developer tools to see why the docs were not accessible to Studio.`;\n\t\t}\n\n\t\treturn (\n\t\t\t<ErrorComponent\n\t\t\t\ttitle=\"API Docs Unavailable\"\n\t\t\t\terror={{ message }}\n\t\t\t\tshowReturnToHome={false}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"pt-6\">\n\t\t\t{apiInaccessibleWarning && (\n\t\t\t\t<ErrorComponent\n\t\t\t\t\ttitle=\"CORS Disabled: HTTP API Not Accessible\"\n\t\t\t\t\tclassName=\"mt-0 mx-4 mb-4 border-yellow text-yellow\"\n\t\t\t\t\terror={{ message: apiInaccessibleWarning }}\n\t\t\t\t\tshowReturnToHome={false}\n\t\t\t\t>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdisabled={isSettingConfiguration}\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\tonClick={enableCORS}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus />\n\t\t\t\t\t\t{isSettingConfiguration ? 'Enabling CORS...' : `Enable CORS for ${window.location.origin}`}\n\t\t\t\t\t</Button>\n\t\t\t\t</ErrorComponent>\n\t\t\t)}\n\t\t\t<Suspense fallback={<Loading centered={true} text=\"Loading API documentation...\" />}>\n\t\t\t\t<SwaggerUI\n\t\t\t\t\tspec={spec}\n\t\t\t\t\tpersistAuthorization={true}\n\t\t\t\t\twithCredentials={true}\n\t\t\t\t\trequestSnippetsEnabled={true}\n\t\t\t\t\tdefaultModelRendering=\"model\"\n\t\t\t\t\trequestSnippets={requestSnippets}\n\t\t\t\t\tplugins={plugins}\n\t\t\t\t\ttryItOutEnabled={true}\n\t\t\t\t/>\n\t\t\t</Suspense>\n\t\t</div>\n\t);\n}\n","import { APIDocs } from '@/features/instance/apis/APIDocs';\nimport { createLazyRoute } from '@tanstack/react-router';\n\nexport const route = createLazyRoute('/apis')({\n\tcomponent: APIDocs,\n});\n"],"file":"index.lazy-BUqvTFi9.js"}
1
+ {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../src/features/instance/apis/plugins.ts","../../src/features/instance/apis/requestSnippets.ts","../../src/integrations/api/instance/status/getOpenAPI.ts","../../src/features/instance/apis/APIDocs.tsx","../../src/features/instance/apis/index.lazy.tsx"],"sourcesContent":["export const SnippedGeneratorNodeJsPlugin = {\n\tfn: {\n\t\trequestSnippetGenerator_fetch: (request: { get: (key: string) => unknown }) => {\n\t\t\tconst url = new URL(request.get('url') as string);\n\t\t\tlet isMultipartFormDataRequest = false;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tconst headers = request.get('headers') as any;\n\t\t\tif (headers && headers.size) {\n\t\t\t\theaders.map((val: string, key: string) => {\n\t\t\t\t\tisMultipartFormDataRequest = isMultipartFormDataRequest\n\t\t\t\t\t\t|| /^content-type$/i.test(key) && /^multipart\\/form-data$/i.test(val);\n\t\t\t\t});\n\t\t\t}\n\t\t\tlet reqBody = request.get('body') as string | object;\n\t\t\tconst reqMethod = request.get('method') as string;\n\t\t\tif (reqBody) {\n\t\t\t\tif (isMultipartFormDataRequest && ['POST', 'PUT', 'PATCH'].includes(reqMethod)) {\n\t\t\t\t\treturn 'throw new Error(\"Currently unsupported content-type: /^multipart\\\\/form-data$/i\");';\n\t\t\t\t} else {\n\t\t\t\t\tif (typeof reqBody !== 'string') {\n\t\t\t\t\t\treqBody = JSON.stringify(reqBody, null, '\\t');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (!reqBody && reqMethod === 'POST') {\n\t\t\t\treqBody = '';\n\t\t\t}\n\n\t\t\tconst stringBody = '`' + (reqBody || '')\n\t\t\t\t.replace(/\\\\n/g, '\\n')\n\t\t\t\t.replace(/`/g, '\\\\`')\n\t\t\t\t+ '`';\n\n\t\t\treturn `const response = await fetch(\"${url.toString()}\", {\n\\tmethod: \"${request.get('method')}\",${\n\t\t\t\theaders && headers.size\n\t\t\t\t\t? `\n\\theaders: {\n\\t\\t${headers.map((val: string, key: string) => `\"${key}\": \"${val}\"`).valueSeq().join(',\\n\\t\\t')}\n\\t},`\n\t\t\t\t\t: ''\n\t\t\t}${\n\t\t\t\treqBody\n\t\t\t\t\t? `\n\\tbody: ${stringBody},`\n\t\t\t\t\t: ''\n\t\t\t}\n});\nconst data = await response.json();\nconsole.log(data);\n`;\n\t\t},\n\t},\n};\n\nexport const plugins = [\n\tSnippedGeneratorNodeJsPlugin,\n];\n","export const requestSnippets = {\n\tgenerators: {\n\t\tfetch: {\n\t\t\ttitle: 'Fetch',\n\t\t\tsyntax: 'javascript',\n\t\t},\n\t},\n};\n","import { InstanceClientIdConfig } from '@/config/instanceClientConfig';\nimport { queryOptions } from '@tanstack/react-query';\n\nexport function getOpenAPIQueryOptions({ entityId, instanceClient }: InstanceClientIdConfig) {\n\treturn queryOptions({\n\t\tqueryKey: ['OpenAPI', entityId] as const,\n\t\tqueryFn: async () => {\n\t\t\tconst { data } = await instanceClient.get('/api/openapi/rest');\n\t\t\treturn data;\n\t\t},\n\t});\n}\n","import { ErrorComponent } from '@/components/ErrorComponent';\nimport { Loading } from '@/components/Loading';\nimport { Button } from '@/components/ui/button';\nimport { useEntityRestURL } from '@/config/useEntityRestURL';\nimport { useInstanceClientIdParams } from '@/config/useInstanceClient';\nimport { plugins } from '@/features/instance/apis/plugins';\nimport { requestSnippets } from '@/features/instance/apis/requestSnippets';\nimport { useRollingConfigUpdate } from '@/hooks/useRollingConfigUpdate';\nimport { getConfigurationQueryOptions } from '@/integrations/api/instance/status/getConfiguration';\nimport { getOpenAPIQueryOptions } from '@/integrations/api/instance/status/getOpenAPI';\nimport { getRegistrationInfoQueryOptions } from '@/integrations/api/instance/status/getRegistrationInfo';\nimport { wasAReleasedBeforeB } from '@/lib/string/wasAReleasedBeforeB';\nimport { useQuery } from '@tanstack/react-query';\nimport { useParams } from '@tanstack/react-router';\nimport { Plus } from 'lucide-react';\nimport { lazy, Suspense, useCallback } from 'react';\n\nconst SwaggerUI = lazy(() => import('swagger-ui-react'));\nimport 'swagger-ui-react/swagger-ui.css';\nimport './swagger.css';\n\nexport function APIDocs() {\n\tconst { instanceId, clusterId }: { instanceId?: string; clusterId?: string } = useParams({ strict: false });\n\tconst operationsParams = useInstanceClientIdParams();\n\tconst {\n\t\tdata: configurationInfo,\n\t\tisLoading: isLoadingConfiguration,\n\t} = useQuery(getConfigurationQueryOptions(operationsParams));\n\tconst { data: registrationInfo, isLoading: isLoadingRegistration } = useQuery(\n\t\tgetRegistrationInfoQueryOptions(operationsParams),\n\t);\n\tconst baseURL = useEntityRestURL();\n\tconst {\n\t\tdata: spec,\n\t\tisLoading: isLoadingDocs,\n\t\terror,\n\t} = useQuery(getOpenAPIQueryOptions(operationsParams));\n\tif (spec?.servers?.length) {\n\t\tspec.servers[0].url = baseURL;\n\t}\n\tconst http = configurationInfo?.http;\n\n\tlet apiInaccessibleWarning: string = '';\n\n\tconst corsDisabled = http?.cors === false;\n\tconst missingFromCORSList = http?.corsAccessList?.length !== undefined\n\t\t&& !http.corsAccessList.includes('*')\n\t\t&& !http.corsAccessList.includes('null')\n\t\t&& !http.corsAccessList.includes(window.location.origin);\n\tif (corsDisabled) {\n\t\tapiInaccessibleWarning = `This ${\n\t\t\tclusterId && !instanceId ? 'cluster' : 'instance'\n\t\t} has CORS disabled currently, so you won't be able to execute API requests from the browser.`;\n\t} else if (missingFromCORSList) {\n\t\tapiInaccessibleWarning = `This ${\n\t\t\tclusterId && !instanceId ? 'cluster' : 'instance'\n\t\t} has CORS enabled, but ${window.location.origin} is not allowed, so you won't be able to execute API requests from the browser.`;\n\t}\n\n\tconst { onConfigUpdate, isPending: isSettingConfiguration } = useRollingConfigUpdate();\n\tconst enableCORS = useCallback(() => {\n\t\tonConfigUpdate({\n\t\t\t...(corsDisabled\n\t\t\t\t? {\n\t\t\t\t\t'http_cors': true,\n\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(missingFromCORSList\n\t\t\t\t? {\n\t\t\t\t\t'http_corsAccessList': [\n\t\t\t\t\t\t...(http?.corsAccessList ?? []),\n\t\t\t\t\t\twindow.location.origin,\n\t\t\t\t\t],\n\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}, [corsDisabled, http?.corsAccessList, missingFromCORSList, onConfigUpdate]);\n\n\tif (isLoadingConfiguration || isLoadingRegistration || isLoadingDocs) {\n\t\treturn <Loading centered={true} text=\"Looking up your instance configuration, one moment.\" />;\n\t}\n\n\tif (error) {\n\t\tlet message: string;\n\t\tif (registrationInfo?.version && !wasAReleasedBeforeB('4.7.0-beta.7', registrationInfo?.version)) {\n\t\t\tmessage =\n\t\t\t\t`API Docs are only available starting in version '4.7.0-beta.7' of Harper, please update your version ${registrationInfo.version}!`;\n\t\t} else {\n\t\t\tmessage =\n\t\t\t\t`We weren't able to look up your docs. Please check the Network tab of your developer tools to see why the docs were not accessible to Studio.`;\n\t\t}\n\n\t\treturn (\n\t\t\t<ErrorComponent\n\t\t\t\ttitle=\"API Docs Unavailable\"\n\t\t\t\terror={{ message }}\n\t\t\t\tshowReturnToHome={false}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"pt-6\">\n\t\t\t{apiInaccessibleWarning && (\n\t\t\t\t<ErrorComponent\n\t\t\t\t\ttitle=\"CORS Disabled: HTTP API Not Accessible\"\n\t\t\t\t\tclassName=\"mt-0 mx-4 mb-4 border-yellow text-yellow\"\n\t\t\t\t\terror={{ message: apiInaccessibleWarning }}\n\t\t\t\t\tshowReturnToHome={false}\n\t\t\t\t>\n\t\t\t\t\t<Button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdisabled={isSettingConfiguration}\n\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\tonClick={enableCORS}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus />\n\t\t\t\t\t\t{isSettingConfiguration ? 'Enabling CORS...' : `Enable CORS for ${window.location.origin}`}\n\t\t\t\t\t</Button>\n\t\t\t\t</ErrorComponent>\n\t\t\t)}\n\t\t\t<Suspense fallback={<Loading centered={true} text=\"Loading API documentation...\" />}>\n\t\t\t\t<SwaggerUI\n\t\t\t\t\tspec={spec}\n\t\t\t\t\tpersistAuthorization={true}\n\t\t\t\t\twithCredentials={true}\n\t\t\t\t\trequestSnippetsEnabled={true}\n\t\t\t\t\tdefaultModelRendering=\"model\"\n\t\t\t\t\trequestSnippets={requestSnippets}\n\t\t\t\t\tplugins={plugins}\n\t\t\t\t\ttryItOutEnabled={true}\n\t\t\t\t/>\n\t\t\t</Suspense>\n\t\t</div>\n\t);\n}\n","import { APIDocs } from '@/features/instance/apis/APIDocs';\nimport { createLazyRoute } from '@tanstack/react-router';\n\nexport const route = createLazyRoute('/apis')({\n\tcomponent: APIDocs,\n});\n"],"file":"index.lazy-CjUGzXtz.js"}
@@ -1,2 +1,2 @@
1
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{i as t,t as n}from"./button-oQgW4t1x.js";import{A as r,I as i}from"./vendor-tanstack-0SjDjtT0.js";import{a}from"./vendor-datadog-DyjkTkvg.js";import{r as o}from"./vendor-react-DeL8Gtgl.js";import{c as s,d as c,f as l,i as u,l as d,n as f,o as p,p as m,s as h,t as g,u as _}from"./select-y6NKMkG_.js";import{l as v,t as y}from"./textarea-DhLMZ3PA.js";import{$n as b,Cn as x,Dt as S,It as C,On as w,Un as T,gn as E,on as D,rn as O,vn as k,wn as A,xn as j,yn as M}from"./index-CyNVanoD.js";import{a as N,c as P,i as F,n as I,o as L,r as R,s as z,t as B}from"./alertDialog-DSs2KlnR.js";function V(){let e=i();return r({mutationFn:async e=>{let{data:n}=await t.post(`/SystemStatus/`,e);return n},onSuccess:()=>e.invalidateQueries({queryKey:k})})}function H(){let e=i();return r({mutationFn:async({id:e,draft:n})=>{await t.patch(`/SystemStatus/${e}`,n)},onSuccess:()=>e.invalidateQueries({queryKey:k})})}function U(){let e=i();return r({mutationFn:async e=>{await t.delete(`/SystemStatus/${e}`)},onSuccess:()=>e.invalidateQueries({queryKey:k})})}var W=e(a(),1),G=o(),K=[{value:`error`,label:`Error / Outage`},{value:`warning`,label:`Warning`},{value:`maintenance`,label:`Maintenance`},{value:`info`,label:`Info`}];function q(e){let t=A(e);if(t===null)return``;let n=new Date(t),r=e=>String(e).padStart(2,`0`);return`${n.getFullYear()}-${r(n.getMonth()+1)}-${r(n.getDate())}T${r(n.getHours())}:${r(n.getMinutes())}`}function J(e){if(!e)return null;let t=Date.parse(e);return Number.isNaN(t)?null:new Date(t).toISOString()}function Y(e){let t=A(e.startAt),n=A(e.endAt);if(t===null&&n===null)return`Always`;let r=e=>e===null?`—`:new Date(e).toLocaleString();return`${r(t)} → ${r(n)}`}function X(){let{data:e,isLoading:t}=E(),[r,i]=(0,W.useState)(!1),[a,o]=(0,W.useState)(null),[s,c]=(0,W.useState)(null),l=U(),u=(0,W.useCallback)(()=>{o(null),i(!0)},[]),d=(0,W.useCallback)(e=>{o(e),i(!0)},[]),f=(0,W.useMemo)(()=>Z({openEdit:d,onDelete:c}),[d]);return(0,G.jsxs)(`div`,{className:`max-w-5xl`,children:[(0,G.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h1`,{className:`text-2xl font-light`,children:`Notifications`}),(0,G.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`System-wide notices shown to all users in the notification center. Times are stored in UTC.`})]}),(0,G.jsxs)(n,{variant:`submit`,onClick:u,className:`shrink-0`,children:[(0,G.jsx)(b,{}),`New notification`]})]}),(0,G.jsx)(`div`,{className:`mt-6`,children:t?(0,G.jsx)(C,{className:`h-40 w-full`}):(0,G.jsx)(S,{columns:f,data:e??[]})}),(0,G.jsx)(Q,{open:r,onOpenChange:i,editing:a}),(0,G.jsx)(B,{open:!!s,onOpenChange:e=>!e&&c(null),children:(0,G.jsxs)(F,{children:[(0,G.jsxs)(z,{children:[(0,G.jsx)(P,{children:`Delete notification?`}),(0,G.jsx)(N,{children:`This removes it for everyone immediately. This can't be undone.`})]}),(0,G.jsxs)(L,{children:[(0,G.jsx)(R,{children:`Cancel`}),(0,G.jsx)(I,{disabled:l.isPending,onClick:e=>{e.preventDefault(),s&&l.mutate(s.id,{onSuccess:()=>c(null)})},children:l.isPending?`Deleting…`:`Delete`})]})]})})]})}function Z({openEdit:e,onDelete:t}){return[{header:`Type`,accessorKey:`type`,size:12,cell:({row:e})=>{let{label:t,badgeVariant:n}=j(e.original.type);return(0,G.jsx)(w,{variant:n,children:e.original.type||t})}},{header:`Message`,accessorKey:`message`,size:40,cell:({row:e})=>(0,G.jsx)(`span`,{className:`line-clamp-2 break-words`,children:e.original.message})},{header:`Active window (local)`,size:28,cell:({row:e})=>(0,G.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:Y(e.original)})},{header:`Link`,size:8,cell:({row:e})=>e.original.url?(0,G.jsx)(M,{url:e.original.url,className:`text-sm text-primary hover:underline dark:text-white`}):(0,G.jsx)(`span`,{className:`text-muted-foreground`,children:`—`})},{header:``,id:`actions`,size:12,cell:({row:r})=>(0,G.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,G.jsx)(n,{variant:`ghost`,size:`icon`,"aria-label":`Edit`,onClick:()=>e(r.original),children:(0,G.jsx)(v,{})}),(0,G.jsx)(n,{variant:`destructiveGhost`,size:`icon`,"aria-label":`Delete`,onClick:()=>t(r.original),children:(0,G.jsx)(T,{})})]})}]}function Q({open:e,onOpenChange:t,editing:r}){let i=V(),a=H(),o=i.isPending||a.isPending,[v,b]=(0,W.useState)(`error`),[S,C]=(0,W.useState)(``),[w,T]=(0,W.useState)(``),[E,k]=(0,W.useState)(``),[A,j]=(0,W.useState)(``),[M,N]=(0,W.useState)(null);return(0,W.useEffect)(()=>{e&&(b(r?.type??`error`),C(r?.message??``),T(r?.url??``),k(q(r?.startAt)),j(q(r?.endAt)),N(null))},[e,r]),(0,G.jsx)(s,{open:e,onOpenChange:t,children:(0,G.jsxs)(d,{children:[(0,G.jsxs)(l,{children:[(0,G.jsx)(m,{children:r?`Edit notification`:`New notification`}),(0,G.jsx)(_,{children:`Shown to all users. Leave start/end empty for an open-ended window.`})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-type`,children:`Type`}),(0,G.jsxs)(g,{value:v,onValueChange:b,children:[(0,G.jsx)(p,{id:`notification-type`,className:`w-full`,children:(0,G.jsx)(h,{})}),(0,G.jsx)(f,{children:K.map(e=>(0,G.jsx)(u,{value:e.value,children:e.label},e.value))})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-message`,children:`Message`}),(0,G.jsx)(y,{id:`notification-message`,rows:3,value:S,onChange:e=>C(e.target.value),placeholder:`The Fabric control plane will be undergoing maintenance…`})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-url`,children:`Link (optional)`}),(0,G.jsx)(O,{id:`notification-url`,value:w,onChange:e=>T(e.target.value),placeholder:`https://status.harper.io or /organizations`}),(0,G.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`An absolute URL opens in a new tab; a path like `,(0,G.jsx)(`code`,{children:`/organizations`}),` links inside Studio.`]})]}),(0,G.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 sm:grid-cols-2`,children:[(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-start`,children:`Start (local time)`}),(0,G.jsx)(O,{id:`notification-start`,type:`datetime-local`,value:E,onChange:e=>k(e.target.value)})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-end`,children:`End (local time)`}),(0,G.jsx)(O,{id:`notification-end`,type:`datetime-local`,value:A,onChange:e=>j(e.target.value)})]})]}),M&&(0,G.jsx)(`p`,{className:`text-sm text-destructive`,children:M})]}),(0,G.jsxs)(c,{children:[(0,G.jsx)(n,{variant:`ghostOutline`,onClick:()=>t(!1),disabled:o,children:`Cancel`}),(0,G.jsx)(n,{variant:`submit`,onClick:()=>{let e=S.trim();if(!e){N(`Message is required.`);return}let n=J(E),o=J(A);if(n&&o&&Date.parse(o)<=Date.parse(n)){N(`End time must be after start time.`);return}let s=w.trim();if(s&&!x(s)){N(`Link must be an http(s) URL, a mailto: address, or a path starting with “/”.`);return}let c={type:v,message:e,url:s||null,startAt:n,endAt:o},l=()=>t(!1);r?a.mutate({id:r.id,draft:c},{onSuccess:l}):i.mutate(c,{onSuccess:l})},disabled:o,children:o?`Saving…`:r?`Save changes`:`Create`})]})]})})}export{X as NotificationsAdminIndex};
2
- //# sourceMappingURL=notifications-BAXHQUOi.js.map
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{i as t,t as n}from"./button-oQgW4t1x.js";import{A as r,I as i}from"./vendor-tanstack-0SjDjtT0.js";import{a}from"./vendor-datadog-DyjkTkvg.js";import{r as o}from"./vendor-react-DeL8Gtgl.js";import{c as s,d as c,f as l,i as u,l as d,n as f,o as p,p as m,s as h,t as g,u as _}from"./select-y6NKMkG_.js";import{l as v,t as y}from"./textarea-DhLMZ3PA.js";import{$n as b,Cn as x,Dt as S,It as C,On as w,Un as T,gn as E,on as D,rn as O,vn as k,wn as A,xn as j,yn as M}from"./index-DfGv-6tB.js";import{a as N,c as P,i as F,n as I,o as L,r as R,s as z,t as B}from"./alertDialog-DSs2KlnR.js";function V(){let e=i();return r({mutationFn:async e=>{let{data:n}=await t.post(`/SystemStatus/`,e);return n},onSuccess:()=>e.invalidateQueries({queryKey:k})})}function H(){let e=i();return r({mutationFn:async({id:e,draft:n})=>{await t.patch(`/SystemStatus/${e}`,n)},onSuccess:()=>e.invalidateQueries({queryKey:k})})}function U(){let e=i();return r({mutationFn:async e=>{await t.delete(`/SystemStatus/${e}`)},onSuccess:()=>e.invalidateQueries({queryKey:k})})}var W=e(a(),1),G=o(),K=[{value:`error`,label:`Error / Outage`},{value:`warning`,label:`Warning`},{value:`maintenance`,label:`Maintenance`},{value:`info`,label:`Info`}];function q(e){let t=A(e);if(t===null)return``;let n=new Date(t),r=e=>String(e).padStart(2,`0`);return`${n.getFullYear()}-${r(n.getMonth()+1)}-${r(n.getDate())}T${r(n.getHours())}:${r(n.getMinutes())}`}function J(e){if(!e)return null;let t=Date.parse(e);return Number.isNaN(t)?null:new Date(t).toISOString()}function Y(e){let t=A(e.startAt),n=A(e.endAt);if(t===null&&n===null)return`Always`;let r=e=>e===null?`—`:new Date(e).toLocaleString();return`${r(t)} → ${r(n)}`}function X(){let{data:e,isLoading:t}=E(),[r,i]=(0,W.useState)(!1),[a,o]=(0,W.useState)(null),[s,c]=(0,W.useState)(null),l=U(),u=(0,W.useCallback)(()=>{o(null),i(!0)},[]),d=(0,W.useCallback)(e=>{o(e),i(!0)},[]),f=(0,W.useMemo)(()=>Z({openEdit:d,onDelete:c}),[d]);return(0,G.jsxs)(`div`,{className:`max-w-5xl`,children:[(0,G.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`h1`,{className:`text-2xl font-light`,children:`Notifications`}),(0,G.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`System-wide notices shown to all users in the notification center. Times are stored in UTC.`})]}),(0,G.jsxs)(n,{variant:`submit`,onClick:u,className:`shrink-0`,children:[(0,G.jsx)(b,{}),`New notification`]})]}),(0,G.jsx)(`div`,{className:`mt-6`,children:t?(0,G.jsx)(C,{className:`h-40 w-full`}):(0,G.jsx)(S,{columns:f,data:e??[]})}),(0,G.jsx)(Q,{open:r,onOpenChange:i,editing:a}),(0,G.jsx)(B,{open:!!s,onOpenChange:e=>!e&&c(null),children:(0,G.jsxs)(F,{children:[(0,G.jsxs)(z,{children:[(0,G.jsx)(P,{children:`Delete notification?`}),(0,G.jsx)(N,{children:`This removes it for everyone immediately. This can't be undone.`})]}),(0,G.jsxs)(L,{children:[(0,G.jsx)(R,{children:`Cancel`}),(0,G.jsx)(I,{disabled:l.isPending,onClick:e=>{e.preventDefault(),s&&l.mutate(s.id,{onSuccess:()=>c(null)})},children:l.isPending?`Deleting…`:`Delete`})]})]})})]})}function Z({openEdit:e,onDelete:t}){return[{header:`Type`,accessorKey:`type`,size:12,cell:({row:e})=>{let{label:t,badgeVariant:n}=j(e.original.type);return(0,G.jsx)(w,{variant:n,children:e.original.type||t})}},{header:`Message`,accessorKey:`message`,size:40,cell:({row:e})=>(0,G.jsx)(`span`,{className:`line-clamp-2 break-words`,children:e.original.message})},{header:`Active window (local)`,size:28,cell:({row:e})=>(0,G.jsx)(`span`,{className:`text-sm text-muted-foreground`,children:Y(e.original)})},{header:`Link`,size:8,cell:({row:e})=>e.original.url?(0,G.jsx)(M,{url:e.original.url,className:`text-sm text-primary hover:underline dark:text-white`}):(0,G.jsx)(`span`,{className:`text-muted-foreground`,children:`—`})},{header:``,id:`actions`,size:12,cell:({row:r})=>(0,G.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,G.jsx)(n,{variant:`ghost`,size:`icon`,"aria-label":`Edit`,onClick:()=>e(r.original),children:(0,G.jsx)(v,{})}),(0,G.jsx)(n,{variant:`destructiveGhost`,size:`icon`,"aria-label":`Delete`,onClick:()=>t(r.original),children:(0,G.jsx)(T,{})})]})}]}function Q({open:e,onOpenChange:t,editing:r}){let i=V(),a=H(),o=i.isPending||a.isPending,[v,b]=(0,W.useState)(`error`),[S,C]=(0,W.useState)(``),[w,T]=(0,W.useState)(``),[E,k]=(0,W.useState)(``),[A,j]=(0,W.useState)(``),[M,N]=(0,W.useState)(null);return(0,W.useEffect)(()=>{e&&(b(r?.type??`error`),C(r?.message??``),T(r?.url??``),k(q(r?.startAt)),j(q(r?.endAt)),N(null))},[e,r]),(0,G.jsx)(s,{open:e,onOpenChange:t,children:(0,G.jsxs)(d,{children:[(0,G.jsxs)(l,{children:[(0,G.jsx)(m,{children:r?`Edit notification`:`New notification`}),(0,G.jsx)(_,{children:`Shown to all users. Leave start/end empty for an open-ended window.`})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-type`,children:`Type`}),(0,G.jsxs)(g,{value:v,onValueChange:b,children:[(0,G.jsx)(p,{id:`notification-type`,className:`w-full`,children:(0,G.jsx)(h,{})}),(0,G.jsx)(f,{children:K.map(e=>(0,G.jsx)(u,{value:e.value,children:e.label},e.value))})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-message`,children:`Message`}),(0,G.jsx)(y,{id:`notification-message`,rows:3,value:S,onChange:e=>C(e.target.value),placeholder:`The Fabric control plane will be undergoing maintenance…`})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-url`,children:`Link (optional)`}),(0,G.jsx)(O,{id:`notification-url`,value:w,onChange:e=>T(e.target.value),placeholder:`https://status.harper.io or /organizations`}),(0,G.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`An absolute URL opens in a new tab; a path like `,(0,G.jsx)(`code`,{children:`/organizations`}),` links inside Studio.`]})]}),(0,G.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 sm:grid-cols-2`,children:[(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-start`,children:`Start (local time)`}),(0,G.jsx)(O,{id:`notification-start`,type:`datetime-local`,value:E,onChange:e=>k(e.target.value)})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(D,{htmlFor:`notification-end`,children:`End (local time)`}),(0,G.jsx)(O,{id:`notification-end`,type:`datetime-local`,value:A,onChange:e=>j(e.target.value)})]})]}),M&&(0,G.jsx)(`p`,{className:`text-sm text-destructive`,children:M})]}),(0,G.jsxs)(c,{children:[(0,G.jsx)(n,{variant:`ghostOutline`,onClick:()=>t(!1),disabled:o,children:`Cancel`}),(0,G.jsx)(n,{variant:`submit`,onClick:()=>{let e=S.trim();if(!e){N(`Message is required.`);return}let n=J(E),o=J(A);if(n&&o&&Date.parse(o)<=Date.parse(n)){N(`End time must be after start time.`);return}let s=w.trim();if(s&&!x(s)){N(`Link must be an http(s) URL, a mailto: address, or a path starting with “/”.`);return}let c={type:v,message:e,url:s||null,startAt:n,endAt:o},l=()=>t(!1);r?a.mutate({id:r.id,draft:c},{onSuccess:l}):i.mutate(c,{onSuccess:l})},disabled:o,children:o?`Saving…`:r?`Save changes`:`Create`})]})]})})}export{X as NotificationsAdminIndex};
2
+ //# sourceMappingURL=notifications-Cj5wCp6-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications-BAXHQUOi.js","names":[],"sources":["../../src/features/admin/notifications/mutations/useNotificationMutations.ts","../../src/features/admin/notifications/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { systemStatusQueryKey } from '@/features/notifications/queries';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\n\n/**\n * Admin CRUD over the central-manager `SystemStatus` table. The resource already gates writes to\n * fabric admins (isFabricAdmin) server-side, so these just need the fabric-admin session. The\n * SystemStatus paths aren't in the generated OpenAPI types yet, so URLs are cast (as elsewhere).\n * The global MutationCache.onError surfaces failures as a toast; each write refetches the list.\n */\nexport interface NotificationDraft {\n\ttype: string;\n\tmessage: string;\n\turl?: string | null;\n\t/** UTC ISO string, or null for an open bound. */\n\tstartAt?: string | null;\n\tendAt?: string | null;\n}\n\nexport function useCreateNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async (draft: NotificationDraft) => {\n\t\t\tconst { data } = await apiClient.post('/SystemStatus/' as '/Cluster/', draft);\n\t\t\treturn data as unknown as SystemStatusNotification;\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n\nexport function useUpdateNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async ({ id, draft }: { id: string; draft: NotificationDraft }) => {\n\t\t\tawait apiClient.patch(`/SystemStatus/${id}` as '/Cluster/{id}', draft);\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n\nexport function useDeleteNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async (id: string) => {\n\t\t\tawait apiClient.delete(`/SystemStatus/${id}` as '/Cluster/{id}');\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n","import { DataTable } from '@/components/DataTable';\nimport {\n\tAlertDialog,\n\tAlertDialogAction,\n\tAlertDialogCancel,\n\tAlertDialogContent,\n\tAlertDialogDescription,\n\tAlertDialogFooter,\n\tAlertDialogHeader,\n\tAlertDialogTitle,\n} from '@/components/ui/alertDialog';\nimport { Badge } from '@/components/ui/badge';\nimport { Button } from '@/components/ui/button';\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogFooter,\n\tDialogHeader,\n\tDialogTitle,\n} from '@/components/ui/dialog';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { Textarea } from '@/components/ui/textarea';\nimport {\n\tNotificationDraft,\n\tuseCreateNotificationMutation,\n\tuseDeleteNotificationMutation,\n\tuseUpdateNotificationMutation,\n} from '@/features/admin/notifications/mutations/useNotificationMutations';\nimport { NotificationLink } from '@/features/notifications/components/NotificationLink';\nimport { useNotifications } from '@/features/notifications/hooks';\nimport { getSeverityConfig, parseNotificationLink, toMs } from '@/features/notifications/notificationHelpers';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { ColumnDef } from '@tanstack/react-table';\nimport { PencilIcon, PlusIcon, Trash2Icon } from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nconst TYPE_OPTIONS = [\n\t{ value: 'error', label: 'Error / Outage' },\n\t{ value: 'warning', label: 'Warning' },\n\t{ value: 'maintenance', label: 'Maintenance' },\n\t{ value: 'info', label: 'Info' },\n];\n\n/** A stored timestamp → the `YYYY-MM-DDTHH:mm` local value a `datetime-local` input expects. */\nfunction toInputValue(value: string | number | null | undefined): string {\n\tconst ms = toMs(value);\n\tif (ms === null) { return ''; }\n\tconst date = new Date(ms);\n\tconst pad = (n: number) => String(n).padStart(2, '0');\n\treturn `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${\n\t\tpad(date.getMinutes())\n\t}`;\n}\n\n/** A `datetime-local` value (local time) → a UTC ISO string, or null when empty. */\nfunction fromInputValue(value: string): string | null {\n\tif (!value) { return null; }\n\tconst ms = Date.parse(value);\n\treturn Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction formatWindow(notification: SystemStatusNotification): string {\n\tconst start = toMs(notification.startAt);\n\tconst end = toMs(notification.endAt);\n\tif (start === null && end === null) { return 'Always'; }\n\tconst fmt = (ms: number | null) => (ms === null ? '—' : new Date(ms).toLocaleString());\n\treturn `${fmt(start)} → ${fmt(end)}`;\n}\n\nexport function NotificationsAdminIndex() {\n\tconst { data, isLoading } = useNotifications();\n\tconst [formOpen, setFormOpen] = useState(false);\n\tconst [editing, setEditing] = useState<SystemStatusNotification | null>(null);\n\tconst [deleteTarget, setDeleteTarget] = useState<SystemStatusNotification | null>(null);\n\tconst deleteMutation = useDeleteNotificationMutation();\n\n\tconst openCreate = useCallback(() => {\n\t\tsetEditing(null);\n\t\tsetFormOpen(true);\n\t}, []);\n\tconst openEdit = useCallback((notification: SystemStatusNotification) => {\n\t\tsetEditing(notification);\n\t\tsetFormOpen(true);\n\t}, []);\n\n\tconst columns = useMemo<ColumnDef<SystemStatusNotification>[]>(\n\t\t() => buildColumns({ openEdit, onDelete: setDeleteTarget }),\n\t\t[openEdit],\n\t);\n\n\treturn (\n\t\t<div className=\"max-w-5xl\">\n\t\t\t<div className=\"flex items-start justify-between gap-4\">\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-2xl font-light\">Notifications</h1>\n\t\t\t\t\t<p className=\"mt-2 text-sm text-muted-foreground\">\n\t\t\t\t\t\tSystem-wide notices shown to all users in the notification center. Times are stored in UTC.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<Button variant=\"submit\" onClick={openCreate} className=\"shrink-0\">\n\t\t\t\t\t<PlusIcon />\n\t\t\t\t\tNew notification\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t<div className=\"mt-6\">\n\t\t\t\t{isLoading ? <Skeleton className=\"h-40 w-full\" /> : <DataTable columns={columns} data={data ?? []} />}\n\t\t\t</div>\n\n\t\t\t<NotificationFormDialog open={formOpen} onOpenChange={setFormOpen} editing={editing} />\n\n\t\t\t<AlertDialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>\n\t\t\t\t<AlertDialogContent>\n\t\t\t\t\t<AlertDialogHeader>\n\t\t\t\t\t\t<AlertDialogTitle>Delete notification?</AlertDialogTitle>\n\t\t\t\t\t\t<AlertDialogDescription>\n\t\t\t\t\t\t\tThis removes it for everyone immediately. This can't be undone.\n\t\t\t\t\t\t</AlertDialogDescription>\n\t\t\t\t\t</AlertDialogHeader>\n\t\t\t\t\t<AlertDialogFooter>\n\t\t\t\t\t\t<AlertDialogCancel>Cancel</AlertDialogCancel>\n\t\t\t\t\t\t<AlertDialogAction\n\t\t\t\t\t\t\tdisabled={deleteMutation.isPending}\n\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tif (!deleteTarget) { return; }\n\t\t\t\t\t\t\t\tdeleteMutation.mutate(deleteTarget.id, { onSuccess: () => setDeleteTarget(null) });\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{deleteMutation.isPending ? 'Deleting…' : 'Delete'}\n\t\t\t\t\t\t</AlertDialogAction>\n\t\t\t\t\t</AlertDialogFooter>\n\t\t\t\t</AlertDialogContent>\n\t\t\t</AlertDialog>\n\t\t</div>\n\t);\n}\n\nfunction buildColumns(\n\t{ openEdit, onDelete }: {\n\t\topenEdit: (notification: SystemStatusNotification) => void;\n\t\tonDelete: (notification: SystemStatusNotification) => void;\n\t},\n): ColumnDef<SystemStatusNotification>[] {\n\treturn [\n\t\t{\n\t\t\theader: 'Type',\n\t\t\taccessorKey: 'type',\n\t\t\tsize: 12,\n\t\t\tcell: ({ row }) => {\n\t\t\t\tconst { label, badgeVariant } = getSeverityConfig(row.original.type);\n\t\t\t\treturn <Badge variant={badgeVariant}>{row.original.type || label}</Badge>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\theader: 'Message',\n\t\t\taccessorKey: 'message',\n\t\t\tsize: 40,\n\t\t\tcell: ({ row }) => <span className=\"line-clamp-2 break-words\">{row.original.message}</span>,\n\t\t},\n\t\t{\n\t\t\theader: 'Active window (local)',\n\t\t\tsize: 28,\n\t\t\tcell: ({ row }) => <span className=\"text-sm text-muted-foreground\">{formatWindow(row.original)}</span>,\n\t\t},\n\t\t{\n\t\t\theader: 'Link',\n\t\t\tsize: 8,\n\t\t\tcell: ({ row }) =>\n\t\t\t\trow.original.url\n\t\t\t\t\t? <NotificationLink url={row.original.url} className=\"text-sm text-primary hover:underline dark:text-white\" />\n\t\t\t\t\t: <span className=\"text-muted-foreground\">—</span>,\n\t\t},\n\t\t{\n\t\t\theader: '',\n\t\t\tid: 'actions',\n\t\t\tsize: 12,\n\t\t\tcell: ({ row }) => (\n\t\t\t\t<div className=\"flex justify-end gap-1\">\n\t\t\t\t\t<Button variant=\"ghost\" size=\"icon\" aria-label=\"Edit\" onClick={() => openEdit(row.original)}>\n\t\t\t\t\t\t<PencilIcon />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"destructiveGhost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\taria-label=\"Delete\"\n\t\t\t\t\t\tonClick={() => onDelete(row.original)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2Icon />\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t),\n\t\t},\n\t];\n}\n\nfunction NotificationFormDialog({\n\topen,\n\tonOpenChange,\n\tediting,\n}: {\n\topen: boolean;\n\tonOpenChange: (open: boolean) => void;\n\tediting: SystemStatusNotification | null;\n}) {\n\tconst createMutation = useCreateNotificationMutation();\n\tconst updateMutation = useUpdateNotificationMutation();\n\tconst isPending = createMutation.isPending || updateMutation.isPending;\n\n\tconst [type, setType] = useState('error');\n\tconst [message, setMessage] = useState('');\n\tconst [url, setUrl] = useState('');\n\tconst [startAt, setStartAt] = useState('');\n\tconst [endAt, setEndAt] = useState('');\n\tconst [error, setError] = useState<string | null>(null);\n\n\t// Reset the form to the edited row (or blanks for create) each time the dialog opens.\n\tuseEffect(() => {\n\t\tif (!open) { return; }\n\t\tsetType(editing?.type ?? 'error');\n\t\tsetMessage(editing?.message ?? '');\n\t\tsetUrl(editing?.url ?? '');\n\t\tsetStartAt(toInputValue(editing?.startAt));\n\t\tsetEndAt(toInputValue(editing?.endAt));\n\t\tsetError(null);\n\t}, [open, editing]);\n\n\tconst submit = () => {\n\t\tconst trimmedMessage = message.trim();\n\t\tif (!trimmedMessage) {\n\t\t\tsetError('Message is required.');\n\t\t\treturn;\n\t\t}\n\t\tconst start = fromInputValue(startAt);\n\t\tconst end = fromInputValue(endAt);\n\t\tif (start && end && Date.parse(end) <= Date.parse(start)) {\n\t\t\tsetError('End time must be after start time.');\n\t\t\treturn;\n\t\t}\n\t\t// Validate the link with the same parser the UI renders with, so the form can't save a URL the\n\t\t// notification would then silently drop (an unsafe scheme, or a typo'd `htp://…`).\n\t\tconst trimmedUrl = url.trim();\n\t\tif (trimmedUrl && !parseNotificationLink(trimmedUrl)) {\n\t\t\tsetError('Link must be an http(s) URL, a mailto: address, or a path starting with “/”.');\n\t\t\treturn;\n\t\t}\n\n\t\tconst draft: NotificationDraft = {\n\t\t\ttype,\n\t\t\tmessage: trimmedMessage,\n\t\t\turl: trimmedUrl || null,\n\t\t\tstartAt: start,\n\t\t\tendAt: end,\n\t\t};\n\t\tconst onSuccess = () => onOpenChange(false);\n\t\tif (editing) {\n\t\t\tupdateMutation.mutate({ id: editing.id, draft }, { onSuccess });\n\t\t} else {\n\t\t\tcreateMutation.mutate(draft, { onSuccess });\n\t\t}\n\t};\n\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogContent>\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<DialogTitle>{editing ? 'Edit notification' : 'New notification'}</DialogTitle>\n\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\tShown to all users. Leave start/end empty for an open-ended window.\n\t\t\t\t\t</DialogDescription>\n\t\t\t\t</DialogHeader>\n\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-type\">Type</Label>\n\t\t\t\t\t\t<Select value={type} onValueChange={setType}>\n\t\t\t\t\t\t\t<SelectTrigger id=\"notification-type\" className=\"w-full\">\n\t\t\t\t\t\t\t\t<SelectValue />\n\t\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t\t{TYPE_OPTIONS.map((option) => (\n\t\t\t\t\t\t\t\t\t<SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t\t</Select>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-message\">Message</Label>\n\t\t\t\t\t\t<Textarea\n\t\t\t\t\t\t\tid=\"notification-message\"\n\t\t\t\t\t\t\trows={3}\n\t\t\t\t\t\t\tvalue={message}\n\t\t\t\t\t\t\tonChange={(event) => setMessage(event.target.value)}\n\t\t\t\t\t\t\tplaceholder=\"The Fabric control plane will be undergoing maintenance…\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-url\">Link (optional)</Label>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tid=\"notification-url\"\n\t\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\t\tonChange={(event) => setUrl(event.target.value)}\n\t\t\t\t\t\t\tplaceholder=\"https://status.harper.io or /organizations\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\tAn absolute URL opens in a new tab; a path like <code>/organizations</code> links inside Studio.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t<Label htmlFor=\"notification-start\">Start (local time)</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"notification-start\"\n\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\tvalue={startAt}\n\t\t\t\t\t\t\t\tonChange={(event) => setStartAt(event.target.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t<Label htmlFor=\"notification-end\">End (local time)</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"notification-end\"\n\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\tvalue={endAt}\n\t\t\t\t\t\t\t\tonChange={(event) => setEndAt(event.target.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{error && <p className=\"text-sm text-destructive\">{error}</p>}\n\t\t\t\t</div>\n\n\t\t\t\t<DialogFooter>\n\t\t\t\t\t<Button variant=\"ghostOutline\" onClick={() => onOpenChange(false)} disabled={isPending}>\n\t\t\t\t\t\tCancel\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button variant=\"submit\" onClick={submit} disabled={isPending}>\n\t\t\t\t\t\t{isPending ? 'Saving…' : editing ? 'Save changes' : 'Create'}\n\t\t\t\t\t</Button>\n\t\t\t\t</DialogFooter>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"notifications-Cj5wCp6-.js","names":[],"sources":["../../src/features/admin/notifications/mutations/useNotificationMutations.ts","../../src/features/admin/notifications/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { systemStatusQueryKey } from '@/features/notifications/queries';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\n\n/**\n * Admin CRUD over the central-manager `SystemStatus` table. The resource already gates writes to\n * fabric admins (isFabricAdmin) server-side, so these just need the fabric-admin session. The\n * SystemStatus paths aren't in the generated OpenAPI types yet, so URLs are cast (as elsewhere).\n * The global MutationCache.onError surfaces failures as a toast; each write refetches the list.\n */\nexport interface NotificationDraft {\n\ttype: string;\n\tmessage: string;\n\turl?: string | null;\n\t/** UTC ISO string, or null for an open bound. */\n\tstartAt?: string | null;\n\tendAt?: string | null;\n}\n\nexport function useCreateNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async (draft: NotificationDraft) => {\n\t\t\tconst { data } = await apiClient.post('/SystemStatus/' as '/Cluster/', draft);\n\t\t\treturn data as unknown as SystemStatusNotification;\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n\nexport function useUpdateNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async ({ id, draft }: { id: string; draft: NotificationDraft }) => {\n\t\t\tawait apiClient.patch(`/SystemStatus/${id}` as '/Cluster/{id}', draft);\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n\nexport function useDeleteNotificationMutation() {\n\tconst queryClient = useQueryClient();\n\treturn useMutation({\n\t\tmutationFn: async (id: string) => {\n\t\t\tawait apiClient.delete(`/SystemStatus/${id}` as '/Cluster/{id}');\n\t\t},\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: systemStatusQueryKey }),\n\t});\n}\n","import { DataTable } from '@/components/DataTable';\nimport {\n\tAlertDialog,\n\tAlertDialogAction,\n\tAlertDialogCancel,\n\tAlertDialogContent,\n\tAlertDialogDescription,\n\tAlertDialogFooter,\n\tAlertDialogHeader,\n\tAlertDialogTitle,\n} from '@/components/ui/alertDialog';\nimport { Badge } from '@/components/ui/badge';\nimport { Button } from '@/components/ui/button';\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogFooter,\n\tDialogHeader,\n\tDialogTitle,\n} from '@/components/ui/dialog';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { Textarea } from '@/components/ui/textarea';\nimport {\n\tNotificationDraft,\n\tuseCreateNotificationMutation,\n\tuseDeleteNotificationMutation,\n\tuseUpdateNotificationMutation,\n} from '@/features/admin/notifications/mutations/useNotificationMutations';\nimport { NotificationLink } from '@/features/notifications/components/NotificationLink';\nimport { useNotifications } from '@/features/notifications/hooks';\nimport { getSeverityConfig, parseNotificationLink, toMs } from '@/features/notifications/notificationHelpers';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { ColumnDef } from '@tanstack/react-table';\nimport { PencilIcon, PlusIcon, Trash2Icon } from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nconst TYPE_OPTIONS = [\n\t{ value: 'error', label: 'Error / Outage' },\n\t{ value: 'warning', label: 'Warning' },\n\t{ value: 'maintenance', label: 'Maintenance' },\n\t{ value: 'info', label: 'Info' },\n];\n\n/** A stored timestamp → the `YYYY-MM-DDTHH:mm` local value a `datetime-local` input expects. */\nfunction toInputValue(value: string | number | null | undefined): string {\n\tconst ms = toMs(value);\n\tif (ms === null) { return ''; }\n\tconst date = new Date(ms);\n\tconst pad = (n: number) => String(n).padStart(2, '0');\n\treturn `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${\n\t\tpad(date.getMinutes())\n\t}`;\n}\n\n/** A `datetime-local` value (local time) → a UTC ISO string, or null when empty. */\nfunction fromInputValue(value: string): string | null {\n\tif (!value) { return null; }\n\tconst ms = Date.parse(value);\n\treturn Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction formatWindow(notification: SystemStatusNotification): string {\n\tconst start = toMs(notification.startAt);\n\tconst end = toMs(notification.endAt);\n\tif (start === null && end === null) { return 'Always'; }\n\tconst fmt = (ms: number | null) => (ms === null ? '—' : new Date(ms).toLocaleString());\n\treturn `${fmt(start)} → ${fmt(end)}`;\n}\n\nexport function NotificationsAdminIndex() {\n\tconst { data, isLoading } = useNotifications();\n\tconst [formOpen, setFormOpen] = useState(false);\n\tconst [editing, setEditing] = useState<SystemStatusNotification | null>(null);\n\tconst [deleteTarget, setDeleteTarget] = useState<SystemStatusNotification | null>(null);\n\tconst deleteMutation = useDeleteNotificationMutation();\n\n\tconst openCreate = useCallback(() => {\n\t\tsetEditing(null);\n\t\tsetFormOpen(true);\n\t}, []);\n\tconst openEdit = useCallback((notification: SystemStatusNotification) => {\n\t\tsetEditing(notification);\n\t\tsetFormOpen(true);\n\t}, []);\n\n\tconst columns = useMemo<ColumnDef<SystemStatusNotification>[]>(\n\t\t() => buildColumns({ openEdit, onDelete: setDeleteTarget }),\n\t\t[openEdit],\n\t);\n\n\treturn (\n\t\t<div className=\"max-w-5xl\">\n\t\t\t<div className=\"flex items-start justify-between gap-4\">\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-2xl font-light\">Notifications</h1>\n\t\t\t\t\t<p className=\"mt-2 text-sm text-muted-foreground\">\n\t\t\t\t\t\tSystem-wide notices shown to all users in the notification center. Times are stored in UTC.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<Button variant=\"submit\" onClick={openCreate} className=\"shrink-0\">\n\t\t\t\t\t<PlusIcon />\n\t\t\t\t\tNew notification\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t<div className=\"mt-6\">\n\t\t\t\t{isLoading ? <Skeleton className=\"h-40 w-full\" /> : <DataTable columns={columns} data={data ?? []} />}\n\t\t\t</div>\n\n\t\t\t<NotificationFormDialog open={formOpen} onOpenChange={setFormOpen} editing={editing} />\n\n\t\t\t<AlertDialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>\n\t\t\t\t<AlertDialogContent>\n\t\t\t\t\t<AlertDialogHeader>\n\t\t\t\t\t\t<AlertDialogTitle>Delete notification?</AlertDialogTitle>\n\t\t\t\t\t\t<AlertDialogDescription>\n\t\t\t\t\t\t\tThis removes it for everyone immediately. This can't be undone.\n\t\t\t\t\t\t</AlertDialogDescription>\n\t\t\t\t\t</AlertDialogHeader>\n\t\t\t\t\t<AlertDialogFooter>\n\t\t\t\t\t\t<AlertDialogCancel>Cancel</AlertDialogCancel>\n\t\t\t\t\t\t<AlertDialogAction\n\t\t\t\t\t\t\tdisabled={deleteMutation.isPending}\n\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tif (!deleteTarget) { return; }\n\t\t\t\t\t\t\t\tdeleteMutation.mutate(deleteTarget.id, { onSuccess: () => setDeleteTarget(null) });\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{deleteMutation.isPending ? 'Deleting…' : 'Delete'}\n\t\t\t\t\t\t</AlertDialogAction>\n\t\t\t\t\t</AlertDialogFooter>\n\t\t\t\t</AlertDialogContent>\n\t\t\t</AlertDialog>\n\t\t</div>\n\t);\n}\n\nfunction buildColumns(\n\t{ openEdit, onDelete }: {\n\t\topenEdit: (notification: SystemStatusNotification) => void;\n\t\tonDelete: (notification: SystemStatusNotification) => void;\n\t},\n): ColumnDef<SystemStatusNotification>[] {\n\treturn [\n\t\t{\n\t\t\theader: 'Type',\n\t\t\taccessorKey: 'type',\n\t\t\tsize: 12,\n\t\t\tcell: ({ row }) => {\n\t\t\t\tconst { label, badgeVariant } = getSeverityConfig(row.original.type);\n\t\t\t\treturn <Badge variant={badgeVariant}>{row.original.type || label}</Badge>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\theader: 'Message',\n\t\t\taccessorKey: 'message',\n\t\t\tsize: 40,\n\t\t\tcell: ({ row }) => <span className=\"line-clamp-2 break-words\">{row.original.message}</span>,\n\t\t},\n\t\t{\n\t\t\theader: 'Active window (local)',\n\t\t\tsize: 28,\n\t\t\tcell: ({ row }) => <span className=\"text-sm text-muted-foreground\">{formatWindow(row.original)}</span>,\n\t\t},\n\t\t{\n\t\t\theader: 'Link',\n\t\t\tsize: 8,\n\t\t\tcell: ({ row }) =>\n\t\t\t\trow.original.url\n\t\t\t\t\t? <NotificationLink url={row.original.url} className=\"text-sm text-primary hover:underline dark:text-white\" />\n\t\t\t\t\t: <span className=\"text-muted-foreground\">—</span>,\n\t\t},\n\t\t{\n\t\t\theader: '',\n\t\t\tid: 'actions',\n\t\t\tsize: 12,\n\t\t\tcell: ({ row }) => (\n\t\t\t\t<div className=\"flex justify-end gap-1\">\n\t\t\t\t\t<Button variant=\"ghost\" size=\"icon\" aria-label=\"Edit\" onClick={() => openEdit(row.original)}>\n\t\t\t\t\t\t<PencilIcon />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"destructiveGhost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\taria-label=\"Delete\"\n\t\t\t\t\t\tonClick={() => onDelete(row.original)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Trash2Icon />\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t),\n\t\t},\n\t];\n}\n\nfunction NotificationFormDialog({\n\topen,\n\tonOpenChange,\n\tediting,\n}: {\n\topen: boolean;\n\tonOpenChange: (open: boolean) => void;\n\tediting: SystemStatusNotification | null;\n}) {\n\tconst createMutation = useCreateNotificationMutation();\n\tconst updateMutation = useUpdateNotificationMutation();\n\tconst isPending = createMutation.isPending || updateMutation.isPending;\n\n\tconst [type, setType] = useState('error');\n\tconst [message, setMessage] = useState('');\n\tconst [url, setUrl] = useState('');\n\tconst [startAt, setStartAt] = useState('');\n\tconst [endAt, setEndAt] = useState('');\n\tconst [error, setError] = useState<string | null>(null);\n\n\t// Reset the form to the edited row (or blanks for create) each time the dialog opens.\n\tuseEffect(() => {\n\t\tif (!open) { return; }\n\t\tsetType(editing?.type ?? 'error');\n\t\tsetMessage(editing?.message ?? '');\n\t\tsetUrl(editing?.url ?? '');\n\t\tsetStartAt(toInputValue(editing?.startAt));\n\t\tsetEndAt(toInputValue(editing?.endAt));\n\t\tsetError(null);\n\t}, [open, editing]);\n\n\tconst submit = () => {\n\t\tconst trimmedMessage = message.trim();\n\t\tif (!trimmedMessage) {\n\t\t\tsetError('Message is required.');\n\t\t\treturn;\n\t\t}\n\t\tconst start = fromInputValue(startAt);\n\t\tconst end = fromInputValue(endAt);\n\t\tif (start && end && Date.parse(end) <= Date.parse(start)) {\n\t\t\tsetError('End time must be after start time.');\n\t\t\treturn;\n\t\t}\n\t\t// Validate the link with the same parser the UI renders with, so the form can't save a URL the\n\t\t// notification would then silently drop (an unsafe scheme, or a typo'd `htp://…`).\n\t\tconst trimmedUrl = url.trim();\n\t\tif (trimmedUrl && !parseNotificationLink(trimmedUrl)) {\n\t\t\tsetError('Link must be an http(s) URL, a mailto: address, or a path starting with “/”.');\n\t\t\treturn;\n\t\t}\n\n\t\tconst draft: NotificationDraft = {\n\t\t\ttype,\n\t\t\tmessage: trimmedMessage,\n\t\t\turl: trimmedUrl || null,\n\t\t\tstartAt: start,\n\t\t\tendAt: end,\n\t\t};\n\t\tconst onSuccess = () => onOpenChange(false);\n\t\tif (editing) {\n\t\t\tupdateMutation.mutate({ id: editing.id, draft }, { onSuccess });\n\t\t} else {\n\t\t\tcreateMutation.mutate(draft, { onSuccess });\n\t\t}\n\t};\n\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogContent>\n\t\t\t\t<DialogHeader>\n\t\t\t\t\t<DialogTitle>{editing ? 'Edit notification' : 'New notification'}</DialogTitle>\n\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\tShown to all users. Leave start/end empty for an open-ended window.\n\t\t\t\t\t</DialogDescription>\n\t\t\t\t</DialogHeader>\n\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-type\">Type</Label>\n\t\t\t\t\t\t<Select value={type} onValueChange={setType}>\n\t\t\t\t\t\t\t<SelectTrigger id=\"notification-type\" className=\"w-full\">\n\t\t\t\t\t\t\t\t<SelectValue />\n\t\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t\t{TYPE_OPTIONS.map((option) => (\n\t\t\t\t\t\t\t\t\t<SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t\t</Select>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-message\">Message</Label>\n\t\t\t\t\t\t<Textarea\n\t\t\t\t\t\t\tid=\"notification-message\"\n\t\t\t\t\t\t\trows={3}\n\t\t\t\t\t\t\tvalue={message}\n\t\t\t\t\t\t\tonChange={(event) => setMessage(event.target.value)}\n\t\t\t\t\t\t\tplaceholder=\"The Fabric control plane will be undergoing maintenance…\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t<Label htmlFor=\"notification-url\">Link (optional)</Label>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tid=\"notification-url\"\n\t\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\t\tonChange={(event) => setUrl(event.target.value)}\n\t\t\t\t\t\t\tplaceholder=\"https://status.harper.io or /organizations\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\tAn absolute URL opens in a new tab; a path like <code>/organizations</code> links inside Studio.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t<Label htmlFor=\"notification-start\">Start (local time)</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"notification-start\"\n\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\tvalue={startAt}\n\t\t\t\t\t\t\t\tonChange={(event) => setStartAt(event.target.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t<Label htmlFor=\"notification-end\">End (local time)</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"notification-end\"\n\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\tvalue={endAt}\n\t\t\t\t\t\t\t\tonChange={(event) => setEndAt(event.target.value)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{error && <p className=\"text-sm text-destructive\">{error}</p>}\n\t\t\t\t</div>\n\n\t\t\t\t<DialogFooter>\n\t\t\t\t\t<Button variant=\"ghostOutline\" onClick={() => onOpenChange(false)} disabled={isPending}>\n\t\t\t\t\t\tCancel\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button variant=\"submit\" onClick={submit} disabled={isPending}>\n\t\t\t\t\t\t{isPending ? 'Saving…' : editing ? 'Save changes' : 'Create'}\n\t\t\t\t\t</Button>\n\t\t\t\t</DialogFooter>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./button-oQgW4t1x.js";import{a as r}from"./vendor-datadog-DyjkTkvg.js";import{r as i}from"./vendor-react-DeL8Gtgl.js";import{Dn as a,En as o,It as s,On as c,Sn as l,Tn as u,_n as d,bn as f,gn as p,wn as m,xn as h,yn as g}from"./index-CyNVanoD.js";var _=e(r(),1),v=i(),y={active:0,upcoming:1,expired:2};function b(){let{data:e,isLoading:t}=p(),n=a(),r=d(),i=(0,_.useMemo)(()=>[...e??[]].sort((e,t)=>{let n=y[l(e,r).state],i=y[l(t,r).state];if(n!==i)return n-i;let a=f[h(e.type).severity]-f[h(t.type).severity];if(a!==0)return a;let o=m(e.endAt)??2**53-1;return(m(t.endAt)??2**53-1)-o}),[e,r]);return(0,v.jsx)(`div`,{className:`mt-32 px-4 pt-4 md:px-12 min-h-[calc(100vh-(--spacing(32)))]`,children:(0,v.jsxs)(`div`,{className:`max-w-3xl`,children:[(0,v.jsx)(`h1`,{className:`text-2xl font-light`,children:`Notifications`}),(0,v.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`System-wide notices, including maintenance windows and downstream provider incidents.`}),(0,v.jsx)(`div`,{className:`mt-6 flex flex-col gap-3`,children:t?(0,v.jsx)(s,{className:`h-24 w-full`}):i.length===0?(0,v.jsx)(`p`,{className:`rounded-md border border-border bg-card p-8 text-center text-sm text-muted-foreground dark:bg-black-dark`,children:`No notifications right now.`}):i.map(e=>(0,v.jsx)(x,{notification:e,acked:n.has(e.id),nowMs:r},e.id))})]})})}function x({notification:e,acked:r,nowMs:i}){let{Icon:a,iconClass:s,label:d,badgeVariant:f}=h(e.type),p=l(e,i);return(0,v.jsxs)(`div`,{className:t(`flex gap-3 rounded-md border border-border bg-card p-4 dark:bg-black-dark`,r&&`opacity-60`,p.state===`expired`&&`opacity-70`),children:[(0,v.jsx)(a,{className:t(`mt-0.5 size-5 shrink-0`,s)}),(0,v.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,v.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,v.jsx)(c,{variant:f,children:d}),p.state!==`active`&&(0,v.jsx)(c,{variant:`outline`,className:`capitalize`,children:p.state}),(0,v.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:p.label})]}),(0,v.jsx)(`p`,{className:`mt-2 text-sm break-words text-foreground`,children:e.message}),(0,v.jsx)(`div`,{className:`mt-2 flex items-center gap-4 text-sm`,children:(0,v.jsx)(g,{url:e.url,className:`font-medium text-primary hover:underline dark:text-white`})})]}),(0,v.jsx)(n,{variant:`ghost`,size:`sm`,className:`shrink-0 text-muted-foreground`,onClick:()=>r?o(e.id):u(e.id),children:r?`Undo`:`Ignore`})]})}export{b as NotificationsCenter};
2
- //# sourceMappingURL=notifications-XVakNKhZ.js.map
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./button-oQgW4t1x.js";import{a as r}from"./vendor-datadog-DyjkTkvg.js";import{r as i}from"./vendor-react-DeL8Gtgl.js";import{Dn as a,En as o,It as s,On as c,Sn as l,Tn as u,_n as d,bn as f,gn as p,wn as m,xn as h,yn as g}from"./index-DfGv-6tB.js";var _=e(r(),1),v=i(),y={active:0,upcoming:1,expired:2};function b(){let{data:e,isLoading:t}=p(),n=a(),r=d(),i=(0,_.useMemo)(()=>[...e??[]].sort((e,t)=>{let n=y[l(e,r).state],i=y[l(t,r).state];if(n!==i)return n-i;let a=f[h(e.type).severity]-f[h(t.type).severity];if(a!==0)return a;let o=m(e.endAt)??2**53-1;return(m(t.endAt)??2**53-1)-o}),[e,r]);return(0,v.jsx)(`div`,{className:`mt-32 px-4 pt-4 md:px-12 min-h-[calc(100vh-(--spacing(32)))]`,children:(0,v.jsxs)(`div`,{className:`max-w-3xl`,children:[(0,v.jsx)(`h1`,{className:`text-2xl font-light`,children:`Notifications`}),(0,v.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`System-wide notices, including maintenance windows and downstream provider incidents.`}),(0,v.jsx)(`div`,{className:`mt-6 flex flex-col gap-3`,children:t?(0,v.jsx)(s,{className:`h-24 w-full`}):i.length===0?(0,v.jsx)(`p`,{className:`rounded-md border border-border bg-card p-8 text-center text-sm text-muted-foreground dark:bg-black-dark`,children:`No notifications right now.`}):i.map(e=>(0,v.jsx)(x,{notification:e,acked:n.has(e.id),nowMs:r},e.id))})]})})}function x({notification:e,acked:r,nowMs:i}){let{Icon:a,iconClass:s,label:d,badgeVariant:f}=h(e.type),p=l(e,i);return(0,v.jsxs)(`div`,{className:t(`flex gap-3 rounded-md border border-border bg-card p-4 dark:bg-black-dark`,r&&`opacity-60`,p.state===`expired`&&`opacity-70`),children:[(0,v.jsx)(a,{className:t(`mt-0.5 size-5 shrink-0`,s)}),(0,v.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,v.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,v.jsx)(c,{variant:f,children:d}),p.state!==`active`&&(0,v.jsx)(c,{variant:`outline`,className:`capitalize`,children:p.state}),(0,v.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:p.label})]}),(0,v.jsx)(`p`,{className:`mt-2 text-sm break-words text-foreground`,children:e.message}),(0,v.jsx)(`div`,{className:`mt-2 flex items-center gap-4 text-sm`,children:(0,v.jsx)(g,{url:e.url,className:`font-medium text-primary hover:underline dark:text-white`})})]}),(0,v.jsx)(n,{variant:`ghost`,size:`sm`,className:`shrink-0 text-muted-foreground`,onClick:()=>r?o(e.id):u(e.id),children:r?`Undo`:`Ignore`})]})}export{b as NotificationsCenter};
2
+ //# sourceMappingURL=notifications-bG86ov79.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications-XVakNKhZ.js","names":[],"sources":["../../src/features/notifications/index.tsx"],"sourcesContent":["import { Badge } from '@/components/ui/badge';\nimport { Button } from '@/components/ui/button';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { ackNotification, unackNotification, useNotificationAcks } from '@/features/notifications/acks';\nimport { NotificationLink } from '@/features/notifications/components/NotificationLink';\nimport { useNotifications, useNow } from '@/features/notifications/hooks';\nimport {\n\tgetSeverityConfig,\n\tgetWindowStatus,\n\tSEVERITY_ORDER,\n\ttoMs,\n\ttype WindowState,\n} from '@/features/notifications/notificationHelpers';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { cn } from '@/lib/cn';\nimport { useMemo } from 'react';\n\nconst STATE_ORDER: Record<WindowState, number> = { active: 0, upcoming: 1, expired: 2 };\n\nexport function NotificationsCenter() {\n\tconst { data, isLoading } = useNotifications();\n\tconst acks = useNotificationAcks();\n\tconst now = useNow();\n\n\tconst sorted = useMemo(() =>\n\t\t[...(data ?? [])].sort((a, b) => {\n\t\t\tconst stateA = STATE_ORDER[getWindowStatus(a, now).state];\n\t\t\tconst stateB = STATE_ORDER[getWindowStatus(b, now).state];\n\t\t\tif (stateA !== stateB) { return stateA - stateB; }\n\t\t\tconst severityDelta = SEVERITY_ORDER[getSeverityConfig(a.type).severity]\n\t\t\t\t- SEVERITY_ORDER[getSeverityConfig(b.type).severity];\n\t\t\tif (severityDelta !== 0) { return severityDelta; }\n\t\t\t// Most recently ending first within a group. Use MAX_SAFE_INTEGER (not Infinity) as the\n\t\t\t// open-ended fallback so two never-ending notices compare as 0, not NaN (unstable sort).\n\t\t\tconst endA = toMs(a.endAt) ?? Number.MAX_SAFE_INTEGER;\n\t\t\tconst endB = toMs(b.endAt) ?? Number.MAX_SAFE_INTEGER;\n\t\t\treturn endB - endA;\n\t\t}), [data, now]);\n\n\treturn (\n\t\t<div className=\"mt-32 px-4 pt-4 md:px-12 min-h-[calc(100vh-(--spacing(32)))]\">\n\t\t\t<div className=\"max-w-3xl\">\n\t\t\t\t<h1 className=\"text-2xl font-light\">Notifications</h1>\n\t\t\t\t<p className=\"mt-2 text-sm text-muted-foreground\">\n\t\t\t\t\tSystem-wide notices, including maintenance windows and downstream provider incidents.\n\t\t\t\t</p>\n\n\t\t\t\t<div className=\"mt-6 flex flex-col gap-3\">\n\t\t\t\t\t{isLoading\n\t\t\t\t\t\t? <Skeleton className=\"h-24 w-full\" />\n\t\t\t\t\t\t: sorted.length === 0\n\t\t\t\t\t\t? (\n\t\t\t\t\t\t\t<p className=\"rounded-md border border-border bg-card p-8 text-center text-sm text-muted-foreground dark:bg-black-dark\">\n\t\t\t\t\t\t\t\tNo notifications right now.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t)\n\t\t\t\t\t\t: sorted.map((notification) => (\n\t\t\t\t\t\t\t<NotificationCard\n\t\t\t\t\t\t\t\tkey={notification.id}\n\t\t\t\t\t\t\t\tnotification={notification}\n\t\t\t\t\t\t\t\tacked={acks.has(notification.id)}\n\t\t\t\t\t\t\t\tnowMs={now}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction NotificationCard({\n\tnotification,\n\tacked,\n\tnowMs,\n}: {\n\tnotification: SystemStatusNotification;\n\tacked: boolean;\n\tnowMs: number;\n}) {\n\tconst { Icon, iconClass, label, badgeVariant } = getSeverityConfig(notification.type);\n\tconst window = getWindowStatus(notification, nowMs);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex gap-3 rounded-md border border-border bg-card p-4 dark:bg-black-dark',\n\t\t\t\tacked && 'opacity-60',\n\t\t\t\twindow.state === 'expired' && 'opacity-70',\n\t\t\t)}\n\t\t>\n\t\t\t<Icon className={cn('mt-0.5 size-5 shrink-0', iconClass)} />\n\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t\t\t<Badge variant={badgeVariant}>{label}</Badge>\n\t\t\t\t\t{window.state !== 'active' && <Badge variant=\"outline\" className=\"capitalize\">{window.state}</Badge>}\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">{window.label}</span>\n\t\t\t\t</div>\n\t\t\t\t<p className=\"mt-2 text-sm break-words text-foreground\">{notification.message}</p>\n\t\t\t\t<div className=\"mt-2 flex items-center gap-4 text-sm\">\n\t\t\t\t\t<NotificationLink\n\t\t\t\t\t\turl={notification.url}\n\t\t\t\t\t\tclassName=\"font-medium text-primary hover:underline dark:text-white\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Button\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\tsize=\"sm\"\n\t\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t\t\tonClick={() => (acked ? unackNotification(notification.id) : ackNotification(notification.id))}\n\t\t\t>\n\t\t\t\t{acked ? 'Undo' : 'Ignore'}\n\t\t\t</Button>\n\t\t</div>\n\t);\n}\n"],"mappings":"yVAiBM,EAA2C,CAAE,OAAQ,EAAG,SAAU,EAAG,QAAS,CAAE,EAEtF,SAAgB,GAAsB,CACrC,GAAM,CAAE,OAAM,aAAc,EAAiB,EACvC,EAAO,EAAoB,EAC3B,EAAM,EAAO,EAEb,GAAA,EAAA,EAAA,QAAA,KACL,CAAC,GAAI,GAAQ,CAAC,CAAE,CAAC,CAAC,MAAM,EAAG,IAAM,CAChC,IAAM,EAAS,EAAY,EAAgB,EAAG,CAAG,CAAC,CAAC,OAC7C,EAAS,EAAY,EAAgB,EAAG,CAAG,CAAC,CAAC,OACnD,GAAI,IAAW,EAAU,OAAO,EAAS,EACzC,IAAM,EAAgB,EAAe,EAAkB,EAAE,IAAI,CAAC,CAAC,UAC5D,EAAe,EAAkB,EAAE,IAAI,CAAC,CAAC,UAC5C,GAAI,IAAkB,EAAK,OAAO,EAGlC,IAAM,EAAO,EAAK,EAAE,KAAK,WAEzB,OADa,EAAK,EAAE,KAAK,YACX,CACf,CAAC,EAAG,CAAC,EAAM,CAAG,CAAC,EAEhB,OACC,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,yEACd,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,qBAAf,EACC,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAU,+BAAsB,eAAiB,CAAA,GACrD,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,8CAAqC,uFAE/C,CAAA,GAEH,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,oCACb,GACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAU,UAAU,aAAe,CAAA,EACnC,EAAO,SAAW,GAEnB,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,oHAA2G,6BAErH,CAAA,EAEF,EAAO,IAAK,IACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAEe,eACd,MAAO,EAAK,IAAI,EAAa,EAAE,EAC/B,MAAO,CACP,EAJK,EAAa,EAIlB,CACD,CACE,CAAA,CACD,GACD,CAAA,CAEP,CAEA,SAAS,EAAiB,CACzB,eACA,QACA,SAKE,CACF,GAAM,CAAE,OAAM,YAAW,QAAO,gBAAiB,EAAkB,EAAa,IAAI,EAC9E,EAAS,EAAgB,EAAc,CAAK,EAElD,OACC,EAAA,EAAA,KAAA,CAAC,MAAD,CACC,UAAW,EACV,4EACA,GAAS,aACT,EAAO,QAAU,WAAa,YAC/B,WALD,EAOC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,UAAW,EAAG,yBAA0B,CAAS,CAAI,CAAA,GAC3D,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,0BAAf,EACC,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,6CAAf,EACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,QAAS,WAAe,CAAa,CAAA,EAC3C,EAAO,QAAU,WAAY,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,QAAQ,UAAU,UAAU,sBAAc,EAAO,KAAa,CAAA,GACnG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,yCAAiC,EAAO,KAAY,CAAA,CAChE,KACL,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,oDAA4C,EAAa,OAAW,CAAA,GACjF,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,iDACd,EAAA,EAAA,IAAA,CAAC,EAAD,CACC,IAAK,EAAa,IAClB,UAAU,0DACV,CAAA,CACG,CAAA,CACD,KACL,EAAA,EAAA,IAAA,CAAC,EAAD,CACC,QAAQ,QACR,KAAK,KACL,UAAU,iCACV,YAAgB,EAAQ,EAAkB,EAAa,EAAE,EAAI,EAAgB,EAAa,EAAE,WAE3F,EAAQ,OAAS,QACX,CAAA,CACJ,GAEP"}
1
+ {"version":3,"file":"notifications-bG86ov79.js","names":[],"sources":["../../src/features/notifications/index.tsx"],"sourcesContent":["import { Badge } from '@/components/ui/badge';\nimport { Button } from '@/components/ui/button';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { ackNotification, unackNotification, useNotificationAcks } from '@/features/notifications/acks';\nimport { NotificationLink } from '@/features/notifications/components/NotificationLink';\nimport { useNotifications, useNow } from '@/features/notifications/hooks';\nimport {\n\tgetSeverityConfig,\n\tgetWindowStatus,\n\tSEVERITY_ORDER,\n\ttoMs,\n\ttype WindowState,\n} from '@/features/notifications/notificationHelpers';\nimport { SystemStatusNotification } from '@/integrations/api/api.patch';\nimport { cn } from '@/lib/cn';\nimport { useMemo } from 'react';\n\nconst STATE_ORDER: Record<WindowState, number> = { active: 0, upcoming: 1, expired: 2 };\n\nexport function NotificationsCenter() {\n\tconst { data, isLoading } = useNotifications();\n\tconst acks = useNotificationAcks();\n\tconst now = useNow();\n\n\tconst sorted = useMemo(() =>\n\t\t[...(data ?? [])].sort((a, b) => {\n\t\t\tconst stateA = STATE_ORDER[getWindowStatus(a, now).state];\n\t\t\tconst stateB = STATE_ORDER[getWindowStatus(b, now).state];\n\t\t\tif (stateA !== stateB) { return stateA - stateB; }\n\t\t\tconst severityDelta = SEVERITY_ORDER[getSeverityConfig(a.type).severity]\n\t\t\t\t- SEVERITY_ORDER[getSeverityConfig(b.type).severity];\n\t\t\tif (severityDelta !== 0) { return severityDelta; }\n\t\t\t// Most recently ending first within a group. Use MAX_SAFE_INTEGER (not Infinity) as the\n\t\t\t// open-ended fallback so two never-ending notices compare as 0, not NaN (unstable sort).\n\t\t\tconst endA = toMs(a.endAt) ?? Number.MAX_SAFE_INTEGER;\n\t\t\tconst endB = toMs(b.endAt) ?? Number.MAX_SAFE_INTEGER;\n\t\t\treturn endB - endA;\n\t\t}), [data, now]);\n\n\treturn (\n\t\t<div className=\"mt-32 px-4 pt-4 md:px-12 min-h-[calc(100vh-(--spacing(32)))]\">\n\t\t\t<div className=\"max-w-3xl\">\n\t\t\t\t<h1 className=\"text-2xl font-light\">Notifications</h1>\n\t\t\t\t<p className=\"mt-2 text-sm text-muted-foreground\">\n\t\t\t\t\tSystem-wide notices, including maintenance windows and downstream provider incidents.\n\t\t\t\t</p>\n\n\t\t\t\t<div className=\"mt-6 flex flex-col gap-3\">\n\t\t\t\t\t{isLoading\n\t\t\t\t\t\t? <Skeleton className=\"h-24 w-full\" />\n\t\t\t\t\t\t: sorted.length === 0\n\t\t\t\t\t\t? (\n\t\t\t\t\t\t\t<p className=\"rounded-md border border-border bg-card p-8 text-center text-sm text-muted-foreground dark:bg-black-dark\">\n\t\t\t\t\t\t\t\tNo notifications right now.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t)\n\t\t\t\t\t\t: sorted.map((notification) => (\n\t\t\t\t\t\t\t<NotificationCard\n\t\t\t\t\t\t\t\tkey={notification.id}\n\t\t\t\t\t\t\t\tnotification={notification}\n\t\t\t\t\t\t\t\tacked={acks.has(notification.id)}\n\t\t\t\t\t\t\t\tnowMs={now}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction NotificationCard({\n\tnotification,\n\tacked,\n\tnowMs,\n}: {\n\tnotification: SystemStatusNotification;\n\tacked: boolean;\n\tnowMs: number;\n}) {\n\tconst { Icon, iconClass, label, badgeVariant } = getSeverityConfig(notification.type);\n\tconst window = getWindowStatus(notification, nowMs);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex gap-3 rounded-md border border-border bg-card p-4 dark:bg-black-dark',\n\t\t\t\tacked && 'opacity-60',\n\t\t\t\twindow.state === 'expired' && 'opacity-70',\n\t\t\t)}\n\t\t>\n\t\t\t<Icon className={cn('mt-0.5 size-5 shrink-0', iconClass)} />\n\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t\t\t<Badge variant={badgeVariant}>{label}</Badge>\n\t\t\t\t\t{window.state !== 'active' && <Badge variant=\"outline\" className=\"capitalize\">{window.state}</Badge>}\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">{window.label}</span>\n\t\t\t\t</div>\n\t\t\t\t<p className=\"mt-2 text-sm break-words text-foreground\">{notification.message}</p>\n\t\t\t\t<div className=\"mt-2 flex items-center gap-4 text-sm\">\n\t\t\t\t\t<NotificationLink\n\t\t\t\t\t\turl={notification.url}\n\t\t\t\t\t\tclassName=\"font-medium text-primary hover:underline dark:text-white\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Button\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\tsize=\"sm\"\n\t\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t\t\tonClick={() => (acked ? unackNotification(notification.id) : ackNotification(notification.id))}\n\t\t\t>\n\t\t\t\t{acked ? 'Undo' : 'Ignore'}\n\t\t\t</Button>\n\t\t</div>\n\t);\n}\n"],"mappings":"yVAiBM,EAA2C,CAAE,OAAQ,EAAG,SAAU,EAAG,QAAS,CAAE,EAEtF,SAAgB,GAAsB,CACrC,GAAM,CAAE,OAAM,aAAc,EAAiB,EACvC,EAAO,EAAoB,EAC3B,EAAM,EAAO,EAEb,GAAA,EAAA,EAAA,QAAA,KACL,CAAC,GAAI,GAAQ,CAAC,CAAE,CAAC,CAAC,MAAM,EAAG,IAAM,CAChC,IAAM,EAAS,EAAY,EAAgB,EAAG,CAAG,CAAC,CAAC,OAC7C,EAAS,EAAY,EAAgB,EAAG,CAAG,CAAC,CAAC,OACnD,GAAI,IAAW,EAAU,OAAO,EAAS,EACzC,IAAM,EAAgB,EAAe,EAAkB,EAAE,IAAI,CAAC,CAAC,UAC5D,EAAe,EAAkB,EAAE,IAAI,CAAC,CAAC,UAC5C,GAAI,IAAkB,EAAK,OAAO,EAGlC,IAAM,EAAO,EAAK,EAAE,KAAK,WAEzB,OADa,EAAK,EAAE,KAAK,YACX,CACf,CAAC,EAAG,CAAC,EAAM,CAAG,CAAC,EAEhB,OACC,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,yEACd,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,qBAAf,EACC,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAU,+BAAsB,eAAiB,CAAA,GACrD,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,8CAAqC,uFAE/C,CAAA,GAEH,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,oCACb,GACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAU,UAAU,aAAe,CAAA,EACnC,EAAO,SAAW,GAEnB,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,oHAA2G,6BAErH,CAAA,EAEF,EAAO,IAAK,IACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAEe,eACd,MAAO,EAAK,IAAI,EAAa,EAAE,EAC/B,MAAO,CACP,EAJK,EAAa,EAIlB,CACD,CACE,CAAA,CACD,GACD,CAAA,CAEP,CAEA,SAAS,EAAiB,CACzB,eACA,QACA,SAKE,CACF,GAAM,CAAE,OAAM,YAAW,QAAO,gBAAiB,EAAkB,EAAa,IAAI,EAC9E,EAAS,EAAgB,EAAc,CAAK,EAElD,OACC,EAAA,EAAA,KAAA,CAAC,MAAD,CACC,UAAW,EACV,4EACA,GAAS,aACT,EAAO,QAAU,WAAa,YAC/B,WALD,EAOC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,UAAW,EAAG,yBAA0B,CAAS,CAAI,CAAA,GAC3D,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,0BAAf,EACC,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,6CAAf,EACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,QAAS,WAAe,CAAa,CAAA,EAC3C,EAAO,QAAU,WAAY,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,QAAQ,UAAU,UAAU,sBAAc,EAAO,KAAa,CAAA,GACnG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,yCAAiC,EAAO,KAAY,CAAA,CAChE,KACL,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,oDAA4C,EAAa,OAAW,CAAA,GACjF,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,iDACd,EAAA,EAAA,IAAA,CAAC,EAAD,CACC,IAAK,EAAa,IAClB,UAAU,0DACV,CAAA,CACG,CAAA,CACD,KACL,EAAA,EAAA,IAAA,CAAC,EAAD,CACC,QAAQ,QACR,KAAK,KACL,UAAU,iCACV,YAAgB,EAAQ,EAAkB,EAAa,EAAE,EAAI,EAAgB,EAAa,EAAE,WAE3F,EAAQ,OAAS,QACX,CAAA,CACJ,GAEP"}
@@ -1,2 +1,2 @@
1
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./authStore-CNoNfv0F.js";import{b as r,v as i}from"./vendor-core-xUefYpUO.js";import{i as a,t as o}from"./button-oQgW4t1x.js";import{A as s,E as c,x as l}from"./vendor-tanstack-0SjDjtT0.js";import{a as u}from"./vendor-datadog-DyjkTkvg.js";import{r as d}from"./vendor-react-DeL8Gtgl.js";import{i as f}from"./useAuth-DvlnspkA.js";import{$ as p,Rt as m,it as h}from"./vendor-ui-Bj22lHGK.js";import{Yn as g,an as _,cn as v,fn as y,in as b,ln as x,rn as S,sn as C,un as w}from"./index-CyNVanoD.js";async function T(e){let{id:t,newPassword:n,confirmNewPassword:r,...i}=e,o={...i};n&&n===r&&(o.password=n);let{data:s}=await a.patch(`/User/${t}`,o);return s}function E(){return s({mutationFn:e=>T(e)})}var D=i({id:r(),firstname:r({error:`Please enter your first name.`}).min(2,{error:`First name is required.`}).max(50,{error:`First name must be less than 50 characters.`}),lastname:r({error:`Please enter your last name.`}).min(2,{error:`Last name is required.`}).max(50,{error:`Last name must be less than 50 characters.`}),newPassword:r({error:`Please enter your new password.`}).min(8,{error:`Password must be 8 characters or more.`}).or(r().max(0)),confirmNewPassword:r().optional()}).refine(e=>e.newPassword===e.confirmNewPassword,{error:`Passwords do not match`,path:[`confirmNewPassword`]}),O=e(u(),1),k=d();function A(){let e=c(),r=l(),{user:i}=f(),a=h({resolver:p(D),defaultValues:{confirmNewPassword:``,firstname:i?.firstname||``,id:i?.id||``,lastname:i?.lastname||``,newPassword:``}}),{control:s,handleSubmit:u,reset:d,formState:{defaultValues:T,isDirty:A,isValid:j}}=a,{mutate:M,isPending:N}=E(),P=(0,O.useCallback)(async i=>{i&&M(i,{onSuccess:a=>{d({...T,...a}),t.updateUserForEntity(n,a),i.newPassword?(m.success(`Profile updated successfully!`,{description:`Please sign in with your new password.`}),y(),r({to:`/sign-in`}),e.invalidate()):m.success(`Profile updated successfully!`)}})},[T,r,d,e,M]);return(0,k.jsxs)(`div`,{className:`mt-20 px-4 pt-4 md:px-12 max-w-2xl`,children:[(0,k.jsx)(`h1`,{className:`text-2xl font-light`,children:`Profile`}),(0,k.jsx)(w,{...a,children:(0,k.jsxs)(`form`,{id:`profile-edit-form`,name:`profile-edit-form`,onSubmit:u(P),className:`grid gap-4 my-4`,children:[(0,k.jsx)(v,{control:s,name:`firstname`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`First Name`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,autoFocus:!0,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(v,{control:s,name:`lastname`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`Last Name`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{htmlFor:`profile-email`,className:`pb-1`,children:`Email`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{id:`profile-email`,type:`email`,enterKeyHint:`next`,autoComplete:`email`,autoCapitalize:`none`,value:i?.email||``,disabled:!0,readOnly:!0})})]}),(0,k.jsx)(v,{control:s,name:`newPassword`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`New Password`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`password`,placeholder:`Optional`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(v,{control:s,name:`confirmNewPassword`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`Confirm New Password`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`password`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(`div`,{className:`flex justify-between w-full`,children:(0,k.jsxs)(o,{type:`submit`,variant:`submit`,disabled:N||!A||!j,children:[(0,k.jsx)(g,{}),` Update Profile`]})})]})})]})}export{A as ProfileIndex};
2
- //# sourceMappingURL=profile-Bc0AYPPO.js.map
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./authStore-CNoNfv0F.js";import{b as r,v as i}from"./vendor-core-xUefYpUO.js";import{i as a,t as o}from"./button-oQgW4t1x.js";import{A as s,E as c,x as l}from"./vendor-tanstack-0SjDjtT0.js";import{a as u}from"./vendor-datadog-DyjkTkvg.js";import{r as d}from"./vendor-react-DeL8Gtgl.js";import{i as f}from"./useAuth-DvlnspkA.js";import{$ as p,Rt as m,it as h}from"./vendor-ui-Bj22lHGK.js";import{Yn as g,an as _,cn as v,fn as y,in as b,ln as x,rn as S,sn as C,un as w}from"./index-DfGv-6tB.js";async function T(e){let{id:t,newPassword:n,confirmNewPassword:r,...i}=e,o={...i};n&&n===r&&(o.password=n);let{data:s}=await a.patch(`/User/${t}`,o);return s}function E(){return s({mutationFn:e=>T(e)})}var D=i({id:r(),firstname:r({error:`Please enter your first name.`}).min(2,{error:`First name is required.`}).max(50,{error:`First name must be less than 50 characters.`}),lastname:r({error:`Please enter your last name.`}).min(2,{error:`Last name is required.`}).max(50,{error:`Last name must be less than 50 characters.`}),newPassword:r({error:`Please enter your new password.`}).min(8,{error:`Password must be 8 characters or more.`}).or(r().max(0)),confirmNewPassword:r().optional()}).refine(e=>e.newPassword===e.confirmNewPassword,{error:`Passwords do not match`,path:[`confirmNewPassword`]}),O=e(u(),1),k=d();function A(){let e=c(),r=l(),{user:i}=f(),a=h({resolver:p(D),defaultValues:{confirmNewPassword:``,firstname:i?.firstname||``,id:i?.id||``,lastname:i?.lastname||``,newPassword:``}}),{control:s,handleSubmit:u,reset:d,formState:{defaultValues:T,isDirty:A,isValid:j}}=a,{mutate:M,isPending:N}=E(),P=(0,O.useCallback)(async i=>{i&&M(i,{onSuccess:a=>{d({...T,...a}),t.updateUserForEntity(n,a),i.newPassword?(m.success(`Profile updated successfully!`,{description:`Please sign in with your new password.`}),y(),r({to:`/sign-in`}),e.invalidate()):m.success(`Profile updated successfully!`)}})},[T,r,d,e,M]);return(0,k.jsxs)(`div`,{className:`mt-20 px-4 pt-4 md:px-12 max-w-2xl`,children:[(0,k.jsx)(`h1`,{className:`text-2xl font-light`,children:`Profile`}),(0,k.jsx)(w,{...a,children:(0,k.jsxs)(`form`,{id:`profile-edit-form`,name:`profile-edit-form`,onSubmit:u(P),className:`grid gap-4 my-4`,children:[(0,k.jsx)(v,{control:s,name:`firstname`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`First Name`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,autoFocus:!0,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(v,{control:s,name:`lastname`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`Last Name`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{htmlFor:`profile-email`,className:`pb-1`,children:`Email`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{id:`profile-email`,type:`email`,enterKeyHint:`next`,autoComplete:`email`,autoCapitalize:`none`,value:i?.email||``,disabled:!0,readOnly:!0})})]}),(0,k.jsx)(v,{control:s,name:`newPassword`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`New Password`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`password`,placeholder:`Optional`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(v,{control:s,name:`confirmNewPassword`,render:({field:e})=>(0,k.jsxs)(C,{children:[(0,k.jsx)(_,{className:`pb-1`,children:`Confirm New Password`}),(0,k.jsx)(x,{children:(0,k.jsx)(S,{type:`password`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(b,{})]})}),(0,k.jsx)(`div`,{className:`flex justify-between w-full`,children:(0,k.jsxs)(o,{type:`submit`,variant:`submit`,disabled:N||!A||!j,children:[(0,k.jsx)(g,{}),` Update Profile`]})})]})})]})}export{A as ProfileIndex};
2
+ //# sourceMappingURL=profile-Ca4u59r1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"profile-Bc0AYPPO.js","names":[],"sources":["../../src/features/profile/mutations/updateUserMutation.ts","../../src/features/profile/mutations/updateUserSchema.ts","../../src/features/profile/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { SchemaUser } from '@/integrations/api/api.gen';\nimport { User } from '@/integrations/api/api.patch';\nimport { useMutation } from '@tanstack/react-query';\nimport z from 'zod';\n\nasync function onUpdateUser(formData: z.infer<typeof UpdateUserSchema>) {\n\tconst { id, newPassword, confirmNewPassword, ...otherFields } = formData;\n\tconst userData: Partial<SchemaUser & { password: string }> = {\n\t\t...otherFields,\n\t};\n\tif (newPassword && newPassword === confirmNewPassword) {\n\t\tuserData.password = newPassword;\n\t}\n\tconst { data } = await apiClient.patch(`/User/${id}` as '/User/{id}', userData);\n\treturn data as Partial<User>;\n}\n\nexport function useUpdateUserMutation() {\n\treturn useMutation({\n\t\tmutationFn: (formData: z.infer<typeof UpdateUserSchema>) => onUpdateUser(formData),\n\t});\n}\n","import { z } from 'zod';\n\nexport const UpdateUserSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfirstname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your first name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'First name is required.' })\n\t\t\t.max(50, { error: 'First name must be less than 50 characters.' }),\n\t\tlastname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your last name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'Last name is required.' })\n\t\t\t.max(50, { error: 'Last name must be less than 50 characters.' }),\n\t\tnewPassword: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your new password.',\n\t\t\t})\n\t\t\t.min(8, { error: 'Password must be 8 characters or more.' })\n\t\t\t.or(z.string().max(0)),\n\t\tconfirmNewPassword: z\n\t\t\t.string()\n\t\t\t.optional(),\n\t})\n\t.refine((data) => data.newPassword === data.confirmNewPassword, {\n\t\terror: 'Passwords do not match',\n\t\tpath: ['confirmNewPassword'],\n\t});\n","import { Button } from '@/components/ui/button';\nimport { Form } from '@/components/ui/form/Form';\nimport { FormControl } from '@/components/ui/form/FormControl';\nimport { FormField } from '@/components/ui/form/FormField';\nimport { FormItem } from '@/components/ui/form/FormItem';\nimport { FormLabel } from '@/components/ui/form/FormLabel';\nimport { FormMessage } from '@/components/ui/form/FormMessage';\nimport { Input } from '@/components/ui/input';\nimport { logoutOnSuccess } from '@/features/auth/handlers/logoutOnSuccess';\nimport { authStore, OverallAppSignIn } from '@/features/auth/store/authStore';\nimport { useUpdateUserMutation } from '@/features/profile/mutations/updateUserMutation';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { useCloudAuth } from '@/hooks/useAuth';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useNavigate, useRouter } from '@tanstack/react-router';\nimport { Save } from 'lucide-react';\nimport { useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\n\nexport function ProfileIndex() {\n\tconst router = useRouter();\n\tconst navigate = useNavigate();\n\tconst { user } = useCloudAuth();\n\n\tconst methods = useForm({\n\t\tresolver: zodResolver(UpdateUserSchema),\n\t\tdefaultValues: {\n\t\t\tconfirmNewPassword: '',\n\t\t\tfirstname: user?.firstname || '',\n\t\t\tid: user?.id || '',\n\t\t\tlastname: user?.lastname || '',\n\t\t\tnewPassword: '',\n\t\t},\n\t});\n\tconst { control, handleSubmit, reset, formState: { defaultValues, isDirty, isValid } } = methods;\n\tconst { mutate: updateUser, isPending: isUpdatePending } = useUpdateUserMutation();\n\n\tconst onSubmitClick = useCallback(\n\t\tasync (formData: z.infer<typeof UpdateUserSchema>) => {\n\t\t\tif (formData) {\n\t\t\t\tupdateUser(formData, {\n\t\t\t\t\tonSuccess: (data) => {\n\t\t\t\t\t\treset({\n\t\t\t\t\t\t\t...defaultValues,\n\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tauthStore.updateUserForEntity(OverallAppSignIn, data);\n\t\t\t\t\t\tif (formData.newPassword) {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!', {\n\t\t\t\t\t\t\t\tdescription: 'Please sign in with your new password.',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogoutOnSuccess();\n\t\t\t\t\t\t\tvoid navigate({ to: '/sign-in' });\n\t\t\t\t\t\t\tvoid router.invalidate();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!');\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[defaultValues, navigate, reset, router, updateUser],\n\t);\n\n\treturn (\n\t\t<div className=\"mt-20 px-4 pt-4 md:px-12 max-w-2xl\">\n\t\t\t<h1 className=\"text-2xl font-light\">Profile</h1>\n\t\t\t<Form {...methods}>\n\t\t\t\t<form\n\t\t\t\t\tid=\"profile-edit-form\"\n\t\t\t\t\tname=\"profile-edit-form\"\n\t\t\t\t\tonSubmit={handleSubmit(onSubmitClick)}\n\t\t\t\t\tclassName=\"grid gap-4 my-4\"\n\t\t\t\t>\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"firstname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">First Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"lastname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Last Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t<FormLabel htmlFor=\"profile-email\" className=\"pb-1\">Email</FormLabel>\n\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"profile-email\"\n\t\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\t\tenterKeyHint=\"next\"\n\t\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\tvalue={user?.email || ''}\n\t\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\t\treadOnly={true}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t</FormItem>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"newPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Optional\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"confirmNewPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Confirm New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<div className=\"flex justify-between w-full\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tvariant=\"submit\"\n\t\t\t\t\t\t\tdisabled={isUpdatePending || !isDirty || !isValid}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Save /> Update Profile\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</Form>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"profile-Ca4u59r1.js","names":[],"sources":["../../src/features/profile/mutations/updateUserMutation.ts","../../src/features/profile/mutations/updateUserSchema.ts","../../src/features/profile/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { SchemaUser } from '@/integrations/api/api.gen';\nimport { User } from '@/integrations/api/api.patch';\nimport { useMutation } from '@tanstack/react-query';\nimport z from 'zod';\n\nasync function onUpdateUser(formData: z.infer<typeof UpdateUserSchema>) {\n\tconst { id, newPassword, confirmNewPassword, ...otherFields } = formData;\n\tconst userData: Partial<SchemaUser & { password: string }> = {\n\t\t...otherFields,\n\t};\n\tif (newPassword && newPassword === confirmNewPassword) {\n\t\tuserData.password = newPassword;\n\t}\n\tconst { data } = await apiClient.patch(`/User/${id}` as '/User/{id}', userData);\n\treturn data as Partial<User>;\n}\n\nexport function useUpdateUserMutation() {\n\treturn useMutation({\n\t\tmutationFn: (formData: z.infer<typeof UpdateUserSchema>) => onUpdateUser(formData),\n\t});\n}\n","import { z } from 'zod';\n\nexport const UpdateUserSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfirstname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your first name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'First name is required.' })\n\t\t\t.max(50, { error: 'First name must be less than 50 characters.' }),\n\t\tlastname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your last name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'Last name is required.' })\n\t\t\t.max(50, { error: 'Last name must be less than 50 characters.' }),\n\t\tnewPassword: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your new password.',\n\t\t\t})\n\t\t\t.min(8, { error: 'Password must be 8 characters or more.' })\n\t\t\t.or(z.string().max(0)),\n\t\tconfirmNewPassword: z\n\t\t\t.string()\n\t\t\t.optional(),\n\t})\n\t.refine((data) => data.newPassword === data.confirmNewPassword, {\n\t\terror: 'Passwords do not match',\n\t\tpath: ['confirmNewPassword'],\n\t});\n","import { Button } from '@/components/ui/button';\nimport { Form } from '@/components/ui/form/Form';\nimport { FormControl } from '@/components/ui/form/FormControl';\nimport { FormField } from '@/components/ui/form/FormField';\nimport { FormItem } from '@/components/ui/form/FormItem';\nimport { FormLabel } from '@/components/ui/form/FormLabel';\nimport { FormMessage } from '@/components/ui/form/FormMessage';\nimport { Input } from '@/components/ui/input';\nimport { logoutOnSuccess } from '@/features/auth/handlers/logoutOnSuccess';\nimport { authStore, OverallAppSignIn } from '@/features/auth/store/authStore';\nimport { useUpdateUserMutation } from '@/features/profile/mutations/updateUserMutation';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { useCloudAuth } from '@/hooks/useAuth';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useNavigate, useRouter } from '@tanstack/react-router';\nimport { Save } from 'lucide-react';\nimport { useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\n\nexport function ProfileIndex() {\n\tconst router = useRouter();\n\tconst navigate = useNavigate();\n\tconst { user } = useCloudAuth();\n\n\tconst methods = useForm({\n\t\tresolver: zodResolver(UpdateUserSchema),\n\t\tdefaultValues: {\n\t\t\tconfirmNewPassword: '',\n\t\t\tfirstname: user?.firstname || '',\n\t\t\tid: user?.id || '',\n\t\t\tlastname: user?.lastname || '',\n\t\t\tnewPassword: '',\n\t\t},\n\t});\n\tconst { control, handleSubmit, reset, formState: { defaultValues, isDirty, isValid } } = methods;\n\tconst { mutate: updateUser, isPending: isUpdatePending } = useUpdateUserMutation();\n\n\tconst onSubmitClick = useCallback(\n\t\tasync (formData: z.infer<typeof UpdateUserSchema>) => {\n\t\t\tif (formData) {\n\t\t\t\tupdateUser(formData, {\n\t\t\t\t\tonSuccess: (data) => {\n\t\t\t\t\t\treset({\n\t\t\t\t\t\t\t...defaultValues,\n\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tauthStore.updateUserForEntity(OverallAppSignIn, data);\n\t\t\t\t\t\tif (formData.newPassword) {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!', {\n\t\t\t\t\t\t\t\tdescription: 'Please sign in with your new password.',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogoutOnSuccess();\n\t\t\t\t\t\t\tvoid navigate({ to: '/sign-in' });\n\t\t\t\t\t\t\tvoid router.invalidate();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!');\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[defaultValues, navigate, reset, router, updateUser],\n\t);\n\n\treturn (\n\t\t<div className=\"mt-20 px-4 pt-4 md:px-12 max-w-2xl\">\n\t\t\t<h1 className=\"text-2xl font-light\">Profile</h1>\n\t\t\t<Form {...methods}>\n\t\t\t\t<form\n\t\t\t\t\tid=\"profile-edit-form\"\n\t\t\t\t\tname=\"profile-edit-form\"\n\t\t\t\t\tonSubmit={handleSubmit(onSubmitClick)}\n\t\t\t\t\tclassName=\"grid gap-4 my-4\"\n\t\t\t\t>\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"firstname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">First Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"lastname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Last Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t<FormLabel htmlFor=\"profile-email\" className=\"pb-1\">Email</FormLabel>\n\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid=\"profile-email\"\n\t\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\t\tenterKeyHint=\"next\"\n\t\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\tvalue={user?.email || ''}\n\t\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\t\treadOnly={true}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t</FormItem>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"newPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Optional\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"confirmNewPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Confirm New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<div className=\"flex justify-between w-full\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tvariant=\"submit\"\n\t\t\t\t\t\t\tdisabled={isUpdatePending || !isDirty || !isValid}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Save /> Update Profile\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</Form>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{A as e}from"./vendor-tanstack-0SjDjtT0.js";import{t}from"./createLucideIcon-BDx8noBh.js";import{r as n}from"./pollUnlessForbidden-HHdQZW1N.js";import{at as r}from"./index-CyNVanoD.js";var i=t(`file`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]),a=t(`folder`,[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]);function o(...e){let t=e.flat(1);return t.map((e,n)=>typeof e==`string`?s(e,n!==0,n!==t.length-1):e).join(`/`)}function s(e,t=!0,n=!0){let r=t&&e[0]===`/`,i=n&&e[e.length-1]===`/`;return r&&i?e.slice(1,-1):r?e.slice(1):i?e.slice(0,-1):e}var c=`https://github.com/HarperFast/create-harper/tree/main`;function l(e){return{...e,npmPackage:`@harperfast/template-${e.name}-studio`,githubUrl:`${c}/template-${e.name}`}}var u=[l({name:`vanilla-ts`,framework:`vanilla`,title:`Vanilla + TypeScript`,description:`The same Web + REST ORM from the first template, but with TypeScript sprinkled in.`,tags:[`Vanilla`,`TypeScript`,`GraphQL`],typescript:!0,ssr:!1}),l({name:`vanilla`,framework:`vanilla`,title:`Vanilla JS`,description:`Define your entities in schema.graphql, add your HTML/CSS/JS in web, and you're cooking!`,tags:[`Vanilla`,`REST`,`GraphQL`,`ORM`],typescript:!1,ssr:!1}),l({name:`react-ts`,framework:`react`,title:`React + TypeScript`,description:`The same Vite-powered React app, with end-to-end type safety from TypeScript.`,tags:[`React`,`TypeScript`,`Vite`,`SPA`],typescript:!0,ssr:!1}),l({name:`react`,framework:`react`,title:`React`,description:`A Vite-powered React single-page app, wired up to Harper's REST + GraphQL APIs out of the box.`,tags:[`React`,`Vite`,`SPA`,`GraphQL`],typescript:!1,ssr:!1}),l({name:`react-ts-ssr`,framework:`react`,title:`React + TypeScript + SSR`,description:`Server-rendered React with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.`,tags:[`React`,`TypeScript`,`SSR`,`Vite`],typescript:!0,ssr:!0}),l({name:`react-ssr`,framework:`react`,title:`React + SSR`,description:`Server-rendered React with Vite for fast first paints, hydrating into a full SPA on Harper.`,tags:[`React`,`SSR`,`Vite`,`GraphQL`],typescript:!1,ssr:!0}),l({name:`vue-ts`,framework:`vue`,title:`Vue + TypeScript`,description:`The same Vite-powered Vue app, with end-to-end type safety from TypeScript.`,tags:[`Vue`,`TypeScript`,`Vite`,`SPA`],typescript:!0,ssr:!1}),l({name:`vue`,framework:`vue`,title:`Vue`,description:`A Vite-powered Vue single-page app, wired up to Harper's REST + GraphQL APIs out of the box.`,tags:[`Vue`,`Vite`,`SPA`,`GraphQL`],typescript:!1,ssr:!1}),l({name:`vue-ts-ssr`,framework:`vue`,title:`Vue + TypeScript + SSR`,description:`Server-rendered Vue with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.`,tags:[`Vue`,`TypeScript`,`SSR`,`Vite`],typescript:!0,ssr:!0}),l({name:`vue-ssr`,framework:`vue`,title:`Vue + SSR`,description:`Server-rendered Vue with Vite for fast first paints, hydrating into a full SPA on Harper.`,tags:[`Vue`,`SSR`,`Vite`,`GraphQL`],typescript:!1,ssr:!0})],d=u.map(e=>e.name),f=[`vanilla`,`react`,`vue`];function p(e){let t=f.indexOf(e);return t===-1?1/0:t}var m=[...u].sort((e,t)=>p(e.framework)-p(t.framework)||Number(e.ssr)-Number(t.ssr)||Number(e.typescript)-Number(t.typescript)).map(e=>({id:e.name,name:e.title,description:e.description,tags:[...e.tags],npm:e.npmPackage,githubUrl:e.githubUrl}));async function h({instanceClient:e,project:t,template:n,entityType:r}){let{data:i}=await e.post(`/`,{operation:`add_component`,project:t,template:n,replicated:r===`cluster`},{timeout:3e5});return i}function g(){return e({mutationFn:h})}function _(e,t,n){for(let r of e)if(r[t]===n)return r}async function v({file:e,project:t,entityType:n,instanceClient:r}){let{data:i}=await r.post(`/`,{operation:`drop_component`,file:e||void 0,project:t,replicated:n===`cluster`});return i}var y=`__root__`,b=`importedApplications`,x=`newApplication`;function S(e){let t={},i=[],a=[],o=[];for(let n of e)r(n)?n.package?a.push(n.path):i.push(n.path):o.push(n.path),C(t,n);return t[y]={index:y,isFolder:!0,children:[x,b,...i,...o].filter(n),data:void 0,canMove:!1,canRename:!1},t[b]={index:b,isFolder:!0,children:a,data:{name:`Imported Applications`,path:b,package:b,project:``,entries:[]},canMove:!1,canRename:!1},t[x]={index:x,isFolder:!1,data:{name:`New Application`,path:x,project:``},canMove:!1,canRename:!1},{items:t,rootId:y}}function C(e,t){let n=t.path;if(r(t)){let i=t,a=[],o=[];for(let e of i.entries)r(e)?a.push(e.path):o.push(e.path);e[n]={index:n,isFolder:!0,children:[...a,...o],data:t,canMove:!1,canRename:!1};for(let t of i.entries)C(e,t)}else e[n]={index:n,isFolder:!1,data:t,canMove:!t.package,canRename:!t.package}}function w(e,t,n,r=[]){let i=[];for(let a of e){let e=n(a,r);i.push(e);let o=a,s=o[t];s&&(e[t]=w(s,t,n,[...r,o]))}return i}function T(e){let t=new Set;return{rootEntries:w(e||[],`entries`,(e,n)=>{let i=r(e)&&e.entries.find(e=>e.name.toLowerCase()===`readme.md`),a=[...n.map(e=>e.name),e.name].join(`/`);return t.add(a),{name:e.name,path:a,project:(n[0]||e)?.name,package:(n[0]||e)?.package,overviewEntry:i&&!r(i)&&{name:i.name,path:[...n.map(e=>e.name),e.name,i.name].join(`/`),project:(n[0]||e)?.name,package:(n[0]||e)?.package}||void 0}}),pathsRegistry:t}}async function E({file:e,payload:t,project:n,entityType:r,instanceClient:i,encoding:a}){let{data:o}=await i.post(`/`,{operation:`set_component_file`,file:e,payload:t,project:n,encoding:a,replicated:r===`cluster`},{timeout:3e5});return o}function D(){return e({mutationFn:E})}export{b as a,v as c,g as d,m as f,i as g,a as h,S as i,_ as l,o as m,D as n,x as o,d as p,T as r,y as s,E as t,h as u};
2
- //# sourceMappingURL=setComponentFile-CYhJWz5K.js.map
1
+ import{A as e}from"./vendor-tanstack-0SjDjtT0.js";import{t}from"./createLucideIcon-BDx8noBh.js";import{r as n}from"./pollUnlessForbidden-HHdQZW1N.js";import{at as r}from"./index-DfGv-6tB.js";var i=t(`file`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]),a=t(`folder`,[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]);function o(...e){let t=e.flat(1);return t.map((e,n)=>typeof e==`string`?s(e,n!==0,n!==t.length-1):e).join(`/`)}function s(e,t=!0,n=!0){let r=t&&e[0]===`/`,i=n&&e[e.length-1]===`/`;return r&&i?e.slice(1,-1):r?e.slice(1):i?e.slice(0,-1):e}var c=`https://github.com/HarperFast/create-harper/tree/main`;function l(e){return{...e,npmPackage:`@harperfast/template-${e.name}-studio`,githubUrl:`${c}/template-${e.name}`}}var u=[l({name:`vanilla-ts`,framework:`vanilla`,title:`Vanilla + TypeScript`,description:`The same Web + REST ORM from the first template, but with TypeScript sprinkled in.`,tags:[`Vanilla`,`TypeScript`,`GraphQL`],typescript:!0,ssr:!1}),l({name:`vanilla`,framework:`vanilla`,title:`Vanilla JS`,description:`Define your entities in schema.graphql, add your HTML/CSS/JS in web, and you're cooking!`,tags:[`Vanilla`,`REST`,`GraphQL`,`ORM`],typescript:!1,ssr:!1}),l({name:`react-ts`,framework:`react`,title:`React + TypeScript`,description:`The same Vite-powered React app, with end-to-end type safety from TypeScript.`,tags:[`React`,`TypeScript`,`Vite`,`SPA`],typescript:!0,ssr:!1}),l({name:`react`,framework:`react`,title:`React`,description:`A Vite-powered React single-page app, wired up to Harper's REST + GraphQL APIs out of the box.`,tags:[`React`,`Vite`,`SPA`,`GraphQL`],typescript:!1,ssr:!1}),l({name:`react-ts-ssr`,framework:`react`,title:`React + TypeScript + SSR`,description:`Server-rendered React with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.`,tags:[`React`,`TypeScript`,`SSR`,`Vite`],typescript:!0,ssr:!0}),l({name:`react-ssr`,framework:`react`,title:`React + SSR`,description:`Server-rendered React with Vite for fast first paints, hydrating into a full SPA on Harper.`,tags:[`React`,`SSR`,`Vite`,`GraphQL`],typescript:!1,ssr:!0}),l({name:`vue-ts`,framework:`vue`,title:`Vue + TypeScript`,description:`The same Vite-powered Vue app, with end-to-end type safety from TypeScript.`,tags:[`Vue`,`TypeScript`,`Vite`,`SPA`],typescript:!0,ssr:!1}),l({name:`vue`,framework:`vue`,title:`Vue`,description:`A Vite-powered Vue single-page app, wired up to Harper's REST + GraphQL APIs out of the box.`,tags:[`Vue`,`Vite`,`SPA`,`GraphQL`],typescript:!1,ssr:!1}),l({name:`vue-ts-ssr`,framework:`vue`,title:`Vue + TypeScript + SSR`,description:`Server-rendered Vue with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.`,tags:[`Vue`,`TypeScript`,`SSR`,`Vite`],typescript:!0,ssr:!0}),l({name:`vue-ssr`,framework:`vue`,title:`Vue + SSR`,description:`Server-rendered Vue with Vite for fast first paints, hydrating into a full SPA on Harper.`,tags:[`Vue`,`SSR`,`Vite`,`GraphQL`],typescript:!1,ssr:!0})],d=u.map(e=>e.name),f=[`vanilla`,`react`,`vue`];function p(e){let t=f.indexOf(e);return t===-1?1/0:t}var m=[...u].sort((e,t)=>p(e.framework)-p(t.framework)||Number(e.ssr)-Number(t.ssr)||Number(e.typescript)-Number(t.typescript)).map(e=>({id:e.name,name:e.title,description:e.description,tags:[...e.tags],npm:e.npmPackage,githubUrl:e.githubUrl}));async function h({instanceClient:e,project:t,template:n,entityType:r}){let{data:i}=await e.post(`/`,{operation:`add_component`,project:t,template:n,replicated:r===`cluster`},{timeout:3e5});return i}function g(){return e({mutationFn:h})}function _(e,t,n){for(let r of e)if(r[t]===n)return r}async function v({file:e,project:t,entityType:n,instanceClient:r}){let{data:i}=await r.post(`/`,{operation:`drop_component`,file:e||void 0,project:t,replicated:n===`cluster`});return i}var y=`__root__`,b=`importedApplications`,x=`newApplication`;function S(e){let t={},i=[],a=[],o=[];for(let n of e)r(n)?n.package?a.push(n.path):i.push(n.path):o.push(n.path),C(t,n);return t[y]={index:y,isFolder:!0,children:[x,b,...i,...o].filter(n),data:void 0,canMove:!1,canRename:!1},t[b]={index:b,isFolder:!0,children:a,data:{name:`Imported Applications`,path:b,package:b,project:``,entries:[]},canMove:!1,canRename:!1},t[x]={index:x,isFolder:!1,data:{name:`New Application`,path:x,project:``},canMove:!1,canRename:!1},{items:t,rootId:y}}function C(e,t){let n=t.path;if(r(t)){let i=t,a=[],o=[];for(let e of i.entries)r(e)?a.push(e.path):o.push(e.path);e[n]={index:n,isFolder:!0,children:[...a,...o],data:t,canMove:!1,canRename:!1};for(let t of i.entries)C(e,t)}else e[n]={index:n,isFolder:!1,data:t,canMove:!t.package,canRename:!t.package}}function w(e,t,n,r=[]){let i=[];for(let a of e){let e=n(a,r);i.push(e);let o=a,s=o[t];s&&(e[t]=w(s,t,n,[...r,o]))}return i}function T(e){let t=new Set;return{rootEntries:w(e||[],`entries`,(e,n)=>{let i=r(e)&&e.entries.find(e=>e.name.toLowerCase()===`readme.md`),a=[...n.map(e=>e.name),e.name].join(`/`);return t.add(a),{name:e.name,path:a,project:(n[0]||e)?.name,package:(n[0]||e)?.package,overviewEntry:i&&!r(i)&&{name:i.name,path:[...n.map(e=>e.name),e.name,i.name].join(`/`),project:(n[0]||e)?.name,package:(n[0]||e)?.package}||void 0}}),pathsRegistry:t}}async function E({file:e,payload:t,project:n,entityType:r,instanceClient:i,encoding:a}){let{data:o}=await i.post(`/`,{operation:`set_component_file`,file:e,payload:t,project:n,encoding:a,replicated:r===`cluster`},{timeout:3e5});return o}function D(){return e({mutationFn:E})}export{b as a,v as c,g as d,m as f,i as g,a as h,S as i,_ as l,o as m,D as n,x as o,d as p,T as r,y as s,E as t,h as u};
2
+ //# sourceMappingURL=setComponentFile-stXkgaau.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setComponentFile-CYhJWz5K.js","names":["__iconNode","templates"],"sources":["../../node_modules/.pnpm/lucide-react@1.26.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/file.mjs","../../node_modules/.pnpm/lucide-react@1.26.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/folder.mjs","../../src/lib/string/paths/joinPath.ts","../../node_modules/.pnpm/create-harper@1.10.12/node_modules/create-harper/lib/constants/templates.js","../../src/features/instance/applications/components/NewApplication/templates.ts","../../src/integrations/api/instance/applications/addComponent.ts","../../src/lib/arrays/findBy.ts","../../src/integrations/api/instance/applications/dropComponent.ts","../../src/features/instance/applications/components/ApplicationsSidebar/specialItems.ts","../../src/features/instance/applications/components/ApplicationsSidebar/buildItems.tsx","../../src/lib/arrays/transformNodes.ts","../../src/features/instance/applications/components/ApplicationsSidebar/calculateRootEntries.ts","../../src/integrations/api/instance/applications/setComponentFile.ts"],"sourcesContent":["/**\n * @license lucide-react v1.26.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M14 2v5a1 1 0 0 0 1 1h5\", key: \"wfsgrz\" }]\n];\nconst File = createLucideIcon(\"file\", __iconNode);\n\nexport { __iconNode, File as default };\n//# sourceMappingURL=file.mjs.map\n","/**\n * @license lucide-react v1.26.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\",\n key: \"1kt360\"\n }\n ]\n];\nconst Folder = createLucideIcon(\"folder\", __iconNode);\n\nexport { __iconNode, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","export function joinPath(...parts: (string | string[])[]): string {\n\tconst flattened = parts.flat(1);\n\treturn flattened\n\t\t.map((p, i) =>\n\t\t\ttypeof p !== 'string'\n\t\t\t\t? p\n\t\t\t\t: trimSlashes(p, i !== 0, i !== flattened.length - 1)\n\t\t)\n\t\t.join('/');\n}\n\nfunction trimSlashes(str: string, start: boolean = true, end: boolean = true) {\n\tconst trimStart = start && str[0] === '/';\n\tconst trimEnd = end && str[str.length - 1] === '/';\n\tif (trimStart && trimEnd) {\n\t\treturn str.slice(1, -1);\n\t}\n\tif (trimStart) {\n\t\treturn str.slice(1);\n\t}\n\tif (trimEnd) {\n\t\treturn str.slice(0, -1);\n\t}\n\treturn str;\n}\n","const CREATE_HARPER_TREE = 'https://github.com/HarperFast/create-harper/tree/main';\n\n/**\n * @typedef {'vanilla' | 'react' | 'vue'} Framework\n */\n\n/**\n * @typedef {Object} TemplateInfo\n * @property {string} name - The canonical template name (e.g. 'vanilla', 'react-ts'). Used to scaffold.\n * @property {Framework} framework - The framework family this template belongs to.\n * @property {string} title - A human-friendly display title.\n * @property {string} description - A short description of the template.\n * @property {string[]} tags - Tags describing the template's stack.\n * @property {boolean} typescript - Whether the template uses TypeScript.\n * @property {boolean} ssr - Whether the template is server-side rendered.\n * @property {string} npmPackage - The published Studio template package for this template.\n * @property {string} githubUrl - A link to the template's source on GitHub.\n */\n\n/**\n * Build a {@link TemplateInfo} entry, deriving the npm package and GitHub URL from the template name.\n *\n * @param {Omit<TemplateInfo, 'npmPackage' | 'githubUrl'>} info\n * @returns {TemplateInfo}\n */\nfunction template(info) {\n\treturn {\n\t\t...info,\n\t\tnpmPackage: `@harperfast/template-${info.name}-studio`,\n\t\tgithubUrl: `${CREATE_HARPER_TREE}/template-${info.name}`,\n\t};\n}\n\n/**\n * The catalog of every template create-harper can scaffold. This is the single source of truth from\n * which {@link templateNames} (the flat name list) and\n * {@link import('./frameworks.js').frameworks} (the interactive picker) are derived.\n *\n * Order is significant: it determines the order of the flat name list and the CLI picker.\n *\n * @type {TemplateInfo[]}\n */\nexport const templates = [\n\ttemplate({\n\t\tname: 'vanilla-ts',\n\t\tframework: 'vanilla',\n\t\ttitle: 'Vanilla + TypeScript',\n\t\tdescription: 'The same Web + REST ORM from the first template, but with TypeScript sprinkled in.',\n\t\ttags: ['Vanilla', 'TypeScript', 'GraphQL'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vanilla',\n\t\tframework: 'vanilla',\n\t\ttitle: 'Vanilla JS',\n\t\tdescription: \"Define your entities in schema.graphql, add your HTML/CSS/JS in web, and you're cooking!\",\n\t\ttags: ['Vanilla', 'REST', 'GraphQL', 'ORM'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react-ts',\n\t\tframework: 'react',\n\t\ttitle: 'React + TypeScript',\n\t\tdescription: 'The same Vite-powered React app, with end-to-end type safety from TypeScript.',\n\t\ttags: ['React', 'TypeScript', 'Vite', 'SPA'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react',\n\t\tframework: 'react',\n\t\ttitle: 'React',\n\t\tdescription: \"A Vite-powered React single-page app, wired up to Harper's REST + GraphQL APIs out of the box.\",\n\t\ttags: ['React', 'Vite', 'SPA', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react-ts-ssr',\n\t\tframework: 'react',\n\t\ttitle: 'React + TypeScript + SSR',\n\t\tdescription: 'Server-rendered React with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.',\n\t\ttags: ['React', 'TypeScript', 'SSR', 'Vite'],\n\t\ttypescript: true,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'react-ssr',\n\t\tframework: 'react',\n\t\ttitle: 'React + SSR',\n\t\tdescription: 'Server-rendered React with Vite for fast first paints, hydrating into a full SPA on Harper.',\n\t\ttags: ['React', 'SSR', 'Vite', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ts',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + TypeScript',\n\t\tdescription: 'The same Vite-powered Vue app, with end-to-end type safety from TypeScript.',\n\t\ttags: ['Vue', 'TypeScript', 'Vite', 'SPA'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vue',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue',\n\t\tdescription: \"A Vite-powered Vue single-page app, wired up to Harper's REST + GraphQL APIs out of the box.\",\n\t\ttags: ['Vue', 'Vite', 'SPA', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ts-ssr',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + TypeScript + SSR',\n\t\tdescription: 'Server-rendered Vue with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.',\n\t\ttags: ['Vue', 'TypeScript', 'SSR', 'Vite'],\n\t\ttypescript: true,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ssr',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + SSR',\n\t\tdescription: 'Server-rendered Vue with Vite for fast first paints, hydrating into a full SPA on Harper.',\n\t\ttags: ['Vue', 'SSR', 'Vite', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: true,\n\t}),\n];\n\n/**\n * The flat list of every template name, in catalog order. This is the canonical, dependency-free list\n * other tools can import to validate or enumerate templates.\n *\n * @type {string[]}\n */\nexport const templateNames = templates.map((t) => t.name);\n","import { templates as catalog } from 'create-harper/templates';\n\n// create-harper is the single source of truth for the template list, descriptions, npm packages, and\n// GitHub links. New templates added there flow through here (and into the createApp agent tool)\n// automatically. create-harper lists TypeScript-first; we re-sort to Studio's established display order\n// (by framework, then non-SSR before SSR, then JavaScript before TypeScript) so the picker and its\n// default selection stay stable.\nconst FRAMEWORK_ORDER = ['vanilla', 'react', 'vue'] as const;\n\n// Rank a framework by its position in FRAMEWORK_ORDER. Any framework not listed (e.g. a future\n// Svelte/Angular template added to create-harper) sorts to the end rather than the top.\nfunction frameworkRank(framework: string): number {\n\tconst index = (FRAMEWORK_ORDER as readonly string[]).indexOf(framework);\n\treturn index === -1 ? Infinity : index;\n}\n\nexport const templates = [...catalog]\n\t.sort((a, b) =>\n\t\tframeworkRank(a.framework) - frameworkRank(b.framework)\n\t\t|| Number(a.ssr) - Number(b.ssr)\n\t\t|| Number(a.typescript) - Number(b.typescript)\n\t)\n\t.map((t) => ({\n\t\t// Widen to `string`: the New Application form supplies the selected id as a plain string.\n\t\tid: t.name as string,\n\t\tname: t.title,\n\t\tdescription: t.description,\n\t\ttags: [...t.tags],\n\t\tnpm: t.npmPackage,\n\t\tgithubUrl: t.githubUrl,\n\t}));\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { ReplicatedResponse } from '@/integrations/api/replication';\nimport { useMutation } from '@tanstack/react-query';\n\nexport interface CreateComponentFormData {\n\tproject: string;\n\ttemplate: string;\n}\n\nexport async function addComponent({\n\tinstanceClient,\n\tproject,\n\ttemplate,\n\tentityType,\n}: CreateComponentFormData & InstanceClientConfig & InstanceTypeConfig): Promise<ReplicatedResponse> {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'add_component',\n\t\tproject,\n\t\ttemplate,\n\t\treplicated: entityType === 'cluster',\n\t}, { timeout: 300_000 });\n\treturn data;\n}\n\nexport function useAddComponentMutation() {\n\treturn useMutation({\n\t\tmutationFn: addComponent,\n\t});\n}\n","export function findBy<T, F extends keyof T>(array: T[], fieldName: F, value: T[F]): T | undefined {\n\tfor (const element of array) {\n\t\tif (element[fieldName] === value) {\n\t\t\treturn element;\n\t\t}\n\t}\n\treturn undefined;\n}\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { ReplicatedResponse } from '@/integrations/api/replication';\nimport { useMutation } from '@tanstack/react-query';\n\ninterface DropComponentRequest extends InstanceClientConfig, InstanceTypeConfig {\n\tproject: string;\n\tfile: string | undefined;\n}\n\nexport async function dropComponent({\n\tfile,\n\tproject,\n\tentityType,\n\tinstanceClient,\n}: DropComponentRequest): Promise<ReplicatedResponse> {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'drop_component',\n\t\tfile: file || undefined,\n\t\tproject,\n\t\treplicated: entityType === 'cluster',\n\t});\n\treturn data;\n}\n\nexport function useDropComponent() {\n\treturn useMutation({\n\t\tmutationFn: dropComponent,\n\t});\n}\n","export const rootId = '__root__';\nexport const importedApplications = 'importedApplications';\nexport const newApplication = 'newApplication';\n","import type { DirectoryEntry } from '@/features/instance/applications/context/directoryEntry';\nimport type { FileEntry } from '@/features/instance/applications/context/fileEntry';\nimport { isDirectory } from '@/features/instance/applications/context/isDirectory';\nimport { excludeFalsy } from '@/lib/arrays/excludeFalsy';\nimport type { TreeItem } from 'react-complex-tree';\nimport { importedApplications, newApplication, rootId } from './specialItems';\n\nexport function buildItems(rootEntries: Array<DirectoryEntry | FileEntry>): {\n\titems: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>>;\n\trootId: string;\n} {\n\tconst items: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>> = {};\n\n\tconst directoryIds: string[] = [];\n\tconst applicationIds: string[] = [];\n\tconst fileIds: string[] = [];\n\tfor (const entry of rootEntries) {\n\t\tif (isDirectory(entry)) {\n\t\t\tif (entry.package) {\n\t\t\t\tapplicationIds.push(entry.path);\n\t\t\t} else {\n\t\t\t\tdirectoryIds.push(entry.path);\n\t\t\t}\n\t\t} else {\n\t\t\tfileIds.push(entry.path);\n\t\t}\n\t\taddEntry(items, entry);\n\t}\n\n\titems[rootId] = {\n\t\tindex: rootId,\n\t\tisFolder: true,\n\t\tchildren: [\n\t\t\tnewApplication,\n\t\t\timportedApplications,\n\t\t\t...directoryIds,\n\t\t\t...fileIds,\n\t\t].filter(\n\t\t\texcludeFalsy,\n\t\t),\n\t\tdata: undefined,\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<undefined>;\n\n\titems[importedApplications] = {\n\t\tindex: importedApplications,\n\t\tisFolder: true,\n\t\tchildren: applicationIds,\n\t\tdata: {\n\t\t\tname: 'Imported Applications',\n\t\t\tpath: importedApplications,\n\t\t\tpackage: importedApplications,\n\t\t\tproject: '',\n\t\t\tentries: [],\n\t\t},\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<DirectoryEntry>;\n\n\titems[newApplication] = {\n\t\tindex: newApplication,\n\t\tisFolder: false,\n\t\tdata: {\n\t\t\tname: 'New Application',\n\t\t\tpath: newApplication,\n\t\t\tproject: '',\n\t\t},\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<FileEntry>;\n\n\treturn { items, rootId };\n}\n\nfunction addEntry(\n\titems: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>>,\n\tentry: DirectoryEntry | FileEntry,\n) {\n\tconst index = entry.path;\n\tif (isDirectory(entry)) {\n\t\tconst dir = entry as DirectoryEntry;\n\t\tconst childDirectoryIds: string[] = [];\n\t\tconst childFileIds: string[] = [];\n\t\tfor (const childEntry of dir.entries) {\n\t\t\tif (isDirectory(childEntry)) {\n\t\t\t\tchildDirectoryIds.push(childEntry.path);\n\t\t\t} else {\n\t\t\t\tchildFileIds.push(childEntry.path);\n\t\t\t}\n\t\t}\n\t\titems[index] = {\n\t\t\tindex,\n\t\t\tisFolder: true,\n\t\t\tchildren: [...childDirectoryIds, ...childFileIds],\n\t\t\tdata: entry,\n\t\t\tcanMove: false,\n\t\t\tcanRename: false,\n\t\t} satisfies TreeItem<DirectoryEntry>;\n\t\tfor (const child of dir.entries) {\n\t\t\taddEntry(items, child);\n\t\t}\n\t} else {\n\t\titems[index] = {\n\t\t\tindex,\n\t\t\tisFolder: false,\n\t\t\tdata: entry,\n\t\t\tcanMove: !entry.package,\n\t\t\tcanRename: !entry.package,\n\t\t} satisfies TreeItem<FileEntry>;\n\t}\n}\n","export function transformNodes<Transformed, Branch, Leaf>(\n\tnodes: Array<Branch | Leaf>,\n\tnestedPropertyName: keyof Branch,\n\ttransformer: (node: Branch | Leaf, parents: Branch[]) => Transformed,\n\tparents: Branch[] = [],\n): Transformed[] {\n\tconst results: Transformed[] = [];\n\n\tfor (const node of nodes) {\n\t\tconst transformed = transformer(node, parents);\n\t\tresults.push(transformed);\n\t\tconst potentialBranch = node as Branch;\n\t\tconst nestedNodes = potentialBranch[nestedPropertyName] as Array<Branch | Leaf>;\n\t\tif (nestedNodes) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t(transformed as any)[nestedPropertyName] = transformNodes(nestedNodes, nestedPropertyName, transformer, [\n\t\t\t\t...parents,\n\t\t\t\tpotentialBranch,\n\t\t\t]);\n\t\t}\n\t}\n\n\treturn results;\n}\n","import { DirectoryEntry } from '@/features/instance/applications/context/directoryEntry';\nimport { FileEntry } from '@/features/instance/applications/context/fileEntry';\nimport { isDirectory } from '@/features/instance/applications/context/isDirectory';\nimport { APIDirectoryEntry, APIFileEntry } from '@/integrations/api/instance/applications/getComponents';\nimport { transformNodes } from '@/lib/arrays/transformNodes';\n\nexport function calculateRootEntries(entries: Array<APIDirectoryEntry | APIFileEntry>): {\n\trootEntries: Array<DirectoryEntry | FileEntry>;\n\tpathsRegistry: Set<string>;\n} {\n\tconst pathsRegistry = new Set<string>();\n\tconst rootEntries = transformNodes(\n\t\tentries || [],\n\t\t'entries',\n\t\t(node: APIFileEntry | APIDirectoryEntry, parents: APIDirectoryEntry[]) => {\n\t\t\tconst readMeAPIFile = isDirectory(node) && node.entries.find(e => e.name.toLowerCase() === 'readme.md');\n\t\t\tconst path = [...parents.map(p => p.name), node.name].join('/');\n\t\t\tpathsRegistry.add(path);\n\t\t\treturn {\n\t\t\t\tname: node.name,\n\t\t\t\tpath,\n\t\t\t\tproject: (parents[0] || node)?.name,\n\t\t\t\tpackage: (parents[0] || node)?.package,\n\t\t\t\toverviewEntry: readMeAPIFile && !isDirectory(readMeAPIFile) && {\n\t\t\t\t\t\t\tname: readMeAPIFile.name,\n\t\t\t\t\t\t\tpath: [...parents.map(p => p.name), node.name, readMeAPIFile.name].join('/'),\n\t\t\t\t\t\t\tproject: (parents[0] || node)?.name,\n\t\t\t\t\t\t\tpackage: (parents[0] || node)?.package,\n\t\t\t\t\t\t} || undefined,\n\t\t\t} satisfies DirectoryEntry | FileEntry;\n\t\t},\n\t);\n\treturn {\n\t\trootEntries,\n\t\tpathsRegistry,\n\t};\n}\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { useMutation } from '@tanstack/react-query';\n\nexport interface SetComponentFileRequest extends InstanceClientConfig, InstanceTypeConfig {\n\tfile: string;\n\tpayload?: string;\n\tproject: string;\n\tencoding?: 'utf8' | 'ASCII' | 'binary' | 'hex' | 'base64' | 'utf16le' | 'latin1' | 'ucs2';\n}\n\nexport async function setComponentFile({\n\tfile,\n\tpayload,\n\tproject,\n\tentityType,\n\tinstanceClient,\n\tencoding,\n}: SetComponentFileRequest) {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'set_component_file',\n\t\tfile,\n\t\tpayload,\n\t\tproject,\n\t\tencoding,\n\t\treplicated: entityType === 'cluster',\n\t}, { timeout: 300_000 });\n\treturn data;\n}\n\nexport function useSetComponentFile() {\n\treturn useMutation({\n\t\tmutationFn: setComponentFile,\n\t});\n}\n"],"x_google_ignoreList":[0,1,3],"mappings":"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"}
1
+ {"version":3,"file":"setComponentFile-stXkgaau.js","names":["__iconNode","templates"],"sources":["../../node_modules/.pnpm/lucide-react@1.26.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/file.mjs","../../node_modules/.pnpm/lucide-react@1.26.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/folder.mjs","../../src/lib/string/paths/joinPath.ts","../../node_modules/.pnpm/create-harper@1.10.12/node_modules/create-harper/lib/constants/templates.js","../../src/features/instance/applications/components/NewApplication/templates.ts","../../src/integrations/api/instance/applications/addComponent.ts","../../src/lib/arrays/findBy.ts","../../src/integrations/api/instance/applications/dropComponent.ts","../../src/features/instance/applications/components/ApplicationsSidebar/specialItems.ts","../../src/features/instance/applications/components/ApplicationsSidebar/buildItems.tsx","../../src/lib/arrays/transformNodes.ts","../../src/features/instance/applications/components/ApplicationsSidebar/calculateRootEntries.ts","../../src/integrations/api/instance/applications/setComponentFile.ts"],"sourcesContent":["/**\n * @license lucide-react v1.26.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M14 2v5a1 1 0 0 0 1 1h5\", key: \"wfsgrz\" }]\n];\nconst File = createLucideIcon(\"file\", __iconNode);\n\nexport { __iconNode, File as default };\n//# sourceMappingURL=file.mjs.map\n","/**\n * @license lucide-react v1.26.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\",\n key: \"1kt360\"\n }\n ]\n];\nconst Folder = createLucideIcon(\"folder\", __iconNode);\n\nexport { __iconNode, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","export function joinPath(...parts: (string | string[])[]): string {\n\tconst flattened = parts.flat(1);\n\treturn flattened\n\t\t.map((p, i) =>\n\t\t\ttypeof p !== 'string'\n\t\t\t\t? p\n\t\t\t\t: trimSlashes(p, i !== 0, i !== flattened.length - 1)\n\t\t)\n\t\t.join('/');\n}\n\nfunction trimSlashes(str: string, start: boolean = true, end: boolean = true) {\n\tconst trimStart = start && str[0] === '/';\n\tconst trimEnd = end && str[str.length - 1] === '/';\n\tif (trimStart && trimEnd) {\n\t\treturn str.slice(1, -1);\n\t}\n\tif (trimStart) {\n\t\treturn str.slice(1);\n\t}\n\tif (trimEnd) {\n\t\treturn str.slice(0, -1);\n\t}\n\treturn str;\n}\n","const CREATE_HARPER_TREE = 'https://github.com/HarperFast/create-harper/tree/main';\n\n/**\n * @typedef {'vanilla' | 'react' | 'vue'} Framework\n */\n\n/**\n * @typedef {Object} TemplateInfo\n * @property {string} name - The canonical template name (e.g. 'vanilla', 'react-ts'). Used to scaffold.\n * @property {Framework} framework - The framework family this template belongs to.\n * @property {string} title - A human-friendly display title.\n * @property {string} description - A short description of the template.\n * @property {string[]} tags - Tags describing the template's stack.\n * @property {boolean} typescript - Whether the template uses TypeScript.\n * @property {boolean} ssr - Whether the template is server-side rendered.\n * @property {string} npmPackage - The published Studio template package for this template.\n * @property {string} githubUrl - A link to the template's source on GitHub.\n */\n\n/**\n * Build a {@link TemplateInfo} entry, deriving the npm package and GitHub URL from the template name.\n *\n * @param {Omit<TemplateInfo, 'npmPackage' | 'githubUrl'>} info\n * @returns {TemplateInfo}\n */\nfunction template(info) {\n\treturn {\n\t\t...info,\n\t\tnpmPackage: `@harperfast/template-${info.name}-studio`,\n\t\tgithubUrl: `${CREATE_HARPER_TREE}/template-${info.name}`,\n\t};\n}\n\n/**\n * The catalog of every template create-harper can scaffold. This is the single source of truth from\n * which {@link templateNames} (the flat name list) and\n * {@link import('./frameworks.js').frameworks} (the interactive picker) are derived.\n *\n * Order is significant: it determines the order of the flat name list and the CLI picker.\n *\n * @type {TemplateInfo[]}\n */\nexport const templates = [\n\ttemplate({\n\t\tname: 'vanilla-ts',\n\t\tframework: 'vanilla',\n\t\ttitle: 'Vanilla + TypeScript',\n\t\tdescription: 'The same Web + REST ORM from the first template, but with TypeScript sprinkled in.',\n\t\ttags: ['Vanilla', 'TypeScript', 'GraphQL'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vanilla',\n\t\tframework: 'vanilla',\n\t\ttitle: 'Vanilla JS',\n\t\tdescription: \"Define your entities in schema.graphql, add your HTML/CSS/JS in web, and you're cooking!\",\n\t\ttags: ['Vanilla', 'REST', 'GraphQL', 'ORM'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react-ts',\n\t\tframework: 'react',\n\t\ttitle: 'React + TypeScript',\n\t\tdescription: 'The same Vite-powered React app, with end-to-end type safety from TypeScript.',\n\t\ttags: ['React', 'TypeScript', 'Vite', 'SPA'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react',\n\t\tframework: 'react',\n\t\ttitle: 'React',\n\t\tdescription: \"A Vite-powered React single-page app, wired up to Harper's REST + GraphQL APIs out of the box.\",\n\t\ttags: ['React', 'Vite', 'SPA', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'react-ts-ssr',\n\t\tframework: 'react',\n\t\ttitle: 'React + TypeScript + SSR',\n\t\tdescription: 'Server-rendered React with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.',\n\t\ttags: ['React', 'TypeScript', 'SSR', 'Vite'],\n\t\ttypescript: true,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'react-ssr',\n\t\tframework: 'react',\n\t\ttitle: 'React + SSR',\n\t\tdescription: 'Server-rendered React with Vite for fast first paints, hydrating into a full SPA on Harper.',\n\t\ttags: ['React', 'SSR', 'Vite', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ts',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + TypeScript',\n\t\tdescription: 'The same Vite-powered Vue app, with end-to-end type safety from TypeScript.',\n\t\ttags: ['Vue', 'TypeScript', 'Vite', 'SPA'],\n\t\ttypescript: true,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vue',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue',\n\t\tdescription: \"A Vite-powered Vue single-page app, wired up to Harper's REST + GraphQL APIs out of the box.\",\n\t\ttags: ['Vue', 'Vite', 'SPA', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: false,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ts-ssr',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + TypeScript + SSR',\n\t\tdescription: 'Server-rendered Vue with Vite and TypeScript for type-safe, SEO-friendly pages on Harper.',\n\t\ttags: ['Vue', 'TypeScript', 'SSR', 'Vite'],\n\t\ttypescript: true,\n\t\tssr: true,\n\t}),\n\ttemplate({\n\t\tname: 'vue-ssr',\n\t\tframework: 'vue',\n\t\ttitle: 'Vue + SSR',\n\t\tdescription: 'Server-rendered Vue with Vite for fast first paints, hydrating into a full SPA on Harper.',\n\t\ttags: ['Vue', 'SSR', 'Vite', 'GraphQL'],\n\t\ttypescript: false,\n\t\tssr: true,\n\t}),\n];\n\n/**\n * The flat list of every template name, in catalog order. This is the canonical, dependency-free list\n * other tools can import to validate or enumerate templates.\n *\n * @type {string[]}\n */\nexport const templateNames = templates.map((t) => t.name);\n","import { templates as catalog } from 'create-harper/templates';\n\n// create-harper is the single source of truth for the template list, descriptions, npm packages, and\n// GitHub links. New templates added there flow through here (and into the createApp agent tool)\n// automatically. create-harper lists TypeScript-first; we re-sort to Studio's established display order\n// (by framework, then non-SSR before SSR, then JavaScript before TypeScript) so the picker and its\n// default selection stay stable.\nconst FRAMEWORK_ORDER = ['vanilla', 'react', 'vue'] as const;\n\n// Rank a framework by its position in FRAMEWORK_ORDER. Any framework not listed (e.g. a future\n// Svelte/Angular template added to create-harper) sorts to the end rather than the top.\nfunction frameworkRank(framework: string): number {\n\tconst index = (FRAMEWORK_ORDER as readonly string[]).indexOf(framework);\n\treturn index === -1 ? Infinity : index;\n}\n\nexport const templates = [...catalog]\n\t.sort((a, b) =>\n\t\tframeworkRank(a.framework) - frameworkRank(b.framework)\n\t\t|| Number(a.ssr) - Number(b.ssr)\n\t\t|| Number(a.typescript) - Number(b.typescript)\n\t)\n\t.map((t) => ({\n\t\t// Widen to `string`: the New Application form supplies the selected id as a plain string.\n\t\tid: t.name as string,\n\t\tname: t.title,\n\t\tdescription: t.description,\n\t\ttags: [...t.tags],\n\t\tnpm: t.npmPackage,\n\t\tgithubUrl: t.githubUrl,\n\t}));\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { ReplicatedResponse } from '@/integrations/api/replication';\nimport { useMutation } from '@tanstack/react-query';\n\nexport interface CreateComponentFormData {\n\tproject: string;\n\ttemplate: string;\n}\n\nexport async function addComponent({\n\tinstanceClient,\n\tproject,\n\ttemplate,\n\tentityType,\n}: CreateComponentFormData & InstanceClientConfig & InstanceTypeConfig): Promise<ReplicatedResponse> {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'add_component',\n\t\tproject,\n\t\ttemplate,\n\t\treplicated: entityType === 'cluster',\n\t}, { timeout: 300_000 });\n\treturn data;\n}\n\nexport function useAddComponentMutation() {\n\treturn useMutation({\n\t\tmutationFn: addComponent,\n\t});\n}\n","export function findBy<T, F extends keyof T>(array: T[], fieldName: F, value: T[F]): T | undefined {\n\tfor (const element of array) {\n\t\tif (element[fieldName] === value) {\n\t\t\treturn element;\n\t\t}\n\t}\n\treturn undefined;\n}\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { ReplicatedResponse } from '@/integrations/api/replication';\nimport { useMutation } from '@tanstack/react-query';\n\ninterface DropComponentRequest extends InstanceClientConfig, InstanceTypeConfig {\n\tproject: string;\n\tfile: string | undefined;\n}\n\nexport async function dropComponent({\n\tfile,\n\tproject,\n\tentityType,\n\tinstanceClient,\n}: DropComponentRequest): Promise<ReplicatedResponse> {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'drop_component',\n\t\tfile: file || undefined,\n\t\tproject,\n\t\treplicated: entityType === 'cluster',\n\t});\n\treturn data;\n}\n\nexport function useDropComponent() {\n\treturn useMutation({\n\t\tmutationFn: dropComponent,\n\t});\n}\n","export const rootId = '__root__';\nexport const importedApplications = 'importedApplications';\nexport const newApplication = 'newApplication';\n","import type { DirectoryEntry } from '@/features/instance/applications/context/directoryEntry';\nimport type { FileEntry } from '@/features/instance/applications/context/fileEntry';\nimport { isDirectory } from '@/features/instance/applications/context/isDirectory';\nimport { excludeFalsy } from '@/lib/arrays/excludeFalsy';\nimport type { TreeItem } from 'react-complex-tree';\nimport { importedApplications, newApplication, rootId } from './specialItems';\n\nexport function buildItems(rootEntries: Array<DirectoryEntry | FileEntry>): {\n\titems: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>>;\n\trootId: string;\n} {\n\tconst items: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>> = {};\n\n\tconst directoryIds: string[] = [];\n\tconst applicationIds: string[] = [];\n\tconst fileIds: string[] = [];\n\tfor (const entry of rootEntries) {\n\t\tif (isDirectory(entry)) {\n\t\t\tif (entry.package) {\n\t\t\t\tapplicationIds.push(entry.path);\n\t\t\t} else {\n\t\t\t\tdirectoryIds.push(entry.path);\n\t\t\t}\n\t\t} else {\n\t\t\tfileIds.push(entry.path);\n\t\t}\n\t\taddEntry(items, entry);\n\t}\n\n\titems[rootId] = {\n\t\tindex: rootId,\n\t\tisFolder: true,\n\t\tchildren: [\n\t\t\tnewApplication,\n\t\t\timportedApplications,\n\t\t\t...directoryIds,\n\t\t\t...fileIds,\n\t\t].filter(\n\t\t\texcludeFalsy,\n\t\t),\n\t\tdata: undefined,\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<undefined>;\n\n\titems[importedApplications] = {\n\t\tindex: importedApplications,\n\t\tisFolder: true,\n\t\tchildren: applicationIds,\n\t\tdata: {\n\t\t\tname: 'Imported Applications',\n\t\t\tpath: importedApplications,\n\t\t\tpackage: importedApplications,\n\t\t\tproject: '',\n\t\t\tentries: [],\n\t\t},\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<DirectoryEntry>;\n\n\titems[newApplication] = {\n\t\tindex: newApplication,\n\t\tisFolder: false,\n\t\tdata: {\n\t\t\tname: 'New Application',\n\t\t\tpath: newApplication,\n\t\t\tproject: '',\n\t\t},\n\t\tcanMove: false,\n\t\tcanRename: false,\n\t} satisfies TreeItem<FileEntry>;\n\n\treturn { items, rootId };\n}\n\nfunction addEntry(\n\titems: Record<string, TreeItem<DirectoryEntry | FileEntry | undefined>>,\n\tentry: DirectoryEntry | FileEntry,\n) {\n\tconst index = entry.path;\n\tif (isDirectory(entry)) {\n\t\tconst dir = entry as DirectoryEntry;\n\t\tconst childDirectoryIds: string[] = [];\n\t\tconst childFileIds: string[] = [];\n\t\tfor (const childEntry of dir.entries) {\n\t\t\tif (isDirectory(childEntry)) {\n\t\t\t\tchildDirectoryIds.push(childEntry.path);\n\t\t\t} else {\n\t\t\t\tchildFileIds.push(childEntry.path);\n\t\t\t}\n\t\t}\n\t\titems[index] = {\n\t\t\tindex,\n\t\t\tisFolder: true,\n\t\t\tchildren: [...childDirectoryIds, ...childFileIds],\n\t\t\tdata: entry,\n\t\t\tcanMove: false,\n\t\t\tcanRename: false,\n\t\t} satisfies TreeItem<DirectoryEntry>;\n\t\tfor (const child of dir.entries) {\n\t\t\taddEntry(items, child);\n\t\t}\n\t} else {\n\t\titems[index] = {\n\t\t\tindex,\n\t\t\tisFolder: false,\n\t\t\tdata: entry,\n\t\t\tcanMove: !entry.package,\n\t\t\tcanRename: !entry.package,\n\t\t} satisfies TreeItem<FileEntry>;\n\t}\n}\n","export function transformNodes<Transformed, Branch, Leaf>(\n\tnodes: Array<Branch | Leaf>,\n\tnestedPropertyName: keyof Branch,\n\ttransformer: (node: Branch | Leaf, parents: Branch[]) => Transformed,\n\tparents: Branch[] = [],\n): Transformed[] {\n\tconst results: Transformed[] = [];\n\n\tfor (const node of nodes) {\n\t\tconst transformed = transformer(node, parents);\n\t\tresults.push(transformed);\n\t\tconst potentialBranch = node as Branch;\n\t\tconst nestedNodes = potentialBranch[nestedPropertyName] as Array<Branch | Leaf>;\n\t\tif (nestedNodes) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t(transformed as any)[nestedPropertyName] = transformNodes(nestedNodes, nestedPropertyName, transformer, [\n\t\t\t\t...parents,\n\t\t\t\tpotentialBranch,\n\t\t\t]);\n\t\t}\n\t}\n\n\treturn results;\n}\n","import { DirectoryEntry } from '@/features/instance/applications/context/directoryEntry';\nimport { FileEntry } from '@/features/instance/applications/context/fileEntry';\nimport { isDirectory } from '@/features/instance/applications/context/isDirectory';\nimport { APIDirectoryEntry, APIFileEntry } from '@/integrations/api/instance/applications/getComponents';\nimport { transformNodes } from '@/lib/arrays/transformNodes';\n\nexport function calculateRootEntries(entries: Array<APIDirectoryEntry | APIFileEntry>): {\n\trootEntries: Array<DirectoryEntry | FileEntry>;\n\tpathsRegistry: Set<string>;\n} {\n\tconst pathsRegistry = new Set<string>();\n\tconst rootEntries = transformNodes(\n\t\tentries || [],\n\t\t'entries',\n\t\t(node: APIFileEntry | APIDirectoryEntry, parents: APIDirectoryEntry[]) => {\n\t\t\tconst readMeAPIFile = isDirectory(node) && node.entries.find(e => e.name.toLowerCase() === 'readme.md');\n\t\t\tconst path = [...parents.map(p => p.name), node.name].join('/');\n\t\t\tpathsRegistry.add(path);\n\t\t\treturn {\n\t\t\t\tname: node.name,\n\t\t\t\tpath,\n\t\t\t\tproject: (parents[0] || node)?.name,\n\t\t\t\tpackage: (parents[0] || node)?.package,\n\t\t\t\toverviewEntry: readMeAPIFile && !isDirectory(readMeAPIFile) && {\n\t\t\t\t\t\t\tname: readMeAPIFile.name,\n\t\t\t\t\t\t\tpath: [...parents.map(p => p.name), node.name, readMeAPIFile.name].join('/'),\n\t\t\t\t\t\t\tproject: (parents[0] || node)?.name,\n\t\t\t\t\t\t\tpackage: (parents[0] || node)?.package,\n\t\t\t\t\t\t} || undefined,\n\t\t\t} satisfies DirectoryEntry | FileEntry;\n\t\t},\n\t);\n\treturn {\n\t\trootEntries,\n\t\tpathsRegistry,\n\t};\n}\n","import { InstanceClientConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { useMutation } from '@tanstack/react-query';\n\nexport interface SetComponentFileRequest extends InstanceClientConfig, InstanceTypeConfig {\n\tfile: string;\n\tpayload?: string;\n\tproject: string;\n\tencoding?: 'utf8' | 'ASCII' | 'binary' | 'hex' | 'base64' | 'utf16le' | 'latin1' | 'ucs2';\n}\n\nexport async function setComponentFile({\n\tfile,\n\tpayload,\n\tproject,\n\tentityType,\n\tinstanceClient,\n\tencoding,\n}: SetComponentFileRequest) {\n\tconst { data } = await instanceClient.post('/', {\n\t\toperation: 'set_component_file',\n\t\tfile,\n\t\tpayload,\n\t\tproject,\n\t\tencoding,\n\t\treplicated: entityType === 'cluster',\n\t}, { timeout: 300_000 });\n\treturn data;\n}\n\nexport function useSetComponentFile() {\n\treturn useMutation({\n\t\tmutationFn: setComponentFile,\n\t});\n}\n"],"x_google_ignoreList":[0,1,3],"mappings":"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"}