@cobaltcore-dev/aurora 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/client/{ContentHeader-DqsGNvtD.mjs → ContentHeader-C51H95X8.mjs} +9 -5
  2. package/dist/client/ContentHeader-C51H95X8.mjs.map +1 -0
  3. package/dist/client/{_flavorId-B9Vqkraj.mjs → _flavorId-DU4gcFna.mjs} +2 -2
  4. package/dist/client/{_flavorId-B9Vqkraj.mjs.map → _flavorId-DU4gcFna.mjs.map} +1 -1
  5. package/dist/client/{_flavorId-CFpNGz52.mjs → _flavorId-iZE2j210.mjs} +3 -3
  6. package/dist/client/{_flavorId-CFpNGz52.mjs.map → _flavorId-iZE2j210.mjs.map} +1 -1
  7. package/dist/client/{_imageId-9NZytfNs.mjs → _imageId-zmaSymWe.mjs} +2 -2
  8. package/dist/client/{_imageId-9NZytfNs.mjs.map → _imageId-zmaSymWe.mjs.map} +1 -1
  9. package/dist/client/_projectId-B_2sZKk-.mjs.map +1 -1
  10. package/dist/client/{_projectId-cW9aQ4Ag.mjs → _projectId-C8BaEHUj.mjs} +9 -7
  11. package/dist/client/_projectId-C8BaEHUj.mjs.map +1 -0
  12. package/dist/client/_projectId-COt93OEF.mjs +84 -0
  13. package/dist/client/_projectId-COt93OEF.mjs.map +1 -0
  14. package/dist/client/{_storageType-2_fau4B5.mjs → _storageType-B-qGcGUQ.mjs} +52 -51
  15. package/dist/client/_storageType-B-qGcGUQ.mjs.map +1 -0
  16. package/dist/client/{_storageType-dRTFMKG3.mjs → _storageType-CepuevDG.mjs} +2 -2
  17. package/dist/client/{_storageType-dRTFMKG3.mjs.map → _storageType-CepuevDG.mjs.map} +1 -1
  18. package/dist/client/{flavors-_P7R-CeT.mjs → flavors-8bZVlzzb.mjs} +2 -2
  19. package/dist/client/{flavors-_P7R-CeT.mjs.map → flavors-8bZVlzzb.mjs.map} +1 -1
  20. package/dist/client/{flavors-m1qDHzeS.mjs → flavors-BfsEBUE-.mjs} +3 -3
  21. package/dist/client/{flavors-m1qDHzeS.mjs.map → flavors-BfsEBUE-.mjs.map} +1 -1
  22. package/dist/client/{images-CpM-T_jM.mjs → images-8FOgju2f.mjs} +2 -2
  23. package/dist/client/{images-CpM-T_jM.mjs.map → images-8FOgju2f.mjs.map} +1 -1
  24. package/dist/client/{images-DHmVgQAh2.mjs → images-BPnTuKFO2.mjs} +3 -3
  25. package/dist/client/{images-DHmVgQAh2.mjs.map → images-BPnTuKFO2.mjs.map} +1 -1
  26. package/dist/client/index.js +10 -10
  27. package/dist/client/index.js.map +1 -1
  28. package/dist/client/{pca-CK5-j7Kk.mjs → pca-5wOBf_KI.mjs} +3 -3
  29. package/dist/client/{pca-CK5-j7Kk.mjs.map → pca-5wOBf_KI.mjs.map} +1 -1
  30. package/dist/client/{pca-C8zWTSSt.mjs → pca-dhrOFfrE.mjs} +2 -2
  31. package/dist/client/{pca-C8zWTSSt.mjs.map → pca-dhrOFfrE.mjs.map} +1 -1
  32. package/dist/client/{projects-CeLhtLvf.mjs → projects-B_PPyZD1.mjs} +2 -2
  33. package/dist/client/{projects-CeLhtLvf.mjs.map → projects-B_PPyZD1.mjs.map} +1 -1
  34. package/dist/client/{projects-ClViaUuv.mjs → projects-Dmewygrp.mjs} +3 -3
  35. package/dist/client/projects-Dmewygrp.mjs.map +1 -0
  36. package/dist/client/{routeInfo-DlDJZnpg.mjs → routeInfo-CHiJfum5.mjs} +6 -5
  37. package/dist/client/routeInfo-CHiJfum5.mjs.map +1 -0
  38. package/dist/server/index.js +0 -40
  39. package/package.json +1 -1
  40. package/dist/client/ContentHeader-DqsGNvtD.mjs.map +0 -1
  41. package/dist/client/_projectId-CLgClx24.mjs +0 -84
  42. package/dist/client/_projectId-CLgClx24.mjs.map +0 -1
  43. package/dist/client/_projectId-cW9aQ4Ag.mjs.map +0 -1
  44. package/dist/client/_storageType-2_fau4B5.mjs.map +0 -1
  45. package/dist/client/projects-ClViaUuv.mjs.map +0 -1
  46. package/dist/client/routeInfo-DlDJZnpg.mjs.map +0 -1
@@ -2,7 +2,7 @@ import { t as e } from "./helpers-1PpYf-fC.mjs";
2
2
  import { createFileRoute as t, lazyRouteComponent as n, redirect as r } from "@tanstack/react-router";
3
3
  import { z as i } from "zod";
4
4
  //#region src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx
