@cobaltcore-dev/aurora 2.0.0 → 2.1.0

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 (115) hide show
  1. package/dist/client/ContentHeader-fKKZVu-o.mjs +116 -0
  2. package/dist/client/ContentHeader-fKKZVu-o.mjs.map +1 -0
  3. package/dist/client/{DeleteFlavorModal-C2MqUgGR.mjs → DeleteFlavorModal-Be2GFiB_.mjs} +3 -2
  4. package/dist/client/DeleteFlavorModal-Be2GFiB_.mjs.map +1 -0
  5. package/dist/client/{RouteIdLevelDefaultError-CSseJ1yG.mjs → RouteIdLevelDefaultError-DPF_x2tG.mjs} +9 -9
  6. package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs.map +1 -0
  7. package/dist/client/StorageNotFound-B-zVinVD.mjs +30 -0
  8. package/dist/client/StorageNotFound-B-zVinVD.mjs.map +1 -0
  9. package/dist/client/{_flavorId-DYv_StX22.mjs → _flavorId-0PioWpEp.mjs} +4 -4
  10. package/dist/client/_flavorId-0PioWpEp.mjs.map +1 -0
  11. package/dist/client/{_flavorId-YV3jCS5g.mjs → _flavorId-B7fp6Nk8.mjs} +3 -3
  12. package/dist/client/{_flavorId-YV3jCS5g.mjs.map → _flavorId-B7fp6Nk8.mjs.map} +1 -1
  13. package/dist/client/{_flavorId-CaA4-Pnf.mjs → _flavorId-CgueqKTs.mjs} +3 -3
  14. package/dist/client/{_flavorId-CaA4-Pnf.mjs.map → _flavorId-CgueqKTs.mjs.map} +1 -1
  15. package/dist/client/{_floatingIpId-Dpsc7GU4.mjs → _floatingIpId-B8r64AL9.mjs} +3 -3
  16. package/dist/client/{_floatingIpId-Dpsc7GU4.mjs.map → _floatingIpId-B8r64AL9.mjs.map} +1 -1
  17. package/dist/client/{_floatingIpId-BeYElanB.mjs → _floatingIpId-lEobpOER.mjs} +2 -2
  18. package/dist/client/{_floatingIpId-BeYElanB.mjs.map → _floatingIpId-lEobpOER.mjs.map} +1 -1
  19. package/dist/client/{_imageId-pBSS0YcC.mjs → _imageId-Ccv8PedW.mjs} +3 -3
  20. package/dist/client/{_imageId-pBSS0YcC.mjs.map → _imageId-Ccv8PedW.mjs.map} +1 -1
  21. package/dist/client/_imageId-CiqEQB_J.mjs +558 -0
  22. package/dist/client/{_imageId-mfKp3JHn.mjs.map → _imageId-CiqEQB_J.mjs.map} +1 -1
  23. package/dist/client/{_imageId-mpXUMCh_.mjs → _imageId-D9LR-02T.mjs} +3 -3
  24. package/dist/client/{_imageId-mpXUMCh_.mjs.map → _imageId-D9LR-02T.mjs.map} +1 -1
  25. package/dist/client/{_projectId-BnTBxKfp.mjs → _projectId-BDARsteX.mjs} +3 -3
  26. package/dist/client/{_projectId-BnTBxKfp.mjs.map → _projectId-BDARsteX.mjs.map} +1 -1
  27. package/dist/client/{_projectId-CVrdJ52s.mjs → _projectId-CtyAHqhH.mjs} +2 -2
  28. package/dist/client/{_projectId-CVrdJ52s.mjs.map → _projectId-CtyAHqhH.mjs.map} +1 -1
  29. package/dist/client/_projectId-D3VOH5lN.mjs +94 -0
  30. package/dist/client/_projectId-D3VOH5lN.mjs.map +1 -0
  31. package/dist/client/{_projectId-AjgJX6Gl.mjs → _projectId-ZBk6vka0.mjs} +83 -81
  32. package/dist/client/_projectId-ZBk6vka0.mjs.map +1 -0
  33. package/dist/client/{_securityGroupId-AO3wnH8g.mjs → _securityGroupId-BwgZnoiR.mjs} +2 -2
  34. package/dist/client/{_securityGroupId-AO3wnH8g.mjs.map → _securityGroupId-BwgZnoiR.mjs.map} +1 -1
  35. package/dist/client/{_securityGroupId-Bq0ZyG6z.mjs → _securityGroupId-Cz2NUHdB.mjs} +3 -3
  36. package/dist/client/{_securityGroupId-Bq0ZyG6z.mjs.map → _securityGroupId-Cz2NUHdB.mjs.map} +1 -1
  37. package/dist/client/{_storageType-CzZ4u9x_.mjs → _storageType-BNpP1A2N.mjs} +3 -2
  38. package/dist/client/_storageType-BNpP1A2N.mjs.map +1 -0
  39. package/dist/client/_storageType-BxSGKhAI.mjs +15 -0
  40. package/dist/client/_storageType-BxSGKhAI.mjs.map +1 -0
  41. package/dist/client/_storageType-DZYCmiLt.mjs +30 -0
  42. package/dist/client/_storageType-DZYCmiLt.mjs.map +1 -0
  43. package/dist/client/{_storageType-c-DAu8qr.mjs → _storageType-UqAMP-8d.mjs} +286 -285
  44. package/dist/client/_storageType-UqAMP-8d.mjs.map +1 -0
  45. package/dist/client/_storageType-u51_7OwJ.mjs +7 -0
  46. package/dist/client/_storageType-u51_7OwJ.mjs.map +1 -0
  47. package/dist/client/components/Errors/RouteIdLevelDefaultError.d.ts +2 -1
  48. package/dist/client/{flavors-ZudiAiTU.mjs → flavors-Ce3J-cFa.mjs} +2 -2
  49. package/dist/client/{flavors-ZudiAiTU.mjs.map → flavors-Ce3J-cFa.mjs.map} +1 -1
  50. package/dist/client/{flavors-Bgq3KZmx.mjs → flavors-D5ThLaXO.mjs} +84 -77
  51. package/dist/client/flavors-D5ThLaXO.mjs.map +1 -0
  52. package/dist/client/{floatingips-B1oLH8z6.mjs → floatingips-DXnRlLvV.mjs} +2 -2
  53. package/dist/client/{floatingips-B1oLH8z6.mjs.map → floatingips-DXnRlLvV.mjs.map} +1 -1
  54. package/dist/client/{floatingips-BtLg3yEQ.mjs → floatingips-HRbuLxiN.mjs} +3 -3
  55. package/dist/client/{floatingips-BtLg3yEQ.mjs.map → floatingips-HRbuLxiN.mjs.map} +1 -1
  56. package/dist/client/{floatingips-BeQEkVH8.mjs → floatingips-nN1kQmsu.mjs} +2 -2
  57. package/dist/client/{floatingips-BeQEkVH8.mjs.map → floatingips-nN1kQmsu.mjs.map} +1 -1
  58. package/dist/client/{images-CnTW3bpy.mjs → images-C8M3ysWR.mjs} +3 -3
  59. package/dist/client/{images-CnTW3bpy.mjs.map → images-C8M3ysWR.mjs.map} +1 -1
  60. package/dist/client/{images-DZHDYDQu.mjs → images-Cf5R28NR.mjs} +2 -2
  61. package/dist/client/{images-DZHDYDQu.mjs.map → images-Cf5R28NR.mjs.map} +1 -1
  62. package/dist/client/index.js +198 -197
  63. package/dist/client/index.js.map +1 -1
  64. package/dist/client/{objects-jYQBFzwg.mjs → objects-BudUAfWY.mjs} +4265 -4275
  65. package/dist/client/objects-BudUAfWY.mjs.map +1 -0
  66. package/dist/client/objects-Dc7sKUr8.mjs +67 -0
  67. package/dist/client/objects-Dc7sKUr8.mjs.map +1 -0
  68. package/dist/client/objects-Dw7oeTq2.mjs +80 -0
  69. package/dist/client/objects-Dw7oeTq2.mjs.map +1 -0
  70. package/dist/client/objects-_g7nGIn5.mjs +25 -0
  71. package/dist/client/objects-_g7nGIn5.mjs.map +1 -0
  72. package/dist/client/objects-eBxvY6_n.mjs +78 -0
  73. package/dist/client/objects-eBxvY6_n.mjs.map +1 -0
  74. package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
  75. package/dist/client/{securitygroups-BRndk7wh.mjs → securitygroups-67fFxiwt.mjs} +2 -2
  76. package/dist/client/{securitygroups-BRndk7wh.mjs.map → securitygroups-67fFxiwt.mjs.map} +1 -1
  77. package/dist/client/{securitygroups--0PS2wbM.mjs → securitygroups-DXrfyuVF.mjs} +3 -3
  78. package/dist/client/{securitygroups--0PS2wbM.mjs.map → securitygroups-DXrfyuVF.mjs.map} +1 -1
  79. package/dist/client/{securitygroups-Cs2Op-tu.mjs → securitygroups-WLB1_IM6.mjs} +3 -3
  80. package/dist/client/{securitygroups-Cs2Op-tu.mjs.map → securitygroups-WLB1_IM6.mjs.map} +1 -1
  81. package/dist/client/{securitygroups-CdN4yAAw.mjs → securitygroups-o0IXZM6S.mjs} +2 -2
  82. package/dist/client/{securitygroups-CdN4yAAw.mjs.map → securitygroups-o0IXZM6S.mjs.map} +1 -1
  83. package/dist/client/serviceCatalog-B3lKWC9V.mjs +6 -0
  84. package/dist/client/serviceCatalog-B3lKWC9V.mjs.map +1 -0
  85. package/dist/client/storageProviders-CJ5rOh13.mjs +15 -0
  86. package/dist/client/storageProviders-CJ5rOh13.mjs.map +1 -0
  87. package/dist/client/trpcClient.d.ts +96 -3
  88. package/dist/client/utils/serviceCatalog.d.ts +9 -0
  89. package/dist/client/utils/storageProviders.d.ts +44 -0
  90. package/dist/server/index.d.ts +96 -3
  91. package/dist/server/index.js +1224 -387
  92. package/package.json +1 -1
  93. package/dist/client/ContentHeader-CPJbgYWn.mjs +0 -115
  94. package/dist/client/ContentHeader-CPJbgYWn.mjs.map +0 -1
  95. package/dist/client/DeleteFlavorModal-C2MqUgGR.mjs.map +0 -1
  96. package/dist/client/RouteIdLevelDefaultError-CSseJ1yG.mjs.map +0 -1
  97. package/dist/client/_flavorId-DYv_StX22.mjs.map +0 -1
  98. package/dist/client/_imageId-mfKp3JHn.mjs +0 -558
  99. package/dist/client/_projectId-AjgJX6Gl.mjs.map +0 -1
  100. package/dist/client/_projectId-DgciZslU.mjs +0 -92
  101. package/dist/client/_projectId-DgciZslU.mjs.map +0 -1
  102. package/dist/client/_storageType-BRWWJtow.mjs +0 -14
  103. package/dist/client/_storageType-BRWWJtow.mjs.map +0 -1
  104. package/dist/client/_storageType-CzZ4u9x_.mjs.map +0 -1
  105. package/dist/client/_storageType-c-DAu8qr.mjs.map +0 -1
  106. package/dist/client/_storageType-zeSZe--V.mjs +0 -7
  107. package/dist/client/_storageType-zeSZe--V.mjs.map +0 -1
  108. package/dist/client/flavors-Bgq3KZmx.mjs.map +0 -1
  109. package/dist/client/objects-25xsh4Ia.mjs +0 -66
  110. package/dist/client/objects-25xsh4Ia.mjs.map +0 -1
  111. package/dist/client/objects-KXY6dgwq.mjs +0 -82
  112. package/dist/client/objects-KXY6dgwq.mjs.map +0 -1
  113. package/dist/client/objects-QryuClU3.mjs +0 -82
  114. package/dist/client/objects-QryuClU3.mjs.map +0 -1
  115. package/dist/client/objects-jYQBFzwg.mjs.map +0 -1
