@harperfast/harper 5.2.0 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/copyDb.ts +40 -11
- package/bin/harper.ts +20 -51
- package/bin/help.ts +216 -0
- package/components/Application.ts +236 -46
- package/components/ApplicationScope.ts +26 -0
- package/components/EntryHandler.ts +410 -105
- package/components/RuntimeModuleTracker.ts +189 -0
- package/components/Scope.ts +68 -24
- package/components/componentLoader.ts +70 -16
- package/components/deployLifecycle.ts +119 -33
- package/components/deploymentRecorder.ts +102 -11
- package/components/mcp/tools/operations.ts +6 -0
- package/components/operations.js +8 -6
- package/config/configUtils.ts +78 -20
- package/config/harperConfigEnvVars.ts +114 -17
- package/config-root.schema.json +10 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +26 -5
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dataLayer/hdbInfoController.ts +8 -0
- package/dataLayer/schemaDescribe.ts +2 -1
- package/dist/bin/copyDb.js +33 -9
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/harper.d.ts +6 -0
- package/dist/bin/harper.js +18 -50
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.d.ts +8 -0
- package/dist/bin/help.js +192 -0
- package/dist/bin/help.js.map +1 -0
- package/dist/components/Application.d.ts +16 -1
- package/dist/components/Application.js +210 -38
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +7 -0
- package/dist/components/ApplicationScope.js +22 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.d.ts +4 -4
- package/dist/components/EntryHandler.js +386 -95
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.d.ts +11 -0
- package/dist/components/RuntimeModuleTracker.js +189 -0
- package/dist/components/RuntimeModuleTracker.js.map +1 -0
- package/dist/components/Scope.d.ts +1 -0
- package/dist/components/Scope.js +69 -22
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +69 -10
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deployLifecycle.d.ts +6 -2
- package/dist/components/deployLifecycle.js +109 -31
- package/dist/components/deployLifecycle.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +6 -0
- package/dist/components/deploymentRecorder.js +94 -12
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +6 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/operations.js +8 -6
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +6 -0
- package/dist/config/configUtils.js +78 -18
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.js +108 -16
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +12 -5
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.js +4 -0
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +2 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +57 -0
- package/dist/resources/DatabaseTransaction.js +284 -104
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -2
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Resources.js +22 -4
- package/dist/resources/Resources.js.map +1 -1
- package/dist/resources/Table.d.ts +8 -6
- package/dist/resources/Table.js +158 -31
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.js +27 -1
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +0 -1
- package/dist/resources/blob.js +15 -7
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/databases.d.ts +22 -5
- package/dist/resources/databases.js +118 -9
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +15 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +128 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/jsResource.d.ts +4 -26
- package/dist/resources/jsResource.js +5 -59
- package/dist/resources/jsResource.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -1
- package/dist/resources/models/Models.js +10 -1
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +9 -0
- package/dist/resources/models/backendRegistry.js +10 -0
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/openaiStream.d.ts +16 -1
- package/dist/resources/models/openaiStream.js +113 -21
- package/dist/resources/models/openaiStream.js.map +1 -1
- package/dist/resources/models/v1/chatCompletions.d.ts +54 -0
- package/dist/resources/models/v1/chatCompletions.js +115 -0
- package/dist/resources/models/v1/chatCompletions.js.map +1 -0
- package/dist/resources/models/v1/embeddings.d.ts +11 -0
- package/dist/resources/models/v1/embeddings.js +71 -0
- package/dist/resources/models/v1/embeddings.js.map +1 -0
- package/dist/resources/models/v1/errors.d.ts +54 -0
- package/dist/resources/models/v1/errors.js +130 -0
- package/dist/resources/models/v1/errors.js.map +1 -0
- package/dist/resources/models/v1/index.d.ts +36 -0
- package/dist/resources/models/v1/index.js +75 -0
- package/dist/resources/models/v1/index.js.map +1 -0
- package/dist/resources/models/v1/models.d.ts +26 -0
- package/dist/resources/models/v1/models.js +44 -0
- package/dist/resources/models/v1/models.js.map +1 -0
- package/dist/resources/models/v1/translation.d.ts +133 -0
- package/dist/resources/models/v1/translation.js +298 -0
- package/dist/resources/models/v1/translation.js.map +1 -0
- package/dist/resources/roles.d.ts +1 -1
- package/dist/resources/roles.js +54 -7
- package/dist/resources/roles.js.map +1 -1
- package/dist/resources/search.d.ts +1 -1
- package/dist/resources/search.js +7 -3
- package/dist/resources/search.js.map +1 -1
- package/dist/security/jsLoader.js +84 -33
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/role.js +4 -0
- package/dist/security/role.js.map +1 -1
- package/dist/security/superUserGuard.d.ts +7 -0
- package/dist/security/superUserGuard.js +23 -0
- package/dist/security/superUserGuard.js.map +1 -0
- package/dist/security/tokenAuthentication.d.ts +0 -1
- package/dist/security/tokenAuthentication.js +6 -2
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.d.ts +6 -1
- package/dist/security/user.js +23 -1
- package/dist/security/user.js.map +1 -1
- package/dist/server/http.d.ts +23 -2
- package/dist/server/http.js +99 -12
- package/dist/server/http.js.map +1 -1
- package/dist/server/operationsServer.d.ts +0 -2
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/multipartParser.js +9 -0
- package/dist/server/serverHelpers/multipartParser.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +2 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +13 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -0
- package/dist/server/serverHelpers/registeredOperations.d.ts +3 -2
- package/dist/server/serverHelpers/registeredOperations.js +14 -13
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +19 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +10 -7
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/static.js +57 -18
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +17 -0
- package/dist/server/storageReclamation.js +90 -6
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/manageThreads.js +8 -0
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +20 -0
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +12 -0
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/diff/differential.js +7 -3
- package/dist/sqlEngine/diff/differential.js.map +1 -1
- package/dist/sqlEngine/parser/normalizer.js +37 -9
- package/dist/sqlEngine/parser/normalizer.js.map +1 -1
- package/dist/sqlTranslator/index.js +6 -1
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/upgradePrompt.d.ts +2 -2
- package/dist/upgrade/upgradePrompt.js +22 -3
- package/dist/upgrade/upgradePrompt.js.map +1 -1
- package/dist/utility/environment/environmentManager.d.ts +11 -0
- package/dist/utility/environment/environmentManager.js +154 -0
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +1 -0
- package/dist/utility/errors/commonErrors.js +1 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +2 -0
- package/dist/utility/hdbTerms.js +2 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/install/installer.js +32 -0
- package/dist/utility/install/installer.js.map +1 -1
- package/dist/utility/lmdb/environmentUtility.js +2 -1
- package/dist/utility/lmdb/environmentUtility.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +7 -0
- package/dist/utility/logging/harper_logger.js +57 -24
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/npm-shrinkwrap.json +208 -198
- package/package.json +10 -8
- package/resources/DESIGN.md +1 -0
- package/resources/DatabaseTransaction.ts +313 -102
- package/resources/ResourceInterface.ts +8 -2
- package/resources/Resources.ts +22 -4
- package/resources/Table.ts +398 -259
- package/resources/analytics/write.ts +22 -20
- package/resources/auditStore.ts +32 -1
- package/resources/blob.ts +15 -8
- package/resources/databases.ts +123 -12
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +119 -45
- package/resources/jsResource.ts +5 -62
- package/resources/models/Models.ts +14 -1
- package/resources/models/backendRegistry.ts +10 -0
- package/resources/models/openaiStream.ts +131 -19
- package/resources/models/v1/chatCompletions.ts +128 -0
- package/resources/models/v1/embeddings.ts +70 -0
- package/resources/models/v1/errors.ts +141 -0
- package/resources/models/v1/index.ts +72 -0
- package/resources/models/v1/models.ts +53 -0
- package/resources/models/v1/translation.ts +362 -0
- package/resources/roles.ts +67 -7
- package/resources/search.ts +8 -3
- package/security/jsLoader.ts +84 -30
- package/security/role.ts +7 -0
- package/security/superUserGuard.ts +20 -0
- package/security/tokenAuthentication.ts +6 -3
- package/security/user.ts +26 -1
- package/server/DESIGN.md +45 -34
- package/server/http.ts +100 -13
- package/server/operationsServer.ts +0 -2
- package/server/serverHelpers/multipartParser.ts +9 -0
- package/server/serverHelpers/operationAuthorizationState.ts +11 -0
- package/server/serverHelpers/registeredOperations.ts +19 -15
- package/server/serverHelpers/serverHandlers.js +20 -3
- package/server/serverHelpers/serverUtilities.ts +10 -7
- package/server/static.ts +75 -20
- package/server/storageReclamation.ts +104 -8
- package/server/threads/manageThreads.js +8 -0
- package/server/threads/socketRouter.ts +20 -0
- package/server/threads/threadServer.js +11 -0
- package/sqlTranslator/index.ts +6 -1
- package/static/defaultConfig.yaml +2 -0
- package/studio/web/assets/{Chat-DoVWScmq.js → Chat-BMUjPklt.js} +5 -5
- package/studio/web/assets/{Chat-DoVWScmq.js.map → Chat-BMUjPklt.js.map} +1 -1
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js → FloatingChat-Cbghuxe5.js} +5 -5
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js.map → FloatingChat-Cbghuxe5.js.map} +1 -1
- package/studio/web/assets/{apiToken-BUI_04o7.js → apiToken-CkgTQAqc.js} +2 -2
- package/studio/web/assets/{apiToken-BUI_04o7.js.map → apiToken-CkgTQAqc.js.map} +1 -1
- package/studio/web/assets/{applications-D03NA7wW.js → applications-WvF4NOTN.js} +13 -13
- package/studio/web/assets/applications-WvF4NOTN.js.map +1 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js +2 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js.map +1 -0
- package/studio/web/assets/index-CDeqVx71.css +1 -0
- package/studio/web/assets/index-Sevt3MVx.js +819 -0
- package/studio/web/assets/index-Sevt3MVx.js.map +1 -0
- package/studio/web/assets/index.lazy-Dg5YYPGg.js +14 -0
- package/studio/web/assets/{index.lazy-Dx3MpyDC.js.map → index.lazy-Dg5YYPGg.js.map} +1 -1
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js → jsonMode-CBSEleE7.js} +2 -2
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js.map → jsonMode-CBSEleE7.js.map} +1 -1
- package/studio/web/assets/languageServices-gxedeeTo.js +2 -0
- package/studio/web/assets/languageServices-gxedeeTo.js.map +1 -0
- package/studio/web/assets/{notifications-0edoFTsb.js → notifications-Ap84YyQp.js} +2 -2
- package/studio/web/assets/{notifications-0edoFTsb.js.map → notifications-Ap84YyQp.js.map} +1 -1
- package/studio/web/assets/notifications-vehqyOLM.js +2 -0
- package/studio/web/assets/{notifications-CwKhipK7.js.map → notifications-vehqyOLM.js.map} +1 -1
- package/studio/web/assets/{pollUnlessForbidden-HHdQZW1N.js → pollUnlessForbidden-BhzefVRn.js} +2 -2
- package/studio/web/assets/pollUnlessForbidden-BhzefVRn.js.map +1 -0
- package/studio/web/assets/{profile-DUfEPQtx.js → profile-DzDpRLHY.js} +2 -2
- package/studio/web/assets/{profile-DUfEPQtx.js.map → profile-DzDpRLHY.js.map} +1 -1
- package/studio/web/assets/queryClient-CgtkoiCY.js +2 -0
- package/studio/web/assets/queryClient-CgtkoiCY.js.map +1 -0
- package/studio/web/assets/regions-DpJ8s7iN.js +2 -0
- package/studio/web/assets/regions-DpJ8s7iN.js.map +1 -0
- package/studio/web/assets/register-BDy01-q3.js +3 -0
- package/studio/web/assets/register-BDy01-q3.js.map +1 -0
- package/studio/web/assets/register-CQHRwNP4.js +3 -0
- package/studio/web/assets/register-CQHRwNP4.js.map +1 -0
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js → setComponentFile-D0aPcI3W.js} +2 -2
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js.map → setComponentFile-D0aPcI3W.js.map} +1 -1
- package/studio/web/assets/setup-I15FAF9H.js +3 -0
- package/studio/web/assets/{setup-B56Oz1_u.js.map → setup-I15FAF9H.js.map} +1 -1
- package/studio/web/assets/status-BF1eJshJ.js +62 -0
- package/studio/web/assets/status-BF1eJshJ.js.map +1 -0
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js → swagger-ui-react-DwSPXXhl.js} +2 -2
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js.map → swagger-ui-react-DwSPXXhl.js.map} +1 -1
- package/studio/web/assets/{textarea-DhLMZ3PA.js → table-DpOjNQHt.js} +2 -10
- package/studio/web/assets/table-DpOjNQHt.js.map +1 -0
- package/studio/web/assets/{tsMode-CrHCRjTK.js → tsMode-Bu51A-VG.js} +2 -2
- package/studio/web/assets/{tsMode-CrHCRjTK.js.map → tsMode-Bu51A-VG.js.map} +1 -1
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js → useEntityRestURL-DrV1zMrN.js} +2 -2
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js.map → useEntityRestURL-DrV1zMrN.js.map} +1 -1
- package/studio/web/index.html +6 -7
- package/upgrade/upgradePrompt.ts +22 -3
- package/utility/environment/environmentManager.ts +152 -0
- package/utility/errors/commonErrors.ts +2 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/install/installer.ts +37 -0
- package/utility/lmdb/environmentUtility.ts +2 -1
- package/utility/logging/harper_logger.ts +57 -26
- package/studio/web/assets/applications-D03NA7wW.js.map +0 -1
- package/studio/web/assets/index-Bh_CNAHr.js +0 -809
- package/studio/web/assets/index-Bh_CNAHr.js.map +0 -1
- package/studio/web/assets/index-C8Mv9kHV.css +0 -1
- package/studio/web/assets/index.lazy-Dx3MpyDC.js +0 -14
- package/studio/web/assets/notifications-CwKhipK7.js +0 -2
- package/studio/web/assets/pollUnlessForbidden-HHdQZW1N.js.map +0 -1
- package/studio/web/assets/queryClient-CbA8wM7J.js +0 -2
- package/studio/web/assets/queryClient-CbA8wM7J.js.map +0 -1
- package/studio/web/assets/setup-B56Oz1_u.js +0 -3
- package/studio/web/assets/status-BAod7p3o.js +0 -62
- package/studio/web/assets/status-BAod7p3o.js.map +0 -1
- package/studio/web/assets/textarea-DhLMZ3PA.js.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/swagger-ui-react-DwSPXXhl.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-Sevt3MVx.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/table-DpOjNQHt.js","assets/chevron-right-anDJCGlp.js","assets/errorText-NpBmvk9I.js","assets/queryClient-CgtkoiCY.js","assets/pollUnlessForbidden-BhzefVRn.js","assets/tokenization-uOBOyHAS.js","assets/index-CDeqVx71.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-BhzefVRn.js";import{An as f,Vn as p,ft as m,lt as h,tr as g}from"./index-Sevt3MVx.js";import{t as _}from"./useEntityRestURL-DrV1zMrN.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
|
+
`).replace(/`/g,"\\`")+"`";return`const response = await fetch("${t.toString()}", {
|
|
4
|
+
\tmethod: "${e.get(`method`)}",${r&&r.size?`
|
|
5
|
+
\theaders: {
|
|
6
|
+
\t\t${r.map((e,t)=>`"${t}": "${e}"`).valueSeq().join(`,
|
|
7
|
+
`)}
|
|
8
|
+
\t},`:``}${i?`
|
|
9
|
+
\tbody: ${o},`:``}
|
|
10
|
+
});
|
|
11
|
+
const data = await response.json();
|
|
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-DwSPXXhl.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])));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}=m(),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)(f,{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)(p,{title:`API Docs Unavailable`,error:{message:e},showReturnToHome:!1})}return(0,S.jsxs)(`div`,{className:`pt-6`,children:[A&&(0,S.jsx)(p,{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)(g,{}),P?`Enabling CORS...`:`Enable CORS for ${window.location.origin}`]})}),(0,S.jsx)(x.Suspense,{fallback:(0,S.jsx)(f,{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-Dg5YYPGg.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-Dx3MpyDC.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-Dg5YYPGg.js"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
//# sourceMappingURL=jsonMode-
|
|
1
|
+
import{t as e}from"./tokenization-uOBOyHAS.js";import{m as t,p as n}from"./editor.api-OBQnf1nL.js";import{t as r}from"./workers-Bhsi-paP.js";import{_ as i,a,c as o,d as s,f as c,g as l,h as u,i as d,l as f,m as p,n as m,o as h,p as g,r as _,s as v,t as y,u as b,v as x}from"./lspLanguageFeatures-DxCM7LI8.js";var S=120*1e3,C=class{constructor(e){this._defaults=e,this._worker=null,this._client=null,this._idleCheckInterval=window.setInterval(()=>this._checkIfIdle(),30*1e3),this._lastUsedTime=0,this._configChangeListener=this._defaults.onDidChange(()=>this._stopWorker())}_stopWorker(){this._worker&&=(this._worker.dispose(),null),this._client=null}dispose(){clearInterval(this._idleCheckInterval),this._configChangeListener.dispose(),this._stopWorker()}_checkIfIdle(){this._worker&&Date.now()-this._lastUsedTime>S&&this._stopWorker()}_getClient(){return this._lastUsedTime=Date.now(),this._client||=(this._worker=r({moduleId:`vs/language/json/jsonWorker`,createWorker:()=>new Worker(new URL(`/assets/json.worker-BBwVQl7H.js`,``+import.meta.url),{type:`module`}),label:this._defaults.languageId,createData:{languageSettings:this._defaults.diagnosticsOptions,languageId:this._defaults.languageId,enableSchemaRequest:this._defaults.diagnosticsOptions.enableSchemaRequest}}),this._worker.getProxy()),this._client}getLanguageServiceWorker(...e){let t;return this._getClient().then(e=>{t=e}).then(t=>{if(this._worker)return this._worker.withSyncedResources(e)}).then(e=>t)}},w;function T(){return new Promise((e,t)=>{if(!w)return t(`JSON not registered!`);e(w)})}var E=class extends _{constructor(e,t,r){super(e,t,r.onDidChange),this._disposables.push(n.onWillDisposeModel(e=>{this._resetSchema(e.uri)})),this._disposables.push(n.onDidChangeModelLanguage(e=>{this._resetSchema(e.model.uri)}))}_resetSchema(e){this._worker().then(t=>{t.resetSchema(e.toString())})}};function D(n){let r=[],i=[],c=new C(n);r.push(c),w=(...e)=>c.getLanguageServiceWorker(...e);function l(){let{languageId:r,modeConfiguration:c}=n;k(i),c.documentFormattingEdits&&i.push(t.registerDocumentFormattingEditProvider(r,new a(w))),c.documentRangeFormattingEdits&&i.push(t.registerDocumentRangeFormattingEditProvider(r,new o(w))),c.completionItems&&i.push(t.registerCompletionItemProvider(r,new y(w,[` `,`:`,`"`]))),c.hovers&&i.push(t.registerHoverProvider(r,new s(w))),c.documentSymbols&&i.push(t.registerDocumentSymbolProvider(r,new f(w))),c.tokens&&i.push(t.setTokensProvider(r,e(!0))),c.colors&&i.push(t.registerColorProvider(r,new d(w))),c.foldingRanges&&i.push(t.registerFoldingRangeProvider(r,new b(w))),c.diagnostics&&i.push(new E(r,w,n)),c.selectionRanges&&i.push(t.registerSelectionRangeProvider(r,new p(w)))}l(),r.push(t.setLanguageConfiguration(n.languageId,A));let u=n.modeConfiguration;return n.onDidChange(e=>{e.modeConfiguration!==u&&(u=e.modeConfiguration,l())}),r.push(O(i)),O(r)}function O(e){return{dispose:()=>k(e)}}function k(e){for(;e.length;)e.pop().dispose()}var A={wordPattern:/(-?\d*\.\d\w*)|([^\[\{\]\}\:\"\,\s]+)/g,comments:{lineComment:`//`,blockComment:[`/*`,`*/`]},brackets:[[`{`,`}`],[`[`,`]`]],autoClosingPairs:[{open:`{`,close:`}`,notIn:[`string`]},{open:`[`,close:`]`,notIn:[`string`]},{open:`"`,close:`"`,notIn:[`string`]}]};export{y as CompletionAdapter,m as DefinitionAdapter,_ as DiagnosticsAdapter,d as DocumentColorAdapter,a as DocumentFormattingEditProvider,h as DocumentHighlightAdapter,v as DocumentLinkAdapter,o as DocumentRangeFormattingEditProvider,f as DocumentSymbolAdapter,b as FoldingRangeAdapter,s as HoverAdapter,c as ReferenceAdapter,g as RenameAdapter,p as SelectionRangeAdapter,C as WorkerManager,u as fromPosition,l as fromRange,T as getWorker,D as setupMode,i as toRange,x as toTextEdit};
|
|
2
|
+
//# sourceMappingURL=jsonMode-CBSEleE7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonMode-Cjj7dtlr.js","names":[],"sources":["../../node_modules/.pnpm/monaco-editor@0.56.0/node_modules/monaco-editor/esm/vs/languages/features/json/workerManager.js","../../node_modules/.pnpm/monaco-editor@0.56.0/node_modules/monaco-editor/esm/vs/languages/features/json/jsonMode.js"],"sourcesContent":["import { createWebWorker } from '../../../internal/common/workers.js';\n\nconst STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;\nclass WorkerManager {\n constructor(defaults) {\n this._defaults = defaults;\n this._worker = null;\n this._client = null;\n this._idleCheckInterval = window.setInterval(() => this._checkIfIdle(), 30 * 1e3);\n this._lastUsedTime = 0;\n this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());\n }\n _stopWorker() {\n if (this._worker) {\n this._worker.dispose();\n this._worker = null;\n }\n this._client = null;\n }\n dispose() {\n clearInterval(this._idleCheckInterval);\n this._configChangeListener.dispose();\n this._stopWorker();\n }\n _checkIfIdle() {\n if (!this._worker) {\n return;\n }\n let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;\n if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {\n this._stopWorker();\n }\n }\n _getClient() {\n this._lastUsedTime = Date.now();\n if (!this._client) {\n this._worker = createWebWorker({\n // module that exports the create() method and returns a `JSONWorker` instance\n moduleId: \"vs/language/json/jsonWorker\",\n createWorker: () => new Worker(new URL('json.worker.js', import.meta.url), { type: \"module\" }),\n label: this._defaults.languageId,\n // passed in to the create() method\n createData: {\n languageSettings: this._defaults.diagnosticsOptions,\n languageId: this._defaults.languageId,\n enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest\n }\n });\n this._client = this._worker.getProxy();\n }\n return this._client;\n }\n getLanguageServiceWorker(...resources) {\n let _client;\n return this._getClient().then((client) => {\n _client = client;\n }).then((_) => {\n if (this._worker) {\n return this._worker.withSyncedResources(resources);\n }\n }).then((_) => _client);\n }\n}\n\nexport { WorkerManager };\n","import { WorkerManager } from './workerManager.js';\nimport { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, CompletionAdapter, HoverAdapter, DocumentSymbolAdapter, DocumentColorAdapter, FoldingRangeAdapter, SelectionRangeAdapter, DiagnosticsAdapter } from '../common/lspLanguageFeatures.js';\nexport { DefinitionAdapter, DocumentHighlightAdapter, DocumentLinkAdapter, ReferenceAdapter, RenameAdapter, fromPosition, fromRange, toRange, toTextEdit } from '../common/lspLanguageFeatures.js';\nimport { createTokenizationSupport } from './tokenization.js';\nimport { languages, editor } from '../../../editor/editor.api.js';\n\nlet worker;\nfunction getWorker() {\n return new Promise((resolve, reject) => {\n if (!worker) {\n return reject(\"JSON not registered!\");\n }\n resolve(worker);\n });\n}\nclass JSONDiagnosticsAdapter extends DiagnosticsAdapter {\n constructor(languageId, worker2, defaults) {\n super(languageId, worker2, defaults.onDidChange);\n this._disposables.push(\n editor.onWillDisposeModel((model) => {\n this._resetSchema(model.uri);\n })\n );\n this._disposables.push(\n editor.onDidChangeModelLanguage((event) => {\n this._resetSchema(event.model.uri);\n })\n );\n }\n _resetSchema(resource) {\n this._worker().then((worker2) => {\n worker2.resetSchema(resource.toString());\n });\n }\n}\nfunction setupMode(defaults) {\n const disposables = [];\n const providers = [];\n const client = new WorkerManager(defaults);\n disposables.push(client);\n worker = (...uris) => {\n return client.getLanguageServiceWorker(...uris);\n };\n function registerProviders() {\n const { languageId, modeConfiguration: modeConfiguration2 } = defaults;\n disposeAll(providers);\n if (modeConfiguration2.documentFormattingEdits) {\n providers.push(\n languages.registerDocumentFormattingEditProvider(\n languageId,\n new DocumentFormattingEditProvider(worker)\n )\n );\n }\n if (modeConfiguration2.documentRangeFormattingEdits) {\n providers.push(\n languages.registerDocumentRangeFormattingEditProvider(\n languageId,\n new DocumentRangeFormattingEditProvider(worker)\n )\n );\n }\n if (modeConfiguration2.completionItems) {\n providers.push(\n languages.registerCompletionItemProvider(\n languageId,\n new CompletionAdapter(worker, [\" \", \":\", '\"'])\n )\n );\n }\n if (modeConfiguration2.hovers) {\n providers.push(\n languages.registerHoverProvider(languageId, new HoverAdapter(worker))\n );\n }\n if (modeConfiguration2.documentSymbols) {\n providers.push(\n languages.registerDocumentSymbolProvider(\n languageId,\n new DocumentSymbolAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.tokens) {\n providers.push(languages.setTokensProvider(languageId, createTokenizationSupport(true)));\n }\n if (modeConfiguration2.colors) {\n providers.push(\n languages.registerColorProvider(\n languageId,\n new DocumentColorAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.foldingRanges) {\n providers.push(\n languages.registerFoldingRangeProvider(\n languageId,\n new FoldingRangeAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.diagnostics) {\n providers.push(new JSONDiagnosticsAdapter(languageId, worker, defaults));\n }\n if (modeConfiguration2.selectionRanges) {\n providers.push(\n languages.registerSelectionRangeProvider(\n languageId,\n new SelectionRangeAdapter(worker)\n )\n );\n }\n }\n registerProviders();\n disposables.push(languages.setLanguageConfiguration(defaults.languageId, richEditConfiguration));\n let modeConfiguration = defaults.modeConfiguration;\n defaults.onDidChange((newDefaults) => {\n if (newDefaults.modeConfiguration !== modeConfiguration) {\n modeConfiguration = newDefaults.modeConfiguration;\n registerProviders();\n }\n });\n disposables.push(asDisposable(providers));\n return asDisposable(disposables);\n}\nfunction asDisposable(disposables) {\n return { dispose: () => disposeAll(disposables) };\n}\nfunction disposeAll(disposables) {\n while (disposables.length) {\n disposables.pop().dispose();\n }\n}\nconst richEditConfiguration = {\n wordPattern: /(-?\\d*\\.\\d\\w*)|([^\\[\\{\\]\\}\\:\\\"\\,\\s]+)/g,\n comments: {\n lineComment: \"//\",\n blockComment: [\"/*\", \"*/\"]\n },\n brackets: [\n [\"{\", \"}\"],\n [\"[\", \"]\"]\n ],\n autoClosingPairs: [\n { open: \"{\", close: \"}\", notIn: [\"string\"] },\n { open: \"[\", close: \"]\", notIn: [\"string\"] },\n { open: '\"', close: '\"', notIn: [\"string\"] }\n ]\n};\n\nexport { CompletionAdapter, DiagnosticsAdapter, DocumentColorAdapter, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, DocumentSymbolAdapter, FoldingRangeAdapter, HoverAdapter, SelectionRangeAdapter, WorkerManager, getWorker, setupMode };\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jsonMode-CBSEleE7.js","names":[],"sources":["../../node_modules/.pnpm/monaco-editor@0.56.0/node_modules/monaco-editor/esm/vs/languages/features/json/workerManager.js","../../node_modules/.pnpm/monaco-editor@0.56.0/node_modules/monaco-editor/esm/vs/languages/features/json/jsonMode.js"],"sourcesContent":["import { createWebWorker } from '../../../internal/common/workers.js';\n\nconst STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;\nclass WorkerManager {\n constructor(defaults) {\n this._defaults = defaults;\n this._worker = null;\n this._client = null;\n this._idleCheckInterval = window.setInterval(() => this._checkIfIdle(), 30 * 1e3);\n this._lastUsedTime = 0;\n this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());\n }\n _stopWorker() {\n if (this._worker) {\n this._worker.dispose();\n this._worker = null;\n }\n this._client = null;\n }\n dispose() {\n clearInterval(this._idleCheckInterval);\n this._configChangeListener.dispose();\n this._stopWorker();\n }\n _checkIfIdle() {\n if (!this._worker) {\n return;\n }\n let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;\n if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {\n this._stopWorker();\n }\n }\n _getClient() {\n this._lastUsedTime = Date.now();\n if (!this._client) {\n this._worker = createWebWorker({\n // module that exports the create() method and returns a `JSONWorker` instance\n moduleId: \"vs/language/json/jsonWorker\",\n createWorker: () => new Worker(new URL('json.worker.js', import.meta.url), { type: \"module\" }),\n label: this._defaults.languageId,\n // passed in to the create() method\n createData: {\n languageSettings: this._defaults.diagnosticsOptions,\n languageId: this._defaults.languageId,\n enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest\n }\n });\n this._client = this._worker.getProxy();\n }\n return this._client;\n }\n getLanguageServiceWorker(...resources) {\n let _client;\n return this._getClient().then((client) => {\n _client = client;\n }).then((_) => {\n if (this._worker) {\n return this._worker.withSyncedResources(resources);\n }\n }).then((_) => _client);\n }\n}\n\nexport { WorkerManager };\n","import { WorkerManager } from './workerManager.js';\nimport { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, CompletionAdapter, HoverAdapter, DocumentSymbolAdapter, DocumentColorAdapter, FoldingRangeAdapter, SelectionRangeAdapter, DiagnosticsAdapter } from '../common/lspLanguageFeatures.js';\nexport { DefinitionAdapter, DocumentHighlightAdapter, DocumentLinkAdapter, ReferenceAdapter, RenameAdapter, fromPosition, fromRange, toRange, toTextEdit } from '../common/lspLanguageFeatures.js';\nimport { createTokenizationSupport } from './tokenization.js';\nimport { languages, editor } from '../../../editor/editor.api.js';\n\nlet worker;\nfunction getWorker() {\n return new Promise((resolve, reject) => {\n if (!worker) {\n return reject(\"JSON not registered!\");\n }\n resolve(worker);\n });\n}\nclass JSONDiagnosticsAdapter extends DiagnosticsAdapter {\n constructor(languageId, worker2, defaults) {\n super(languageId, worker2, defaults.onDidChange);\n this._disposables.push(\n editor.onWillDisposeModel((model) => {\n this._resetSchema(model.uri);\n })\n );\n this._disposables.push(\n editor.onDidChangeModelLanguage((event) => {\n this._resetSchema(event.model.uri);\n })\n );\n }\n _resetSchema(resource) {\n this._worker().then((worker2) => {\n worker2.resetSchema(resource.toString());\n });\n }\n}\nfunction setupMode(defaults) {\n const disposables = [];\n const providers = [];\n const client = new WorkerManager(defaults);\n disposables.push(client);\n worker = (...uris) => {\n return client.getLanguageServiceWorker(...uris);\n };\n function registerProviders() {\n const { languageId, modeConfiguration: modeConfiguration2 } = defaults;\n disposeAll(providers);\n if (modeConfiguration2.documentFormattingEdits) {\n providers.push(\n languages.registerDocumentFormattingEditProvider(\n languageId,\n new DocumentFormattingEditProvider(worker)\n )\n );\n }\n if (modeConfiguration2.documentRangeFormattingEdits) {\n providers.push(\n languages.registerDocumentRangeFormattingEditProvider(\n languageId,\n new DocumentRangeFormattingEditProvider(worker)\n )\n );\n }\n if (modeConfiguration2.completionItems) {\n providers.push(\n languages.registerCompletionItemProvider(\n languageId,\n new CompletionAdapter(worker, [\" \", \":\", '\"'])\n )\n );\n }\n if (modeConfiguration2.hovers) {\n providers.push(\n languages.registerHoverProvider(languageId, new HoverAdapter(worker))\n );\n }\n if (modeConfiguration2.documentSymbols) {\n providers.push(\n languages.registerDocumentSymbolProvider(\n languageId,\n new DocumentSymbolAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.tokens) {\n providers.push(languages.setTokensProvider(languageId, createTokenizationSupport(true)));\n }\n if (modeConfiguration2.colors) {\n providers.push(\n languages.registerColorProvider(\n languageId,\n new DocumentColorAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.foldingRanges) {\n providers.push(\n languages.registerFoldingRangeProvider(\n languageId,\n new FoldingRangeAdapter(worker)\n )\n );\n }\n if (modeConfiguration2.diagnostics) {\n providers.push(new JSONDiagnosticsAdapter(languageId, worker, defaults));\n }\n if (modeConfiguration2.selectionRanges) {\n providers.push(\n languages.registerSelectionRangeProvider(\n languageId,\n new SelectionRangeAdapter(worker)\n )\n );\n }\n }\n registerProviders();\n disposables.push(languages.setLanguageConfiguration(defaults.languageId, richEditConfiguration));\n let modeConfiguration = defaults.modeConfiguration;\n defaults.onDidChange((newDefaults) => {\n if (newDefaults.modeConfiguration !== modeConfiguration) {\n modeConfiguration = newDefaults.modeConfiguration;\n registerProviders();\n }\n });\n disposables.push(asDisposable(providers));\n return asDisposable(disposables);\n}\nfunction asDisposable(disposables) {\n return { dispose: () => disposeAll(disposables) };\n}\nfunction disposeAll(disposables) {\n while (disposables.length) {\n disposables.pop().dispose();\n }\n}\nconst richEditConfiguration = {\n wordPattern: /(-?\\d*\\.\\d\\w*)|([^\\[\\{\\]\\}\\:\\\"\\,\\s]+)/g,\n comments: {\n lineComment: \"//\",\n blockComment: [\"/*\", \"*/\"]\n },\n brackets: [\n [\"{\", \"}\"],\n [\"[\", \"]\"]\n ],\n autoClosingPairs: [\n { open: \"{\", close: \"}\", notIn: [\"string\"] },\n { open: \"[\", close: \"]\", notIn: [\"string\"] },\n { open: '\"', close: '\"', notIn: [\"string\"] }\n ]\n};\n\nexport { CompletionAdapter, DiagnosticsAdapter, DocumentColorAdapter, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, DocumentSymbolAdapter, FoldingRangeAdapter, HoverAdapter, SelectionRangeAdapter, WorkerManager, getWorker, setupMode };\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"languageServices-gxedeeTo.js","names":[],"sources":["../../src/lib/monaco/languageServices.ts"],"sourcesContent":["/**\n * Typed access to Monaco's TypeScript/JavaScript and JSON language-service\n * defaults for our curated build.\n *\n * monaco-editor 0.55 moved these defaults off the `monaco.languages` namespace\n * — now deprecated no-op stubs on the `editor.api` entry — to top-level\n * `typescript` / `json` namespaces. The package's main entry (`monaco-editor`)\n * re-exports those namespaces, but it also bundles all ~90 languages, so it is\n * off-limits here (it would defeat the curated build; see `./setup`).\n *\n * 0.56 made that a non-problem: each language feature now has its own public\n * `register` entry point that exports the very same singletons *with* real type\n * declarations — so this is a plain re-export, pulling in no extra languages.\n * These are the same modules `./setup` imports for their registration side\n * effects; naming them once here keeps the \"don't reach for the main entry\"\n * rationale in one place.\n */\nexport * as json from 'monaco-editor/languages/features/json/register';\nexport * as typescript from 'monaco-editor/languages/features/typescript/register';\n"],"mappings":""}
|
|
@@ -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{
|
|
2
|
-
//# sourceMappingURL=notifications-
|
|
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{Cn as a,Dn as o,En as s,Lt as c,On as l,Sn as u,Tn as d,_n as f,bn as p,kn as m,vn as h,xn as g}from"./index-Sevt3MVx.js";var _=e(r(),1),v=i(),y={active:0,upcoming:1,expired:2};function b(){let{data:e,isLoading:t}=f(),n=l(),r=h(),i=(0,_.useMemo)(()=>[...e??[]].sort((e,t)=>{let n=y[a(e,r).state],i=y[a(t,r).state];if(n!==i)return n-i;let o=g[u(e.type).severity]-g[u(t.type).severity];if(o!==0)return o;let s=d(e.endAt)??2**53-1;return(d(t.endAt)??2**53-1)-s}),[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)(c,{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:c,iconClass:l,label:d,badgeVariant:f}=u(e.type),h=a(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`,h.state===`expired`&&`opacity-70`),children:[(0,v.jsx)(c,{className:t(`mt-0.5 size-5 shrink-0`,l)}),(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)(m,{variant:f,children:d}),h.state!==`active`&&(0,v.jsx)(m,{variant:`outline`,className:`capitalize`,children:h.state}),(0,v.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:h.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)(p,{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):s(e.id),children:r?`Undo`:`Ignore`})]})}export{b as NotificationsCenter};
|
|
2
|
+
//# sourceMappingURL=notifications-Ap84YyQp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications-
|
|
1
|
+
{"version":3,"file":"notifications-Ap84YyQp.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"}
|
|
@@ -0,0 +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{c as v}from"./table-DpOjNQHt.js";import{Et as y,Gn as b,Lt as x,Ot as S,Sn as C,Tn as w,_n as T,bn as E,in as D,kn as O,sn as k,tr as A,wn as j,yn as M}from"./index-Sevt3MVx.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:M})})}function H(){let e=i();return r({mutationFn:async({id:e,draft:n})=>{await t.patch(`/SystemStatus/${e}`,n)},onSuccess:()=>e.invalidateQueries({queryKey:M})})}function U(){let e=i();return r({mutationFn:async e=>{await t.delete(`/SystemStatus/${e}`)},onSuccess:()=>e.invalidateQueries({queryKey:M})})}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=w(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=w(e.startAt),n=w(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}=T(),[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)(A,{}),`New notification`]})]}),(0,G.jsx)(`div`,{className:`mt-6`,children:t?(0,G.jsx)(x,{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}=C(e.original.type);return(0,G.jsx)(O,{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)(E,{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)(b,{})})]})}]}function Q({open:e,onOpenChange:t,editing:r}){let i=V(),a=H(),o=i.isPending||a.isPending,[v,b]=(0,W.useState)(`error`),[x,S]=(0,W.useState)(``),[C,w]=(0,W.useState)(``),[T,E]=(0,W.useState)(``),[O,A]=(0,W.useState)(``),[M,N]=(0,W.useState)(null);return(0,W.useEffect)(()=>{e&&(b(r?.type??`error`),S(r?.message??``),w(r?.url??``),E(q(r?.startAt)),A(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)(k,{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)(k,{htmlFor:`notification-message`,children:`Message`}),(0,G.jsx)(y,{id:`notification-message`,rows:3,value:x,onChange:e=>S(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)(k,{htmlFor:`notification-url`,children:`Link (optional)`}),(0,G.jsx)(D,{id:`notification-url`,value:C,onChange:e=>w(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)(k,{htmlFor:`notification-start`,children:`Start (local time)`}),(0,G.jsx)(D,{id:`notification-start`,type:`datetime-local`,value:T,onChange:e=>E(e.target.value)})]}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsx)(k,{htmlFor:`notification-end`,children:`End (local time)`}),(0,G.jsx)(D,{id:`notification-end`,type:`datetime-local`,value:O,onChange:e=>A(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=x.trim();if(!e){N(`Message is required.`);return}let n=J(T),o=J(O);if(n&&o&&Date.parse(o)<=Date.parse(n)){N(`End time must be after start time.`);return}let s=C.trim();if(s&&!j(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-vehqyOLM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications-CwKhipK7.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-vehqyOLM.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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"}
|
package/studio/web/assets/{pollUnlessForbidden-HHdQZW1N.js → pollUnlessForbidden-BhzefVRn.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{t,u as n}from"./authStore-CNoNfv0F.js";import{C as r}from"./vendor-tanstack-0SjDjtT0.js";import{a as i}from"./vendor-datadog-DyjkTkvg.js";var a=e(i(),1);function o(e={}){let{instanceId:i,clusterId:a}=r({strict:!1});return n({id:t,...e})}function s(e={}){let{instanceId:i,clusterId:a}=r({strict:!1});return{instanceClient:n({id:t,...e}),entityType:`instance`}}function c(e={}){let{instanceId:t,clusterId:n}=r({strict:!1});return(0,a.useMemo)(()=>l({instanceId:t,clusterId:n,...e}),[e.instanceId??t,e.clusterId??n,e.operationsUrl,e.port,e.secure,e.disableFabricConnect,e.forceFabricConnect])}function l({instanceId:e,clusterId:r,...i}){let a=t;if(!a)throw Error(`id could not be automatically calculated in useInstanceClientIdParams`);return{instanceClient:n({id:a,...i}),entityId:a,entityType:`instance`}}function u(e){return!!e}function d(e){return e?.response?.status??e?.status}function f(e){return d(e)===403}function p(e){return t=>f(t.state.error)?!1:e??!1}function
|
|
2
|
-
//# sourceMappingURL=pollUnlessForbidden-
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{t,u as n}from"./authStore-CNoNfv0F.js";import{C as r}from"./vendor-tanstack-0SjDjtT0.js";import{a as i}from"./vendor-datadog-DyjkTkvg.js";var a=e(i(),1);function o(e={}){let{instanceId:i,clusterId:a}=r({strict:!1});return n({id:t,...e})}function s(e={}){let{instanceId:i,clusterId:a}=r({strict:!1});return{instanceClient:n({id:t,...e}),entityType:`instance`}}function c(e={}){let{instanceId:t,clusterId:n}=r({strict:!1});return(0,a.useMemo)(()=>l({instanceId:t,clusterId:n,...e}),[e.instanceId??t,e.clusterId??n,e.operationsUrl,e.port,e.secure,e.disableFabricConnect,e.forceFabricConnect])}function l({instanceId:e,clusterId:r,...i}){let a=t;if(!a)throw Error(`id could not be automatically calculated in useInstanceClientIdParams`);return{instanceClient:n({id:a,...i}),entityId:a,entityType:`instance`}}function u(e){return!!e}function d(e){return e?.response?.status??e?.status}function f(e){return d(e)===403}function p(e){let t=d(e);return t===400||t===403}function m(e){return t=>f(t.state.error)?!1:e??!1}function h(e=3){return(t,n)=>!p(n)&&t<e}export{o as a,l as i,h as n,c as o,u as r,s,m as t};
|
|
2
|
+
//# sourceMappingURL=pollUnlessForbidden-BhzefVRn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pollUnlessForbidden-BhzefVRn.js","names":[],"sources":["../../src/config/useInstanceClient.tsx","../../src/lib/arrays/excludeFalsy.ts","../../src/react-query/pollUnlessForbidden.ts"],"sourcesContent":["import { isLocalStudio } from '@/config/constants';\nimport { getInstanceClient } from '@/config/getInstanceClient';\nimport { InstanceClientConfig, InstanceClientIdConfig, InstanceTypeConfig } from '@/config/instanceClientConfig';\nimport { OverallAppSignIn } from '@/features/auth/store/authStore';\nimport { useParams } from '@tanstack/react-router';\nimport { useMemo } from 'react';\n\ninterface UseParams {\n\tclusterId?: string;\n\tdisableFabricConnect?: boolean;\n\tforceFabricConnect?: boolean;\n\tinstanceId?: string;\n\toperationsUrl?: string | null;\n\tport?: number;\n\tsecure?: boolean;\n}\n\nexport function useInstanceClient(\n\tparams: UseParams = {},\n) {\n\tconst { instanceId, clusterId }: { instanceId?: string; clusterId?: string } = useParams({ strict: false });\n\tconst id = isLocalStudio ? OverallAppSignIn : params.instanceId ?? instanceId ?? params.clusterId ?? clusterId;\n\treturn getInstanceClient({ id, ...params });\n}\n\nexport function useInstanceClientParams(\n\tparams: UseParams = {},\n): InstanceClientConfig & InstanceTypeConfig {\n\tconst { instanceId, clusterId }: { instanceId?: string; clusterId?: string } = useParams({ strict: false });\n\tconst id = isLocalStudio ? OverallAppSignIn : params.instanceId ?? instanceId ?? params.clusterId ?? clusterId;\n\treturn {\n\t\tinstanceClient: getInstanceClient({ id, ...params }),\n\t\tentityType: (isLocalStudio || instanceId) ? 'instance' : 'cluster',\n\t};\n}\n\nexport function useInstanceClientIdParams(\n\tparams: UseParams = {},\n): InstanceClientIdConfig & InstanceTypeConfig {\n\tconst { instanceId, clusterId }: { instanceId?: string; clusterId?: string } = useParams({ strict: false });\n\treturn useMemo(\n\t\t() => getInstanceClientIdFromParams({ instanceId, clusterId, ...params }),\n\t\t[\n\t\t\tparams.instanceId ?? instanceId,\n\t\t\tparams.clusterId ?? clusterId,\n\t\t\tparams.operationsUrl,\n\t\t\tparams.port,\n\t\t\tparams.secure,\n\t\t\tparams.disableFabricConnect,\n\t\t\tparams.forceFabricConnect,\n\t\t],\n\t);\n}\n\nexport function getInstanceClientIdFromParams({\n\tinstanceId,\n\tclusterId,\n\t...params\n}: UseParams): InstanceClientIdConfig & InstanceTypeConfig {\n\tconst id = isLocalStudio ? OverallAppSignIn : instanceId ?? clusterId;\n\tif (!id) {\n\t\tthrow new Error('id could not be automatically calculated in useInstanceClientIdParams');\n\t}\n\treturn {\n\t\tinstanceClient: getInstanceClient({ id, ...params }),\n\t\tentityId: id,\n\t\tentityType: (isLocalStudio || instanceId) ? 'instance' : 'cluster',\n\t};\n}\n","export function excludeFalsy<T>(item: T | undefined | 0 | false | null): item is T {\n\treturn !!item;\n}\n","/** The only part of React Query's `Query` this wrapper reads. Typed structurally\n * (rather than as `Query`) because `Query` is invariant in its data type, so a\n * concrete `Query<StatusResponse, …>` will not accept a `(query: Query) => …`\n * callback. A supertype parameter accepts every instantiation. */\ninterface QueryErrorState {\n\tstate: { error: unknown };\n}\n\n/** HTTP status off an axios-style error, tolerating both the axios shape\n * (`error.response.status`) and a bare `{ status }`. */\nfunction errorStatus(err: unknown): number | undefined {\n\treturn (err as { response?: { status?: number } })?.response?.status\n\t\t?? (err as { status?: number })?.status;\n}\n\n/** A 403 means the caller is authenticated but not permitted on this resource.\n * Unlike a 401 (session lost — the auth layer clears auth and redirects), a 403\n * is stable: the same request will keep failing until permissions change, so\n * repeating it is pure waste. */\nexport function isForbiddenError(err: unknown): boolean {\n\treturn errorStatus(err) === 403;\n}\n\n/** A rejection the server will repeat verbatim for an unchanged request.\n *\n * 400 — the request itself was refused by a validator/parser, not work that failed\n * partway. Studio sends operations whose shape depends on the target's Harper build\n * (unknown metric names, `bucket_ms`, operations a pre-4.6 instance doesn't\n * implement), so a poll can 400 on every tick indefinitely.\n * 403 — authenticated but not permitted; stable until permissions change.\n *\n * Both are deterministic, so an *immediate* retry of the same request can only\n * produce the same status. This is deliberately narrower than \"all 4xx\": a 401 is\n * resolved by the auth layer re-authenticating, and 404/409 can reflect a resource\n * that is still being created. */\nexport function isDeterministicRejection(err: unknown): boolean {\n\tconst status = errorStatus(err);\n\treturn status === 400 || status === 403;\n}\n\n/**\n * Wrap a fixed poll interval so polling STOPS once the endpoint answers 403.\n *\n * `refetchInterval` fires on a timer regardless of the query's error state, so a\n * poll against a resource the user may not touch retries forever. On 2026-07-27 a\n * single session sat on `/$organizationId/$clusterId/instances/` for ~58 minutes\n * while three 10s polls — `GET /Cluster/{id}` and `POST /HDBInstance/{id}/operation`\n * for two instances — all 403'd: ~1,045 doomed requests and 525 handled errors, each\n * one a `console.error` + a toast through the global React Query error handler\n * (`queryClient.ts`). That one session was 525 of the 526 403s Studio reported to RUM\n * that day. 403s are deliberately kept in RUM (see `shouldKeepEvent`), so an\n * unbounded 403 poll also drowns real signal in Error Tracking.\n *\n * Stopping is not permanent: returning `false` only cancels the *timer*. The query\n * still refetches on remount and on window focus (`refetchOnWindowFocus` defaults to\n * true), so if the user is granted access the UI recovers on their next interaction\n * without a reload — it just no longer hammers the endpoint in the background.\n *\n * Only 403 stops the timer. 5xx, network failures, and timeouts are transient\n * (instance restarting, unreachable) and should keep polling so the UI self-heals.\n *\n * A 400 deliberately does NOT stop the timer, even though it is just as\n * deterministic (`isDeterministicRejection`). Halting on it would freeze a poll\n * whose 400 came from state that is still settling — a certificate challenge\n * mid-provision, an argument derived from a not-yet-loaded resource — until the user\n * remounts or refocuses the tab. `retryUnlessRejected` removes the retry\n * amplification instead, which is the part that is waste either way. Whether the\n * timer itself should stop on a *sustained* 400 is open in #1569.\n */\nexport function pollUnlessForbidden(interval: number | false | undefined) {\n\treturn (query: QueryErrorState) => (isForbiddenError(query.state.error) ? false : (interval ?? false));\n}\n\n/**\n * `retry` predicate that gives up immediately on a deterministic rejection (400 /\n * 403) but otherwise keeps React Query's default retry count.\n *\n * For 403 this is what makes `pollUnlessForbidden` engage on the FIRST one.\n * `state.error` is only populated once retries are exhausted (until then the failure\n * lives in `failureReason`), so on a query left at the default `retry: 3` the poll\n * timer cannot see the 403 until three more doomed requests have gone out — ~30s\n * later on a query that also sets `retryDelay: 10_000`.\n *\n * For 400 the poll timer deliberately keeps running (see `pollUnlessForbidden`) —\n * this only removes the retry amplification, which is worth two distinct things:\n *\n * - On the five callers that leave `retryDelay` at React Query's default\n * exponential backoff (1s/2s/4s), a 400ing tick spent 4 requests inside ~7s.\n * Those become 1.\n * - On `getStatus`, which pins `retryDelay: 10_000`, the request *rate* was already\n * one per interval, so nothing is saved there — what changes is latency to\n * visibility: the 400 reaches `state.error`, the error handler, and the UI on the\n * first request rather than ~30s later.\n *\n * RUM (2026-08-07) motivates it: 26 first-party 400s in 24h against a ~1–3/day\n * baseline, one page re-issuing the same rejected operation every ~60s for half an\n * hour.\n *\n * `failureCount < maxRetries` is exactly the semantics of the numeric form\n * (`retry: 3`), so transient failures keep the retry behavior they had before.\n */\nexport function retryUnlessRejected(maxRetries = 3) {\n\treturn (failureCount: number, error: unknown) => !isDeterministicRejection(error) && failureCount < maxRetries;\n}\n"],"mappings":"mNAiBA,SAAgB,EACf,EAAoB,CAAC,EACpB,CACD,GAAM,CAAE,aAAY,aAA2D,EAAU,CAAE,OAAQ,EAAM,CAAC,EAE1G,OAAO,EAAkB,CAAE,GADA,EACI,GAAG,CAAO,CAAC,CAC3C,CAEA,SAAgB,EACf,EAAoB,CAAC,EACuB,CAC5C,GAAM,CAAE,aAAY,aAA2D,EAAU,CAAE,OAAQ,EAAM,CAAC,EAE1G,MAAO,CACN,eAAgB,EAAkB,CAAE,GAFV,EAEc,GAAG,CAAO,CAAC,EACnD,WAA4C,UAC7C,CACD,CAEA,SAAgB,EACf,EAAoB,CAAC,EACyB,CAC9C,GAAM,CAAE,aAAY,aAA2D,EAAU,CAAE,OAAQ,EAAM,CAAC,EAC1G,OAAA,EAAA,EAAA,QAAA,KACO,EAA8B,CAAE,aAAY,YAAW,GAAG,CAAO,CAAC,EACxE,CACC,EAAO,YAAc,EACrB,EAAO,WAAa,EACpB,EAAO,cACP,EAAO,KACP,EAAO,OACP,EAAO,qBACP,EAAO,kBACR,CACD,CACD,CAEA,SAAgB,EAA8B,CAC7C,aACA,YACA,GAAG,GACuD,CAC1D,IAAM,EAAqB,EAC3B,GAAI,CAAC,EACJ,MAAU,MAAM,uEAAuE,EAExF,MAAO,CACN,eAAgB,EAAkB,CAAE,KAAI,GAAG,CAAO,CAAC,EACnD,SAAU,EACV,WAA4C,UAC7C,CACD,CCpEA,SAAgB,EAAgB,EAAmD,CAClF,MAAO,CAAC,CAAC,CACV,CCQA,SAAS,EAAY,EAAkC,CACtD,OAAQ,GAA4C,UAAU,QACzD,GAA6B,MACnC,CAMA,SAAgB,EAAiB,EAAuB,CACvD,OAAO,EAAY,CAAG,IAAM,GAC7B,CAcA,SAAgB,EAAyB,EAAuB,CAC/D,IAAM,EAAS,EAAY,CAAG,EAC9B,OAAO,IAAW,KAAO,IAAW,GACrC,CA+BA,SAAgB,EAAoB,EAAsC,CACzE,MAAQ,IAA4B,EAAiB,EAAM,MAAM,KAAK,EAAI,GAAS,GAAY,EAChG,CA8BA,SAAgB,EAAoB,EAAa,EAAG,CACnD,OAAQ,EAAsB,IAAmB,CAAC,EAAyB,CAAK,GAAK,EAAe,CACrG"}
|
|
@@ -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{
|
|
2
|
-
//# sourceMappingURL=profile-
|
|
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{Zn as g,an as _,cn as v,dn as y,in as b,ln as x,on as S,pn as C,un as w}from"./index-Sevt3MVx.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.`}),C(),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)(y,{...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)(x,{control:s,name:`firstname`,render:({field:e})=>(0,k.jsxs)(v,{children:[(0,k.jsx)(S,{className:`pb-1`,children:`First Name`}),(0,k.jsx)(w,{children:(0,k.jsx)(b,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,autoFocus:!0,...e})}),(0,k.jsx)(_,{})]})}),(0,k.jsx)(x,{control:s,name:`lastname`,render:({field:e})=>(0,k.jsxs)(v,{children:[(0,k.jsx)(S,{className:`pb-1`,children:`Last Name`}),(0,k.jsx)(w,{children:(0,k.jsx)(b,{type:`text`,className:`dark:bg-black dark:border-black`,autoCapitalize:`words`,...e})}),(0,k.jsx)(_,{})]})}),(0,k.jsxs)(v,{children:[(0,k.jsx)(S,{htmlFor:`profile-email`,className:`pb-1`,children:`Email`}),(0,k.jsx)(w,{children:(0,k.jsx)(b,{id:`profile-email`,type:`email`,enterKeyHint:`next`,autoComplete:`email`,autoCapitalize:`none`,value:i?.email||``,disabled:!0,readOnly:!0})})]}),(0,k.jsx)(x,{control:s,name:`newPassword`,render:({field:e})=>(0,k.jsxs)(v,{children:[(0,k.jsx)(S,{className:`pb-1`,children:`New Password`}),(0,k.jsx)(w,{children:(0,k.jsx)(b,{type:`password`,placeholder:`Optional`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(_,{})]})}),(0,k.jsx)(x,{control:s,name:`confirmNewPassword`,render:({field:e})=>(0,k.jsxs)(v,{children:[(0,k.jsx)(S,{className:`pb-1`,children:`Confirm New Password`}),(0,k.jsx)(w,{children:(0,k.jsx)(b,{type:`password`,className:`dark:bg-black dark:border-black`,autoComplete:`new-password`,autoCapitalize:`none`,...e})}),(0,k.jsx)(_,{})]})}),(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-DzDpRLHY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-DUfEPQtx.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-DzDpRLHY.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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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{L as e,R as t,z as n}from"./vendor-tanstack-0SjDjtT0.js";import{Rt as r}from"./vendor-ui-Bj22lHGK.js";import{t as i}from"./errorText-NpBmvk9I.js";function a(e){let t=`Error`,n=`We had some trouble!`,a=!0;console.error(e);let o=e,s=e;if(typeof e==`string`)n=e;else if(o?.response?.data){let e=o.response.data;if(typeof e==`string`)n=e;else if(typeof e.title==`string`&&e.title){typeof e.code==`string`&&e.code&&(t=e.code);let r=i(e.detail);n=r?`${e.title}: ${r}`:e.title,a=!1}else n=i(e.error)??i(e.message)??n}else n=i(s?.message)??n;if(a&&n.includes(`:`)&&!n.startsWith(`{`)&&!n.startsWith(`[`)){let e=n.split(`:`);t=e.shift(),n=e.join(`:`)}let c=o?.code===`ECONNABORTED`||o?.code===`ETIMEDOUT`,l=o?.response?.status===403;r.error(t,{id:c?`request-timeout`:l?`request-forbidden`:void 0,description:n,action:{label:`Dismiss`,onClick:()=>r.dismiss()}})}var o=new e({queryCache:new t({onError:a}),mutationCache:new n({onError:(e,t,n,r)=>{r.meta?.skipGlobalErrorToast||a(e)}})});export{o as n,a as t};
|
|
2
|
+
//# sourceMappingURL=queryClient-CgtkoiCY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryClient-CgtkoiCY.js","names":[],"sources":["../../src/react-query/queryClient.ts"],"sourcesContent":["import { errorText } from '@/lib/errorText';\nimport { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query';\nimport { AxiosError } from 'axios';\nimport { toast } from 'sonner';\n\nexport function errorHandler(rawErr: unknown) {\n\tlet errorTitle = 'Error';\n\tlet errorMsg = 'We had some trouble!';\n\tlet splitTitleFromMsg = true;\n\tconsole.error(rawErr);\n\tconst axiosWrappedErr = rawErr as AxiosError<\n\t\tstring | { error?: unknown; message?: unknown; code?: unknown; title?: unknown; detail?: unknown }\n\t>;\n\tconst otherErr = rawErr as { message?: unknown };\n\tif (typeof rawErr === 'string') {\n\t\terrorMsg = rawErr;\n\t} else if (axiosWrappedErr?.response?.data) {\n\t\tconst data = axiosWrappedErr.response.data;\n\t\tif (typeof data === 'string') {\n\t\t\terrorMsg = data;\n\t\t} else if (typeof data.title === 'string' && data.title) {\n\t\t\t// Harper 5 REST errors are RFC 9457 Problem Details: the \"Code: message\" string\n\t\t\t// became { code, title, detail? }. Map code → toast title and title (+ detail) →\n\t\t\t// description. The title is a plain sentence that may itself contain colons\n\t\t\t// (\"Plan not found: plan-123\"), so skip the \"Title: detail\" split below.\n\t\t\tif (typeof data.code === 'string' && data.code) {\n\t\t\t\terrorTitle = data.code;\n\t\t\t}\n\t\t\tconst detail = errorText(data.detail);\n\t\t\terrorMsg = detail ? `${data.title}: ${detail}` : data.title;\n\t\t\tsplitTitleFromMsg = false;\n\t\t} else {\n\t\t\t// `error`/`message` can be a structured object (e.g. Harper's deploy failures) —\n\t\t\t// extract its nested message (or JSON) rather than showing \"[object Object]\" (#1426).\n\t\t\terrorMsg = errorText(data.error) ?? errorText(data.message) ?? errorMsg;\n\t\t}\n\t} else {\n\t\terrorMsg = errorText(otherErr?.message) ?? errorMsg;\n\t}\n\t// The JSON fallback from errorText produces messages full of colons that are not\n\t// \"Title: detail\" shaped — don't split those.\n\tif (splitTitleFromMsg && errorMsg.includes(':') && !errorMsg.startsWith('{') && !errorMsg.startsWith('[')) {\n\t\tconst split = errorMsg.split(':');\n\t\terrorTitle = split.shift()!;\n\t\terrorMsg = split.join(':');\n\t}\n\t// Axios surfaces request timeouts as ECONNABORTED / ETIMEDOUT. Multiple\n\t// queries can timeout in parallel and stack up identical toasts; collapse\n\t// them onto a single id so the user sees one instead of a wall.\n\tconst isTimeout = axiosWrappedErr?.code === 'ECONNABORTED' || axiosWrappedErr?.code === 'ETIMEDOUT';\n\t// Same collapse for 403s. `pollUnlessForbidden` stops polls that 403, but other\n\t// repeat sources remain (route preloads and background queries firing while\n\t// signed out, #1546), and a permission failure repeated N times is still one\n\t// thing for the user to know.\n\tconst isForbidden = axiosWrappedErr?.response?.status === 403;\n\ttoast.error(errorTitle, {\n\t\tid: isTimeout ? 'request-timeout' : isForbidden ? 'request-forbidden' : undefined,\n\t\tdescription: errorMsg,\n\t\taction: {\n\t\t\tlabel: 'Dismiss',\n\t\t\tonClick: () => toast.dismiss(),\n\t\t},\n\t});\n}\n\nexport const queryClient = new QueryClient({\n\tqueryCache: new QueryCache({\n\t\tonError: errorHandler,\n\t}),\n\tmutationCache: new MutationCache({\n\t\t// Every mutation error routes through the shared toast by default. A mutation can opt out\n\t\t// — to render its own inline UI or redirect instead — with `meta: { skipGlobalErrorToast: true }`\n\t\t// (e.g. the cloud login flow redirects an unverified user to the email-verification page).\n\t\tonError: (error, _variables, _context, mutation) => {\n\t\t\tif (mutation.meta?.skipGlobalErrorToast) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\terrorHandler(error);\n\t\t},\n\t}),\n});\n"],"mappings":"yJAKA,SAAgB,EAAa,EAAiB,CAC7C,IAAI,EAAa,QACb,EAAW,uBACX,EAAoB,GACxB,QAAQ,MAAM,CAAM,EACpB,IAAM,EAAkB,EAGlB,EAAW,EACjB,GAAI,OAAO,GAAW,SACrB,EAAW,OACL,GAAI,GAAiB,UAAU,KAAM,CAC3C,IAAM,EAAO,EAAgB,SAAS,KACtC,GAAI,OAAO,GAAS,SACnB,EAAW,OACL,GAAI,OAAO,EAAK,OAAU,UAAY,EAAK,MAAO,CAKpD,OAAO,EAAK,MAAS,UAAY,EAAK,OACzC,EAAa,EAAK,MAEnB,IAAM,EAAS,EAAU,EAAK,MAAM,EACpC,EAAW,EAAS,GAAG,EAAK,MAAM,IAAI,IAAW,EAAK,MACtD,EAAoB,EACrB,KAGC,GAAW,EAAU,EAAK,KAAK,GAAK,EAAU,EAAK,OAAO,GAAK,CAEjE,KACC,GAAW,EAAU,GAAU,OAAO,GAAK,EAI5C,GAAI,GAAqB,EAAS,SAAS,GAAG,GAAK,CAAC,EAAS,WAAW,GAAG,GAAK,CAAC,EAAS,WAAW,GAAG,EAAG,CAC1G,IAAM,EAAQ,EAAS,MAAM,GAAG,EAChC,EAAa,EAAM,MAAM,EACzB,EAAW,EAAM,KAAK,GAAG,CAC1B,CAIA,IAAM,EAAY,GAAiB,OAAS,gBAAkB,GAAiB,OAAS,YAKlF,EAAc,GAAiB,UAAU,SAAW,IAC1D,EAAM,MAAM,EAAY,CACvB,GAAI,EAAY,kBAAoB,EAAc,oBAAsB,IAAA,GACxE,YAAa,EACb,OAAQ,CACP,MAAO,UACP,YAAe,EAAM,QAAQ,CAC9B,CACD,CAAC,CACF,CAEA,IAAa,EAAc,IAAI,EAAY,CAC1C,WAAY,IAAI,EAAW,CAC1B,QAAS,CACV,CAAC,EACD,cAAe,IAAI,EAAc,CAIhC,SAAU,EAAO,EAAY,EAAU,IAAa,CAC/C,EAAS,MAAM,sBAGnB,EAAa,CAAK,CACnB,CACD,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,b as n,c as r,l as i,v as a}from"./vendor-core-xUefYpUO.js";import{i as o,t as s}from"./button-oQgW4t1x.js";import{A as c,I as l,N as u,j as d}from"./vendor-tanstack-0SjDjtT0.js";import{a as f}from"./vendor-datadog-DyjkTkvg.js";import{r as p}from"./vendor-react-DeL8Gtgl.js";import{$ as m,Rt as h,it as g}from"./vendor-ui-Bj22lHGK.js";import{c as _,d as v,i as y,l as b,n as x,o as S,p as C,s as w,t as T,u as ee}from"./select-y6NKMkG_.js";import{c as E,i as D,n as O,o as k,r as A,s as j,t as M}from"./table-DpOjNQHt.js";import{r as N,t as P}from"./x-C3uc0qMD.js";import{Bn as te,Mn as ne,Nn as re,an as F,cn as I,dn as L,gn as ie,hn as ae,in as R,jn as oe,kn as z,ln as B,mn as se,on as V,or as ce,tr as H,un as U}from"./index-Sevt3MVx.js";var W=e(f(),1),G=p();function K({options:e,selected:t,onChange:n,placeholder:r=`Select…`,emptyText:i=`No options`,ariaLabel:a,disabled:o,id:c,allowRepeats:l,maxVisibleOptions:u}){let[d,f]=(0,W.useState)(!1),[p,m]=(0,W.useState)(``),h=(0,W.useRef)(null),g=(0,W.useRef)(null),_=(0,W.useMemo)(()=>new Set(t),[t]),v=(0,W.useMemo)(()=>new Map(e.map(e=>[e.value,e.label])),[e]);(0,W.useEffect)(()=>{if(!d)return;let e=0,t=requestAnimationFrame(()=>{e=requestAnimationFrame(()=>h.current?.focus())});return()=>{cancelAnimationFrame(t),cancelAnimationFrame(e)}},[d]);let y=(0,W.useMemo)(()=>{let t=p.trim().toLowerCase();return t?e.filter(e=>e.label.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)):e},[e,p]),b=u?y.slice(0,u):y,x=y.length-b.length,S=e=>{l?n([...t,e]):_.has(e)?n(t.filter(t=>t!==e)):n([...t,e])},C=e=>n(t.filter((t,n)=>n!==e)),w=e=>{let t=g.current?.querySelectorAll(`[role="menuitemcheckbox"]:not([data-disabled])`);t?.length&&(e===`first`?t[0]:t[t.length-1]).focus()};return(0,G.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,G.jsxs)(oe,{open:d,onOpenChange:e=>{f(e),e||m(``)},children:[(0,G.jsx)(te,{asChild:!0,disabled:o,children:(0,G.jsxs)(s,{id:c,type:`button`,variant:`outline`,"aria-label":a,className:`w-full justify-between font-normal`,children:[(0,G.jsx)(`span`,{className:t.length?`truncate`:`truncate text-muted-foreground`,children:t.length?`${t.length} selected`:r}),(0,G.jsx)(N,{className:`size-4 shrink-0 opacity-60`})]})}),(0,G.jsxs)(re,{ref:g,className:`w-(--radix-dropdown-menu-trigger-width) max-h-72 overflow-y-auto`,align:`start`,children:[(0,G.jsx)(`input`,{ref:h,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault(),w(e.key===`ArrowDown`?`first`:`last`);return}e.key.length===1&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.stopPropagation()},placeholder:`Filter…`,"aria-label":`Filter options`,className:`mb-1 w-full rounded-md border bg-transparent px-2 py-1 text-sm outline-none`}),y.length===0?(0,G.jsx)(`div`,{className:`px-2 py-1.5 text-sm text-muted-foreground`,children:i}):b.map(e=>(0,G.jsx)(ne,{checked:_.has(e.value),onCheckedChange:()=>S(e.value),onSelect:e=>e.preventDefault(),children:e.label},e.value)),x>0&&(0,G.jsxs)(`div`,{className:`px-2 py-1.5 text-xs text-muted-foreground`,children:[x,` more — keep typing to narrow`]})]})]}),t.length>0&&(0,G.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:t.map((e,t)=>{let n=v.get(e)??e;return(0,G.jsxs)(z,{variant:`secondary`,className:`gap-1`,children:[n,(0,G.jsx)(`button`,{type:`button`,"aria-label":`Remove ${n}`,onClick:()=>C(t),className:`ml-0.5 rounded-sm hover:text-destructive`,children:(0,G.jsx)(P,{className:`size-3`})})]},`${e}-${t}`)})})]})}async function le(e){let{data:t}=await o.post(`/Admin/Region/`,e);return t}function ue(){return c({mutationFn:le})}async function de({id:e,changes:t}){let{data:n}=await o.patch(`/Admin/Region/${e}`,t);return n}function fe(){return c({mutationFn:de})}async function pe(){let{data:e}=await o.get(`/Location/`);return e}var me=[`fabric-admin`,`locations`];function he(){return d({queryKey:me,queryFn:pe,retry:!1})}function q(e,t){return t?`${e} (${t})`:e}async function ge(){let e=[];for(let t=0;t<40;t++){let n=t*500,r=[`status=ne=DELETED`,`sort(name)`,`limit(${n},${n+500})`].join(`&`),{data:i}=await o.get(`/Admin/Organization/?${r}`),a=i;if(e.push(...a),a.length<500)return{organizations:e,truncated:!1}}return{organizations:e,truncated:!0}}var _e=[`fabric-admin`,`organizations`];function J(){return d({queryKey:_e,queryFn:ge,retry:!1})}async function ve(){let{data:e}=await o.get(`/Admin/Region/`);return e}var Y=[`fabric-admin`,`regions`];function X(){return d({queryKey:Y,queryFn:ve,retry:!1})}var Z=a({id:n().trim().min(1,`ID is required`).regex(/^[a-z0-9-]+$/,`Use lowercase letters, numbers, and hyphens only`),region:n().trim().min(1,`Region is required`),instanceCount:t({error:`Enter a whole number`}).int(`Must be a whole number`).min(1,`Must be at least 1`),purchasedBlockMultiplier:t({error:`Enter a whole number`}).int(`Must be a whole number`).min(1,`Must be at least 1`),latencyDescription:n().trim().min(1,`Latency description is required`),linodePreferredLocations:r(n()),gcpPreferredLocations:r(n()),forceLocations:i(),active:i(),organizationIds:r(n())}).superRefine((e,t)=>{e.forceLocations&&!e.linodePreferredLocations.length&&!e.gcpPreferredLocations.length&&t.addIssue({code:`custom`,path:[`forceLocations`],message:`Add at least one preferred location, or turn off Force locations`})}),ye=100;function Q(e){return{id:e?.id??``,region:e?.region??``,instanceCount:e?.instanceCount??1,purchasedBlockMultiplier:e?.purchasedBlockMultiplier??1,latencyDescription:e?.latencyDescription??``,linodePreferredLocations:e?.linodePreferredLocations??[],gcpPreferredLocations:e?.gcpPreferredLocations??[],forceLocations:e?.forceLocations??!1,active:e?.active??!0,organizationIds:e?.organizationIds??[]}}function be({open:e,onOpenChange:t,region:n}){let r=!!n,i=l(),{data:a=[]}=u({...he(),enabled:e}),{data:o}=u({...J(),enabled:e}),c=o?.organizations??[],{data:d=[]}=u({...X(),enabled:e}),{mutate:f,isPending:p}=ue(),{mutate:E,isPending:D}=fe(),O=p||D,k=(0,W.useMemo)(()=>a.filter(e=>e.cloudProvider===`linode`).map(e=>({value:e.location,label:`${e.locationName} (${e.location})`})),[a]),A=(0,W.useMemo)(()=>a.filter(e=>e.cloudProvider===`gcp`).map(e=>({value:e.location,label:`${e.locationName} (${e.location})`})),[a]),j=(0,W.useMemo)(()=>c.map(e=>({value:e.id,label:q(e.id,e.name)})),[c]),M=(0,W.useMemo)(()=>{let e=new Set;for(let t of a)for(let n of t.regions??[])e.add(n);return n?.region&&e.add(n.region),[...e].sort()},[a,n]),N=g({resolver:m(Z),defaultValues:Q(n)});(0,W.useEffect)(()=>{e&&N.reset(Q(n))},[e,n,N]);let P=e=>{let a=e=>e.trim().toLowerCase(),o=!n||a(n.latencyDescription)!==a(e.latencyDescription),s=d.filter(e=>e.id!==n?.id);if(o&&s.some(t=>a(t.latencyDescription)===a(e.latencyDescription))){N.setError(`latencyDescription`,{message:`A region with this latency description already exists`});return}let c=e.organizationIds.length>0?e.organizationIds:null,l=()=>{h.success(r?`Region updated`:`Region created`),i.invalidateQueries({queryKey:Y}),t(!1)};if(n){let{id:t,...r}=e;E({id:n.id,changes:{...r,organizationIds:c}},{onSuccess:l})}else f({...e,organizationIds:c},{onSuccess:l})};return(0,G.jsx)(_,{open:e,onOpenChange:t,children:(0,G.jsxs)(b,{className:`max-w-2xl`,children:[(0,G.jsx)(C,{children:r?`Edit region`:`Create region`}),(0,G.jsx)(ee,{children:r?`Update this region. Its ID is fixed once created.`:`Define a new deployment region. Leave organizations empty to make it public (all organizations).`}),(0,G.jsx)(L,{...N,children:(0,G.jsxs)(`form`,{className:`my-4 flex flex-col gap-4`,onSubmit:N.handleSubmit(P),children:[(0,G.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 sm:grid-cols-2 items-start`,children:[(0,G.jsx)(B,{control:N.control,name:`id`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Region ID`}),(0,G.jsx)(U,{children:(0,G.jsx)(R,{placeholder:`e.g. us-east-1`,...e,disabled:r})}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`region`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Region`}),(0,G.jsx)(U,{children:(0,G.jsxs)(T,{value:e.value,onValueChange:e.onChange,children:[(0,G.jsx)(S,{className:`w-full`,children:(0,G.jsx)(w,{placeholder:`Select a region`})}),(0,G.jsx)(x,{children:M.map(e=>(0,G.jsx)(y,{value:e,children:e},e))})]})}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`instanceCount`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Instance count`}),(0,G.jsx)(U,{children:(0,G.jsx)(R,{type:`number`,min:1,step:1,name:e.name,ref:e.ref,onBlur:e.onBlur,value:Number.isFinite(e.value)?e.value:``,onChange:t=>e.onChange(t.target.valueAsNumber)})}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`purchasedBlockMultiplier`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 pb-1`,children:[(0,G.jsx)(V,{className:`!pb-0`,children:`Purchased block multiplier`}),(0,G.jsxs)(se,{children:[(0,G.jsx)(ie,{asChild:!0,children:(0,G.jsx)(`button`,{type:`button`,"aria-label":`What is the purchased block multiplier?`,className:`text-muted-foreground hover:text-foreground`,children:(0,G.jsx)(ce,{className:`size-3.5`})})}),(0,G.jsx)(ae,{className:`max-w-xs`,children:`How many purchased blocks a cluster in this region is billed for. One block covers a baseline cluster: a 2-node cluster is 1 block and a 4-node cluster is 2 blocks. Each block carries one license against the selected plan's limits; once they're all used up, this many are issued and billed again.`})]})]}),(0,G.jsx)(U,{children:(0,G.jsx)(R,{type:`number`,min:1,step:1,name:e.name,ref:e.ref,onBlur:e.onBlur,value:Number.isFinite(e.value)?e.value:``,onChange:t=>e.onChange(t.target.valueAsNumber)})}),(0,G.jsx)(F,{})]})})]}),(0,G.jsx)(B,{control:N.control,name:`latencyDescription`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Latency description`}),(0,G.jsx)(U,{children:(0,G.jsx)(R,{placeholder:`e.g. 280ms, medium distribution`,...e})}),(0,G.jsx)(F,{})]})}),(0,G.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 sm:grid-cols-2 items-start`,children:[(0,G.jsx)(B,{control:N.control,name:`linodePreferredLocations`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Linode preferred locations`}),(0,G.jsx)(U,{children:(0,G.jsx)(K,{options:k,selected:e.value,onChange:e.onChange,placeholder:`Any Linode location`,emptyText:`No Linode locations`,ariaLabel:`Linode preferred locations`,allowRepeats:!0})}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`gcpPreferredLocations`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`GCP preferred locations`}),(0,G.jsx)(U,{children:(0,G.jsx)(K,{options:A,selected:e.value,onChange:e.onChange,placeholder:`Any GCP location`,emptyText:`No GCP locations`,ariaLabel:`GCP preferred locations`,allowRepeats:!0})}),(0,G.jsx)(F,{})]})})]}),(0,G.jsx)(B,{control:N.control,name:`forceLocations`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(U,{children:(0,G.jsx)(`input`,{type:`checkbox`,className:`size-4`,checked:e.value,onChange:t=>e.onChange(t.target.checked)})}),(0,G.jsx)(V,{className:`!pb-0`,children:`Force locations`})]}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Pin deployments to the preferred locations above instead of treating them as hints.`}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`active`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(U,{children:(0,G.jsx)(`input`,{type:`checkbox`,className:`size-4`,checked:e.value,onChange:t=>e.onChange(t.target.checked)})}),(0,G.jsx)(V,{className:`!pb-0`,children:`Active`})]}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Inactive regions stay available to existing deployments but aren't offered for new ones.`}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(B,{control:N.control,name:`organizationIds`,render:({field:e})=>(0,G.jsxs)(I,{children:[(0,G.jsx)(V,{className:`pb-1`,children:`Organizations (customer scope)`}),(0,G.jsx)(U,{children:(0,G.jsx)(K,{options:j,selected:e.value,onChange:e.onChange,placeholder:`Public — all organizations`,emptyText:`No organizations`,ariaLabel:`Organizations`,maxVisibleOptions:ye})}),o?.truncated&&(0,G.jsx)(`p`,{className:`text-xs text-destructive`,children:`Too many organizations to list them all — some may be missing from this picker.`}),(0,G.jsx)(F,{})]})}),(0,G.jsx)(v,{children:(0,G.jsxs)(`div`,{className:`flex w-full justify-between`,children:[(0,G.jsx)(s,{variant:`destructiveOutline`,type:`button`,onClick:()=>t(!1),disabled:O,children:`Cancel`}),(0,G.jsx)(s,{variant:`submit`,disabled:O,children:O?`Saving…`:r?`Save changes`:`Create region`})]})})]})})]})})}function $({organizationIds:e,orgNameById:t}){return e==null||e.length===0?(0,G.jsx)(G.Fragment,{children:`Public`}):(0,G.jsx)(`div`,{className:`flex flex-col gap-0.5`,children:e.map(e=>(0,G.jsx)(`span`,{className:`break-words`,children:q(e,t.get(e))},e))})}function xe(){let{data:e,isLoading:t,isError:n}=u(X()),{data:r}=u(J()),[i,a]=(0,W.useState)(!1),[o,c]=(0,W.useState)(null),[l,d]=(0,W.useState)(``),f=(0,W.useMemo)(()=>new Map((r?.organizations??[]).map(e=>[e.id,e.name])),[r]),p=(0,W.useMemo)(()=>{let t=l.trim().toLowerCase();return!t||!e?e??[]:e.filter(e=>e.region.toLowerCase().includes(t)||e.id.toLowerCase().includes(t)||e.latencyDescription.toLowerCase().includes(t)||(e.organizationIds??[]).some(e=>e.toLowerCase().includes(t)||(f.get(e)??``).toLowerCase().includes(t)))},[e,l,f]),m=()=>{c(null),a(!0)},h=e=>{c(e),a(!0)};return(0,G.jsxs)(`div`,{className:`max-w-4xl`,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:`Regions`}),(0,G.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:`Deployment regions customers can provision into. A region scoped to organizations is only offered to those customers; otherwise it's available to everyone.`})]}),(0,G.jsxs)(s,{variant:`submit`,onClick:m,className:`shrink-0`,children:[(0,G.jsx)(H,{}),`Create region`]})]}),(0,G.jsx)(`div`,{className:`mt-6`,children:t?(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Loading regions…`}):n?(0,G.jsx)(`p`,{className:`text-sm text-destructive`,children:`Couldn't load regions.`}):!e||e.length===0?(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No regions yet. Create one to get started.`}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(R,{value:l,onChange:e=>d(e.target.value),placeholder:`Filter by ID, region, description, or organization…`,"aria-label":`Filter regions`,className:`mb-4 max-w-md`}),p.length===0?(0,G.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`No regions match “`,l,`”.`]}):(0,G.jsxs)(M,{children:[(0,G.jsx)(k,{children:(0,G.jsxs)(j,{children:[(0,G.jsx)(D,{children:`ID`}),(0,G.jsx)(D,{children:`Region`}),(0,G.jsx)(D,{className:`text-right pr-6`,children:`Instances`}),(0,G.jsx)(D,{children:`Description`}),(0,G.jsx)(D,{children:`Scope`}),(0,G.jsx)(D,{className:`w-0`})]})}),(0,G.jsx)(O,{children:p.map(e=>(0,G.jsxs)(j,{className:e.active===!1?`opacity-60`:void 0,children:[(0,G.jsx)(A,{className:`font-mono font-medium`,children:(0,G.jsxs)(`span`,{className:`inline-flex items-center gap-2`,children:[e.id,e.active===!1&&(0,G.jsx)(z,{variant:`secondary`,className:`text-[10px]`,children:`Inactive`})]})}),(0,G.jsx)(A,{children:e.region}),(0,G.jsx)(A,{className:`text-right pr-6`,children:e.instanceCount}),(0,G.jsx)(A,{className:`text-muted-foreground`,children:e.latencyDescription}),(0,G.jsx)(A,{children:(0,G.jsx)($,{organizationIds:e.organizationIds,orgNameById:f})}),(0,G.jsx)(A,{className:`text-right`,children:(0,G.jsx)(s,{variant:`ghost`,size:`icon`,"aria-label":`Edit ${e.id}`,onClick:()=>h(e),children:(0,G.jsx)(E,{})})})]},e.id))})]})]})}),(0,G.jsx)(be,{open:i,onOpenChange:a,region:o})]})}export{$ as RegionScope,xe as RegionsIndex};
|
|
2
|
+
//# sourceMappingURL=regions-DpJ8s7iN.js.map
|