5
- var a = () => import("./_storageType-zeSZe--V.mjs"), o = () => import("./_storageType-2_fau4B5.mjs"), s = (t, n) => {
5
+ var a = () => import("./_storageType-zeSZe--V.mjs"), o = () => import("./_storageType-B-qGcGUQ.mjs"), s = (t, n) => {
6
6
  let { provider: i, projectId: a } = n, o = e(t);
7
7
  if (!o["object-store"]) throw r({
8
8
  to: "/projects/$projectId",
@@ -77,4 +77,4 @@ var a = () => import("./_storageType-zeSZe--V.mjs"), o = () => import("./_storag
77
77
  //#endregion
78
78
  export { l as t };
79
79
 
80
- //# sourceMappingURL=_storageType-dRTFMKG3.mjs.map
80
+ //# sourceMappingURL=_storageType-CepuevDG.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_storageType-dRTFMKG3.mjs","names":["createFileRoute","redirect","z","getServiceIndex","checkServiceAvailability","availableServices","type","name","params","projectId","provider","serviceIndex","to","hasSwift","Boolean","hasCeph","cephFallbackEnabled","hasEffectiveCeph","fallbackProvider","fallbackStorageType","storageType","containersSearchSchema","object","sortBy","enum","optional","sortDirection","search","string","Route","staticData","section","service","sectionCrumb","labelKey","crumb","useParamAsLabel","RouteInfo","validateSearch","head","match","meta","title","component","lazyRouteComponent","$$splitComponentImporter","notFoundComponent","$$splitNotFoundComponentImporter","loader","context","trpcClient","auth","getAvailableServices","query","client","beforeLoad"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx"],"sourcesContent":["import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { SwiftContainers } from \"../../-components/Swift/Containers\"\nimport { CephBuckets } from \"../../-components/Ceph/Buckets\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\n/**\n * Validates that the requested storage provider is available for the given project,\n * and redirects to an appropriate fallback route when it is not.\n *\n * Redirect rules (in priority order):\n * 1. No `object-store` service at all → redirect to the project overview.\n * 2. Unknown provider (neither \"swift\" nor \"ceph\") → redirect to the first\n * available provider, or to the project overview if none exist.\n * 3. Requested provider unavailable → redirect to the other provider,\n * or to the project overview if no alternative exists.\n *\n * Ceph has a temporary fallback flag (`cephFallbackEnabled`) that treats it as\n * available even when absent from the OpenStack service catalog.\n *\n * @throws {redirect} - Always throws a TanStack Router redirect; never returns normally\n * when the requested provider/project combination is unavailable.\n */\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n }\n) => {\n const { provider, projectId } = params\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if no storage services available\n if (!serviceIndex[\"object-store\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n // Check provider availability\n const hasSwift = Boolean(serviceIndex[\"object-store\"][\"swift\"])\n const hasCeph = Boolean(serviceIndex[\"object-store\"][\"ceph\"])\n\n // TEMPORARY: Allow Ceph access even if not in catalog (relies on env config)\n // TODO: Properly register Ceph in OpenStack service catalog\n const cephFallbackEnabled = true // Set to false once Ceph is in catalog\n\n // Effective availability includes fallback flag for Ceph\n const hasEffectiveCeph = hasCeph || cephFallbackEnabled\n const fallbackProvider = hasSwift ? \"swift\" : hasEffectiveCeph ? \"ceph\" : null\n const fallbackStorageType = hasSwift ? \"containers\" : hasEffectiveCeph ? \"buckets\" : null\n\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider || !fallbackStorageType) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: fallbackProvider, storageType: fallbackStorageType },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"ceph\", storageType: \"buckets\" },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"swift\", storageType: \"containers\" },\n })\n }\n}\n\n// Search params schema\n// - sortBy: active sort column — persisted for deep links and back navigation\n// - sortDirection: \"asc\" | \"desc\" — persisted alongside sortBy\n// - search: active filter string — persisted so deep links preserve the current search\nconst containersSearchSchema = z.object({\n sortBy: z.enum([\"name\", \"count\", \"bytes\", \"last_modified\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: z.string().optional(),\n})\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType/\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n sectionCrumb: { labelKey: \"Storage\" },\n crumb: { useParamAsLabel: \"provider\" },\n } satisfies RouteInfo,\n validateSearch: containersSearchSchema,\n head: ({ match }) => ({\n meta: [\n {\n title:\n match.params.provider === \"swift\"\n ? \"Object Storage (Swift)\"\n : match.params.provider === \"ceph\"\n ? \"Object Storage (Ceph)\"\n : \"Storage Overview\",\n },\n ],\n }),\n component: () => {\n return <StorageDashboard />\n },\n notFoundComponent: () => {\n return <p>Storage service not found</p>\n },\n loader: async ({ context }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n\n return {\n client: trpcClient,\n availableServices,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n checkServiceAvailability(availableServices!, params)\n },\n})\n\nfunction StorageDashboard() {\n const { project, provider } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n select: (params) => {\n return { project: params.projectId, provider: params.provider, storageType: params.storageType }\n },\n })\n\n const { t } = useLingui()\n\n let pageTitle: string\n switch (provider) {\n case \"swift\":\n pageTitle = t`Object Storage (Swift)`\n break\n case \"ceph\":\n pageTitle = t`Object Storage (Ceph)`\n break\n default:\n pageTitle = t`Storage Overview`\n }\n\n return (\n <div>\n <ContentHeader title={pageTitle} projectId={project} />\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider]}\n fallback={\n <div className=\"p-4 text-center\">\n <Trans>Error loading component</Trans>\n </div>\n }\n >\n {(() => {\n switch (provider) {\n case \"swift\":\n return <SwiftContainers />\n case \"ceph\":\n return <CephBuckets />\n default:\n return <div>Storage Overview Page</div> // replace when available\n }\n })()}\n </ErrorBoundary>\n ) : (\n <div className=\"p-4 text-center\">\n <Trans>No project selected</Trans>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":";;;;sGA2BaI,KACXC,GAIAG,MAAAA;CAKA,IAAM,EAAEE,aAAUD,iBAAcD,GAE1BG,IAAeR,EAAgBE,CAAAA;CAGrC,IAAI,CAACM,EAAa,iBAChB,MAAMV,EAAS;EACbW,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;CAIF,IAAMI,IAAWC,EAAQH,EAAa,gBAAgB,OAQhDM,IAPUH,EAAQH,EAAa,gBAAgB,QAOjBK,IAC9BE,IAAmBL,IAAW,UAAUI,IAAmB,SAAS,MACpEE,IAAsBN,IAAW,eAAeI,IAAmB,YAAY;CAErF,IAAIP,MAAa,WAAWA,MAAa,QAOvC,MALQT,EADJ,CAACiB,KAAoB,CAACC,IACT;EACbP,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,IAEa;EACbG,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAUQ;GAAkBE,aAAaD;EAAoB;CACpF,CALE;CAQJ,IAAIT,MAAa,WAAW,CAACG,GAQ3B,MAAMZ,EAPDgB,IAOU;EACbL,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAU;GAAQU,aAAa;EAAU;CAChE,IATiB;EACbR,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;CASJ,IAAIC,MAAa,UAAU,CAACO,GAQ1B,MAAMhB,EAPDY,IAOU;EACbD,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAU;GAASU,aAAa;EAAa;CACpE,IATiB;EACbR,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;AAQN,GAMMY,IAAyBnB,EAAEoB,OAAO;CACtCC,QAAQrB,EAAEsB,KAAK;EAAC;EAAQ;EAAS;EAAS;EAAgB,EAAEC,SAAQ;CACpEC,eAAexB,EAAEsB,KAAK,CAAC,OAAO,MAAA,CAAO,EAAEC,SAAQ;CAC/CE,QAAQzB,EAAE0B,OAAM,EAAGH,SAAQ;AAC7B,CAAA,GAEaI,IAAQ7B,EAAgB,4DAAA,EAA8D;CACjG8B,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAEC,iBAAiB,WAAW;CACvC;CACAE,gBAAgBjB;CAChBkB,OAAO,EAAEC,gBAAa,EACpBC,MAAM,CACJ,EACEC,OACEF,EAAMhC,OAAOE,aAAa,UACtB,2BACA8B,EAAMhC,OAAOE,aAAa,SACxB,0BACA,mBACV,CAAA,EAEJ;CACAiC,WAASC,EAAAC,GAAA,WAAA;CAGTC,mBAAiBF,EAAAG,GAAA,mBAAA;CAGjBC,QAAQ,OAAO,EAAEC,iBAAS;EACxB,IAAM,EAAEC,kBAAeD;EAGvB,OAAO;GACLK,QAAQJ;GACR7C,mBAAAA,MAJ8B6C,GAAYC,KAAKC,qBAAqBC,MAAAA;EAKtE;CACF;CACAE,YAAY,OAAO,EAAEN,YAASzC,gBAAQ;EACpC,IAAM,EAAE0C,kBAAeD;EAEvB7C,EAAyBC,MADO6C,GAAYC,KAAKC,qBAAqBC,MAAAA,GACzB7C,CAAAA;CAC/C;AACF,CAAA"}
1
+ {"version":3,"file":"_storageType-CepuevDG.mjs","names":["createFileRoute","redirect","z","getServiceIndex","checkServiceAvailability","availableServices","type","name","params","projectId","provider","serviceIndex","to","hasSwift","Boolean","hasCeph","cephFallbackEnabled","hasEffectiveCeph","fallbackProvider","fallbackStorageType","storageType","containersSearchSchema","object","sortBy","enum","optional","sortDirection","search","string","Route","staticData","section","service","sectionCrumb","labelKey","crumb","useParamAsLabel","RouteInfo","validateSearch","head","match","meta","title","component","lazyRouteComponent","$$splitComponentImporter","notFoundComponent","$$splitNotFoundComponentImporter","loader","context","trpcClient","auth","getAvailableServices","query","client","beforeLoad"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx"],"sourcesContent":["import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { SwiftContainers } from \"../../-components/Swift/Containers\"\nimport { CephBuckets } from \"../../-components/Ceph/Buckets\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\n/**\n * Validates that the requested storage provider is available for the given project,\n * and redirects to an appropriate fallback route when it is not.\n *\n * Redirect rules (in priority order):\n * 1. No `object-store` service at all → redirect to the project overview.\n * 2. Unknown provider (neither \"swift\" nor \"ceph\") → redirect to the first\n * available provider, or to the project overview if none exist.\n * 3. Requested provider unavailable → redirect to the other provider,\n * or to the project overview if no alternative exists.\n *\n * Ceph has a temporary fallback flag (`cephFallbackEnabled`) that treats it as\n * available even when absent from the OpenStack service catalog.\n *\n * @throws {redirect} - Always throws a TanStack Router redirect; never returns normally\n * when the requested provider/project combination is unavailable.\n */\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n }\n) => {\n const { provider, projectId } = params\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if no storage services available\n if (!serviceIndex[\"object-store\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n // Check provider availability\n const hasSwift = Boolean(serviceIndex[\"object-store\"][\"swift\"])\n const hasCeph = Boolean(serviceIndex[\"object-store\"][\"ceph\"])\n\n // TEMPORARY: Allow Ceph access even if not in catalog (relies on env config)\n // TODO: Properly register Ceph in OpenStack service catalog\n const cephFallbackEnabled = true // Set to false once Ceph is in catalog\n\n // Effective availability includes fallback flag for Ceph\n const hasEffectiveCeph = hasCeph || cephFallbackEnabled\n const fallbackProvider = hasSwift ? \"swift\" : hasEffectiveCeph ? \"ceph\" : null\n const fallbackStorageType = hasSwift ? \"containers\" : hasEffectiveCeph ? \"buckets\" : null\n\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider || !fallbackStorageType) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: fallbackProvider, storageType: fallbackStorageType },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"ceph\", storageType: \"buckets\" },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"swift\", storageType: \"containers\" },\n })\n }\n}\n\n// Search params schema\n// - sortBy: active sort column — persisted for deep links and back navigation\n// - sortDirection: \"asc\" | \"desc\" — persisted alongside sortBy\n// - search: active filter string — persisted so deep links preserve the current search\nconst containersSearchSchema = z.object({\n sortBy: z.enum([\"name\", \"count\", \"bytes\", \"last_modified\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: z.string().optional(),\n})\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType/\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n sectionCrumb: { labelKey: \"Storage\" },\n crumb: { useParamAsLabel: \"provider\" },\n } satisfies RouteInfo,\n validateSearch: containersSearchSchema,\n head: ({ match }) => ({\n meta: [\n {\n title:\n match.params.provider === \"swift\"\n ? \"Object Storage (Swift)\"\n : match.params.provider === \"ceph\"\n ? \"Object Storage (Ceph)\"\n : \"Storage Overview\",\n },\n ],\n }),\n component: () => {\n return <StorageDashboard />\n },\n notFoundComponent: () => {\n return <p>Storage service not found</p>\n },\n loader: async ({ context }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n\n return {\n client: trpcClient,\n availableServices,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n checkServiceAvailability(availableServices!, params)\n },\n})\n\nfunction StorageDashboard() {\n const { project, provider } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n select: (params) => {\n return { project: params.projectId, provider: params.provider, storageType: params.storageType }\n },\n })\n\n const { t } = useLingui()\n\n let pageTitle: string\n switch (provider) {\n case \"swift\":\n pageTitle = t`Object Storage (Swift)`\n break\n case \"ceph\":\n pageTitle = t`Object Storage (Ceph)`\n break\n default:\n pageTitle = t`Storage Overview`\n }\n\n return (\n <div>\n <ContentHeader title={pageTitle} projectId={project} />\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider]}\n fallback={\n <div className=\"p-4 text-center\">\n <Trans>Error loading component</Trans>\n </div>\n }\n >\n {(() => {\n switch (provider) {\n case \"swift\":\n return <SwiftContainers />\n case \"ceph\":\n return <CephBuckets />\n default:\n return <div>Storage Overview Page</div> // replace when available\n }\n })()}\n </ErrorBoundary>\n ) : (\n <div className=\"p-4 text-center\">\n <Trans>No project selected</Trans>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":";;;;sGA2BaI,KACXC,GAIAG,MAAAA;CAKA,IAAM,EAAEE,aAAUD,iBAAcD,GAE1BG,IAAeR,EAAgBE,CAAAA;CAGrC,IAAI,CAACM,EAAa,iBAChB,MAAMV,EAAS;EACbW,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;CAIF,IAAMI,IAAWC,EAAQH,EAAa,gBAAgB,OAQhDM,IAPUH,EAAQH,EAAa,gBAAgB,QAOjBK,IAC9BE,IAAmBL,IAAW,UAAUI,IAAmB,SAAS,MACpEE,IAAsBN,IAAW,eAAeI,IAAmB,YAAY;CAErF,IAAIP,MAAa,WAAWA,MAAa,QAOvC,MALQT,EADJ,CAACiB,KAAoB,CAACC,IACT;EACbP,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,IAEa;EACbG,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAUQ;GAAkBE,aAAaD;EAAoB;CACpF,CALE;CAQJ,IAAIT,MAAa,WAAW,CAACG,GAQ3B,MAAMZ,EAPDgB,IAOU;EACbL,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAU;GAAQU,aAAa;EAAU;CAChE,IATiB;EACbR,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;CASJ,IAAIC,MAAa,UAAU,CAACO,GAQ1B,MAAMhB,EAPDY,IAOU;EACbD,IAAI;EACJJ,QAAQ;GAAE,GAAGA;GAAQE,UAAU;GAASU,aAAa;EAAa;CACpE,IATiB;EACbR,IAAI;EACJJ,QAAQ,EAAEC,aAAU;CACtB,CAAA;AAQN,GAMMY,IAAyBnB,EAAEoB,OAAO;CACtCC,QAAQrB,EAAEsB,KAAK;EAAC;EAAQ;EAAS;EAAS;EAAgB,EAAEC,SAAQ;CACpEC,eAAexB,EAAEsB,KAAK,CAAC,OAAO,MAAA,CAAO,EAAEC,SAAQ;CAC/CE,QAAQzB,EAAE0B,OAAM,EAAGH,SAAQ;AAC7B,CAAA,GAEaI,IAAQ7B,EAAgB,4DAAA,EAA8D;CACjG8B,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAEC,iBAAiB,WAAW;CACvC;CACAE,gBAAgBjB;CAChBkB,OAAO,EAAEC,gBAAa,EACpBC,MAAM,CACJ,EACEC,OACEF,EAAMhC,OAAOE,aAAa,UACtB,2BACA8B,EAAMhC,OAAOE,aAAa,SACxB,0BACA,mBACV,CAAA,EAEJ;CACAiC,WAASC,EAAAC,GAAA,WAAA;CAGTC,mBAAiBF,EAAAG,GAAA,mBAAA;CAGjBC,QAAQ,OAAO,EAAEC,iBAAS;EACxB,IAAM,EAAEC,kBAAeD;EAGvB,OAAO;GACLK,QAAQJ;GACR7C,mBAAAA,MAJ8B6C,GAAYC,KAAKC,qBAAqBC,MAAAA;EAKtE;CACF;CACAE,YAAY,OAAO,EAAEN,YAASzC,gBAAQ;EACpC,IAAM,EAAE0C,kBAAeD;EAEvB7C,EAAyBC,MADO6C,GAAYC,KAAKC,qBAAqBC,MAAAA,GACzB7C,CAAAA;CAC/C;AACF,CAAA"}
@@ -8,9 +8,9 @@ var r = e("/_auth/projects/$projectId/compute/flavors/")({
8
8
  crumb: { labelKey: "Flavors" }
9
9
  },
10
10
  head: () => ({ meta: [{ title: n._({ id: "neiJm0" }) }] }),
11
- component: t(() => import("./flavors-m1qDHzeS.mjs"), "component")
11
+ component: t(() => import("./flavors-BfsEBUE-.mjs"), "component")
12
12
  });
13
13
  //#endregion
14
14
  export { r as t };
15
15
 
16
- //# sourceMappingURL=flavors-_P7R-CeT.mjs.map
16
+ //# sourceMappingURL=flavors-8bZVlzzb.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flavors-_P7R-CeT.mjs","names":["createFileRoute","t","Route","staticData","section","service","sectionCrumb","labelKey","crumb","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/flavors/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Flavors } from \"../-components/Flavors/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/flavors/\")({\n staticData: {\n section: \"compute\",\n service: \"flavors\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Flavors\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Flavors` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n return (\n <>\n <ContentHeader title={t`Flavors`} projectId={projectId} />\n <Flavors project={projectId} client={trpcClient!} />\n </>\n )\n}\n"],"mappings":";;AAOA,IAAaE,IAAQF,EAAgB,6CAAA,EAA+C;CAClFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAED,UAAU,UAAU;CAC/B;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOX,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAU,CAAA,EAAG;CAC7CY,WAASC,0CAAA,WAAA;AACX,CAAA"}
1
+ {"version":3,"file":"flavors-8bZVlzzb.mjs","names":["createFileRoute","t","Route","staticData","section","service","sectionCrumb","labelKey","crumb","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/flavors/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Flavors } from \"../-components/Flavors/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/flavors/\")({\n staticData: {\n section: \"compute\",\n service: \"flavors\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Flavors\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Flavors` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n return (\n <>\n <ContentHeader title={t`Flavors`} projectId={projectId} />\n <Flavors project={projectId} client={trpcClient!} />\n </>\n )\n}\n"],"mappings":";;AAOA,IAAaE,IAAQF,EAAgB,6CAAA,EAA+C;CAClFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAED,UAAU,UAAU;CAC/B;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOX,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAU,CAAA,EAAG;CAC7CY,WAASC,0CAAA,WAAA;AACX,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { D as e, E as t, G as n, H as r, J as i, L as a, N as o, Q as s, S as c, V as l, Y as u, _ as d, ct as f, et as p, it as m, k as h, m as g, ot as _, p as v, rt as y, x as b } from "./build-BdRRmNf5.mjs";
2
2
  import { t as x } from "./useErrorTranslation-Dc0eE8Zt.mjs";
3
- import { t as S } from "./flavors-_P7R-CeT.mjs";
4
- import { t as C } from "./ContentHeader-DqsGNvtD.mjs";
3
+ import { t as S } from "./flavors-8bZVlzzb.mjs";
4
+ import { t as C } from "./ContentHeader-C51H95X8.mjs";
5
5
  import { n as w, r as T, t as E } from "./DeleteFlavorModal-C3m7bQJu.mjs";
6
6
  import { t as D } from "./SortInput-VK7IYqQv.mjs";
7
7
  import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
@@ -646,4 +646,4 @@ function $() {
646
646
  //#endregion
647
647
  export { $ as component };
648
648
 
649
- //# sourceMappingURL=flavors-m1qDHzeS.mjs.map
649
+ //# sourceMappingURL=flavors-BfsEBUE-.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flavors-m1qDHzeS.mjs","names":["DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","ContentHeading","PopupMenu","PopupMenuOptions","PopupMenuItem","Spinner","Stack","Pagination","DeleteFlavorModal","useEffect","useState","EditSpecModal","ManageAccessModal","useParams","useNavigate","FlavorListContainer","flavors","isLoading","client","project","onFlavorDeleted","canDeleteFlavor","canMangageAccess","canManageSpecs","canListSpecs","currentPage","totalPages","onPageChange","useLingui","navigate","deleteModalOpen","setDeleteModalOpen","specModalOpen","setSpecModalOpen","accessModalOpen","setAccessModalOpen","selectedFlavor","setSelectedFlavor","inputPage","setInputPage","toString","projectId","from","openDeleteModal","flavor","openSpecModal","openAccessModal","closeDeleteModal","handleDeleteSuccess","name","updateCurrentPage","newPage","div","data-testid","colSpan","distribution","alignment","variant","length","columns","className","p","minContentColumns","map","id","onClick","to","params","flavorId","vcpus","ram","disk","swap","t","e","stopPropagation","label","disabled","pages","onPressPrevious","Math","max","onPressNext","min","onSelectChange","selectedPage","onInputChange","newInputPage","undefined","String","onKeyDown","key","parseInt","isNaN","isOpen","onClose","onSuccess","canEdit","validateField","field","value","t","undefined","idStr","String","trim","idRegex","test","msg","nameStr","length","vcpus","Number","isNaN","ram","disk","swap","rxtx","str","ephemeral","cleanFlavorData","flavor","result","name","isValidValue","isValidNumber","id","description","rxtx_factor","Boolean","React","useState","Modal","Form","FormRow","FormSection","TextInput","Message","Spinner","Stack","Checkbox","validateField","cleanFlavorData","useErrorTranslation","CreateFlavorModal","client","isOpen","onClose","project","onSuccess","useLingui","translateError","newFlavor","setNewFlavor","errors","setErrors","isLoading","setIsLoading","generalError","setGeneralError","handleInputChange","e","name","value","type","checked","target","prev","newState","handleNumericInputChange","handleBlur","error","handleSubmit","preventDefault","newErrors","requiredFields","forEach","key","optionalFields","undefined","Object","keys","length","t","flavorData","compute","createFlavor","mutate","project_id","flavor","handleClose","errorMessage","message","dismissError","onCancel","size","title","open","onConfirm","cancelButtonLabel","confirmButtonLabel","distribution","alignment","variant","onDismiss","text","id","label","onChange","onBlur","errortext","required","description","String","vcpus","Number","ram","disk","swap","defaultValue","rxtx_factor","helptext","use","Suspense","useState","useRef","startTransition","useEffect","useCallback","ErrorBoundary","useSearch","useNavigate","TRPCClientError","Message","Button","Stack","Spinner","DataGridToolbar","SearchInput","SortInput","FlavorListContainer","CreateFlavorModal","PAGE_SIZE","createFlavorsPromise","client","project","sortBy","sortDirection","searchTerm","compute","getFlavorsByProjectId","query","project_id","then","res","listError","undefined","catch","err","data","code","flavors","privateFlavorError","message","createPermissionsPromise","canUser","permission","canCreate","canDelete","canManageAccess","canCreateSpecs","canDeleteSpecs","canListSpecs","canManageSpecs","FlavorsContent","flavorsPromise","permissionsPromise","onFlavorDeleted","onFlavorCreated","setSearchTerm","sortSettings","handleSortChange","createModalOpen","setCreateModalOpen","currentPage","onPageChange","useLingui","permissions","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","p","totalPages","Math","max","ceil","length","safePage","min","paginatedFlavors","slice","isOpen","onClose","onSuccess","className","text","t","variant","distribution","alignment","gap","options","onSortByChange","v","onSortDirectionChange","dir","label","onClick","placeholder","data-testid","value","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","isLoading","canDeleteFlavor","canMangageAccess","Flavors","navigate","searchParams","strict","setSortSettings","search","page","success","setSuccess","setFlavorsPromise","refetchFlavors","handleFlavorDeleted","flavorName","timestamp","Date","now","handleFlavorCreated","newSortSettings","settings","toString","prev","replace","handleSearchChange","term","searchValue","handlePageChange","div","onDismiss","dismissible","fallbackRender","error","Error","fallback","direction","size","useLingui","Flavors","ContentHeader","Route","RouteComponent","t","projectId","useParams","trpcClient","useRouteContext","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/FlavorListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/flavorValidation.ts","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/CreateFlavorModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/List.tsx","../../src/client/routes/_auth/projects/$projectId/compute/flavors/index.tsx?tsr-split=component"],"sourcesContent":["import { Flavor } from \"@/server/Compute/types/flavor\"\nimport {\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n ContentHeading,\n PopupMenu,\n PopupMenuOptions,\n PopupMenuItem,\n Spinner,\n Stack,\n Pagination,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { DeleteFlavorModal } from \"./DeleteFlavorModal\"\nimport { useEffect, useState } from \"react\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport { EditSpecModal } from \"./EditSpecModal\"\nimport { ManageAccessModal } from \"./ManageAccessModal\"\nimport { useParams, useNavigate } from \"@tanstack/react-router\"\n\ninterface FlavorListContainerProps {\n flavors?: Flavor[]\n isLoading: boolean\n client: TrpcClient\n project: string\n onFlavorDeleted?: (flavorName: string) => void\n canDeleteFlavor?: boolean\n canMangageAccess?: boolean\n canManageSpecs?: boolean\n canListSpecs?: boolean\n currentPage?: number\n totalPages?: number\n onPageChange?: (page: number) => void\n}\n\nexport const FlavorListContainer = ({\n flavors,\n isLoading,\n client,\n project,\n onFlavorDeleted,\n canDeleteFlavor,\n canMangageAccess,\n canManageSpecs,\n canListSpecs,\n currentPage = 1,\n totalPages = 1,\n onPageChange,\n}: FlavorListContainerProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const [deleteModalOpen, setDeleteModalOpen] = useState(false)\n const [specModalOpen, setSpecModalOpen] = useState(false)\n const [accessModalOpen, setAccessModalOpen] = useState(false)\n const [selectedFlavor, setSelectedFlavor] = useState<Flavor | null>(null)\n const [inputPage, setInputPage] = useState<string>(currentPage.toString())\n\n useEffect(() => {\n setInputPage(currentPage.toString())\n }, [currentPage])\n\n const { projectId } = useParams({\n from: \"/_auth/projects/$projectId/compute/flavors/\",\n })\n\n const openDeleteModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setDeleteModalOpen(true)\n }\n\n const openSpecModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setSpecModalOpen(true)\n }\n\n const openAccessModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setAccessModalOpen(true)\n }\n\n const closeDeleteModal = () => {\n setDeleteModalOpen(false)\n setSelectedFlavor(null)\n }\n\n const handleDeleteSuccess = () => {\n if (selectedFlavor && onFlavorDeleted) {\n onFlavorDeleted(selectedFlavor.name || \"\")\n }\n closeDeleteModal()\n }\n\n const updateCurrentPage = (newPage: number) => {\n if (newPage >= 1 && newPage <= totalPages) {\n onPageChange?.(newPage)\n setInputPage(newPage.toString())\n }\n }\n\n if (isLoading) {\n return (\n <div data-testid=\"loading\">\n <div data-testid=\"loading\">\n <DataGridRow>\n <DataGridCell colSpan={3}>\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n <Trans>Loading...</Trans>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n </div>\n </div>\n )\n }\n\n if (!flavors || flavors.length === 0) {\n return (\n <DataGrid columns={7} className=\"flavors\" data-testid=\"no-flavors\">\n <DataGridRow>\n <DataGridCell colSpan={7}>\n <ContentHeading>\n <Trans>No flavors found</Trans>\n </ContentHeading>\n <p>\n <Trans>\n There are no flavors available for this project with the current filters applied. Try adjusting your\n filter criteria or create a new flavor.\n </Trans>\n </p>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n )\n }\n\n return (\n <>\n <DataGrid columns={7} minContentColumns={[6]} className=\"flavors\" data-testid=\"flavors-table\">\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>vCPU</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>RAM (MiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Root Disk (GiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Swap (MiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Access Type</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell></DataGridHeadCell>\n </DataGridRow>\n\n {flavors.map((flavor) => (\n <DataGridRow\n key={flavor.id}\n data-testid={`flavor-row-${flavor.id}`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/flavors/$flavorId\",\n params: { projectId, flavorId: flavor.id },\n })\n }\n >\n <DataGridCell>{flavor.name || flavor.id}</DataGridCell>\n <DataGridCell>{flavor.vcpus || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.ram || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.disk || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.swap || \"–\"}</DataGridCell>\n <DataGridCell>{flavor[\"os-flavor-access:is_public\"] === false ? t`Private` : t`Public`}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Details`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/flavors/$flavorId\",\n params: { projectId, flavorId: flavor.id },\n })\n }\n />\n {(canManageSpecs || canListSpecs) && (\n <PopupMenuItem\n label={canManageSpecs ? t`Edit Metadata` : t`Metadata`}\n onClick={() => openSpecModal(flavor)}\n />\n )}\n {canMangageAccess && (\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() => openAccessModal(flavor)}\n disabled={flavor[\"os-flavor-access:is_public\"] !== false}\n />\n )}\n {canDeleteFlavor && (\n <PopupMenuItem label={t`Delete Flavor`} onClick={() => openDeleteModal(flavor)} />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n ))}\n </DataGrid>\n {totalPages > 1 && (\n <div className=\"flex justify-center py-4\">\n <Pagination\n variant=\"input\"\n currentPage={currentPage}\n pages={totalPages}\n onPressPrevious={() => updateCurrentPage(Math.max(currentPage - 1, 1))}\n onPressNext={() => updateCurrentPage(Math.min(currentPage + 1, totalPages))}\n onSelectChange={(selectedPage: number) => {\n updateCurrentPage(selectedPage)\n }}\n onInputChange={(newInputPage?: number) => {\n setInputPage(newInputPage === undefined ? \"\" : String(newInputPage))\n }}\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" && inputPage !== \"\") {\n const newPage = parseInt(inputPage, 10)\n if (!isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {\n updateCurrentPage(newPage)\n }\n }\n }}\n />\n </div>\n )}\n <DeleteFlavorModal\n client={client}\n isOpen={deleteModalOpen}\n onClose={closeDeleteModal}\n project={project}\n flavor={selectedFlavor}\n onSuccess={handleDeleteSuccess}\n />\n <EditSpecModal\n client={client}\n isOpen={specModalOpen}\n onClose={() => setSpecModalOpen(false)}\n project={project}\n flavor={selectedFlavor}\n canEdit={canManageSpecs}\n />\n\n <ManageAccessModal\n client={client}\n isOpen={accessModalOpen}\n onClose={() => setAccessModalOpen(false)}\n project={project}\n flavor={selectedFlavor}\n />\n </>\n )\n}\n","import { msg } from \"@lingui/core/macro\"\nimport { MessageDescriptor } from \"@lingui/core\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\n\nexport const validateField = (\n field: FlavorFormField,\n value: string | number | boolean | null | undefined,\n t: (descriptor: MessageDescriptor) => string\n): string | undefined => {\n switch (field) {\n case \"id\":\n if (!value) return undefined\n {\n const idStr = String(value).trim()\n const idRegex = /^[a-zA-Z0-9.\\-_]*$/\n return idRegex.test(idStr)\n ? undefined\n : t(msg`ID must only contain alphanumeric characters, hyphens, underscores, and dots.`)\n }\n\n case \"name\": {\n const nameStr = String(value || \"\").trim()\n return nameStr.length >= 2 && nameStr.length <= 50 ? undefined : t(msg`Name must be 2-50 characters long.`)\n }\n\n case \"vcpus\": {\n const vcpus = Number(value)\n return !isNaN(vcpus) && vcpus >= 1 ? undefined : t(msg`VCPUs must be an integer ≥ 1.`)\n }\n\n case \"ram\": {\n const ram = Number(value)\n return !isNaN(ram) && ram >= 128 ? undefined : t(msg`RAM must be an integer ≥ 128 MB.`)\n }\n\n case \"disk\": {\n const disk = Number(value)\n return !isNaN(disk) && disk >= 0 ? undefined : t(msg`Root Disk must be an integer ≥ 0.`)\n }\n\n case \"swap\":\n if (value === \"\" || value === undefined || value === null) return undefined\n {\n const swap = Number(value)\n return !isNaN(swap) && swap >= 0 ? undefined : t(msg`Swap Disk must be an integer ≥ 0.`)\n }\n\n case \"rxtx_factor\": {\n const rxtx = Number(value)\n return !isNaN(rxtx) && rxtx >= 1 ? undefined : t(msg`RX/TX Factor must be an integer ≥ 1.`)\n }\n\n case \"description\":\n if (!value) return undefined\n {\n const str = String(value)\n return str.length < 65535 ? undefined : t(msg`Description must be less than 65535 characters.`)\n }\n\n case \"OS-FLV-EXT-DATA:ephemeral\": {\n const ephemeral = Number(value)\n return !isNaN(ephemeral) && ephemeral >= 0 ? undefined : t(msg`Ephemeral Disk must be an integer ≥ 0.`)\n }\n\n case \"os-flavor-access:is_public\": {\n if (value === undefined || value === null) {\n return undefined\n }\n if (typeof value === \"boolean\") {\n return undefined\n }\n if (typeof value === \"string\" && (value === \"true\" || value === \"false\")) {\n return undefined\n }\n return t(msg`Invalid value for public flavor setting.`)\n }\n\n default:\n return undefined\n }\n}\n\nexport type FlavorFormField =\n | \"id\"\n | \"name\"\n | \"vcpus\"\n | \"ram\"\n | \"disk\"\n | \"swap\"\n | \"description\"\n | \"rxtx_factor\"\n | \"OS-FLV-EXT-DATA:ephemeral\"\n | \"os-flavor-access:is_public\"\n\nexport interface FieldErrors {\n id?: string\n name?: string\n vcpus?: string\n ram?: string\n disk?: string\n swap?: string\n rxtx_factor?: string\n description?: string\n \"OS-FLV-EXT-DATA:ephemeral\"?: string\n \"os-flavor-access:is_public\"?: string\n}\n\nexport const cleanFlavorData = (flavor: Partial<Flavor>) => {\n const result: {\n name: string\n vcpus: number\n ram: number\n disk: number\n \"OS-FLV-EXT-DATA:ephemeral\"?: number\n id?: string\n swap?: number\n rxtx_factor?: number\n description?: string\n \"os-flavor-access:is_public\"?: boolean\n } = {\n name: String(flavor.name),\n vcpus: Number(flavor.vcpus),\n ram: Number(flavor.ram),\n disk: Number(flavor.disk),\n }\n\n const isValidValue = (value: string | undefined | null) => {\n return value !== undefined && value !== null && value !== \"\" && String(value).trim() !== \"\"\n }\n\n const isValidNumber = (value: string | number | undefined | null) => {\n return value !== undefined && value !== null && value !== \"\" && String(value).trim() !== \"\" && !isNaN(Number(value))\n }\n\n if (isValidValue(flavor.id)) {\n result.id = String(flavor.id).trim()\n }\n\n if (isValidValue(flavor.description)) {\n result.description = String(flavor.description).trim()\n }\n\n if (isValidNumber(flavor.swap)) {\n result.swap = Number(flavor.swap)\n }\n\n if (isValidNumber(flavor.rxtx_factor)) {\n result.rxtx_factor = Number(flavor.rxtx_factor)\n }\n\n if (isValidNumber(flavor[\"OS-FLV-EXT-DATA:ephemeral\"])) {\n result[\"OS-FLV-EXT-DATA:ephemeral\"] = Number(flavor[\"OS-FLV-EXT-DATA:ephemeral\"])\n }\n\n if (flavor[\"os-flavor-access:is_public\"] !== undefined) {\n result[\"os-flavor-access:is_public\"] = Boolean(flavor[\"os-flavor-access:is_public\"])\n }\n\n return result\n}\n","import React, { useState } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Message,\n Spinner,\n Stack,\n Checkbox,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\nimport { validateField, FlavorFormField, FieldErrors } from \"./flavorValidation\"\nimport { cleanFlavorData } from \"./flavorValidation\"\nimport { useErrorTranslation } from \"@/client/utils/useErrorTranslation\"\n\ninterface CreateFlavorModalProps {\n client: TrpcClient\n isOpen: boolean\n onClose: () => void\n project: string\n onSuccess: (name: string) => void\n}\n\nexport const CreateFlavorModal: React.FC<CreateFlavorModalProps> = ({\n client,\n isOpen,\n onClose,\n project,\n onSuccess,\n}) => {\n const { t } = useLingui()\n const { translateError } = useErrorTranslation()\n const [newFlavor, setNewFlavor] = useState<Partial<Flavor>>({\n \"os-flavor-access:is_public\": true,\n })\n const [errors, setErrors] = useState<FieldErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n const [generalError, setGeneralError] = useState<string | null>(null)\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target\n\n setNewFlavor((prev) => {\n const newState = {\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }\n\n return newState\n })\n if (generalError) setGeneralError(null)\n }\n\n const handleNumericInputChange = (name: FlavorFormField, value: number | undefined) => {\n setNewFlavor((prev) => ({\n ...prev,\n [name]: value,\n }))\n if (generalError) setGeneralError(null)\n }\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n const { name, value } = e.target\n const error = validateField(name as FlavorFormField, value, t)\n setErrors((prev) => ({\n ...prev,\n [name]: error,\n }))\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n setGeneralError(null)\n\n const newErrors: FieldErrors = {}\n\n const requiredFields: FlavorFormField[] = [\"name\", \"vcpus\", \"ram\", \"disk\"]\n requiredFields.forEach((key) => {\n const error = validateField(key, newFlavor[key], t)\n if (error) {\n newErrors[key] = error\n }\n })\n\n const optionalFields: FlavorFormField[] = [\n \"id\",\n \"swap\",\n \"OS-FLV-EXT-DATA:ephemeral\",\n \"rxtx_factor\",\n \"description\",\n \"os-flavor-access:is_public\",\n ]\n optionalFields.forEach((key) => {\n const value = newFlavor[key]\n\n if (value !== undefined && value !== \"\" && value !== null) {\n const error = validateField(key, value, t)\n if (error) {\n newErrors[key] = error\n }\n }\n })\n\n if (Object.keys(newErrors).length > 0) {\n setErrors(newErrors)\n setGeneralError(t`Please fix the validation errors below.`)\n return\n }\n\n try {\n setIsLoading(true)\n\n const flavorData = cleanFlavorData(newFlavor)\n\n await client.compute.createFlavor.mutate({\n project_id: project,\n flavor: flavorData,\n })\n\n onSuccess(flavorData.name)\n handleClose()\n } catch (error) {\n const errorMessage = (error as Error)?.message\n ? translateError((error as Error).message)\n : t`Failed to create flavor. Please try again.`\n setGeneralError(errorMessage)\n } finally {\n setIsLoading(false)\n }\n }\n\n const handleClose = () => {\n setNewFlavor({\n \"os-flavor-access:is_public\": true,\n })\n setErrors({})\n setGeneralError(null)\n onClose()\n }\n\n const dismissError = () => {\n setGeneralError(null)\n }\n\n return (\n <Modal\n onCancel={handleClose}\n size=\"large\"\n title={t`Create Flavor`}\n open={isOpen}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n confirmButtonLabel={t`Create New Flavor`}\n >\n {isLoading && (\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n </Stack>\n )}\n {!isLoading && (\n <Form>\n {generalError && (\n <FormRow>\n <Message onDismiss={dismissError} text={generalError} variant=\"error\" />\n </FormRow>\n )}\n\n <FormSection>\n <FormRow>\n <TextInput\n id=\"id\"\n name=\"id\"\n label={t`Flavor ID`}\n value={newFlavor.id || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.id}\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Flavor Name`}\n value={newFlavor.name || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.name}\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"description\"\n name=\"description\"\n label={t`Description`}\n value={newFlavor.description || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.description}\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"vcpus\"\n name=\"vcpus\"\n label={t`VCPUs`}\n value={String(newFlavor.vcpus || \"\")}\n onChange={(e) => handleNumericInputChange(\"vcpus\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.vcpus}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"ram\"\n name=\"ram\"\n label={t`RAM (MiB)`}\n value={String(newFlavor.ram || \"\")}\n onChange={(e) => handleNumericInputChange(\"ram\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.ram}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"disk\"\n name=\"disk\"\n label={t`Disk (GiB)`}\n value={String(newFlavor.disk || \"\")}\n onChange={(e) => handleNumericInputChange(\"disk\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.disk}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"OS-FLV-EXT-DATA:ephemeral\"\n name=\"OS-FLV-EXT-DATA:ephemeral\"\n label={t`Ephemeral Disk (GiB)`}\n value={String(newFlavor[\"OS-FLV-EXT-DATA:ephemeral\"] || \"\")}\n onChange={(e) => handleNumericInputChange(\"OS-FLV-EXT-DATA:ephemeral\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors[\"OS-FLV-EXT-DATA:ephemeral\"]}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"swap\"\n name=\"swap\"\n label={t`Swap (MiB)`}\n value={String(newFlavor.swap || \"\")}\n onChange={(e) => handleNumericInputChange(\"swap\", e.target.value ? Number(e.target.value) : undefined)}\n onBlur={handleBlur}\n errortext={errors.swap}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"rxtx_factor\"\n name=\"rxtx_factor\"\n label={t`RX/TX Factor`}\n defaultValue={1}\n value={String(newFlavor.rxtx_factor || \"\")}\n onChange={(e) => handleNumericInputChange(\"rxtx_factor\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.rxtx_factor}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <Checkbox\n name=\"os-flavor-access:is_public\"\n label={t`Public Flavor`}\n helptext={t`If checked, this flavor will be available to all tenants. If unchecked, access must be explicitly granted to specific tenants.`}\n checked={!!newFlavor[\"os-flavor-access:is_public\"]}\n onChange={handleInputChange}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { use, Suspense, useState, useRef, startTransition, useEffect, useCallback } from \"react\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useSearch, useNavigate } from \"@tanstack/react-router\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { Message, Button, Stack, Spinner, DataGridToolbar, SearchInput } from \"@cloudoperators/juno-ui-components\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { FlavorListContainer } from \"./-components/FlavorListContainer\"\nimport { CreateFlavorModal } from \"./-components/CreateFlavorModal\"\nimport type { FlavorsSearchParams } from \"@/client/routes/_auth/projects/$projectId/compute/flavors\"\n\nconst PAGE_SIZE = 50\n\ninterface FlavorsProps {\n client: TrpcClient\n project: string\n}\n\ntype RequiredSortSettings = {\n options: SortSettings[\"options\"]\n sortBy: string\n sortDirection: \"asc\" | \"desc\"\n}\n\nconst createFlavorsPromise = (\n client: TrpcClient,\n project: string,\n sortBy: string,\n sortDirection: string,\n searchTerm: string\n) => {\n return client.compute.getFlavorsByProjectId\n .query({ project_id: project, sortBy, sortDirection, searchTerm })\n .then((res) => ({ ...res, listError: undefined as string | undefined }))\n .catch((err: unknown) => {\n if (err instanceof TRPCClientError && err.data?.code === \"FORBIDDEN\") {\n return { flavors: [] as Flavor[], privateFlavorError: undefined, listError: err.message }\n }\n throw err\n })\n}\n\nconst createPermissionsPromise = (client: TrpcClient, project: string) => {\n return client.compute.canUser\n .query({\n project_id: project,\n permission: [\n \"flavors:create\",\n \"flavors:delete\",\n \"flavors:list_projects\",\n \"flavor_specs:create\",\n \"flavor_specs:delete\",\n \"flavor_specs:list\",\n ],\n })\n .then(([canCreate, canDelete, canManageAccess, canCreateSpecs, canDeleteSpecs, canListSpecs]) => ({\n canCreate,\n canDelete,\n canManageAccess,\n canManageSpecs: canCreateSpecs || canDeleteSpecs,\n canListSpecs,\n }))\n}\n\nfunction FlavorsContent({\n flavorsPromise,\n permissionsPromise,\n client,\n project,\n onFlavorDeleted,\n onFlavorCreated,\n searchTerm,\n setSearchTerm,\n sortSettings,\n handleSortChange,\n createModalOpen,\n setCreateModalOpen,\n currentPage,\n onPageChange,\n}: {\n flavorsPromise: Promise<{ flavors: Flavor[]; privateFlavorError?: string; listError?: string }>\n permissionsPromise: Promise<{\n canCreate: boolean\n canDelete: boolean\n canManageAccess: boolean\n canManageSpecs: boolean\n canListSpecs: boolean\n }>\n client: TrpcClient\n project: string\n onFlavorDeleted: (name: string) => void\n onFlavorCreated: (name: string) => void\n searchTerm: string\n setSearchTerm: (term: string) => void\n sortSettings: SortSettings\n handleSortChange: (settings: SortSettings) => void\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n currentPage: number\n onPageChange: (page: number) => void\n}) {\n const { t } = useLingui()\n const { flavors, privateFlavorError, listError } = use(flavorsPromise)\n const permissions = use(permissionsPromise)\n const [localSearchTerm, setLocalSearchTerm] = useState(searchTerm)\n const debounceTimer = useRef<number | undefined>(undefined)\n\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n if (listError) {\n return <p>{listError}</p>\n }\n\n const totalPages = Math.max(1, Math.ceil(flavors.length / PAGE_SIZE))\n const safePage = Math.min(currentPage, totalPages)\n const paginatedFlavors = flavors.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n\n useEffect(() => {\n if (currentPage > totalPages) onPageChange(1)\n }, [totalPages, currentPage, onPageChange])\n\n return (\n <>\n <CreateFlavorModal\n client={client}\n isOpen={createModalOpen}\n project={project}\n onClose={() => setCreateModalOpen(false)}\n onSuccess={onFlavorCreated}\n />\n\n {privateFlavorError && (\n <Message\n className=\"mb-4\"\n text={t`Private flavors could not be loaded. You may be seeing an incomplete list.`}\n variant=\"warning\"\n />\n )}\n\n {/* Zone 1 — sort + create action, no background */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n </Stack>\n {permissions.canCreate && (\n <Button variant=\"primary\" label={t`Create Flavor`} onClick={() => setCreateModalOpen(true)} />\n )}\n </Stack>\n\n {/* Zone 2 — search bar */}\n <DataGridToolbar>\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search flavors...`}\n data-testid=\"searchbar\"\n value={localSearchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setLocalSearchTerm(v)\n clearTimeout(debounceTimer.current)\n debounceTimer.current = window.setTimeout(() => setSearchTerm(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n setSearchTerm(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n setSearchTerm(\"\")\n }}\n />\n </Stack>\n </DataGridToolbar>\n\n <FlavorListContainer\n flavors={paginatedFlavors}\n isLoading={false}\n client={client}\n project={project}\n onFlavorDeleted={onFlavorDeleted}\n canDeleteFlavor={permissions.canDelete}\n canMangageAccess={permissions.canManageAccess}\n canManageSpecs={permissions.canManageSpecs}\n canListSpecs={permissions.canListSpecs}\n currentPage={safePage}\n totalPages={totalPages}\n onPageChange={onPageChange}\n />\n </>\n )\n}\nexport const Flavors = ({ client, project }: FlavorsProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const searchParams = useSearch({ strict: false }) as FlavorsSearchParams\n\n const [sortSettings, setSortSettings] = useState<RequiredSortSettings>({\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`VCPUs`, value: \"vcpus\" },\n { label: t`RAM`, value: \"ram\" },\n { label: t`Root Disk`, value: \"disk\" },\n { label: t`Swap`, value: \"swap\" },\n ],\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n })\n\n const [searchTerm, setSearchTerm] = useState(searchParams.search || \"\")\n const currentPage = searchParams.page ?? 1\n const [success, setSuccess] = useState<{ message: string; timestamp: number } | undefined>()\n const [createModalOpen, setCreateModalOpen] = useState(false)\n\n const [flavorsPromise, setFlavorsPromise] = useState(() =>\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchTerm)\n )\n const [permissionsPromise] = useState(() => createPermissionsPromise(client, project))\n\n const refetchFlavors = () => {\n startTransition(() => {\n setFlavorsPromise(\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchTerm)\n )\n })\n }\n\n const handleFlavorDeleted = (flavorName: string) => {\n setSuccess({\n message: t`Flavor \"${flavorName}\" has been successfully deleted.`,\n timestamp: Date.now(),\n })\n setTimeout(() => setSuccess(undefined), 5000)\n refetchFlavors()\n }\n\n const handleFlavorCreated = (flavorName: string) => {\n setSuccess({\n message: t`Flavor \"${flavorName}\" has been successfully created.`,\n timestamp: Date.now(),\n })\n setTimeout(() => setSuccess(undefined), 5000)\n refetchFlavors()\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: RequiredSortSettings = {\n options: newSortSettings.options,\n sortBy: newSortSettings.sortBy?.toString() || \"name\",\n sortDirection: newSortSettings.sortDirection || \"asc\",\n }\n\n setSortSettings(settings)\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n sortBy: settings.sortBy,\n sortDirection: settings.sortDirection,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n startTransition(() => {\n setFlavorsPromise(createFlavorsPromise(client, project, settings.sortBy, settings.sortDirection, searchTerm))\n })\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n setSearchTerm(searchValue)\n\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n search: searchValue || undefined,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n startTransition(() => {\n setFlavorsPromise(\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchValue)\n )\n })\n }\n\n const handlePageChange = useCallback(\n (page: number) => {\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n page: page === 1 ? undefined : page,\n })) as unknown as true,\n })\n },\n [navigate]\n )\n\n return (\n <div className=\"relative\">\n {success && (\n <Message\n className=\"absolute -top-14 right-0 left-0 z-50\"\n text={success.message}\n variant=\"info\"\n onDismiss={() => setSuccess(undefined)}\n dismissible\n />\n )}\n\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <Message variant=\"error\" text={error instanceof Error ? error.message : t`An unexpected error occurred.`} />\n )}\n >\n <Suspense\n fallback={\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Flavors...</Trans>\n </Stack>\n }\n >\n <FlavorsContent\n flavorsPromise={flavorsPromise}\n permissionsPromise={permissionsPromise}\n client={client}\n project={project}\n onFlavorDeleted={handleFlavorDeleted}\n onFlavorCreated={handleFlavorCreated}\n searchTerm={searchTerm}\n setSearchTerm={handleSearchChange}\n sortSettings={sortSettings}\n handleSortChange={handleSortChange}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n currentPage={currentPage}\n onPageChange={handlePageChange}\n />\n </Suspense>\n </ErrorBoundary>\n </div>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Flavors } from \"../-components/Flavors/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/flavors/\")({\n staticData: {\n section: \"compute\",\n service: \"flavors\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Flavors\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Flavors` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n return (\n <>\n <ContentHeader title={t`Flavors`} projectId={projectId} />\n <Flavors project={projectId} client={trpcClient!} />\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flavors-BfsEBUE-.mjs","names":["DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","ContentHeading","PopupMenu","PopupMenuOptions","PopupMenuItem","Spinner","Stack","Pagination","DeleteFlavorModal","useEffect","useState","EditSpecModal","ManageAccessModal","useParams","useNavigate","FlavorListContainer","flavors","isLoading","client","project","onFlavorDeleted","canDeleteFlavor","canMangageAccess","canManageSpecs","canListSpecs","currentPage","totalPages","onPageChange","useLingui","navigate","deleteModalOpen","setDeleteModalOpen","specModalOpen","setSpecModalOpen","accessModalOpen","setAccessModalOpen","selectedFlavor","setSelectedFlavor","inputPage","setInputPage","toString","projectId","from","openDeleteModal","flavor","openSpecModal","openAccessModal","closeDeleteModal","handleDeleteSuccess","name","updateCurrentPage","newPage","div","data-testid","colSpan","distribution","alignment","variant","length","columns","className","p","minContentColumns","map","id","onClick","to","params","flavorId","vcpus","ram","disk","swap","t","e","stopPropagation","label","disabled","pages","onPressPrevious","Math","max","onPressNext","min","onSelectChange","selectedPage","onInputChange","newInputPage","undefined","String","onKeyDown","key","parseInt","isNaN","isOpen","onClose","onSuccess","canEdit","validateField","field","value","t","undefined","idStr","String","trim","idRegex","test","msg","nameStr","length","vcpus","Number","isNaN","ram","disk","swap","rxtx","str","ephemeral","cleanFlavorData","flavor","result","name","isValidValue","isValidNumber","id","description","rxtx_factor","Boolean","React","useState","Modal","Form","FormRow","FormSection","TextInput","Message","Spinner","Stack","Checkbox","validateField","cleanFlavorData","useErrorTranslation","CreateFlavorModal","client","isOpen","onClose","project","onSuccess","useLingui","translateError","newFlavor","setNewFlavor","errors","setErrors","isLoading","setIsLoading","generalError","setGeneralError","handleInputChange","e","name","value","type","checked","target","prev","newState","handleNumericInputChange","handleBlur","error","handleSubmit","preventDefault","newErrors","requiredFields","forEach","key","optionalFields","undefined","Object","keys","length","t","flavorData","compute","createFlavor","mutate","project_id","flavor","handleClose","errorMessage","message","dismissError","onCancel","size","title","open","onConfirm","cancelButtonLabel","confirmButtonLabel","distribution","alignment","variant","onDismiss","text","id","label","onChange","onBlur","errortext","required","description","String","vcpus","Number","ram","disk","swap","defaultValue","rxtx_factor","helptext","use","Suspense","useState","useRef","startTransition","useEffect","useCallback","ErrorBoundary","useSearch","useNavigate","TRPCClientError","Message","Button","Stack","Spinner","DataGridToolbar","SearchInput","SortInput","FlavorListContainer","CreateFlavorModal","PAGE_SIZE","createFlavorsPromise","client","project","sortBy","sortDirection","searchTerm","compute","getFlavorsByProjectId","query","project_id","then","res","listError","undefined","catch","err","data","code","flavors","privateFlavorError","message","createPermissionsPromise","canUser","permission","canCreate","canDelete","canManageAccess","canCreateSpecs","canDeleteSpecs","canListSpecs","canManageSpecs","FlavorsContent","flavorsPromise","permissionsPromise","onFlavorDeleted","onFlavorCreated","setSearchTerm","sortSettings","handleSortChange","createModalOpen","setCreateModalOpen","currentPage","onPageChange","useLingui","permissions","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","p","totalPages","Math","max","ceil","length","safePage","min","paginatedFlavors","slice","isOpen","onClose","onSuccess","className","text","t","variant","distribution","alignment","gap","options","onSortByChange","v","onSortDirectionChange","dir","label","onClick","placeholder","data-testid","value","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","isLoading","canDeleteFlavor","canMangageAccess","Flavors","navigate","searchParams","strict","setSortSettings","search","page","success","setSuccess","setFlavorsPromise","refetchFlavors","handleFlavorDeleted","flavorName","timestamp","Date","now","handleFlavorCreated","newSortSettings","settings","toString","prev","replace","handleSearchChange","term","searchValue","handlePageChange","div","onDismiss","dismissible","fallbackRender","error","Error","fallback","direction","size","useLingui","Flavors","ContentHeader","Route","RouteComponent","t","projectId","useParams","trpcClient","useRouteContext","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/FlavorListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/flavorValidation.ts","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/-components/CreateFlavorModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Flavors/List.tsx","../../src/client/routes/_auth/projects/$projectId/compute/flavors/index.tsx?tsr-split=component"],"sourcesContent":["import { Flavor } from \"@/server/Compute/types/flavor\"\nimport {\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n ContentHeading,\n PopupMenu,\n PopupMenuOptions,\n PopupMenuItem,\n Spinner,\n Stack,\n Pagination,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { DeleteFlavorModal } from \"./DeleteFlavorModal\"\nimport { useEffect, useState } from \"react\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport { EditSpecModal } from \"./EditSpecModal\"\nimport { ManageAccessModal } from \"./ManageAccessModal\"\nimport { useParams, useNavigate } from \"@tanstack/react-router\"\n\ninterface FlavorListContainerProps {\n flavors?: Flavor[]\n isLoading: boolean\n client: TrpcClient\n project: string\n onFlavorDeleted?: (flavorName: string) => void\n canDeleteFlavor?: boolean\n canMangageAccess?: boolean\n canManageSpecs?: boolean\n canListSpecs?: boolean\n currentPage?: number\n totalPages?: number\n onPageChange?: (page: number) => void\n}\n\nexport const FlavorListContainer = ({\n flavors,\n isLoading,\n client,\n project,\n onFlavorDeleted,\n canDeleteFlavor,\n canMangageAccess,\n canManageSpecs,\n canListSpecs,\n currentPage = 1,\n totalPages = 1,\n onPageChange,\n}: FlavorListContainerProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const [deleteModalOpen, setDeleteModalOpen] = useState(false)\n const [specModalOpen, setSpecModalOpen] = useState(false)\n const [accessModalOpen, setAccessModalOpen] = useState(false)\n const [selectedFlavor, setSelectedFlavor] = useState<Flavor | null>(null)\n const [inputPage, setInputPage] = useState<string>(currentPage.toString())\n\n useEffect(() => {\n setInputPage(currentPage.toString())\n }, [currentPage])\n\n const { projectId } = useParams({\n from: \"/_auth/projects/$projectId/compute/flavors/\",\n })\n\n const openDeleteModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setDeleteModalOpen(true)\n }\n\n const openSpecModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setSpecModalOpen(true)\n }\n\n const openAccessModal = (flavor: Flavor) => {\n setSelectedFlavor(flavor)\n setAccessModalOpen(true)\n }\n\n const closeDeleteModal = () => {\n setDeleteModalOpen(false)\n setSelectedFlavor(null)\n }\n\n const handleDeleteSuccess = () => {\n if (selectedFlavor && onFlavorDeleted) {\n onFlavorDeleted(selectedFlavor.name || \"\")\n }\n closeDeleteModal()\n }\n\n const updateCurrentPage = (newPage: number) => {\n if (newPage >= 1 && newPage <= totalPages) {\n onPageChange?.(newPage)\n setInputPage(newPage.toString())\n }\n }\n\n if (isLoading) {\n return (\n <div data-testid=\"loading\">\n <div data-testid=\"loading\">\n <DataGridRow>\n <DataGridCell colSpan={3}>\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n <Trans>Loading...</Trans>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n </div>\n </div>\n )\n }\n\n if (!flavors || flavors.length === 0) {\n return (\n <DataGrid columns={7} className=\"flavors\" data-testid=\"no-flavors\">\n <DataGridRow>\n <DataGridCell colSpan={7}>\n <ContentHeading>\n <Trans>No flavors found</Trans>\n </ContentHeading>\n <p>\n <Trans>\n There are no flavors available for this project with the current filters applied. Try adjusting your\n filter criteria or create a new flavor.\n </Trans>\n </p>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n )\n }\n\n return (\n <>\n <DataGrid columns={7} minContentColumns={[6]} className=\"flavors\" data-testid=\"flavors-table\">\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>vCPU</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>RAM (MiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Root Disk (GiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Swap (MiB)</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Access Type</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell></DataGridHeadCell>\n </DataGridRow>\n\n {flavors.map((flavor) => (\n <DataGridRow\n key={flavor.id}\n data-testid={`flavor-row-${flavor.id}`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/flavors/$flavorId\",\n params: { projectId, flavorId: flavor.id },\n })\n }\n >\n <DataGridCell>{flavor.name || flavor.id}</DataGridCell>\n <DataGridCell>{flavor.vcpus || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.ram || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.disk || \"–\"}</DataGridCell>\n <DataGridCell>{flavor.swap || \"–\"}</DataGridCell>\n <DataGridCell>{flavor[\"os-flavor-access:is_public\"] === false ? t`Private` : t`Public`}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Details`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/flavors/$flavorId\",\n params: { projectId, flavorId: flavor.id },\n })\n }\n />\n {(canManageSpecs || canListSpecs) && (\n <PopupMenuItem\n label={canManageSpecs ? t`Edit Metadata` : t`Metadata`}\n onClick={() => openSpecModal(flavor)}\n />\n )}\n {canMangageAccess && (\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() => openAccessModal(flavor)}\n disabled={flavor[\"os-flavor-access:is_public\"] !== false}\n />\n )}\n {canDeleteFlavor && (\n <PopupMenuItem label={t`Delete Flavor`} onClick={() => openDeleteModal(flavor)} />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n ))}\n </DataGrid>\n {totalPages > 1 && (\n <div className=\"flex justify-center py-4\">\n <Pagination\n variant=\"input\"\n currentPage={currentPage}\n pages={totalPages}\n onPressPrevious={() => updateCurrentPage(Math.max(currentPage - 1, 1))}\n onPressNext={() => updateCurrentPage(Math.min(currentPage + 1, totalPages))}\n onSelectChange={(selectedPage: number) => {\n updateCurrentPage(selectedPage)\n }}\n onInputChange={(newInputPage?: number) => {\n setInputPage(newInputPage === undefined ? \"\" : String(newInputPage))\n }}\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" && inputPage !== \"\") {\n const newPage = parseInt(inputPage, 10)\n if (!isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {\n updateCurrentPage(newPage)\n }\n }\n }}\n />\n </div>\n )}\n <DeleteFlavorModal\n client={client}\n isOpen={deleteModalOpen}\n onClose={closeDeleteModal}\n project={project}\n flavor={selectedFlavor}\n onSuccess={handleDeleteSuccess}\n />\n <EditSpecModal\n client={client}\n isOpen={specModalOpen}\n onClose={() => setSpecModalOpen(false)}\n project={project}\n flavor={selectedFlavor}\n canEdit={canManageSpecs}\n />\n\n <ManageAccessModal\n client={client}\n isOpen={accessModalOpen}\n onClose={() => setAccessModalOpen(false)}\n project={project}\n flavor={selectedFlavor}\n />\n </>\n )\n}\n","import { msg } from \"@lingui/core/macro\"\nimport { MessageDescriptor } from \"@lingui/core\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\n\nexport const validateField = (\n field: FlavorFormField,\n value: string | number | boolean | null | undefined,\n t: (descriptor: MessageDescriptor) => string\n): string | undefined => {\n switch (field) {\n case \"id\":\n if (!value) return undefined\n {\n const idStr = String(value).trim()\n const idRegex = /^[a-zA-Z0-9.\\-_]*$/\n return idRegex.test(idStr)\n ? undefined\n : t(msg`ID must only contain alphanumeric characters, hyphens, underscores, and dots.`)\n }\n\n case \"name\": {\n const nameStr = String(value || \"\").trim()\n return nameStr.length >= 2 && nameStr.length <= 50 ? undefined : t(msg`Name must be 2-50 characters long.`)\n }\n\n case \"vcpus\": {\n const vcpus = Number(value)\n return !isNaN(vcpus) && vcpus >= 1 ? undefined : t(msg`VCPUs must be an integer ≥ 1.`)\n }\n\n case \"ram\": {\n const ram = Number(value)\n return !isNaN(ram) && ram >= 128 ? undefined : t(msg`RAM must be an integer ≥ 128 MB.`)\n }\n\n case \"disk\": {\n const disk = Number(value)\n return !isNaN(disk) && disk >= 0 ? undefined : t(msg`Root Disk must be an integer ≥ 0.`)\n }\n\n case \"swap\":\n if (value === \"\" || value === undefined || value === null) return undefined\n {\n const swap = Number(value)\n return !isNaN(swap) && swap >= 0 ? undefined : t(msg`Swap Disk must be an integer ≥ 0.`)\n }\n\n case \"rxtx_factor\": {\n const rxtx = Number(value)\n return !isNaN(rxtx) && rxtx >= 1 ? undefined : t(msg`RX/TX Factor must be an integer ≥ 1.`)\n }\n\n case \"description\":\n if (!value) return undefined\n {\n const str = String(value)\n return str.length < 65535 ? undefined : t(msg`Description must be less than 65535 characters.`)\n }\n\n case \"OS-FLV-EXT-DATA:ephemeral\": {\n const ephemeral = Number(value)\n return !isNaN(ephemeral) && ephemeral >= 0 ? undefined : t(msg`Ephemeral Disk must be an integer ≥ 0.`)\n }\n\n case \"os-flavor-access:is_public\": {\n if (value === undefined || value === null) {\n return undefined\n }\n if (typeof value === \"boolean\") {\n return undefined\n }\n if (typeof value === \"string\" && (value === \"true\" || value === \"false\")) {\n return undefined\n }\n return t(msg`Invalid value for public flavor setting.`)\n }\n\n default:\n return undefined\n }\n}\n\nexport type FlavorFormField =\n | \"id\"\n | \"name\"\n | \"vcpus\"\n | \"ram\"\n | \"disk\"\n | \"swap\"\n | \"description\"\n | \"rxtx_factor\"\n | \"OS-FLV-EXT-DATA:ephemeral\"\n | \"os-flavor-access:is_public\"\n\nexport interface FieldErrors {\n id?: string\n name?: string\n vcpus?: string\n ram?: string\n disk?: string\n swap?: string\n rxtx_factor?: string\n description?: string\n \"OS-FLV-EXT-DATA:ephemeral\"?: string\n \"os-flavor-access:is_public\"?: string\n}\n\nexport const cleanFlavorData = (flavor: Partial<Flavor>) => {\n const result: {\n name: string\n vcpus: number\n ram: number\n disk: number\n \"OS-FLV-EXT-DATA:ephemeral\"?: number\n id?: string\n swap?: number\n rxtx_factor?: number\n description?: string\n \"os-flavor-access:is_public\"?: boolean\n } = {\n name: String(flavor.name),\n vcpus: Number(flavor.vcpus),\n ram: Number(flavor.ram),\n disk: Number(flavor.disk),\n }\n\n const isValidValue = (value: string | undefined | null) => {\n return value !== undefined && value !== null && value !== \"\" && String(value).trim() !== \"\"\n }\n\n const isValidNumber = (value: string | number | undefined | null) => {\n return value !== undefined && value !== null && value !== \"\" && String(value).trim() !== \"\" && !isNaN(Number(value))\n }\n\n if (isValidValue(flavor.id)) {\n result.id = String(flavor.id).trim()\n }\n\n if (isValidValue(flavor.description)) {\n result.description = String(flavor.description).trim()\n }\n\n if (isValidNumber(flavor.swap)) {\n result.swap = Number(flavor.swap)\n }\n\n if (isValidNumber(flavor.rxtx_factor)) {\n result.rxtx_factor = Number(flavor.rxtx_factor)\n }\n\n if (isValidNumber(flavor[\"OS-FLV-EXT-DATA:ephemeral\"])) {\n result[\"OS-FLV-EXT-DATA:ephemeral\"] = Number(flavor[\"OS-FLV-EXT-DATA:ephemeral\"])\n }\n\n if (flavor[\"os-flavor-access:is_public\"] !== undefined) {\n result[\"os-flavor-access:is_public\"] = Boolean(flavor[\"os-flavor-access:is_public\"])\n }\n\n return result\n}\n","import React, { useState } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Message,\n Spinner,\n Stack,\n Checkbox,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\nimport { validateField, FlavorFormField, FieldErrors } from \"./flavorValidation\"\nimport { cleanFlavorData } from \"./flavorValidation\"\nimport { useErrorTranslation } from \"@/client/utils/useErrorTranslation\"\n\ninterface CreateFlavorModalProps {\n client: TrpcClient\n isOpen: boolean\n onClose: () => void\n project: string\n onSuccess: (name: string) => void\n}\n\nexport const CreateFlavorModal: React.FC<CreateFlavorModalProps> = ({\n client,\n isOpen,\n onClose,\n project,\n onSuccess,\n}) => {\n const { t } = useLingui()\n const { translateError } = useErrorTranslation()\n const [newFlavor, setNewFlavor] = useState<Partial<Flavor>>({\n \"os-flavor-access:is_public\": true,\n })\n const [errors, setErrors] = useState<FieldErrors>({})\n const [isLoading, setIsLoading] = useState(false)\n const [generalError, setGeneralError] = useState<string | null>(null)\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target\n\n setNewFlavor((prev) => {\n const newState = {\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }\n\n return newState\n })\n if (generalError) setGeneralError(null)\n }\n\n const handleNumericInputChange = (name: FlavorFormField, value: number | undefined) => {\n setNewFlavor((prev) => ({\n ...prev,\n [name]: value,\n }))\n if (generalError) setGeneralError(null)\n }\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n const { name, value } = e.target\n const error = validateField(name as FlavorFormField, value, t)\n setErrors((prev) => ({\n ...prev,\n [name]: error,\n }))\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n setGeneralError(null)\n\n const newErrors: FieldErrors = {}\n\n const requiredFields: FlavorFormField[] = [\"name\", \"vcpus\", \"ram\", \"disk\"]\n requiredFields.forEach((key) => {\n const error = validateField(key, newFlavor[key], t)\n if (error) {\n newErrors[key] = error\n }\n })\n\n const optionalFields: FlavorFormField[] = [\n \"id\",\n \"swap\",\n \"OS-FLV-EXT-DATA:ephemeral\",\n \"rxtx_factor\",\n \"description\",\n \"os-flavor-access:is_public\",\n ]\n optionalFields.forEach((key) => {\n const value = newFlavor[key]\n\n if (value !== undefined && value !== \"\" && value !== null) {\n const error = validateField(key, value, t)\n if (error) {\n newErrors[key] = error\n }\n }\n })\n\n if (Object.keys(newErrors).length > 0) {\n setErrors(newErrors)\n setGeneralError(t`Please fix the validation errors below.`)\n return\n }\n\n try {\n setIsLoading(true)\n\n const flavorData = cleanFlavorData(newFlavor)\n\n await client.compute.createFlavor.mutate({\n project_id: project,\n flavor: flavorData,\n })\n\n onSuccess(flavorData.name)\n handleClose()\n } catch (error) {\n const errorMessage = (error as Error)?.message\n ? translateError((error as Error).message)\n : t`Failed to create flavor. Please try again.`\n setGeneralError(errorMessage)\n } finally {\n setIsLoading(false)\n }\n }\n\n const handleClose = () => {\n setNewFlavor({\n \"os-flavor-access:is_public\": true,\n })\n setErrors({})\n setGeneralError(null)\n onClose()\n }\n\n const dismissError = () => {\n setGeneralError(null)\n }\n\n return (\n <Modal\n onCancel={handleClose}\n size=\"large\"\n title={t`Create Flavor`}\n open={isOpen}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n confirmButtonLabel={t`Create New Flavor`}\n >\n {isLoading && (\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n </Stack>\n )}\n {!isLoading && (\n <Form>\n {generalError && (\n <FormRow>\n <Message onDismiss={dismissError} text={generalError} variant=\"error\" />\n </FormRow>\n )}\n\n <FormSection>\n <FormRow>\n <TextInput\n id=\"id\"\n name=\"id\"\n label={t`Flavor ID`}\n value={newFlavor.id || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.id}\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Flavor Name`}\n value={newFlavor.name || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.name}\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"description\"\n name=\"description\"\n label={t`Description`}\n value={newFlavor.description || \"\"}\n onChange={handleInputChange}\n onBlur={handleBlur}\n errortext={errors.description}\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"vcpus\"\n name=\"vcpus\"\n label={t`VCPUs`}\n value={String(newFlavor.vcpus || \"\")}\n onChange={(e) => handleNumericInputChange(\"vcpus\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.vcpus}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"ram\"\n name=\"ram\"\n label={t`RAM (MiB)`}\n value={String(newFlavor.ram || \"\")}\n onChange={(e) => handleNumericInputChange(\"ram\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.ram}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"disk\"\n name=\"disk\"\n label={t`Disk (GiB)`}\n value={String(newFlavor.disk || \"\")}\n onChange={(e) => handleNumericInputChange(\"disk\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.disk}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"OS-FLV-EXT-DATA:ephemeral\"\n name=\"OS-FLV-EXT-DATA:ephemeral\"\n label={t`Ephemeral Disk (GiB)`}\n value={String(newFlavor[\"OS-FLV-EXT-DATA:ephemeral\"] || \"\")}\n onChange={(e) => handleNumericInputChange(\"OS-FLV-EXT-DATA:ephemeral\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors[\"OS-FLV-EXT-DATA:ephemeral\"]}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"swap\"\n name=\"swap\"\n label={t`Swap (MiB)`}\n value={String(newFlavor.swap || \"\")}\n onChange={(e) => handleNumericInputChange(\"swap\", e.target.value ? Number(e.target.value) : undefined)}\n onBlur={handleBlur}\n errortext={errors.swap}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"rxtx_factor\"\n name=\"rxtx_factor\"\n label={t`RX/TX Factor`}\n defaultValue={1}\n value={String(newFlavor.rxtx_factor || \"\")}\n onChange={(e) => handleNumericInputChange(\"rxtx_factor\", Number(e.target.value))}\n onBlur={handleBlur}\n errortext={errors.rxtx_factor}\n type=\"number\"\n />\n </FormRow>\n <FormRow>\n <Checkbox\n name=\"os-flavor-access:is_public\"\n label={t`Public Flavor`}\n helptext={t`If checked, this flavor will be available to all tenants. If unchecked, access must be explicitly granted to specific tenants.`}\n checked={!!newFlavor[\"os-flavor-access:is_public\"]}\n onChange={handleInputChange}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { use, Suspense, useState, useRef, startTransition, useEffect, useCallback } from \"react\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useSearch, useNavigate } from \"@tanstack/react-router\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport { Flavor } from \"@/server/Compute/types/flavor\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { Message, Button, Stack, Spinner, DataGridToolbar, SearchInput } from \"@cloudoperators/juno-ui-components\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { FlavorListContainer } from \"./-components/FlavorListContainer\"\nimport { CreateFlavorModal } from \"./-components/CreateFlavorModal\"\nimport type { FlavorsSearchParams } from \"@/client/routes/_auth/projects/$projectId/compute/flavors\"\n\nconst PAGE_SIZE = 50\n\ninterface FlavorsProps {\n client: TrpcClient\n project: string\n}\n\ntype RequiredSortSettings = {\n options: SortSettings[\"options\"]\n sortBy: string\n sortDirection: \"asc\" | \"desc\"\n}\n\nconst createFlavorsPromise = (\n client: TrpcClient,\n project: string,\n sortBy: string,\n sortDirection: string,\n searchTerm: string\n) => {\n return client.compute.getFlavorsByProjectId\n .query({ project_id: project, sortBy, sortDirection, searchTerm })\n .then((res) => ({ ...res, listError: undefined as string | undefined }))\n .catch((err: unknown) => {\n if (err instanceof TRPCClientError && err.data?.code === \"FORBIDDEN\") {\n return { flavors: [] as Flavor[], privateFlavorError: undefined, listError: err.message }\n }\n throw err\n })\n}\n\nconst createPermissionsPromise = (client: TrpcClient, project: string) => {\n return client.compute.canUser\n .query({\n project_id: project,\n permission: [\n \"flavors:create\",\n \"flavors:delete\",\n \"flavors:list_projects\",\n \"flavor_specs:create\",\n \"flavor_specs:delete\",\n \"flavor_specs:list\",\n ],\n })\n .then(([canCreate, canDelete, canManageAccess, canCreateSpecs, canDeleteSpecs, canListSpecs]) => ({\n canCreate,\n canDelete,\n canManageAccess,\n canManageSpecs: canCreateSpecs || canDeleteSpecs,\n canListSpecs,\n }))\n}\n\nfunction FlavorsContent({\n flavorsPromise,\n permissionsPromise,\n client,\n project,\n onFlavorDeleted,\n onFlavorCreated,\n searchTerm,\n setSearchTerm,\n sortSettings,\n handleSortChange,\n createModalOpen,\n setCreateModalOpen,\n currentPage,\n onPageChange,\n}: {\n flavorsPromise: Promise<{ flavors: Flavor[]; privateFlavorError?: string; listError?: string }>\n permissionsPromise: Promise<{\n canCreate: boolean\n canDelete: boolean\n canManageAccess: boolean\n canManageSpecs: boolean\n canListSpecs: boolean\n }>\n client: TrpcClient\n project: string\n onFlavorDeleted: (name: string) => void\n onFlavorCreated: (name: string) => void\n searchTerm: string\n setSearchTerm: (term: string) => void\n sortSettings: SortSettings\n handleSortChange: (settings: SortSettings) => void\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n currentPage: number\n onPageChange: (page: number) => void\n}) {\n const { t } = useLingui()\n const { flavors, privateFlavorError, listError } = use(flavorsPromise)\n const permissions = use(permissionsPromise)\n const [localSearchTerm, setLocalSearchTerm] = useState(searchTerm)\n const debounceTimer = useRef<number | undefined>(undefined)\n\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n if (listError) {\n return <p>{listError}</p>\n }\n\n const totalPages = Math.max(1, Math.ceil(flavors.length / PAGE_SIZE))\n const safePage = Math.min(currentPage, totalPages)\n const paginatedFlavors = flavors.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n\n useEffect(() => {\n if (currentPage > totalPages) onPageChange(1)\n }, [totalPages, currentPage, onPageChange])\n\n return (\n <>\n <CreateFlavorModal\n client={client}\n isOpen={createModalOpen}\n project={project}\n onClose={() => setCreateModalOpen(false)}\n onSuccess={onFlavorCreated}\n />\n\n {privateFlavorError && (\n <Message\n className=\"mb-4\"\n text={t`Private flavors could not be loaded. You may be seeing an incomplete list.`}\n variant=\"warning\"\n />\n )}\n\n {/* Zone 1 — sort + create action, no background */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n </Stack>\n {permissions.canCreate && (\n <Button variant=\"primary\" label={t`Create Flavor`} onClick={() => setCreateModalOpen(true)} />\n )}\n </Stack>\n\n {/* Zone 2 — search bar */}\n <DataGridToolbar>\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search flavors...`}\n data-testid=\"searchbar\"\n value={localSearchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setLocalSearchTerm(v)\n clearTimeout(debounceTimer.current)\n debounceTimer.current = window.setTimeout(() => setSearchTerm(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n setSearchTerm(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n setSearchTerm(\"\")\n }}\n />\n </Stack>\n </DataGridToolbar>\n\n <FlavorListContainer\n flavors={paginatedFlavors}\n isLoading={false}\n client={client}\n project={project}\n onFlavorDeleted={onFlavorDeleted}\n canDeleteFlavor={permissions.canDelete}\n canMangageAccess={permissions.canManageAccess}\n canManageSpecs={permissions.canManageSpecs}\n canListSpecs={permissions.canListSpecs}\n currentPage={safePage}\n totalPages={totalPages}\n onPageChange={onPageChange}\n />\n </>\n )\n}\nexport const Flavors = ({ client, project }: FlavorsProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const searchParams = useSearch({ strict: false }) as FlavorsSearchParams\n\n const [sortSettings, setSortSettings] = useState<RequiredSortSettings>({\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`VCPUs`, value: \"vcpus\" },\n { label: t`RAM`, value: \"ram\" },\n { label: t`Root Disk`, value: \"disk\" },\n { label: t`Swap`, value: \"swap\" },\n ],\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n })\n\n const [searchTerm, setSearchTerm] = useState(searchParams.search || \"\")\n const currentPage = searchParams.page ?? 1\n const [success, setSuccess] = useState<{ message: string; timestamp: number } | undefined>()\n const [createModalOpen, setCreateModalOpen] = useState(false)\n\n const [flavorsPromise, setFlavorsPromise] = useState(() =>\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchTerm)\n )\n const [permissionsPromise] = useState(() => createPermissionsPromise(client, project))\n\n const refetchFlavors = () => {\n startTransition(() => {\n setFlavorsPromise(\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchTerm)\n )\n })\n }\n\n const handleFlavorDeleted = (flavorName: string) => {\n setSuccess({\n message: t`Flavor \"${flavorName}\" has been successfully deleted.`,\n timestamp: Date.now(),\n })\n setTimeout(() => setSuccess(undefined), 5000)\n refetchFlavors()\n }\n\n const handleFlavorCreated = (flavorName: string) => {\n setSuccess({\n message: t`Flavor \"${flavorName}\" has been successfully created.`,\n timestamp: Date.now(),\n })\n setTimeout(() => setSuccess(undefined), 5000)\n refetchFlavors()\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: RequiredSortSettings = {\n options: newSortSettings.options,\n sortBy: newSortSettings.sortBy?.toString() || \"name\",\n sortDirection: newSortSettings.sortDirection || \"asc\",\n }\n\n setSortSettings(settings)\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n sortBy: settings.sortBy,\n sortDirection: settings.sortDirection,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n startTransition(() => {\n setFlavorsPromise(createFlavorsPromise(client, project, settings.sortBy, settings.sortDirection, searchTerm))\n })\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n setSearchTerm(searchValue)\n\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n search: searchValue || undefined,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n startTransition(() => {\n setFlavorsPromise(\n createFlavorsPromise(client, project, sortSettings.sortBy, sortSettings.sortDirection, searchValue)\n )\n })\n }\n\n const handlePageChange = useCallback(\n (page: number) => {\n navigate({\n search: ((prev: FlavorsSearchParams) => ({\n ...prev,\n page: page === 1 ? undefined : page,\n })) as unknown as true,\n })\n },\n [navigate]\n )\n\n return (\n <div className=\"relative\">\n {success && (\n <Message\n className=\"absolute -top-14 right-0 left-0 z-50\"\n text={success.message}\n variant=\"info\"\n onDismiss={() => setSuccess(undefined)}\n dismissible\n />\n )}\n\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <Message variant=\"error\" text={error instanceof Error ? error.message : t`An unexpected error occurred.`} />\n )}\n >\n <Suspense\n fallback={\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Flavors...</Trans>\n </Stack>\n }\n >\n <FlavorsContent\n flavorsPromise={flavorsPromise}\n permissionsPromise={permissionsPromise}\n client={client}\n project={project}\n onFlavorDeleted={handleFlavorDeleted}\n onFlavorCreated={handleFlavorCreated}\n searchTerm={searchTerm}\n setSearchTerm={handleSearchChange}\n sortSettings={sortSettings}\n handleSortChange={handleSortChange}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n currentPage={currentPage}\n onPageChange={handlePageChange}\n />\n </Suspense>\n </ErrorBoundary>\n </div>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Flavors } from \"../-components/Flavors/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/flavors/\")({\n staticData: {\n section: \"compute\",\n service: \"flavors\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Flavors\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Flavors` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n return (\n <>\n <ContentHeader title={t`Flavors`} projectId={projectId} />\n <Flavors project={projectId} client={trpcClient!} />\n </>\n )\n}\n"],"mappings":"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"}
@@ -8,9 +8,9 @@ var r = e("/_auth/projects/$projectId/compute/images/")({
8
8
  crumb: { labelKey: "Images" }
9
9
  },
10
10
  head: () => ({ meta: [{ title: n._({ id: "an5hVd" }) }] }),
11
- component: t(() => import("./images-DHmVgQAh2.mjs"), "component")
11
+ component: t(() => import("./images-BPnTuKFO2.mjs"), "component")
12
12
  });
13
13
  //#endregion
14
14
  export { r as t };
15
15
 
16
- //# sourceMappingURL=images-CpM-T_jM.mjs.map
16
+ //# sourceMappingURL=images-8FOgju2f.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"images-CpM-T_jM.mjs","names":["createFileRoute","t","Route","staticData","section","service","sectionCrumb","labelKey","crumb","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/images/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Images } from \"../-components/Images/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/images/\")({\n staticData: {\n section: \"compute\",\n service: \"images\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Images\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Images` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return (\n <>\n <ContentHeader title={t`Images`} projectId={projectId} />\n <Images client={trpcClient} project={projectId} />\n </>\n )\n}\n"],"mappings":";;AAOA,IAAaE,IAAQF,EAAgB,4CAAA,EAA8C;CACjFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAED,UAAU,SAAS;CAC9B;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOX,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAS,CAAA,EAAG;CAC5CY,WAASC,0CAAA,WAAA;AACX,CAAA"}
1
+ {"version":3,"file":"images-8FOgju2f.mjs","names":["createFileRoute","t","Route","staticData","section","service","sectionCrumb","labelKey","crumb","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/images/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Images } from \"../-components/Images/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/images/\")({\n staticData: {\n section: \"compute\",\n service: \"images\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Images\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Images` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return (\n <>\n <ContentHeader title={t`Images`} projectId={projectId} />\n <Images client={trpcClient} project={projectId} />\n </>\n )\n}\n"],"mappings":";;AAOA,IAAaE,IAAQF,EAAgB,4CAAA,EAA8C;CACjFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAED,UAAU,SAAS;CAC9B;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOX,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAS,CAAA,EAAG;CAC5CY,WAASC,0CAAA,WAAA;AACX,CAAA"}
@@ -1,8 +1,8 @@
1
1
  import { $ as e, D as t, E as n, G as r, H as i, J as a, L as o, N as s, Q as c, S as l, V as u, Y as d, Z as f, _ as p, ct as m, et as h, f as g, it as _, k as v, l as y, lt as b, m as x, n as ee, nt as S, ot as C, p as te, q as w, rt as T, v as E, x as ne } from "./build-BdRRmNf5.mjs";
2
2
  import { n as D, r as O } from "./trpcClient-BzPUgiM2.mjs";
3
3
  import { t as re } from "./cn-DM4Cy3jv.mjs";
4
- import { t as k } from "./images-CpM-T_jM.mjs";
5
- import { t as A } from "./ContentHeader-DqsGNvtD.mjs";
4
+ import { t as k } from "./images-8FOgju2f.mjs";
5
+ import { t as A } from "./ContentHeader-C51H95X8.mjs";
6
6
  import { t as j } from "./SortInput-VK7IYqQv.mjs";
7
7
  import { A as M, C as ie, D as ae, E as oe, F as N, I as P, M as F, N as I, O as L, P as R, S as z, T as B, _ as V, a as se, b as ce, c as H, d as U, f as le, g as W, h as ue, i as de, j as fe, k as pe, l as me, m as he, n as ge, o as _e, p as ve, r as ye, s as be, t as xe, u as Se, v as Ce, w as we, x as Te, y as Ee } from "./ImageToastNotifications-BuDXpTkl.mjs";
8
8
  import { t as De } from "./useProjectId-DBc5lpoU.mjs";
@@ -1887,4 +1887,4 @@ function ut() {
1887
1887
  //#endregion
1888
1888
  export { ut as component };
1889
1889
 
1890
- //# sourceMappingURL=images-DHmVgQAh2.mjs.map
1890
+ //# sourceMappingURL=images-BPnTuKFO2.mjs.map