@@ -1,92 +0,0 @@
1
- import { Q as e, f as t } from "./build-WuxXRAqf.mjs";
2
- import { t as n } from "./Slot-CWb612-_.mjs";
3
- import { t as r } from "./helpers-1PpYf-fC.mjs";
4
- import { t as i } from "./ContentHeader-CPJbgYWn.mjs";
5
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
- import { useLoaderData as s, useNavigate as c, useRouteContext as l } from "@tanstack/react-router";
7
- import { Trans as u, useLingui as d } from "@lingui/react";
8
- //#region src/client/routes/_auth/projects/$projectId/index.tsx?tsr-split=component
9
- function f({ group: e, label: r, to: i, service: s }) {
10
- let u = c(), { slots: d } = l({ strict: !1 });
11
- return /*#__PURE__*/ o(t, {
12
- onClick: () => u({ to: i }),
13
- className: "flex min-h-40 flex-col gap-4 px-3 pt-2 pb-3",
14
- "data-testid": "service-card",
15
- children: [/*#__PURE__*/ o("div", {
16
- className: "flex min-w-0 flex-col",
17
- children: [/*#__PURE__*/ a("p", {
18
- className: "text-theme-light text-xs leading-5 font-medium",
19
- children: e
20
- }), /*#__PURE__*/ o("div", {
21
- className: "flex items-center gap-2",
22
- children: [/*#__PURE__*/ a("p", {
23
- className: "text-theme-high text-lg leading-7 font-bold",
24
- "data-testid": "service-card-label",
25
- children: r
26
- }), d?.serviceBadge && /*#__PURE__*/ a(n, {
27
- component: d.serviceBadge,
28
- useShadowDOM: !1,
29
- currentService: s
30
- })]
31
- })]
32
- }), /*#__PURE__*/ a("div", { className: "flex-1" })]
33
- });
34
- }
35
- function p() {
36
- let { crumbProject: t, availableServices: n, projectId: c, description: p } = s({ from: "/_auth/projects/$projectId" }), { i18n: m, _: h } = d(), { enabledServices: g, serviceExtensions: _ } = l({ strict: !1 }), v = (e) => !g || g.includes(e), y = r(n ?? []), b = `/projects/${c}`, x = [];
37
- y.image?.glance && v("images") && x.push({
38
- group: m._({ id: "rp0Bd0" }),
39
- label: m._({ id: "an5hVd" }),
40
- to: `${b}/compute/images`,
41
- service: "images"
42
- }), y.compute?.nova && v("flavors") && x.push({
43
- group: m._({ id: "rp0Bd0" }),
44
- label: m._({ id: "neiJm0" }),
45
- to: `${b}/compute/flavors`,
46
- service: "flavors"
47
- }), y.network && (v("securitygroups") && x.push({
48
- group: m._({ id: "OR475H" }),
49
- label: m._({ id: "4opp4r" }),
50
- to: `${b}/network/securitygroups`,
51
- service: "securitygroups"
52
- }), v("floatingips") && x.push({
53
- group: m._({ id: "OR475H" }),
54
- label: m._({ id: "u77/s4" }),
55
- to: `${b}/network/floatingips`,
56
- service: "floatingips"
57
- })), y["object-store"]?.swift && v("containers") && x.push({
58
- group: m._({ id: "BrrIs8" }),
59
- label: m._({ id: "+OEi73" }),
60
- to: `${b}/storage/swift/containers`,
61
- service: "containers"
62
- }), y["object-store-ceph"]?.ceph && v("ceph-containers") && x.push({
63
- group: m._({ id: "BrrIs8" }),
64
- label: m._({ id: "KhNDX4" }),
65
- to: `${b}/storage/ceph/buckets`,
66
- service: "ceph-containers"
67
- });
68
- for (let e of _ ?? []) y[e.serviceType]?.[e.serviceName] && (!g || g.includes(e.serviceType)) && x.push({
69
- group: m._({ id: "MILoeL" }),
70
- label: e.label,
71
- to: `/projects/${c}/services/${e.serviceType}`,
72
- service: e.serviceType
73
- });
74
- return /*#__PURE__*/ o(e, {
75
- direction: "vertical",
76
- children: [/*#__PURE__*/ a(i, {
77
- title: t?.name ?? m._({ id: "e0NrBM" }),
78
- projectId: c,
79
- description: p
80
- }), x.length > 0 ? /*#__PURE__*/ a("div", {
81
- className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4",
82
- children: x.map((e) => /*#__PURE__*/ a(f, { ...e }, e.to))
83
- }) : /*#__PURE__*/ a("p", {
84
- className: "text-theme-light text-sm",
85
- children: /*#__PURE__*/ a(u, { id: "Q1W//7" })
86
- })]
87
- });
88
- }
89
- //#endregion
90
- export { p as component };
91
-
92
- //# sourceMappingURL=_projectId-DgciZslU.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_projectId-DgciZslU.mjs","names":["useLoaderData","useNavigate","Card","Stack","getServiceIndex","Trans","useLingui","useRouteContext","ContentHeader","Slot","ServiceCardProps","group","label","to","service","ServiceCard","navigate","slots","strict","serviceBadge","RouteComponent","crumbProject","availableServices","projectId","description","from","t","enabledServices","serviceExtensions","isEnabled","includes","serviceIndex","base","cards","push","extension","serviceType","serviceName","name","length","map","card","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/index.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, useLoaderData, useNavigate } from \"@tanstack/react-router\"\nimport { Card, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { useRouteContext } from \"@tanstack/react-router\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { Slot } from \"@/client/components/Slot\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/\")({\n staticData: {\n analytics: {\n name: \"projects.detail\",\n },\n } satisfies RouteInfo,\n component: RouteComponent,\n})\n\ninterface ServiceCardProps {\n group: string\n label: string\n to: string\n service: string\n}\n\nfunction ServiceCard({ group, label, to, service }: ServiceCardProps) {\n const navigate = useNavigate()\n const { slots } = useRouteContext({ strict: false })\n\n return (\n <Card\n onClick={() => navigate({ to: to as never })}\n className=\"flex min-h-40 flex-col gap-4 px-3 pt-2 pb-3\"\n data-testid=\"service-card\"\n >\n <div className=\"flex min-w-0 flex-col\">\n <p className=\"text-theme-light text-xs leading-5 font-medium\">{group}</p>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-theme-high text-lg leading-7 font-bold\" data-testid=\"service-card-label\">\n {label}\n </p>\n {slots?.serviceBadge && <Slot component={slots.serviceBadge} useShadowDOM={false} currentService={service} />}\n </div>\n </div>\n <div className=\"flex-1\" />\n </Card>\n )\n}\n\nfunction RouteComponent() {\n const { crumbProject, availableServices, projectId, description } = useLoaderData({\n from: \"/_auth/projects/$projectId\",\n })\n const { t } = useLingui()\n const { enabledServices, serviceExtensions } = useRouteContext({ strict: false })\n const isEnabled = (service: string) => !enabledServices || enabledServices.includes(service)\n\n const serviceIndex = getServiceIndex(availableServices ?? [])\n const base = `/projects/${projectId}`\n\n const cards: ServiceCardProps[] = []\n\n if (serviceIndex[\"image\"]?.[\"glance\"] && isEnabled(\"images\"))\n cards.push({ group: t`Compute`, label: t`Images`, to: `${base}/compute/images`, service: \"images\" })\n if (serviceIndex[\"compute\"]?.[\"nova\"] && isEnabled(\"flavors\"))\n cards.push({ group: t`Compute`, label: t`Flavors`, to: `${base}/compute/flavors`, service: \"flavors\" })\n if (serviceIndex[\"network\"]) {\n if (isEnabled(\"securitygroups\"))\n cards.push({\n group: t`Network`,\n label: t`Security Groups`,\n to: `${base}/network/securitygroups`,\n service: \"securitygroups\",\n })\n if (isEnabled(\"floatingips\"))\n cards.push({\n group: t`Network`,\n label: t`Floating IPs`,\n to: `${base}/network/floatingips`,\n service: \"floatingips\",\n })\n }\n if (serviceIndex[\"object-store\"]?.[\"swift\"] && isEnabled(\"containers\"))\n cards.push({\n group: t`Storage`,\n label: t`Object Storage (Swift)`,\n to: `${base}/storage/swift/containers`,\n service: \"containers\",\n })\n if (serviceIndex[\"object-store-ceph\"]?.[\"ceph\"] && isEnabled(\"ceph-containers\"))\n cards.push({\n group: t`Storage`,\n label: t`Object Storage (Ceph)`,\n to: `${base}/storage/ceph/buckets`,\n service: \"ceph-containers\",\n })\n\n for (const extension of serviceExtensions ?? []) {\n // if the extension's service is in the catalog and enabled, display a card for it\n if (\n serviceIndex[extension.serviceType]?.[extension.serviceName] &&\n (!enabledServices || enabledServices.includes(extension.serviceType))\n )\n cards.push({\n group: t`Services`,\n label: extension.label,\n to: `/projects/${projectId}/services/${extension.serviceType}`,\n service: extension.serviceType,\n })\n }\n\n return (\n <Stack direction=\"vertical\">\n <ContentHeader title={crumbProject?.name ?? t`Project`} projectId={projectId} description={description} />\n {cards.length > 0 ? (\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4\">\n {cards.map((card) => (\n <ServiceCard key={card.to} {...card} />\n ))}\n </div>\n ) : (\n <p className=\"text-theme-light text-sm\">\n <Trans>No services available for this project.</Trans>\n </p>\n )}\n </Stack>\n )\n}\n"],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- import { t as e } from "./_storageType-CzZ4u9x_.mjs";
2
- import { t } from "./useSetBreadcrumb-tn7lBaQV.mjs";
3
- import { jsx as n } from "react/jsx-runtime";
4
- import { Outlet as r } from "@tanstack/react-router";
5
- import { useLingui as i } from "@lingui/react";
6
- //#region src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType.tsx?tsr-split=component
7
- function a() {
8
- let { i18n: a, _: o } = i(), { provider: s } = e.useParams(), c = s === "swift" ? a._({ id: "+OEi73" }) : s === "ceph" ? a._({ id: "KhNDX4" }) : a._({ id: "BrrIs8" });
9
- return t(e.id, c), /*#__PURE__*/ n(r, {});
10
- }
11
- //#endregion
12
- export { a as component };
13
-
14
- //# sourceMappingURL=_storageType-BRWWJtow.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_storageType-BRWWJtow.mjs","names":["Outlet","useLingui","useSetBreadcrumb","Route","StorageTypeLayout","t","provider","useParams","label","id","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n } satisfies RouteInfo,\n component: StorageTypeLayout,\n})\n\nfunction StorageTypeLayout() {\n const { t } = useLingui()\n const { provider } = Route.useParams()\n const label =\n provider === \"swift\" ? t`Object Storage (Swift)` : provider === \"ceph\" ? t`Object Storage (Ceph)` : t`Storage`\n useSetBreadcrumb(Route.id, label)\n return <Outlet />\n}\n"],"mappings":";;;;;;AAaA,SAASI,IAAAA;CACP,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQH,EAAAA,GACR,EAAEK,gBAAaH,EAAMI,UAAS,GAC9BC,IACJF,MAAa,UAAUD,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,IAA2BC,MAAa,SAASD,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,IAA0BA,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;CAEvG,OADAH,EAAiBC,EAAMM,IAAID,CAAAA,GACpB,gBAAC,GAAA,CAAA,CAAA;AACV"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"_storageType-CzZ4u9x_.mjs","names":["createFileRoute","Route","staticData","section","service","RouteInfo","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType.tsx"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n } satisfies RouteInfo,\n component: StorageTypeLayout,\n})\n\nfunction StorageTypeLayout() {\n const { t } = useLingui()\n const { provider } = Route.useParams()\n const label =\n provider === \"swift\" ? t`Object Storage (Swift)` : provider === \"ceph\" ? t`Object Storage (Ceph)` : t`Storage`\n useSetBreadcrumb(Route.id, label)\n return <Outlet />\n}\n"],"mappings":";AAKA,IAAaC,IAAQD,EAAgB,2DAAA,CAAA,CAA6D;CAChGE,YAAY;EACVC,SAAS;EACTC,SAAS;CACX;CACAE,WAASC,+CAAA,WAAA;AACX,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"_storageType-c-DAu8qr.mjs","names":["useState","trpcReact","Modal","TextInput","Stack","Message","useProjectId","useModalTracking","CreateContainerModal","isOpen","onClose","onSuccess","onPartialSuccess","maxContainerNameLength","existingContainers","useLingui","projectId","containerName","setContainerName","nameError","setNameError","submitError","setSubmitError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","createContainerMutation","storage","swift","createContainer","useMutation","data","listContainers","invalidate","name","trim","optionsApplied","optionsError","t","handleClose","onError","error","code","message","reset","validateName","trimmed","length","includes","some","c","handleNameChange","e","value","target","handleSubmit","mutate","project_id","container","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","isPending","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","dismissible","onDismiss","role","aria-live","data-testid","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","autoFocus","placeholder","useEffect","useState","useNavigate","useParams","Button","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","Status","formatBytesBinary","formatSwiftDate","useVirtualizedTableBody","CreateContainerModal","EmptyContainerModal","DeleteContainerModal","EditContainerMetadataModal","ManageContainerAccessModal","ContainerTableView","containers","createModalOpen","setCreateModalOpen","maxContainerNameLength","existingContainers","onCreateSuccess","onCreatePartialSuccess","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","onPropertiesSuccess","onPropertiesError","onAclSuccess","onAclError","selectedContainers","setSelectedContainers","hasAnyBulkAction","projectId","provider","storageType","from","useLingui","navigate","scrollbarWidth","setScrollbarWidth","emptyModalContainer","setEmptyModalContainer","deleteModalContainer","setDeleteModalContainer","propertiesModalContainer","setPropertiesModalContainer","accessControlModalContainer","setAccessControlModalContainer","ref","tableBodyRef","elementRef","parentRef","height","bodyHeight","virtualItems","totalSize","measureElement","count","length","current","width","offsetWidth","clientWidth","handleSelectContainer","containerName","includes","filter","name","columnCount","gridColumnTemplate","div","className","style","paddingRight","columns","data-testid","marginRight","colSpan","status","title","t","body","position","map","virtualRow","container","index","isSelected","handleRowNavigate","to","params","data-index","top","left","transform","start","display","gridTemplateColumns","alignItems","tabIndex","onClick","onKeyDown","e","key","preventDefault","stopPropagation","checked","onChange","span","toLocaleString","last_modified","bytes","as","icon","aria-label","label","isOpen","onClose","onSuccess","onPartialSuccess","onError","Tooltip","TooltipTrigger","TooltipContent","Icon","formatBytesBinary","LimitItem","label","value","undefined","span","className","icon","size","CapabilityItem","Section","title","children","ContainerLimitsTooltip","serviceInfo","accountInfo","open","useLingui","swift","capabilityMap","account_quotas","t","container_quotas","bulk_delete","bulk_upload","slo","container_sync","tempurl","symlink","versioned_writes","capabilities","Object","entries","filter","key","map","triggerEvent","placement","objectCount","toLocaleString","bytesUsed","quotaBytes","max_file_size","max_container_name_length","max_object_name_length","container_listing_limit","account_listing_limit","max_header_size","max_meta_count","max_meta_name_length","max_meta_value_length","max_meta_overall_size","max_deletes_per_request","max_containers_per_extraction","max_manifest_segments","length","cap","z","useForm","useStore","useState","trpcReact","Modal","Status","Stack","Form","FormSection","TextInput","useProjectId","useModalTracking","MAX_VISIBLE","CONFIRM_WORD","EmptyContainersModal","isOpen","containers","onClose","onComplete","i18n","useLingui","projectId","progress","setProgress","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","transform","val","trim","refine","value","message","t","form","defaultValues","validators","onSubmit","emptyContainerMutation","isPending","emptiedCount","totalDeleted","errors","total","length","i","current","container","deleted","mutateAsync","project_id","name","err","Error","String","push","utils","storage","swift","listContainers","invalidate","handleClose","canEmpty","store","state","isSubmitting","values","useUtils","emptyContainer","useMutation","reset","totalCount","visibleContainers","slice","hiddenCount","progressCurrent","progressTotal","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","cancelButtonLabel","onConfirm","handleSubmit","disableConfirmButton","disableCancelButton","disableCloseButton","size","status","className","div","p","strong","direction","gap","map","count","span","_","plural","id","e","preventDefault","Field","children","field","label","placeholder","onChange","handleChange","target","disabled","autoFocus","required","useState","useEffect","useRef","startTransition","SortInput","trpcReact","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Status","Stack","toast","formatBytesBinary","parseSwiftDate","ContainerTableView","getContainerCreatedToast","getContainerCreatedWithWarningToast","getContainerEmptiedToast","getContainerEmptyErrorToast","getContainerDeletedToast","getContainerDeleteErrorToast","getContainerUpdatedToast","getContainerUpdateErrorToast","getContainerAclUpdatedToast","getContainerAclUpdateErrorToast","getContainersEmptyCompleteToast","ContainerLimitsTooltip","EmptyContainersModal","useNavigate","Route","useProjectId","SwiftContainers","i18n","useLingui","projectId","navigate","from","fullPath","sortBy","sortDirection","search","searchParam","useSearch","hasAnyBulkAction","createModalOpen","setCreateModalOpen","emptyAllModalOpen","setEmptyAllModalOpen","selectedContainers","setSelectedContainers","localSearchTerm","setLocalSearchTerm","debounceTimer","undefined","clearTimeout","current","handleCreateSuccess","containerName","message","options","success","handleCreatePartialSuccess","reason","warning","handleEmptySuccess","deletedCount","handleEmptyError","errorMessage","error","handleDeleteSuccess","handleDeleteError","handlePropertiesSuccess","handlePropertiesError","handleAclSuccess","handleAclError","handleEmptyAllComplete","emptiedCount","totalDeleted","errors","length","failedContainerNames","Set","map","e","split","prev","filter","name","has","severity","sortSettings","label","t","value","data","containers","isLoading","storage","swift","listContainers","useQuery","project_id","format","accountInfo","getAccountMetadata","serviceInfo","getServiceInfo","sortContainers","sort","a","b","comparison","localeCompare","count","bytes","last_modified","at","getTime","bt","filteredContainers","container","toLowerCase","includes","sortedContainers","handleSearchChange","term","handleSortChange","newSortSettings","resolvedSortBy","toString","resolvedDirection","status","title","body","bytesUsed","quotaBytes","remainingBytes","selectedContainerSummaries","c","hasSelection","selectedCount","totalCount","filteredCount","isFiltered","displayedNames","allSelected","every","n","someSelected","some","handleToggleSelectAll","div","className","direction","distribution","alignment","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","variant","onClick","placeholder","data-testid","onInput","currentTarget","window","setTimeout","onSearch","onClear","checked","indeterminate","onChange","as","disabled","size","icon","_","plural","span","maxContainerNameLength","max_container_name_length","existingContainers","onCreateSuccess","onCreatePartialSuccess","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","onPropertiesSuccess","onPropertiesError","onAclSuccess","onAclError","isOpen","onClose","onComplete","useParams","ErrorBoundary","SwiftContainers","CephBuckets","Trans","useLingui","ContentHeader","StorageDashboard","project","provider","from","select","params","projectId","storageType","t","pageTitle","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/CreateContainerModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerLimitsTooltip.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/EmptyContainersModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx?tsr-split=component"],"sourcesContent":["import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\n\ninterface CreateContainerModalProps {\n isOpen: boolean\n onClose: () => void\n onSuccess?: (containerName: string) => void\n onPartialSuccess?: (containerName: string, reason: string) => void\n maxContainerNameLength?: number\n existingContainers?: ContainerSummary[]\n}\n\nexport const CreateContainerModal = ({\n isOpen,\n onClose,\n onSuccess,\n onPartialSuccess,\n maxContainerNameLength = 256,\n existingContainers = [],\n}: CreateContainerModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [containerName, setContainerName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [submitError, setSubmitError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.container.create\",\n })\n\n const utils = trpcReact.useUtils()\n\n const createContainerMutation = trpcReact.storage.swift.createContainer.useMutation({\n onSuccess: (data) => {\n utils.storage.swift.listContainers.invalidate()\n const name = containerName.trim()\n if (data.optionsApplied) {\n onSuccess?.(name)\n } else {\n onPartialSuccess?.(name, data.optionsError ?? t`The container's settings could not be applied.`)\n }\n handleClose()\n },\n onError: (error) => {\n if (error.data?.code === \"CONFLICT\") {\n setNameError(t`A container with this name already exists`)\n setSubmitError(null)\n } else {\n setSubmitError(error.message || t`The container could not be created. Try again or choose a different name.`)\n }\n\n resetTracking()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setContainerName(\"\")\n setNameError(null)\n setSubmitError(null)\n resetTracking()\n createContainerMutation.reset()\n onClose()\n }\n\n const validateName = (name: string): boolean => {\n const trimmed = name.trim()\n\n if (!trimmed) {\n setNameError(t`Container name is required`)\n return false\n }\n if (trimmed.length > maxContainerNameLength) {\n setNameError(t`Container name must be ${maxContainerNameLength} characters or fewer`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNameError(t`Container name cannot contain slashes`)\n return false\n }\n\n if (existingContainers.some((c) => c.name === trimmed)) {\n setNameError(t`A container with this name already exists`)\n return false\n }\n\n setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setContainerName(value)\n setSubmitError(null)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(containerName)) return\n setSubmitError(null)\n markSubmitted()\n createContainerMutation.mutate({\n project_id: projectId,\n container: containerName.trim(),\n })\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") {\n handleSubmit()\n }\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Create Container`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={createContainerMutation.isPending ? t`Creating...` : t`Create`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={createContainerMutation.isPending || !containerName.trim()}\n disableCancelButton={createContainerMutation.isPending}\n disableCloseButton={createContainerMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {submitError && (\n <Message\n variant=\"error\"\n dismissible\n onDismiss={() => setSubmitError(null)}\n role=\"alert\"\n aria-live=\"assertive\"\n data-testid=\"create-container-error\"\n >\n {submitError}\n </Message>\n )}\n <p className=\"text-theme-default\">\n <Trans>\n Inside a project, objects are stored in containers. Containers are where you define access permissions and\n quotas.\n </Trans>\n </p>\n <TextInput\n label={t`Container name`}\n required\n value={containerName}\n onChange={handleNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={createContainerMutation.isPending}\n autoFocus\n placeholder={t`Enter container name`}\n />\n </Stack>\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport {\n Button,\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { formatSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { useVirtualizedTableBody } from \"@/client/hooks/useVirtualizedTableBody\"\nimport { CreateContainerModal } from \"./CreateContainerModal\"\nimport { EmptyContainerModal } from \"./EmptyContainerModal\"\nimport { DeleteContainerModal } from \"./DeleteContainerModal\"\nimport { EditContainerMetadataModal } from \"./EditContainerMetadataModal\"\nimport { ManageContainerAccessModal } from \"./ManageContainerAccessModal\"\n\ninterface ContainerTableViewProps {\n containers: ContainerSummary[]\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n maxContainerNameLength?: number\n existingContainers?: ContainerSummary[]\n onCreateSuccess: (containerName: string) => void\n onCreatePartialSuccess: (containerName: string, reason: string) => void\n onEmptySuccess: (containerName: string, deletedCount: number) => void\n onEmptyError: (containerName: string, errorMessage: string) => void\n onDeleteSuccess: (containerName: string) => void\n onDeleteError: (containerName: string, errorMessage: string) => void\n onPropertiesSuccess: (containerName: string) => void\n onPropertiesError: (containerName: string, errorMessage: string) => void\n onAclSuccess: (containerName: string) => void\n onAclError: (containerName: string, errorMessage: string) => void\n selectedContainers: string[]\n setSelectedContainers: (containers: string[]) => void\n // When false, the row-selection column (header checkbox + per-row checkboxes)\n // is dropped entirely and the grid renders one fewer column. Defaults to true\n // so existing callers that don't pass it keep the selectable layout.\n hasAnyBulkAction?: boolean\n}\n\nexport const ContainerTableView = ({\n containers,\n createModalOpen,\n setCreateModalOpen,\n maxContainerNameLength,\n existingContainers = [],\n onCreateSuccess,\n onCreatePartialSuccess,\n onEmptySuccess,\n onEmptyError,\n onDeleteSuccess,\n onDeleteError,\n onPropertiesSuccess,\n onPropertiesError,\n onAclSuccess,\n onAclError,\n selectedContainers,\n setSelectedContainers,\n hasAnyBulkAction = true,\n}: ContainerTableViewProps) => {\n const { projectId, provider, storageType } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n })\n\n const { t } = useLingui()\n const navigate = useNavigate()\n\n const [scrollbarWidth, setScrollbarWidth] = useState(0)\n const [emptyModalContainer, setEmptyModalContainer] = useState<ContainerSummary | null>(null)\n const [deleteModalContainer, setDeleteModalContainer] = useState<ContainerSummary | null>(null)\n const [propertiesModalContainer, setPropertiesModalContainer] = useState<ContainerSummary | null>(null)\n const [accessControlModalContainer, setAccessControlModalContainer] = useState<ContainerSummary | null>(null)\n\n // Height measured from the space actually left below the table, plus a\n // virtualizer that stays silent until that height is known.\n const {\n ref: tableBodyRef,\n elementRef: parentRef,\n height: bodyHeight,\n virtualItems,\n totalSize,\n measureElement,\n } = useVirtualizedTableBody({ count: containers.length })\n\n // Calculate scrollbar width\n useEffect(() => {\n if (parentRef.current) {\n const width = parentRef.current.offsetWidth - parentRef.current.clientWidth\n setScrollbarWidth(width)\n }\n }, [containers.length, bodyHeight])\n\n const handleSelectContainer = (containerName: string) => {\n if (selectedContainers.includes(containerName)) {\n setSelectedContainers(selectedContainers.filter((name) => name !== containerName))\n } else {\n setSelectedContainers([...selectedContainers, containerName])\n }\n }\n\n // Column count and template depend on whether the selection column is shown.\n // With selection: checkbox, name, count, last modified, size, actions menu (6).\n // Without selection: the leading 40px checkbox column is dropped (5).\n const columnCount = hasAnyBulkAction ? 6 : 5\n const gridColumnTemplate = hasAnyBulkAction\n ? \"40px minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n : \"minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n className=\"containers\"\n data-testid=\"containers-table-header\"\n >\n <DataGridRow>\n {hasAnyBulkAction && <DataGridHeadCell />}\n <DataGridHeadCell>\n <Trans>Container Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Object Count</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Total Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell style={{ marginRight: `-${scrollbarWidth}px` }} />\n </DataGridRow>\n\n {(!containers || containers.length === 0) && (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status\n status=\"empty\"\n title={t`No containers found`}\n body={t`There are no containers available with the current search criteria. Try adjusting your search term.`}\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n\n {/* Virtualized Table Body — sized to the space actually left below the\n table, so banners above it shrink the table instead of growing the\n page. */}\n <div\n ref={tableBodyRef}\n className=\"overflow-auto\"\n style={{ height: `${bodyHeight ?? 0}px` }}\n data-testid=\"containers-table-body\"\n >\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n style={{\n height: `${totalSize}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n const container = containers[virtualRow.index]\n const isSelected = selectedContainers.includes(container.name)\n\n const handleRowNavigate = () =>\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider, storageType, containerName: container.name },\n })\n\n return (\n <DataGridRow\n key={container.name}\n data-index={virtualRow.index}\n ref={measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"grid\",\n gridTemplateColumns: gridColumnTemplate,\n alignItems: \"stretch\",\n }}\n data-testid={`container-row-${container.name}`}\n tabIndex={0}\n onClick={handleRowNavigate}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n handleRowNavigate()\n }\n }}\n >\n {hasAnyBulkAction && (\n <DataGridCell\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.stopPropagation()\n }\n }}\n >\n <Checkbox\n checked={isSelected}\n onChange={() => handleSelectContainer(container.name)}\n data-testid={`select-container-${container.name}`}\n />\n </DataGridCell>\n )}\n <DataGridCell className=\"min-w-0 overflow-hidden\">\n <span className=\"block truncate\" title={container.name}>\n {container.name}\n </span>\n </DataGridCell>\n <DataGridCell>{container.count.toLocaleString()}</DataGridCell>\n <DataGridCell>{formatSwiftDate(container.last_modified) ?? t`N/A`}</DataGridCell>\n <DataGridCell>{formatBytesBinary(container.bytes)}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button\n icon=\"moreVert\"\n title={t`Container actions`}\n aria-label={t`Container actions`}\n className=\"!bg-transparent\"\n />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() => setAccessControlModalContainer(container)}\n data-testid={`access-control-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Preview and Edit metadata`}\n onClick={() => setPropertiesModalContainer(container)}\n data-testid={`properties-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Empty Container`}\n onClick={() => setEmptyModalContainer(container)}\n data-testid={`empty-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Delete Container`}\n onClick={() => setDeleteModalContainer(container)}\n data-testid={`delete-action-${container.name}`}\n />\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </div>\n </div>\n\n <CreateContainerModal\n isOpen={createModalOpen}\n onClose={() => setCreateModalOpen(false)}\n onSuccess={onCreateSuccess}\n onPartialSuccess={onCreatePartialSuccess}\n maxContainerNameLength={maxContainerNameLength}\n existingContainers={existingContainers}\n />\n\n <EmptyContainerModal\n isOpen={emptyModalContainer !== null}\n container={emptyModalContainer}\n onClose={() => setEmptyModalContainer(null)}\n onSuccess={onEmptySuccess}\n onError={onEmptyError}\n />\n\n <DeleteContainerModal\n isOpen={deleteModalContainer !== null}\n container={deleteModalContainer}\n onClose={() => setDeleteModalContainer(null)}\n onSuccess={onDeleteSuccess}\n onError={onDeleteError}\n />\n\n <EditContainerMetadataModal\n isOpen={propertiesModalContainer !== null}\n container={propertiesModalContainer}\n onClose={() => setPropertiesModalContainer(null)}\n onSuccess={onPropertiesSuccess}\n onError={onPropertiesError}\n />\n\n <ManageContainerAccessModal\n isOpen={accessControlModalContainer !== null}\n container={accessControlModalContainer}\n onClose={() => setAccessControlModalContainer(null)}\n onSuccess={onAclSuccess}\n onError={onAclError}\n />\n </>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Tooltip, TooltipTrigger, TooltipContent, Icon } from \"@cloudoperators/juno-ui-components\"\nimport { ServiceInfo, AccountInfo } from \"@/server/Storage/types/swift\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface ContainerLimitsTooltipProps {\n serviceInfo?: ServiceInfo\n accountInfo?: AccountInfo\n open?: boolean\n}\n\ninterface LimitItemProps {\n label: string\n value?: string | number\n}\n\nconst LimitItem = ({ label, value }: LimitItemProps) => {\n if (value === undefined || value === null) return null\n return (\n <span className=\"flex items-start gap-1.5\">\n <Icon icon=\"check\" size=\"16px\" className=\"text-theme-success mt-0.5 shrink-0\" />\n <span>\n <span className=\"font-medium\">{label}:</span> {value}\n </span>\n </span>\n )\n}\n\nconst CapabilityItem = ({ label }: { label: string }) => (\n <span className=\"flex items-start gap-1.5\">\n <Icon icon=\"check\" size=\"16px\" className=\"text-theme-success mt-0.5 shrink-0\" />\n <span>{label}</span>\n </span>\n)\n\nconst Section = ({ title, children }: { title: React.ReactNode; children: React.ReactNode }) => (\n <span className=\"flex flex-col gap-1.5\">\n <span className=\"text-theme-default block font-semibold\">{title}</span>\n {children}\n </span>\n)\n\nexport const ContainerLimitsTooltip = ({ serviceInfo, accountInfo, open }: ContainerLimitsTooltipProps) => {\n const { t } = useLingui()\n\n const swift = serviceInfo?.swift\n\n const capabilityMap = {\n account_quotas: t`Account quotas`,\n container_quotas: t`Container quotas`,\n bulk_delete: t`Efficient bulk deletion`,\n bulk_upload: t`Bulk upload of archive files`,\n slo: t`Static large object support`,\n container_sync: t`Container syncing`,\n tempurl: t`Temporary URLs`,\n symlink: t`Symlinks`,\n versioned_writes: t`Versioned writes`,\n } as const\n\n const capabilities = Object.entries(capabilityMap)\n .filter(([key]) => swift?.[key as keyof typeof swift])\n .map(([, label]) => label)\n\n return (\n <Tooltip triggerEvent=\"hover\" placement=\"bottom-end\" open={open}>\n <TooltipTrigger className=\"max-h-5\">\n <span>\n <Icon icon=\"info\" size=\"20px\" className=\"text-theme-light hover:text-theme-default cursor-pointer\" />\n </span>\n </TooltipTrigger>\n <TooltipContent className=\"z-10 w-72 text-sm\">\n <span className=\"flex flex-col gap-3 p-1\">\n {/* Account stats */}\n {accountInfo && (\n <Section title={<Trans>Account</Trans>}>\n <LimitItem label={t`Objects`} value={accountInfo.objectCount.toLocaleString()} />\n <LimitItem label={t`Used`} value={formatBytesBinary(accountInfo.bytesUsed)} />\n {accountInfo.quotaBytes !== undefined && (\n <LimitItem label={t`Quota`} value={formatBytesBinary(accountInfo.quotaBytes)} />\n )}\n </Section>\n )}\n\n {/* Limits */}\n {swift && (\n <Section title={<Trans>Limits</Trans>}>\n <LimitItem\n label={t`Max file size`}\n value={swift.max_file_size !== undefined ? formatBytesBinary(swift.max_file_size) : undefined}\n />\n <LimitItem label={t`Max container name length`} value={swift.max_container_name_length} />\n <LimitItem label={t`Max object name length`} value={swift.max_object_name_length} />\n <LimitItem label={t`Container listing limit`} value={swift.container_listing_limit?.toLocaleString()} />\n <LimitItem label={t`Account listing limit`} value={swift.account_listing_limit?.toLocaleString()} />\n <LimitItem label={t`Max header size`} value={swift.max_header_size} />\n <LimitItem label={t`Max meta count`} value={swift.max_meta_count} />\n <LimitItem label={t`Max meta name length`} value={swift.max_meta_name_length} />\n <LimitItem label={t`Max meta value length`} value={swift.max_meta_value_length} />\n <LimitItem label={t`Max meta overall size`} value={swift.max_meta_overall_size} />\n {swift.bulk_delete && (\n <LimitItem\n label={t`Max deletes per request`}\n value={swift.bulk_delete.max_deletes_per_request.toLocaleString()}\n />\n )}\n {swift.bulk_upload && (\n <LimitItem\n label={t`Max containers per extraction`}\n value={swift.bulk_upload.max_containers_per_extraction.toLocaleString()}\n />\n )}\n {swift.slo && (\n <LimitItem label={t`Max SLO segments`} value={swift.slo.max_manifest_segments.toLocaleString()} />\n )}\n </Section>\n )}\n\n {/* Capabilities */}\n {capabilities.length > 0 && (\n <Section title={<Trans>Capabilities</Trans>}>\n {capabilities.map((cap) => (\n <CapabilityItem key={cap} label={cap} />\n ))}\n </Section>\n )}\n </span>\n </TooltipContent>\n </Tooltip>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useState } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Status, Stack, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\n// Max number of container names shown in the list before truncating\nconst MAX_VISIBLE = 20\n\n// The literal word the user must type to confirm this destructive action.\n// The gating logic (isConfirmed) compares against this constant, NOT the\n// translated label — so a mistranslated label can never weaken or break the\n// confirmation gate. The English label below should name the same word for clarity.\nconst CONFIRM_WORD = \"empty\"\n\ninterface EmptyContainersResult {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n}\n\ninterface EmptyContainersModalProps {\n isOpen: boolean\n containers: ContainerSummary[]\n onClose: () => void\n onComplete?: (result: EmptyContainersResult) => void\n}\n\nexport const EmptyContainersModal = ({ isOpen, containers, onClose, onComplete }: EmptyContainersModalProps) => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n\n const [progress, setProgress] = useState<{ current: number; total: number } | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.containers.empty\",\n })\n\n const formSchema = z.object({\n confirm: z\n .string()\n .transform((val) => val.trim())\n .refine((value) => value === CONFIRM_WORD, {\n message: t`Type \"${CONFIRM_WORD}\" to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (emptyContainerMutation.isPending || progress !== null) return\n\n markSubmitted()\n let emptiedCount = 0\n let totalDeleted = 0\n const errors: string[] = []\n const total = containers.length\n\n for (let i = 0; i < containers.length; i++) {\n setProgress({ current: i + 1, total })\n const container = containers[i]\n\n try {\n const deleted = await emptyContainerMutation.mutateAsync({ project_id: projectId, container: container.name })\n totalDeleted += deleted\n emptiedCount++\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n errors.push(`${container.name}: ${message}`)\n }\n }\n\n if (emptiedCount > 0) {\n await utils.storage.swift.listContainers.invalidate()\n }\n\n onComplete?.({ emptiedCount, totalDeleted, errors })\n\n handleClose()\n },\n })\n\n const canEmpty = useStore(form.store, (state) => state.isSubmitting || state.values.confirm.trim() !== CONFIRM_WORD)\n\n const utils = trpcReact.useUtils()\n\n const emptyContainerMutation = trpcReact.storage.swift.emptyContainer.useMutation()\n\n const handleClose = () => {\n trackClose()\n emptyContainerMutation.reset()\n setProgress(null)\n form.reset()\n resetTracking()\n onClose()\n }\n\n if (!isOpen || containers.length === 0) return null\n\n const totalCount = containers.length\n const visibleContainers = containers.slice(0, MAX_VISIBLE)\n const hiddenCount = totalCount - visibleContainers.length\n const isPending = emptyContainerMutation.isPending || progress !== null\n const progressCurrent = progress?.current\n const progressTotal = progress?.total\n\n return (\n <Modal\n title={<Plural value={totalCount} one=\"Empty Container\" other=\"Empty # Containers\" />}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isPending ? t`Emptying...` : t`Empty`}\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || canEmpty}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Status\n status=\"progress\"\n title={\n progress ? t`Emptying Container ${progressCurrent} of ${progressTotal}, Please Wait...` : t`Emptying...`\n }\n className=\"mt-0\"\n />\n ) : (\n <div>\n <p>\n <Trans>All objects in the selected containers will be permanently deleted. This cannot be undone.</Trans>\n </p>\n <p>\n <Trans>\n For <strong>dynamic</strong> and <strong>static large objects</strong> only the manifests are deleted —\n the related segments are not deleted.\n </Trans>\n </p>\n <div className=\"my-6\">\n <p className=\"text-sm font-semibold\">\n <Trans>Containers to be emptied:</Trans>\n </p>\n <div className=\"bg-theme-background-lvl-2 mt-2 max-h-48 overflow-y-auto rounded p-3\">\n <Stack direction=\"vertical\" gap=\"1\">\n {visibleContainers.map((container) => {\n const count = container.count\n return (\n <div key={container.name} className=\"text-theme-default overflow-x-hidden text-sm wrap-anywhere\">\n {container.name}\n {count != null && (\n <span className=\"text-theme-light ml-2\">\n ({i18n._(plural(count, { one: \"# object\", other: \"# objects\" }))})\n </span>\n )}\n </div>\n )\n })}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"empty-containers-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n children={(field) => (\n <TextInput\n label={t`Type \"empty\" to confirm`}\n placeholder={CONFIRM_WORD}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n disabled={isPending}\n autoFocus\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </div>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Button,\n Checkbox,\n DataGridToolbar,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n SearchInput,\n Status,\n Stack,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { parseSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { ContainerTableView } from \"./ContainerTableView\"\nimport {\n getContainerCreatedToast,\n getContainerCreatedWithWarningToast,\n getContainerEmptiedToast,\n getContainerEmptyErrorToast,\n getContainerDeletedToast,\n getContainerDeleteErrorToast,\n getContainerUpdatedToast,\n getContainerUpdateErrorToast,\n getContainerAclUpdatedToast,\n getContainerAclUpdateErrorToast,\n getContainersEmptyCompleteToast,\n} from \"./ContainerToastNotifications\"\nimport { ContainerLimitsTooltip } from \"./ContainerLimitsTooltip\"\nimport { EmptyContainersModal } from \"./EmptyContainersModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"../../../$provider/$storageType/\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\nexport const SwiftContainers = () => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n // Sort and search state are persisted in the URL so they survive navigation,\n // browser back/forward, and deep links.\n const { sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n\n // Whether the list exposes any bulk action — drives the selection column in\n // ContainerTableView and the Zone 3 bulk-action controls. Hardcoded to true\n // for now; the only bulk action today is the destructive Empty.\n //\n // TODO(perms): wire this to the real Swift container permission source\n // (e.g. a usePermissions hook or a tRPC permissions query) instead of\n // hardcoding it.\n const hasAnyBulkAction = true\n\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [emptyAllModalOpen, setEmptyAllModalOpen] = useState(false)\n const [selectedContainers, setSelectedContainers] = useState<string[]>([])\n\n // Local mirror of the committed search term so typing stays responsive while\n // the URL commit is debounced (see Zone 2 SearchInput below).\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParam)\n const debounceTimer = useRef<number | undefined>(undefined)\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n // Keep the input in sync when the committed search term changes from outside\n // the input — browser back/forward, deep links, or programmatic navigation —\n // so the field never drifts from the URL-backed filter state. When the change\n // originated from our own debounced commit, searchParam already equals\n // localSearchTerm, so this is a no-op and won't disturb the caret.\n useEffect(() => {\n setLocalSearchTerm(searchParam)\n }, [searchParam])\n\n const handleCreateSuccess = (containerName: string) => {\n const { message, ...options } = getContainerCreatedToast(containerName)\n toast.success(message, options)\n }\n\n const handleCreatePartialSuccess = (containerName: string, reason: string) => {\n const { message, ...options } = getContainerCreatedWithWarningToast(containerName, reason)\n toast.warning(message, options)\n }\n\n const handleEmptySuccess = (containerName: string, deletedCount: number) => {\n const { message, ...options } = getContainerEmptiedToast(containerName, deletedCount)\n toast.success(message, options)\n }\n\n const handleEmptyError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerEmptyErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleDeleteSuccess = (containerName: string) => {\n const { message, ...options } = getContainerDeletedToast(containerName)\n toast.success(message, options)\n }\n\n const handleDeleteError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerDeleteErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handlePropertiesSuccess = (containerName: string) => {\n const { message, ...options } = getContainerUpdatedToast(containerName)\n toast.success(message, options)\n }\n\n const handlePropertiesError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerUpdateErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleAclSuccess = (containerName: string) => {\n const { message, ...options } = getContainerAclUpdatedToast(containerName)\n toast.success(message, options)\n }\n\n const handleAclError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerAclUpdateErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleEmptyAllComplete = ({\n emptiedCount,\n totalDeleted,\n errors,\n }: {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n }) => {\n if (errors.length === 0) {\n setSelectedContainers([])\n } else {\n // Extract the container name from each error string formatted as \"<containerName>: <message>\".\n // Using exact name extraction avoids the false-positive substring match that\n // errorMessage.includes(containerName) would produce (e.g. \"foo\" matched inside \"foobar\" error).\n const failedContainerNames = new Set(errors.map((e) => e.split(\": \")[0]))\n setSelectedContainers((prev) => prev.filter((name) => failedContainerNames.has(name)))\n }\n\n const { message, severity, ...options } = getContainersEmptyCompleteToast(emptiedCount, totalDeleted, errors)\n toast[severity](message, options)\n }\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Container Name`, value: \"name\" },\n { label: t`Object Count`, value: \"count\" },\n { label: t`Total Size`, value: \"bytes\" },\n { label: t`Last Modified`, value: \"last_modified\" },\n ],\n sortBy: sortBy ?? \"name\",\n sortDirection: sortDirection ?? \"asc\",\n }\n\n // Fetch containers from tRPC\n const {\n data: containers,\n isLoading,\n error,\n } = trpcReact.storage.swift.listContainers.useQuery({\n project_id: projectId,\n format: \"json\",\n })\n\n // Fetch account metadata for quota information\n const { data: accountInfo } = trpcReact.storage.swift.getAccountMetadata.useQuery({\n project_id: projectId,\n })\n\n // Fetch Swift service info\n const { data: serviceInfo } = trpcReact.storage.swift.getServiceInfo.useQuery()\n\n // Sort containers based on sort settings\n const sortContainers = (containers: ContainerSummary[]): ContainerSummary[] => {\n return [...containers].sort((a, b) => {\n let comparison: number\n\n switch (sortBy ?? \"name\") {\n case \"name\":\n comparison = a.name.localeCompare(b.name)\n break\n case \"count\":\n comparison = a.count - b.count\n break\n case \"bytes\":\n comparison = a.bytes - b.bytes\n break\n case \"last_modified\": {\n // Both missing → equal (keeps the comparator transitive); exactly one\n // missing → push it to the end.\n if (!a.last_modified && !b.last_modified) return 0\n if (!a.last_modified || !b.last_modified) {\n return a.last_modified ? -1 : 1\n }\n // #1236: Swift listing timestamps are UTC without a \"Z\" — parse them as\n // UTC so the ordering is correct (matters near DST boundaries). If a\n // (non-empty) value can't be parsed, treat the pair as equal so the\n // order is left untouched (matches the old NaN behaviour).\n const at = parseSwiftDate(a.last_modified)?.getTime()\n const bt = parseSwiftDate(b.last_modified)?.getTime()\n comparison = at == null || bt == null ? 0 : at - bt\n break\n }\n default:\n comparison = a.name.localeCompare(b.name)\n }\n\n return (sortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n }\n\n // Filter containers based on search term\n const filteredContainers = (containers || []).filter((container) =>\n container.name.toLowerCase().includes(searchParam.toLowerCase())\n )\n\n // Apply sorting to filtered containers\n const sortedContainers = sortContainers(filteredContainers)\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({ ...prev, search: value || undefined }),\n })\n })\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const resolvedSortBy = (newSortSettings.sortBy?.toString() || \"name\") as\n \"name\" | \"count\" | \"bytes\" | \"last_modified\"\n const resolvedDirection = (newSortSettings.sortDirection || \"asc\") as \"asc\" | \"desc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n sortBy: resolvedSortBy,\n sortDirection: resolvedDirection,\n }),\n })\n })\n }\n\n // Handle loading state\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Containers...`} />\n }\n\n // Handle error state\n if (error) {\n return <Status status=\"error\" title={t`Error Loading Containers`} body={error.message} />\n }\n\n // Calculate quota information\n const bytesUsed = accountInfo?.bytesUsed || 0\n const quotaBytes = accountInfo?.quotaBytes || 0\n const remainingBytes = quotaBytes > 0 ? quotaBytes - bytesUsed : 0\n\n // Resolve selected ContainerSummary objects from the full unfiltered list so\n // the modal always operates on what was actually selected — not the filtered\n // subset currently visible in the table.\n const selectedContainerSummaries = (containers || []).filter((c) => selectedContainers.includes(c.name))\n const hasSelection = selectedContainerSummaries.length > 0\n const selectedCount = selectedContainerSummaries.length\n\n const totalCount = (containers || []).length\n const filteredCount = filteredContainers.length\n const isFiltered = filteredCount !== totalCount\n\n // Select-all operates on the currently displayed (filtered + sorted) rows.\n const displayedNames = sortedContainers.map((c) => c.name)\n const allSelected = displayedNames.length > 0 && displayedNames.every((n) => selectedContainers.includes(n))\n const someSelected = displayedNames.some((n) => selectedContainers.includes(n))\n\n const handleToggleSelectAll = () => {\n if (allSelected) {\n setSelectedContainers((prev) => prev.filter((n) => !displayedNames.includes(n)))\n } else {\n setSelectedContainers((prev) => [...new Set([...prev, ...displayedNames])])\n }\n }\n\n return (\n <div className=\"relative\">\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and the create action (plain Stack, no background) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-40\"\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setCreateModalOpen(true)}>\n <Trans>Create Container</Trans>\n </Button>\n </Stack>\n\n {/* Zone 2 — search (+ filter pills). DataGridToolbar provides the background.\n Swift containers expose no filterable dimensions yet, so there is no\n FiltersInput / SelectedFilters here. When filter dimensions are added,\n add FiltersInput alongside the search (switch the inner Stack to\n distribution=\"between\") and render SelectedFilters below, using\n applyFilterSelection from urlHelpers for merge logic. */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search containers...`}\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(() => handleSearchChange(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — bulk actions (gated) plus the container/quota info.\n Unlike the Images reference (where Zone 3 carries only bulk actions and is\n omitted entirely without permissions), this bar also hosts the Swift-specific\n count + remaining-quota + limits info, which must always be visible. So the\n bar always renders; only the bulk controls are gated. Bulk controls\n sit on the left; the count + quota are pushed right via ml-auto so they\n stay right-aligned regardless of whether the bulk block renders. */}\n <DataGridToolbar>\n <Stack distribution=\"start\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {hasAnyBulkAction ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected && !allSelected}\n onChange={handleToggleSelectAll}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={!hasSelection} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {hasSelection && (\n <PopupMenuOptions>\n <PopupMenuItem\n disabled={!hasSelection}\n label={i18n._(\n plural(selectedCount, {\n one: \"Empty Container\",\n other: \"Empty # Containers\",\n })\n )}\n onClick={() => setEmptyAllModalOpen(true)}\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n\n <div className=\"text-theme-light ml-auto flex items-center gap-1\" data-testid=\"containers-info-block\">\n {isFiltered ? (\n <Plural\n value={filteredCount}\n one={`${filteredCount} of ${totalCount} container`}\n other={`${filteredCount} of ${totalCount} containers`}\n />\n ) : (\n <Plural value={totalCount} one={`${totalCount} container`} other={`${totalCount} containers`} />\n )}\n {quotaBytes > 0 && (\n <>\n <span>,</span>\n <span>\n <Trans>Remaining Quota:</Trans>{\" \"}\n <span className=\"text-theme-default font-semibold\">{formatBytesBinary(remainingBytes)}</span>\n </span>\n </>\n )}\n <ContainerLimitsTooltip serviceInfo={serviceInfo} accountInfo={accountInfo} />\n </div>\n </Stack>\n </DataGridToolbar>\n </Stack>\n\n <ContainerTableView\n containers={sortedContainers}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n maxContainerNameLength={serviceInfo?.swift?.max_container_name_length}\n existingContainers={containers}\n onCreateSuccess={handleCreateSuccess}\n onCreatePartialSuccess={handleCreatePartialSuccess}\n onEmptySuccess={handleEmptySuccess}\n onEmptyError={handleEmptyError}\n onDeleteSuccess={handleDeleteSuccess}\n onDeleteError={handleDeleteError}\n onPropertiesSuccess={handlePropertiesSuccess}\n onPropertiesError={handlePropertiesError}\n onAclSuccess={handleAclSuccess}\n onAclError={handleAclError}\n selectedContainers={selectedContainers}\n setSelectedContainers={setSelectedContainers}\n hasAnyBulkAction={hasAnyBulkAction}\n />\n\n <EmptyContainersModal\n isOpen={emptyAllModalOpen}\n containers={selectedContainerSummaries}\n onClose={() => setEmptyAllModalOpen(false)}\n onComplete={handleEmptyAllComplete}\n />\n </div>\n )\n}\n","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 analytics: {\n name: \"storage.objectstore.list\",\n },\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":";;;;;;;;;;;;;;;;AAiBA,IAAaQ,MAAwB,EACnCC,WACAC,YACAC,cACAC,qBACAC,4BAAyB,KACzBC,wBAAqB,CAAA,QACK;CAC1B,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAYV,EAAAA,GACZ,CAACW,GAAeC,KAAoBlB,EAAS,EAAA,GAC7C,CAACmB,GAAWC,KAAgBpB,EAAwB,IAAA,GACpD,CAACqB,GAAaC,KAAkBtB,EAAwB,IAAA,GAExD,EAAEuB,eAAYC,kBAAeC,qBAAkBlB,EAAiB;EACpEE;EACAiB,cAAc;CAChB,CAAA,GAEMC,IAAQ1B,EAAU2B,SAAQ,GAE1BC,IAA0B5B,EAAU6B,QAAQC,MAAMC,gBAAgBC,YAAY;EAClFtB,YAAYuB,MAAAA;GACVP,EAAMG,QAAQC,MAAMI,eAAeC,WAAU;GAC7C,IAAMC,IAAOpB,EAAcqB,KAAI;GAM/BI,AALIR,EAAKK,iBACP5B,IAAY0B,CAAAA,IAEZzB,IAAmByB,GAAMH,EAAKM,gBAAgBC,EAAAA,EAAC,EAAA,IAAA,SAA+C,CAAA,CAAA,GAEhGC,EAAAA;EACF;EACAC,UAAUC,MAAAA;GAQRnB,AAPImB,EAAMV,MAAMW,SAAS,cACvBzB,EAAaqB,EAAAA,EAAC,EAAA,IAAA,SAA0C,CAAA,CAAA,GACxDnB,EAAe,IAAA,KAEfA,EAAesB,EAAME,WAAWL,EAAAA,EAAC,EAAA,IAAA,SAA0E,CAAA,CAAA,GAG7GhB,EAAAA;EACF;CACF,CAAA,GAEMiB,UAAc;EAOlBhC,AANAa,EAAAA,GACAL,EAAiB,EAAA,GACjBE,EAAa,IAAA,GACbE,EAAe,IAAA,GACfG,EAAAA,GACAI,EAAwBkB,MAAK,GAC7BrC,EAAAA;CACF,GAEMsC,KAAgBX,MAAAA;EACpB,IAAMY,IAAUZ,EAAKC,KAAI;EAqBzB,OAnBKW,IAIDA,EAAQC,SAASrC,KACnBO,EAAaqB,EAAAA,EAAC;;GAA0B5B,QAAAA,EAAAA,0BAAAA;EAA2C,CAAA,CAAA,GAC5E,MAELoC,EAAQE,SAAS,GAAA,KACnB/B,EAAaqB,EAAAA,EAAC,EAAA,IAAA,SAAsC,CAAA,CAAA,GAC7C,MAGL3B,EAAmBsC,MAAMC,MAAMA,EAAEhB,SAASY,CAAAA,KAC5C7B,EAAaqB,EAAAA,EAAC,EAAA,IAAA,SAA0C,CAAA,CAAA,GACjD,OAGTrB,EAAa,IAAA,GACN,OAlBLA,EAAaqB,EAAAA,EAAC,EAAA,IAAA,SAA2B,CAAA,CAAA,GAClC;CAkBX,GAEMa,KAAoBC,MAAAA;EACxB,IAAMC,IAAQD,EAAEE,OAAOD;EAGvB,AAFAtC,EAAiBsC,CAAAA,GACjBlC,EAAe,IAAA,GACXH,KAAW6B,EAAaQ,CAAAA;CAC9B,GAEME,UAAe;EACdV,EAAa/B,CAAAA,MAClBK,EAAe,IAAA,GACfE,EAAAA,GACAK,EAAwB8B,OAAO;GAC7BC,YAAY5C;GACZ6C,WAAW5C,EAAcqB,KAAI;EAC/B,CAAA;CACF;CAUA,OAFK7B,IAGH,gBAACP,GAAAA;EACC8D,OAAOvB,EAAAA,EAAC,EAAA,IAAA,SAAiB,CAAA;EACzBwB,MAAMxD;EACNyD,UAAUxB;EACVyB,oBAAoBtC,EAAwBuC,YAAY3B,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA,IAAIA,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EACjF4B,WAAWX;EACXY,mBAAmB7B,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC3B8B,MAAK;EACLC,sBAAsB3C,EAAwBuC,aAAa,CAACnD,EAAcqB,KAAI;EAC9EmC,qBAAqB5C,EAAwBuC;EAC7CM,oBAAoB7C,EAAwBuC;EAE5C,UAAA,gBAAChE,GAAAA;GAAMuE,WAAU;GAAWC,KAAI;;IAC7BvD,KACC,gBAAChB,GAAAA;KACCwE,SAAQ;KACRC,aAAW;KACXC,iBAAiBzD,EAAe,IAAA;KAChC0D,MAAK;KACLC,aAAU;KACVC,eAAY;KAEX7D,UAAAA;;IAGL,gBAAC8D,KAAAA;KAAEC,WAAU;KACX,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;IAKF,gBAACjF,GAAAA;KACCkF,OAAO5C,EAAAA,EAAC,EAAA,IAAA,SAAe,CAAA;KACvB6C,UAAQ;KACR9B,OAAOvC;KACPsE,UAAUjC;KACVkC,YA7CejC,MAAAA;MACrB,AAAIA,EAAEQ,QAAQ,WACZL,EAAAA;KAEJ;KA0CQ+B,SAAS,CAAC,CAACtE;KACXuE,WAAWvE,KAAawE,KAAAA;KACxBC,UAAU/D,EAAwBuC;KAClCyB,WAAS;KACTC,aAAarD,EAAAA,EAAC,EAAA,IAAA,SAAqB,CAAA;;;;MA5CvB;AAiDtB,GCtHa6E,MAAsB,EACjCC,eACAC,oBACAC,uBACAC,2BACAC,wBAAqB,CAAA,GACrBC,oBACAC,2BACAC,mBACAC,iBACAC,oBACAC,kBACAC,wBACAC,sBACAC,iBACAC,eACAC,uBACAC,0BACAC,sBAAmB,SACK;CACxB,IAAM,EAAEC,eAAWC,cAAUC,oBAAgBzC,GAAU,EACrD0C,MAAM,6DACR,CAAA,GAEM,EAAA,MAAA,GAAA,GAAA,OAAQC,EAAAA,GACRC,KAAW7C,GAAAA,GAEX,CAAC8C,IAAgBC,MAAqBhD,EAAS,CAAA,GAC/C,CAACiD,IAAqBC,KAA0BlD,EAAkC,IAAA,GAClF,CAACmD,GAAsBC,MAA2BpD,EAAkC,IAAA,GACpF,CAACqD,GAA0BC,KAA+BtD,EAAkC,IAAA,GAC5F,CAACuD,GAA6BC,MAAkCxD,EAAkC,IAAA,GAIlG,EACJyD,KAAKC,GACLC,YAAYC,GACZC,QAAQC,GACRC,kBACAC,eACAC,sBACEjD,GAAwB,EAAEkD,OAAO3C,EAAW4C,OAAO,CAAA;CAGvDpE,SAAU;EACR,IAAI6D,EAAUQ,SAAS;GACrB,IAAMC,IAAQT,EAAUQ,QAAQE,cAAcV,EAAUQ,QAAQG;GAChEvB,GAAkBqB,CAAAA;EACpB;CACF,GAAG,CAAC9C,EAAW4C,QAAQL,CAAW,CAAA;CAElC,IAAMU,KAAyBC,MAAAA;EAC7B,AAAInC,EAAmBoC,SAASD,CAAAA,IAC9BlC,EAAsBD,EAAmBqC,QAAQC,MAASA,MAASH,CAAAA,CAAAA,IAEnElC,EAAsB,CAAID,GAAAA,GAAoBmC,CAAc,CAAA;CAEhE,GAKMI,IAAcrC,IAAmB,IAAI,GACrCsC,IAAqBtC,IACvB,0FACA;CAEJ,OACE,gBAAA,IAAA,EAAA,UAAA;EACE,gBAACuC,OAAAA;GAAIC,WAAU;GAEb,UAAA,CAAA,gBAACD,OAAAA;IAAIE,OAAO,EAAEC,cAAc,GAAGnC,GAAe,IAAI;IAChD,UAAA,gBAAC1C,GAAAA;KACC8E,SAASN;KACWC;KACpBE,WAAU;KACVI,eAAY;KAEZ,UAAA,CAAA,gBAAC7E,GAAAA,EAAAA,UAAAA;MACEiC,KAAoB,gBAAClC,GAAAA,CAAAA,CAAAA;MACtB,gBAACA,GAAAA,EACC,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA;MAEF,gBAACA,GAAAA,EACC,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA;MAEF,gBAACA,GAAAA,EACC,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA;MAEF,gBAACA,GAAAA,EACC,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA;MAEF,gBAACA,GAAAA,EAAiB2E,OAAO,EAAEI,aAAa,IAAItC,GAAe,IAAI,EAAA,CAAA;KAG/D,EAAA,CAAA,IAAA,CAACxB,KAAcA,EAAW4C,WAAW,MACrC,gBAAC5D,GAAAA,EACC,UAAA,gBAACC,GAAAA;MAAa8E,SAAST;MACrB,UAAA,gBAAChE,GAAAA;OACC0E,QAAO;OACPC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAoB,CAAA;OAC5BC,MAAMD,EAAAA,EAAC,EAAA,IAAA,SAAoG,CAAA;;;;GAWvH,CAAA,GAAA,gBAACV,OAAAA;IACCtB,KAAKC;IACLsB,WAAU;IACVC,OAAO,EAAEpB,QAAQ,GAAGC,KAAc,EAAE,IAAI;IACxCsB,eAAY;IAEZ,UAAA,gBAAC/E,GAAAA;KACC8E,SAASN;KACWC;KACpBG,OAAO;MACLpB,QAAQ,GAAGG,GAAU;MACrBK,OAAO;MACPsB,UAAU;KACZ;KAEC5B,UAAAA,GAAa6B,KAAKC,MAAAA;MACjB,IAAMC,IAAYvE,EAAWsE,EAAWE,QAClCC,IAAa1D,EAAmBoC,SAASoB,EAAUlB,IAAI,GAEvDqB,UACJnD,GAAS;OACPoD,IAAI;OACJC,QAAQ;QAAE1D;QAAWC;QAAUC;QAAa8B,eAAeqB,EAAUlB;OAAK;MAC5E,CAAA;MAEF,OACE,gBAACrE,GAAAA;OAEC6F,cAAYP,EAAWE;OACvBtC,KAAKQ;OACLgB,OAAO;QACLU,UAAU;QACVU,KAAK;QACLC,MAAM;QACNjC,OAAO;QACPkC,WAAW,cAAcV,EAAWW,MAAM;QAC1CC,SAAS;QACTC,qBAAqB5B;QACrB6B,YAAY;OACd;OACAvB,eAAa,iBAAiBU,EAAUlB;OACxCgC,UAAU;OACVC,SAASZ;OACTa,YAAYC,MAAAA;QACV,CAAIA,EAAEC,QAAQ,WAAWD,EAAEC,QAAQ,SACjCD,EAAEE,eAAc,GAChBhB,EAAAA;OAEJ;;QAECzD,KACC,gBAAChC,GAAAA;SACCqG,UAAUE,MAAMA,EAAEG,gBAAe;SACjCJ,YAAYC,MAAAA;UACV,CAAIA,EAAEC,QAAQ,WAAWD,EAAEC,QAAQ,QACjCD,EAAEG,gBAAe;SAErB;SAEA,UAAA,gBAAC9G,GAAAA;UACC+G,SAASnB;UACToB,gBAAgB5C,EAAsBsB,EAAUlB,IAAI;UACpDQ,eAAa,oBAAoBU,EAAUlB;;;QAIjD,gBAACpE,GAAAA;SAAawE,WAAU;SACtB,UAAA,gBAACqC,QAAAA;UAAKrC,WAAU;UAAiBQ,OAAOM,EAAUlB;UAC/CkB,UAAAA,EAAUlB;;;QAGf,gBAACpE,GAAAA,EAAcsF,UAAAA,EAAU5B,MAAMoD,eAAc,EAAA,CAAA;QAC7C,gBAAC9G,GAAAA,EAAcO,UAAAA,EAAgB+E,EAAUyB,aAAa,KAAK9B,EAAAA,EAAC,EAAA,IAAA,SAAI,CAAA,EAAA,CAAA;QAChE,gBAACjF,GAAAA,EAAcM,UAAAA,EAAkBgF,EAAU0B,KAAK,EAAA,CAAA;QAChD,gBAAChH,GAAAA;SAAaqG,UAAUE,MAAMA,EAAEG,gBAAe;SAC7C,UAAA,gBAACzG,GAAAA,EAAAA,UAAAA,CACC,gBAACG,GAAAA;UAAgB6G,IAAG;UAClB,UAAA,gBAACtH,GAAAA;WACCuH,MAAK;WACLlC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAkB,CAAA;WAC1BkC,cAAYlC,EAAAA,EAAC,EAAA,IAAA,SAAkB,CAAA;WAC/BT,WAAU;;SAGd,CAAA,GAAA,gBAACrE,GAAAA,EAAAA,UAAAA;UACC,gBAACD,GAAAA;WACCkH,OAAOnC,EAAAA,EAAC,EAAA,IAAA,SAAc,CAAA;WACtBoB,eAAerD,GAA+BsC,CAAAA;WAC9CV,eAAa,yBAAyBU,EAAUlB;;UAElD,gBAAClE,GAAAA;WACCkH,OAAOnC,EAAAA,EAAC,EAAA,IAAA,SAA0B,CAAA;WAClCoB,eAAevD,EAA4BwC,CAAAA;WAC3CV,eAAa,qBAAqBU,EAAUlB;;UAE9C,gBAAClE,GAAAA;WACCkH,OAAOnC,EAAAA,EAAC,EAAA,IAAA,SAAgB,CAAA;WACxBoB,eAAe3D,EAAuB4C,CAAAA;WACtCV,eAAa,gBAAgBU,EAAUlB;;UAEzC,gBAAClE,GAAAA;WACCkH,OAAOnC,EAAAA,EAAC,EAAA,IAAA,SAAiB,CAAA;WACzBoB,eAAezD,GAAwB0C,CAAAA;WACvCV,eAAa,iBAAiBU,EAAUlB;;;;;MA5E3CkB,GAAAA,EAAUlB,IAAI;KAmFzB,CAAA;;;;EAKN,gBAAC3D,IAAAA;GACC4G,QAAQrG;GACRsG,eAAerG,EAAmB,EAAA;GAClCsG,WAAWnG;GACXoG,kBAAkBnG;GACMH;GACJC;;EAGtB,gBAACT,GAAAA;GACC2G,QAAQ5E,OAAwB;GAChC6C,WAAW7C;GACX6E,eAAe5E,EAAuB,IAAA;GACtC6E,WAAWjG;GACXmG,SAASlG;;EAGX,gBAACZ,IAAAA;GACC0G,QAAQ1E,MAAyB;GACjC2C,WAAW3C;GACX2E,eAAe1E,GAAwB,IAAA;GACvC2E,WAAW/F;GACXiG,SAAShG;;EAGX,gBAACb,GAAAA;GACCyG,QAAQxE,MAA6B;GACrCyC,WAAWzC;GACXyE,eAAexE,EAA4B,IAAA;GAC3CyE,WAAW7F;GACX+F,SAAS9F;;EAGX,gBAACd,GAAAA;GACCwG,QAAQtE,MAAgC;GACxCuC,WAAWvC;GACXuE,eAAetE,GAA+B,IAAA;GAC9CuE,WAAW3F;GACX6F,SAAS5F;;;AAIjB,GChTMkG,KAAa,EAAEC,UAAOC,eACtBA,KAAiC,OAAa,OAEhD,gBAACE,QAAAA;CAAKC,WAAU;CACd,UAAA,CAAA,gBAACP,GAAAA;EAAKQ,MAAK;EAAQC,MAAK;EAAOF,WAAU;CACzC,CAAA,GAAA,gBAACD,QAAAA,EAAAA,UAAAA;EACC,gBAACA,QAAAA;GAAKC,WAAU;GAAeJ,UAAAA,CAAAA,GAAM,GAAA;;EAAQ;EAAEC;;IAMjDM,KAAkB,EAAEP,eACxB,gBAACG,QAAAA;CAAKC,WAAU;CACd,UAAA,CAAA,gBAACP,GAAAA;EAAKQ,MAAK;EAAQC,MAAK;EAAOF,WAAU;CACzC,CAAA,GAAA,gBAACD,QAAAA,EAAMH,UAAAA,EAAAA,CAAAA,CAAAA;IAILQ,KAAW,EAAEC,UAAOC,kBACxB,gBAACP,QAAAA;CAAKC,WAAU;CACd,UAAA,CAAA,gBAACD,QAAAA;EAAKC,WAAU;EAA0CK,UAAAA;CACzDC,CAAAA,GAAAA,CAAAA;IAIQC,KAA0B,EAAEC,gBAAaC,gBAAaC,cAAmC;CACpG,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GAERC,IAAQJ,GAAaI,OAErBC,IAAgB;EACpBC,gBAAgBC,EAAAA,EAAC,EAAA,IAAA,SAAe,CAAA;EAChCC,kBAAkBD,EAAAA,EAAC,EAAA,IAAA,SAAiB,CAAA;EACpCE,aAAaF,EAAAA,EAAC,EAAA,IAAA,SAAwB,CAAA;EACtCG,aAAaH,EAAAA,EAAC,EAAA,IAAA,SAA6B,CAAA;EAC3CI,KAAKJ,EAAAA,EAAC,EAAA,IAAA,SAA4B,CAAA;EAClCK,gBAAgBL,EAAAA,EAAC,EAAA,IAAA,SAAkB,CAAA;EACnCM,SAASN,EAAAA,EAAC,EAAA,IAAA,SAAe,CAAA;EACzBO,SAASP,EAAAA,EAAC,EAAA,IAAA,SAAS,CAAA;EACnBQ,kBAAkBR,EAAAA,EAAC,EAAA,IAAA,SAAiB,CAAA;CACtC,GAEMS,IAAeC,OAAOC,QAAQb,CAAAA,CAAAA,CACjCc,QAAQ,CAACC,OAAShB,IAAQgB,EAA0B,CAAA,CACpDC,KAAK,GAAGjC,OAAWA,CAAAA;CAEtB,OACE,gBAACN,GAAAA;EAAQwC,cAAa;EAAQC,WAAU;EAAmBrB;EACzD,UAAA,CAAA,gBAACnB,GAAAA;GAAeS,WAAU;GACxB,UAAA,gBAACD,QAAAA,EACC,UAAA,gBAACN,GAAAA;IAAKQ,MAAK;IAAOC,MAAK;IAAOF,WAAU;;EAG5C,CAAA,GAAA,gBAACR,GAAAA;GAAeQ,WAAU;GACxB,UAAA,gBAACD,QAAAA;IAAKC,WAAU;;KAEbS,KACC,gBAACL,GAAAA;MAAQC,OAAO,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;OACd,gBAACV,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAQ,CAAA;QAAGlB,OAAOY,EAAYuB,YAAYC,eAAc;;OAC3E,gBAACtC,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;QAAGlB,OAAOH,EAAkBe,EAAYyB,SAAS;;OACxEzB,EAAY0B,eAAerC,KAAAA,KAC1B,gBAACH,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAM,CAAA;QAAGlB,OAAOH,EAAkBe,EAAY0B,UAAU;;;;KAMhFvB,KACC,gBAACR,GAAAA;MAAQC,OAAO,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;OACd,gBAACV,GAAAA;QACCC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAc,CAAA;QACtBlB,OAAOe,EAAMwB,kBAAkBtC,KAAAA,IAAqDA,KAAAA,IAAzCJ,EAAkBkB,EAAMwB,aAAa;;OAElF,gBAACzC,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAA0B,CAAA;QAAGlB,OAAOe,EAAMyB;;OAC7D,gBAAC1C,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAuB,CAAA;QAAGlB,OAAOe,EAAM0B;;OAC1D,gBAAC3C,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAwB,CAAA;QAAGlB,OAAOe,EAAM2B,yBAAyBN,eAAAA;;OACpF,gBAACtC,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAsB,CAAA;QAAGlB,OAAOe,EAAM4B,uBAAuBP,eAAAA;;OAChF,gBAACtC,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAgB,CAAA;QAAGlB,OAAOe,EAAM6B;;OACnD,gBAAC9C,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAe,CAAA;QAAGlB,OAAOe,EAAM8B;;OAClD,gBAAC/C,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAqB,CAAA;QAAGlB,OAAOe,EAAM+B;;OACxD,gBAAChD,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAsB,CAAA;QAAGlB,OAAOe,EAAMgC;;OACzD,gBAACjD,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAsB,CAAA;QAAGlB,OAAOe,EAAMiC;;OACxDjC,EAAMK,eACL,gBAACtB,GAAAA;QACCC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAwB,CAAA;QAChClB,OAAOe,EAAMK,YAAY6B,wBAAwBb,eAAc;;OAGlErB,EAAMM,eACL,gBAACvB,GAAAA;QACCC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAA8B,CAAA;QACtClB,OAAOe,EAAMM,YAAY6B,8BAA8Bd,eAAc;;OAGxErB,EAAMO,OACL,gBAACxB,GAAAA;QAAUC,OAAOmB,EAAAA,EAAC,EAAA,IAAA,SAAiB,CAAA;QAAGlB,OAAOe,EAAMO,IAAI6B,sBAAsBf,eAAc;;;;KAMjGT,EAAayB,SAAS,KACrB,gBAAC7C,GAAAA;MAAQC,OAAO,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;MACbmB,UAAAA,EAAaK,KAAKqB,MACjB,gBAAC/C,GAAAA,EAAyBP,OAAOsD,EAAZA,GAAAA,CAAAA,CAAAA;;;;;;AAQrC,GCrHMc,KAAc,IAMdC,IAAe,SAeRC,MAAwB,EAAEC,WAAQC,eAAYC,YAASC,oBAAuC;CACzG,IAAM,EAAA,MAAA,GAAKC,SAAI,GAAA,MAAKC,EAAAA,GACdC,IAAYX,EAAAA,GAEZ,CAACY,GAAUC,KAAerB,EAAoD,IAAA,GAE9E,EAAEsB,eAAYC,kBAAeC,qBAAkBf,EAAiB;EACpEI;EACAY,cAAc;CAChB,CAAA,GAEMC,IAAa7B,EAAE8B,OAAO,EAC1BC,SAAS/B,EACNgC,OAAM,CAAA,CACNC,WAAWC,MAAQA,EAAIC,KAAI,CAAA,CAAA,CAC3BC,QAAQC,MAAUA,MAAUvB,GAAc,EACzCwB,SAASC,EAAAA,EAAC;;EAASzB,QAAAA,EAAAA,gBAAAA;CAAyB,CAAA,EAC9C,CAAA,EACJ,CAAA,GAEM0B,IAAOvC,EAAQ;EACnBwC,eAAe,EACbV,SAAS,GACX;EACAW,YAAY,EACVC,UAAUd,EACZ;EACAc,UAAU,YAAA;GACR,IAAIC,EAAuBC,aAAatB,MAAa,MAAM;GAE3DG,EAAAA;GACA,IAAIoB,IAAe,GACfC,IAAe,GACbC,IAAmB,CAAA,GACnBC,IAAQhC,EAAWiC;GAEzB,KAAK,IAAIC,IAAI,GAAGA,IAAIlC,EAAWiC,QAAQC,KAAK;IAC1C3B,EAAY;KAAE4B,SAASD,IAAI;KAAGF;IAAM,CAAA;IACpC,IAAMI,IAAYpC,EAAWkC;IAE7B,IAAI;KACF,IAAMG,IAAU,MAAMV,EAAuBW,YAAY;MAAEC,YAAYlC;MAAW+B,WAAWA,EAAUI;KAAK,CAAA;KAE5GX,AADAC,KAAgBO,GAChBR;IACF,SAASY,GAAK;KACZ,IAAMpB,IAAUoB,aAAeC,QAAQD,EAAIpB,UAAUsB,OAAOF,CAAAA;KAC5DV,EAAOa,KAAK,GAAGR,EAAUI,KAAK,IAAInB,GAAS;IAC7C;GACF;GAQA6B,AANIrB,IAAe,KACjB,MAAMgB,EAAMC,QAAQC,MAAMC,eAAeC,WAAU,GAGrD/C,IAAa;IAAE2B;IAAcC;IAAcC;GAAO,CAAA,GAElDmB,EAAAA;EACF;CACF,CAAA,GAEMC,IAAWlE,GAASsC,EAAK6B,QAAQC,MAAUA,EAAMC,gBAAgBD,EAAME,OAAOzC,QAAQI,KAAI,MAAOrB,CAAAA,GAEjGgD,IAAQ1D,EAAUqE,SAAQ,GAE1B7B,IAAyBxC,EAAU2D,QAAQC,MAAMU,eAAeC,YAAW,GAE3ER,UAAc;EAMlBjD,AALAO,EAAAA,GACAmB,EAAuBgC,MAAK,GAC5BpD,EAAY,IAAA,GACZgB,EAAKoC,MAAK,GACVjD,EAAAA,GACAT,EAAAA;CACF;CAEA,IAAI,CAACF,KAAUC,EAAWiC,WAAW,GAAG,OAAO;CAE/C,IAAM2B,IAAa5D,EAAWiC,QACxB4B,IAAoB7D,EAAW8D,MAAM,GAAGlE,EAAAA,GACxCmE,IAAcH,IAAaC,EAAkB5B,QAC7CL,IAAYD,EAAuBC,aAAatB,MAAa,MAC7D0D,IAAkB1D,GAAU6B,SAC5B8B,KAAgB3D,GAAU0B;CAEhC,OACE,gBAAC5C,GAAAA;EACC8E,OAAO,gBAAA,GAAA;;GAAeN,QAAAA,EAAAA,cAAAA;;EACtBO,MAAMpE;EACNqE,gBAAU;GAERlB,AADA1C,EAAAA,GACA0C,EAAAA;EACF;EACAmB,oBAAoBzC,IAAYN,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA,IAAIA,EAAAA,EAAC,EAAA,IAAA,SAAM,CAAA;EACxDgD,sBAAqB;EACrBC,mBAAmBjD,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC3BkD,WAAWjD,EAAKkD;EAChBC,sBAAsB9C,KAAauB;EACnCwB,qBAAqB/C;EACrBgD,oBAAoBhD;EACpBiD,MAAK;EAEJjD,UAAAA,IACC,gBAACvC,GAAAA;GACCyF,QAAO;GACPZ,OACE5D,IAAWgB,EAAAA,EAAC;;;KAAsB0C;KAAsBC;;GAA8B,CAAA,IAAI3C,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA;GAEzGyD,WAAU;EAGZ,CAAA,IAAA,gBAACC,OAAAA,EAAAA,UAAAA;GACC,gBAACC,KAAAA,EACC,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA;GAEF,gBAACA,KAAAA,EACC,UAAA,gBAAA,GAAA;;;KACOC,GAAAA,gBAAAA,UAAAA,CAAAA,CAAAA;KAA6BA,GAAAA,gBAAAA,UAAAA,CAAAA,CAAAA;;;GAItC,gBAACF,OAAAA;IAAID,WAAU;IACb,UAAA,CAAA,gBAACE,KAAAA;KAAEF,WAAU;KACX,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;IAEF,CAAA,GAAA,gBAACC,OAAAA;KAAID,WAAU;KACb,UAAA,gBAACzF,GAAAA;MAAM6F,WAAU;MAAWC,KAAI;MAC7BvB,UAAAA,CAAAA,EAAkBwB,KAAKjD,MAAAA;OACtB,IAAMkD,IAAQlD,EAAUkD;OACxB,OACE,gBAACN,OAAAA;QAAyBD,WAAU;QACjC3C,UAAAA,CAAAA,EAAUI,MACV8C,KAAS,QACR,gBAACC,QAAAA;SAAKR,WAAU;;UAAwB;UACpC5E,EAAKqF,EAAEC,EAAAA,EAAOH;;WAAAA,QAAAA,EAAAA,SAAAA;UAAI,CAAA,CAAA;UAA6C;;;OAJ7DlD,GAAAA,EAAUI,IAAI;MAS5B,CAAA,GACCuB,IAAc,KACb,gBAACiB,OAAAA;OAAID,WAAU;OACb,UAAA,gBAAA,GAAA;;QAAchB,QAAAA,EAAAA,eAAAA;;;;;;GAOxB,gBAACxE,GAAAA;IACCwF,WAAU;IACVW,IAAG;IACHhE,WAAWiE,MAAAA;KAETpE,AADAoE,EAAEC,eAAc,GAChBrE,EAAKkD,aAAY;IACnB;IAEA,UAAA,gBAACjF,GAAAA,EACC,UAAA,gBAAC+B,EAAKsE,OAAK;KACTrD,MAAK;KACLsD,WAAWC,MACT,gBAACtG,GAAAA;MACCuG,OAAO1E,EAAAA,EAAC,EAAA,IAAA,SAAwB,CAAA;MAChC2E,aAAapG;MACb6F,IAAIK,EAAMvD;MACVA,MAAMuD,EAAMvD;MACZpB,OAAO2E,EAAM1C,MAAMjC;MACnB8E,WAAWP,MAAMI,EAAMI,aAAaR,EAAES,OAAOhF,KAAK;MAClDiF,UAAUzE;MACV0E,WAAS;MACTC,UAAQ;;;;;;AAU5B,GC1KaqC,WAAkB;CAC7B,IAAM,EAAA,MAAA,GAAKC,SAAI,GAAA,MAAKC,EAAAA,GACdC,IAAYJ,EAAAA,GACZK,IAAWP,GAAY,EAAEQ,MAAMP,EAAMQ,SAAS,CAAA,GAI9C,EAAEC,WAAQC,kBAAeC,QAAQC,IAAc,OAAOZ,EAAMa,UAAS,GAWrE,CAACE,GAAiBC,KAAsBlD,EAAS,EAAA,GACjD,CAACmD,GAAmBC,KAAwBpD,EAAS,EAAA,GACrD,CAACqD,GAAoBC,KAAyBtD,EAAmB,CAAA,CAAE,GAInE,CAACuD,GAAiBC,KAAsBxD,EAAS8C,CAAAA,GACjDW,IAAgBvD,GAA2BwD,KAAAA,CAAAA;CAQjDzD,AAPAA,eAAsB0D,aAAaF,EAAcG,OAAO,GAAG,CAAA,CAAE,GAO7D3D,SAAU;EACRuD,EAAmBV,CAAAA;CACrB,GAAG,CAACA,CAAY,CAAA;CAEhB,IAAMe,MAAuBC,MAAAA;EAC3B,IAAM,EAAEC,YAAS,GAAGC,MAAY5C,EAAyB0C,CAAAA;EACzD9C,EAAMiD,QAAQF,GAASC,CAAAA;CACzB,GAEME,MAA8BJ,GAAuBK,MAAAA;EACzD,IAAM,EAAEJ,YAAS,GAAGC,MAAY3C,GAAoCyC,GAAeK,CAAAA;EACnFnD,EAAMoD,QAAQL,GAASC,CAAAA;CACzB,GAEMK,KAAsBP,GAAuBQ,MAAAA;EACjD,IAAM,EAAEP,YAAS,GAAGC,MAAY1C,EAAyBwC,GAAeQ,CAAAA;EACxEtD,EAAMiD,QAAQF,GAASC,CAAAA;CACzB,GAEMO,KAAoBT,GAAuBU,MAAAA;EAC/C,IAAM,EAAET,YAAS,GAAGC,MAAYzC,GAA4BuC,GAAeU,CAAAA;EAC3ExD,EAAMyD,MAAMV,GAASC,CAAAA;CACvB,GAEMU,KAAuBZ,MAAAA;EAC3B,IAAM,EAAEC,YAAS,GAAGC,MAAYxC,EAAyBsC,CAAAA;EACzD9C,EAAMiD,QAAQF,GAASC,CAAAA;CACzB,GAEMW,MAAqBb,GAAuBU,MAAAA;EAChD,IAAM,EAAET,YAAS,GAAGC,MAAYvC,GAA6BqC,GAAeU,CAAAA;EAC5ExD,EAAMyD,MAAMV,GAASC,CAAAA;CACvB,GAEMY,KAA2Bd,MAAAA;EAC/B,IAAM,EAAEC,YAAS,GAAGC,MAAYtC,GAAyBoC,CAAAA;EACzD9C,EAAMiD,QAAQF,GAASC,CAAAA;CACzB,GAEMa,KAAyBf,GAAuBU,MAAAA;EACpD,IAAM,EAAET,YAAS,GAAGC,MAAYrC,GAA6BmC,GAAeU,CAAAA;EAC5ExD,EAAMyD,MAAMV,GAASC,CAAAA;CACvB,GAEMc,KAAoBhB,MAAAA;EACxB,IAAM,EAAEC,YAAS,GAAGC,MAAYpC,GAA4BkC,CAAAA;EAC5D9C,EAAMiD,QAAQF,GAASC,CAAAA;CACzB,GAEMe,MAAkBjB,GAAuBU,MAAAA;EAC7C,IAAM,EAAET,YAAS,GAAGC,MAAYnC,GAAgCiC,GAAeU,CAAAA;EAC/ExD,EAAMyD,MAAMV,GAASC,CAAAA;CACvB,GAEMgB,MAA0B,EAC9BC,iBACAC,iBACAC,gBAKD;EACC,IAAIA,EAAOC,WAAW,GACpB9B,EAAsB,CAAA,CAAE;OACnB;GAIL,IAAM+B,IAAuB,IAAIC,IAAIH,EAAOI,KAAKC,MAAMA,EAAEC,MAAM,IAAA,CAAK,CAAC,EAAE,CAAA;GACvEnC,GAAuBoC,MAASA,EAAKC,QAAQC,MAASP,EAAqBQ,IAAID,CAAAA,CAAAA,CAAAA;EACjF;EAEA,IAAM,EAAE7B,YAAS+B,aAAU,GAAG9B,MAAYlC,GAAgCmD,GAAcC,GAAcC,CAAAA;EACtGnE,EAAM8E,EAAS,CAAC/B,GAASC,CAAAA;CAC3B,GAEM+B,IAA6B;EACjC/B,SAAS;GACP;IAAEgC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAe,CAAA;IAAGC,OAAO;GAAO;GAC1C;IAAEF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAa,CAAA;IAAGC,OAAO;GAAQ;GACzC;IAAEF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAW,CAAA;IAAGC,OAAO;GAAQ;GACvC;IAAEF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAc,CAAA;IAAGC,OAAO;GAAgB;EACnD;EACDvD,QAAQA,KAAU;EAClBC,eAAeA,KAAiB;CAClC,GAGM,EACJuD,MAAMC,GACNC,cACA5B,cACEpE,EAAUiG,QAAQC,MAAMC,eAAeC,SAAS;EAClDC,YAAYnE;EACZoE,QAAQ;CACV,CAAA,GAGM,EAAER,MAAMS,MAAgBvG,EAAUiG,QAAQC,MAAMM,mBAAmBJ,SAAS,EAChFC,YAAYnE,EACd,CAAA,GAGM,EAAE4D,MAAMW,OAAgBzG,EAAUiG,QAAQC,MAAMQ,eAAeN,SAAQ,GAGvEO,MAAkBZ,MACf,CAAIA,GAAAA,CAAW,CAAA,CAACa,MAAMC,GAAGC,MAAAA;EAC9B,IAAIC;EAEJ,QAAQzE,KAAU,QAAlB;GACE,KAAK;IACHyE,IAAaF,EAAEtB,KAAKyB,cAAcF,EAAEvB,IAAI;IACxC;GACF,KAAK;IACHwB,IAAaF,EAAEI,QAAQH,EAAEG;IACzB;GACF,KAAK;IACHF,IAAaF,EAAEK,QAAQJ,EAAEI;IACzB;GACF,KAAK,iBAAiB;IAGpB,IAAI,CAACL,EAAEM,iBAAiB,CAACL,EAAEK,eAAe,OAAO;IACjD,IAAI,CAACN,EAAEM,iBAAiB,CAACL,EAAEK,eACzB,OAAON,EAAEM,gBAAgB,KAAK;IAMhC,IAAMC,IAAKvG,EAAegG,EAAEM,aAAa,CAAA,EAAGE,QAAAA,GACtCC,IAAKzG,EAAeiG,EAAEK,aAAa,CAAA,EAAGE,QAAAA;IAC5CN,IAAaK,KAAM,QAAQE,KAAM,OAAO,IAAIF,IAAKE;IACjD;GACF;GACA,SACEP,IAAaF,EAAEtB,KAAKyB,cAAcF,EAAEvB,IAAI;EAC5C;EAEA,QAAQhD,KAAiB,WAAW,SAAS,CAACwE,IAAaA;CAC7D,CAAA,GAIIQ,MAAsBxB,KAAc,CAAA,EAAA,CAAIT,QAAQkC,MACpDA,EAAUjC,KAAKkC,YAAW,CAAA,CAAGC,SAASjF,EAAYgF,YAAW,CAAA,CAAA,GAIzDE,KAAmBhB,GAAeY,EAAAA,GAElCK,MAAsBC,MAAAA;EAC1B,IAAMhC,IAAQ,OAAOgC,KAAS,WAAWA,IAAO;EAChD/H,QAAgB;GACdqC,EAAS,EACPK,SAAS6C,OAAU;IAAE,GAAGA;IAAM7C,QAAQqD,KAASxC,KAAAA;GAAU,GAC3D,CAAA;EACF,CAAA;CACF,GAEMyE,MAAoBC,MAAAA;EACxB,IAAMC,IAAkBD,EAAgBzF,QAAQ2F,SAAAA,KAAc,QAExDC,IAAqBH,EAAgBxF,iBAAiB;EAC5DzC,QAAgB;GACdqC,EAAS,EACPK,SAAS6C,OAAU;IACjB,GAAGA;IACH/C,QAAQ0F;IACRzF,eAAe2F;GACjB,GACF,CAAA;EACF,CAAA;CACF;CAGA,IAAIlC,GACF,OAAO,gBAACvF,GAAAA;EAAO0H,QAAO;EAAWC,OAAOxC,EAAAA,EAAC,EAAA,IAAA,SAAsB,CAAA;;CAIjE,IAAIxB,IACF,OAAO,gBAAC3D,GAAAA;EAAO0H,QAAO;EAAQC,OAAOxC,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA;EAAGyC,MAAMjE,GAAMV;;CAIhF,IAAM4E,KAAY/B,GAAa+B,aAAa,GACtCC,KAAahC,GAAagC,cAAc,GACxCC,KAAiBD,KAAa,IAAIA,KAAaD,KAAY,GAK3DG,MAA8B1C,KAAc,CAAA,EAAA,CAAIT,QAAQoD,MAAM1F,EAAmB0E,SAASgB,EAAEnD,IAAI,CAAA,GAChGoD,KAAeF,GAA2B1D,SAAS,GACnD6D,KAAgBH,GAA2B1D,QAE3C8D,MAAc9C,KAAc,CAAA,EAAA,CAAIhB,QAChC+D,KAAgBvB,GAAmBxC,QACnCgE,KAAaD,OAAkBD,IAG/BG,IAAiBrB,GAAiBzC,KAAKwD,MAAMA,EAAEnD,IAAI,GACnD0D,KAAcD,EAAejE,SAAS,KAAKiE,EAAeE,OAAOC,MAAMnG,EAAmB0E,SAASyB,CAAAA,CAAAA,GACnGC,KAAeJ,EAAeK,MAAMF,MAAMnG,EAAmB0E,SAASyB,CAAAA,CAAAA;CAU5E,OACE,gBAACI,OAAAA;EAAIC,WAAU;;GACb,gBAAC9I,GAAAA;IAAM+I,WAAU;;KAEf,gBAAC/I,GAAAA;MAAMgJ,cAAa;MAAMC,WAAU;MAASC,KAAI;MAAIJ,WAAU;MAC7D,UAAA,CAAA,gBAAC9I,GAAAA;OAAMkJ,KAAI;OAAMD,WAAU;OACzB,UAAA,gBAAC5J,IAAAA;QACC4D,SAAS+B,EAAa/B;QACtBrB,QAAQoD,EAAapD;QACrBC,eAAemD,EAAanD,iBAAiB;QAC7CsH,iBAAgB;QAChBC,iBAAiBC,MACfjC,GAAiB;SAAE,GAAGpC;SAAcpD,QAAQyH;SAAGxH,eAAemD,EAAanD;QAAc,CAAA;QAE3FyH,wBAAwBC,MAAQnC,GAAiB;SAAE,GAAGpC;SAAcnD,eAAe0H;QAAI,CAAA;;MAG3F,CAAA,GAAA,gBAAChK,GAAAA;OAAOiK,SAAQ;OAAUV,WAAU;OAAoBW,eAAetH,EAAmB,EAAA;OACxF,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;KAUJ,gBAAC1C,GAAAA,EACC,UAAA,gBAACO,GAAAA;MAAM+I,WAAU;MAAWG,KAAI;MAC9B,UAAA,gBAAClJ,GAAAA;OAAMgJ,cAAa;OAAMC,WAAU;OAClC,UAAA,gBAACnJ,GAAAA;QACC4J,aAAaxE,EAAAA,EAAC,EAAA,IAAA,SAAqB,CAAA;QACnCyE,eAAY;QACZxE,OAAO3C;QACPoH,UAAUnF,MAAAA;SACR,IAAM4E,IAAI5E,EAAEoF,cAAc1E;SAG1BzC,AAFAD,EAAmB4G,CAAAA,GACnBzG,aAAaF,EAAcG,OAAO,GAClCH,EAAcG,UAAUiH,OAAOC,iBAAiB7C,GAAmBmC,CAAAA,GAAI,GAAA;QACzE;QACAW,WAAWX,MAAAA;SAETnC,AADAtE,aAAaF,EAAcG,OAAO,GAClCqE,GAAmB,OAAOmC,KAAM,WAAWA,IAAI,EAAA;QACjD;QACAY,eAAS;SAGP/C,AAFAtE,aAAaF,EAAcG,OAAO,GAClCJ,EAAmB,EAAA,GACnByE,GAAmB,EAAA;QACrB;;;;KAaR,gBAACzH,GAAAA,EACC,UAAA,gBAACO,GAAAA;MAAMgJ,cAAa;MAAQE,KAAI;MAAID,WAAU;MAASH,WAAU;MAE7D,UAAA,CAAA,gBAAC9I,GAAAA;OAAMkJ,KAAI;OAAID,WAAU;OACvB,UAAA,CAAA,gBAACzJ,GAAAA;QACC0K,SAAS3B;QACT4B,eAAezB,MAAgB,CAACH;QAChC6B,gBA7Ec;SAC5B,AACE7H,EADEgG,MACqB5D,MAASA,EAAKC,QAAQ6D,MAAM,CAACH,EAAetB,SAASyB,CAAAA,CAAAA,KAErD9D,MAAS,CAAI,mBAAA,IAAIJ,IAAI,CAAII,GAAAA,GAAS2D,GAAAA,CAAe,CAAA,CAAE,CAAA;QAE9E;OAyEc,CAAA,GAAA,gBAAC5I,GAAAA;QAAUoJ,WAAU;QACnB,UAAA,CAAA,gBAACjJ,GAAAA;SAAgBwK,IAAG;SAClB,UAAA,gBAAC9K,GAAAA;UAAO+K,UAAU,CAACrC;UAAcsC,MAAK;UAAQC,MAAK;UAAWvF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAQ,CAAA;;QAE/E+C,CAAAA,GAAAA,MACC,gBAACrI,GAAAA,EACC,UAAA,gBAACD,GAAAA;SACC2K,UAAU,CAACrC;SACXhD,OAAO3D,EAAKmJ,EACVC,EAAAA,EAAOxC;;UAAAA,QAAAA,EAAAA,kBAAAA;SAAY,CAAA,CAAA;SAKrBuB,eAAepH,EAAqB,EAAA;;;MAO9C,CAAA,GAGF,gBAACwG,OAAAA;OAAIC,WAAU;OAAmDa,eAAY;;QAC3EtB,KACC,gBAAA,GAAA;;;UACSD;UACqBD;;QAI9B,CAAA,IAAA,gBAAA,GAAA;;SAAeA,QAAAA,EAAAA,eAAAA;;QAEhBN,KAAa,KACZ,gBAAA,IAAA,EAAA,UAAA,CACE,gBAAC8C,QAAAA,EAAK,UAAA,IAAA,CAAA,GACN,gBAACA,QAAAA,EAAAA,UAAAA;SACC,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;SAAgC;SAChC,gBAACA,QAAAA;UAAK7B,WAAU;UAAoC5I,UAAAA,EAAkB4H,EAAAA;;;QAI5E,gBAAC9G,GAAAA;SAAoC+E;SAA0BF;;;;;;;GAMvE,gBAACzF,IAAAA;IACCiF,YAAY4B;IACK/E;IACGC;IACpByI,wBAAwB7E,IAAaP,OAAOqF;IAC5CC,oBAAoBzF;IACpB0F,iBAAiBjI;IACjBkI,wBAAwB7H;IACxB8H,gBAAgB3H;IAChB4H,cAAc1H;IACd2H,iBAAiBxH;IACjByH,eAAexH;IACfyH,qBAAqBxH;IACrByH,mBAAmBxH;IACnByH,cAAcxH;IACdyH,YAAYxH;IACQ1B;IACGC;IACLN;;GAGpB,gBAAChB,IAAAA;IACCwK,QAAQrJ;IACRiD,YAAY0C;IACZ2D,eAAerJ,EAAqB,EAAA;IACpCsJ,YAAY1H;;;;AAIpB;;;AC3RA,SAASkI,KAAAA;CACP,IAAM,EAAEC,YAASC,gBAAaT,GAAU;EACtCU,MAAM;EACNC,SAASC,OACA;GAAEJ,SAASI,EAAOC;GAAWJ,UAAUG,EAAOH;GAAUK,aAAaF,EAAOE;EAAY;CAEnG,CAAA,GAEM,EAAA,MAAA,GAAA,GAAA,MAAQT,EAAAA,GAEVW;CACJ,QAAQP,GAAR;EACE,KAAK;GACHO,IAAYD,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;GACb;EACF,KAAK;GACHC,IAAYD,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;GACb;EACF,SACEC,IAAYD,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;CACjB;CAEA,OACE,gBAAC,OAAA,EAAA,UAAA,CACC,gBAAC,GAAA;EAAc,OAAOC;EAAW,WAAWR;CAC3CA,CAAAA,GAAAA,IACC,gBAAC,GAAA;EACC,WAAW,CAACA,GAASC,CAAS;EAC9B,UACE,gBAAC,OAAA;GAAI,WAAU;GACb,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;EAIH,iBAAC;GACA,QAAQA,GAAR;IACE,KAAK,SACH,OAAO,gBAAC,IAAA,CAAA,CAAA;IACV,KAAK,QACH,OAAO,gBAAC,GAAA,CAAA,CAAA;IACV,SACE,OAAO,gBAAC,OAAA,EAAI,UAAA,wBAAA,CAAA;GAChB;EACF,EAAA,CAAA;CAGF,CAAA,IAAA,gBAAC,OAAA;EAAI,WAAU;EACb,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;AAKV;AAAC,IAAAQ,WAzEU,gBAAC,IAAA,CAAA,CAAA"}
@@ -1,7 +0,0 @@
1
- import { jsx as e } from "react/jsx-runtime";
2
- //#region src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx?tsr-split=notFoundComponent
3
- var t = () => /*#__PURE__*/ e("p", { children: "Storage service not found" });
4
- //#endregion
5
- export { t as notFoundComponent };
6
-
7
- //# sourceMappingURL=_storageType-zeSZe--V.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_storageType-zeSZe--V.mjs","names":["SplitNotFoundComponent","notFoundComponent"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx?tsr-split=notFoundComponent"],"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 analytics: {\n name: \"storage.objectstore.list\",\n },\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":";;AA2GA,IAAAA,UAgCW,gBAAC,KAAA,EAAE,UAAA,4BAAA,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"flavors-Bgq3KZmx.mjs","names":["DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuOptions","PopupMenuItem","PopupMenuSectionSeparator","Status","Pagination","DeleteFlavorModal","useEffect","useState","EditSpecModal","ManageAccessModal","useParams","useNavigate","FlavorListContainer","flavors","isLoading","client","project","onFlavorDeleted","canDeleteFlavor","canMangageAccess","canManageSpecs","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","status","title","t","columns","minContentColumns","className","data-testid","length","map","id","onClick","to","params","flavorId","vcpus","ram","disk","swap","e","stopPropagation","label","colSpan","body","div","variant","pages","onPressPrevious","Math","max","onPressNext","min","onSelectChange","selectedPage","onInputChange","newInputPage","undefined","String","onKeyDown","key","parseInt","isNaN","isOpen","onClose","onSuccess","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","Status","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","undefined","handleNumericInputChange","handleBlur","error","handleSubmit","preventDefault","newErrors","requiredFields","forEach","key","optionalFields","Object","keys","length","t","flavorData","compute","createFlavor","mutate","project_id","flavor","handleClose","errorMessage","message","dismissError","isFormValid","field","onCancel","size","title","open","onConfirm","cancelButtonLabel","confirmButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","status","className","onDismiss","text","variant","id","label","onChange","onBlur","errortext","helptext","required","description","String","vcpus","Number","ram","disk","swap","defaultValue","rxtx_factor","use","Suspense","useState","useRef","startTransition","useEffect","useCallback","ErrorBoundary","useSearch","useNavigate","TRPCClientError","toast","Message","Button","Stack","DataGridToolbar","SearchInput","Status","SortInput","FlavorListContainer","CreateFlavorModal","getFlavorCreatedToast","getFlavorDeletedToast","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","canAddProject","canRemoveProject","canCreateSpecs","canDeleteSpecs","canManageAccess","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","selectClassName","selectWidth","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","setFlavorsPromise","refetchFlavors","handleFlavorDeleted","flavorName","success","handleFlavorCreated","newSortSettings","settings","toString","prev","replace","handleSearchChange","term","searchValue","handlePageChange","div","fallbackRender","error","status","title","body","Error","fallback","useLingui","Flavors","ContentHeader","Route","RouteComponent","t","projectId","useParams","trpcClient","useRouteContext","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/flavors/-components/FlavorListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/compute/flavors/-components/flavorValidation.ts","../../src/client/routes/_auth/projects/$projectId/compute/flavors/-components/CreateFlavorModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/flavors/-components/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 PopupMenu,\n PopupMenuOptions,\n PopupMenuItem,\n PopupMenuSectionSeparator,\n Status,\n Pagination,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, 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 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 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 <Status status=\"progress\" title={t`Loading...`} />\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 && flavors.length > 0 ? (\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 {canManageSpecs && <PopupMenuItem label={t`Edit Metadata`} onClick={() => openSpecModal(flavor)} />}\n {canMangageAccess && flavor[\"os-flavor-access:is_public\"] === false && (\n <PopupMenuItem label={t`Manage Access`} onClick={() => openAccessModal(flavor)} />\n )}\n <PopupMenuItem\n label={t`Show Details`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/flavors/$flavorId\",\n params: { projectId, flavorId: flavor.id },\n })\n }\n />\n {canDeleteFlavor && (\n <>\n <PopupMenuSectionSeparator />\n <PopupMenuItem label={t`Delete Flavor`} onClick={() => openDeleteModal(flavor)} />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n ))\n ) : (\n <DataGridRow>\n <DataGridCell colSpan={7}>\n <Status\n status=\"empty\"\n title={t`No flavors found`}\n body={t`There are no flavors available for this project with the current filters applied. Try adjusting your filter criteria or create a new flavor.`}\n />\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 />\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 Status,\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 // Clear error for this field when user changes the value\n setErrors((prev) => ({\n ...prev,\n [name]: undefined,\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 // Clear error for this field when user changes the value\n setErrors((prev) => ({\n ...prev,\n [name]: undefined,\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 const isFormValid = () => {\n // Check required fields are filled and have no errors\n const requiredFields: FlavorFormField[] = [\"name\", \"vcpus\", \"ram\", \"disk\"]\n\n for (const field of requiredFields) {\n const value = newFlavor[field]\n // Field must have a value\n if (value === undefined || value === \"\" || value === null) return false\n // Field must not have a validation error\n if (validateField(field, value, t)) return false\n }\n\n // Check optional fields for errors (if they have values)\n const optionalFields: FlavorFormField[] = [\"id\", \"swap\", \"OS-FLV-EXT-DATA:ephemeral\", \"rxtx_factor\", \"description\"]\n\n for (const field of optionalFields) {\n const value = newFlavor[field]\n // Skip empty optional fields\n if (value === undefined || value === \"\" || value === null) continue\n // Field must not have a validation error\n if (validateField(field, value, t)) return false\n }\n\n return true\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 disableConfirmButton={!isFormValid() || isLoading}\n disableCancelButton={isLoading}\n disableCloseButton={isLoading}\n >\n {isLoading && <Status status=\"progress\" title={t`Creating Flavor...`} className=\"mt-0\" />}\n {!isLoading && (\n <Form>\n {generalError && (\n <FormRow>\n <Message onDismiss={dismissError} text={generalError} variant=\"error\" />\n </FormRow>\n )}\n\n <FormSection title={t`Flavor Information`}>\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 helptext={t`Auto-generated if not provided. Only alphanumeric, hyphens, underscores, and dots allowed.`}\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 helptext={t`2-50 characters.`}\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 <Checkbox\n name=\"os-flavor-access:is_public\"\n label={t`Public Flavor`}\n helptext={t`When checked, all tenants can use this flavor. Otherwise, grant access explicitly.`}\n checked={!!newFlavor[\"os-flavor-access:is_public\"]}\n onChange={handleInputChange}\n />\n </FormRow>\n </FormSection>\n\n <FormSection title={t`Hardware Specifications`}>\n <FormRow>\n <TextInput\n id=\"vcpus\"\n name=\"vcpus\"\n label={t`vCPU`}\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 helptext={t`Minimum 128 MB.`}\n type=\"number\"\n required\n />\n </FormRow>\n <FormRow>\n <TextInput\n id=\"disk\"\n name=\"disk\"\n label={t`Root 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 helptext={t`Defaults to 1.`}\n type=\"number\"\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 { 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 { toast, Message, Button, Stack, DataGridToolbar, SearchInput, Status } from \"@cloudoperators/juno-ui-components\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { FlavorListContainer } from \"./FlavorListContainer\"\nimport { CreateFlavorModal } from \"./CreateFlavorModal\"\nimport { getFlavorCreatedToast, getFlavorDeletedToast } from \"./FlavorToastNotifications\"\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:add_project\",\n \"flavors:remove_project\",\n \"flavor_specs:create\",\n \"flavor_specs:delete\",\n ],\n })\n .then(([canCreate, canDelete, canAddProject, canRemoveProject, canCreateSpecs, canDeleteSpecs]) => ({\n canCreate,\n canDelete,\n canManageAccess: canAddProject || canRemoveProject,\n canManageSpecs: canCreateSpecs || canDeleteSpecs,\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 }>\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=\"2\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-45\"\n selectWidth=\"auto\"\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n {permissions.canCreate && (\n <Button variant=\"primary\" label={t`Create Flavor`} onClick={() => setCreateModalOpen(true)} />\n )}\n </Stack>\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 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`vCPU`, value: \"vcpus\" },\n { label: t`RAM (MiB)`, value: \"ram\" },\n { label: t`Root Disk (GiB)`, value: \"disk\" },\n { label: t`Swap (MiB)`, 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 [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 const { message, ...options } = getFlavorDeletedToast(flavorName)\n toast.success(message, options)\n refetchFlavors()\n }\n\n const handleFlavorCreated = (flavorName: string) => {\n const { message, ...options } = getFlavorCreatedToast(flavorName)\n toast.success(message, options)\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 <ErrorBoundary\n fallbackRender={({ error }) => (\n <Status\n status=\"error\"\n title={t`Failed to Load Flavors`}\n body={error instanceof Error ? error.message : t`An unexpected error occurred.`}\n />\n )}\n >\n <Suspense fallback={<Status status=\"progress\" title={t`Loading Flavors...`} />}>\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/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 analytics: {\n name: \"compute.flavors.list\",\n },\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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"}