@cobaltcore-dev/aurora 0.17.1 → 0.19.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.
- package/dist/client/AuthProvider-Cj_Btfnc.mjs +56 -0
- package/dist/client/AuthProvider-Cj_Btfnc.mjs.map +1 -0
- package/dist/client/{BucketToastNotifications-D2Cq2VrV.mjs → BucketToastNotifications-BGd2wVmh.mjs} +2 -2
- package/dist/client/{BucketToastNotifications-D2Cq2VrV.mjs.map → BucketToastNotifications-BGd2wVmh.mjs.map} +1 -1
- package/dist/client/DeletePcaModal-BU6kbKsw.mjs +80 -0
- package/dist/client/DeletePcaModal-BU6kbKsw.mjs.map +1 -0
- package/dist/client/DetailsInfo-BUyuYpJj.mjs +52 -0
- package/dist/client/DetailsInfo-BUyuYpJj.mjs.map +1 -0
- package/dist/client/{FloatingIpActionModals-BUc6yaQ8.mjs → FloatingIpActionModals-DAtZoYGS.mjs} +22 -22
- package/dist/client/{FloatingIpActionModals-BUc6yaQ8.mjs.map → FloatingIpActionModals-DAtZoYGS.mjs.map} +1 -1
- package/dist/client/{ImageToastNotifications-Dz-VsSwl.mjs → ImageToastNotifications-BhjU1bfT.mjs} +7 -7
- package/dist/client/{ImageToastNotifications-Dz-VsSwl.mjs.map → ImageToastNotifications-BhjU1bfT.mjs.map} +1 -1
- package/dist/client/{_auth-6uste_10.mjs → _auth-BtRCgHQe.mjs} +2 -2
- package/dist/client/{_auth-6uste_10.mjs.map → _auth-BtRCgHQe.mjs.map} +1 -1
- package/dist/client/{_flavorId-Cx5tf2KQ.mjs → _flavorId-BQY7YhNx.mjs} +2 -2
- package/dist/client/{_flavorId-Cx5tf2KQ.mjs.map → _flavorId-BQY7YhNx.mjs.map} +1 -1
- package/dist/client/{_flavorId-C6RJfhh8.mjs → _flavorId-sS1sg_DZ.mjs} +3 -3
- package/dist/client/{_flavorId-C6RJfhh8.mjs.map → _flavorId-sS1sg_DZ.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-B0l4YNQc.mjs → _floatingIpId-BHZGh8U8.mjs} +2 -2
- package/dist/client/{_floatingIpId-B0l4YNQc.mjs.map → _floatingIpId-BHZGh8U8.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-cpueAc2F2.mjs → _floatingIpId-CR3aD38l2.mjs} +5 -5
- package/dist/client/{_floatingIpId-cpueAc2F2.mjs.map → _floatingIpId-CR3aD38l2.mjs.map} +1 -1
- package/dist/client/{_imageId-Bv711w1n.mjs → _imageId-Cf-Xdksv.mjs} +3 -3
- package/dist/client/{_imageId-Bv711w1n.mjs.map → _imageId-Cf-Xdksv.mjs.map} +1 -1
- package/dist/client/_pcaId-B7j0sXnY.mjs +545 -0
- package/dist/client/_pcaId-B7j0sXnY.mjs.map +1 -0
- package/dist/client/{_projectId-fEA6fnFQ.mjs → _projectId-Cq9JnhRj.mjs} +3 -3
- package/dist/client/{_projectId-fEA6fnFQ.mjs.map → _projectId-Cq9JnhRj.mjs.map} +1 -1
- package/dist/client/{_projectId-w-tZz0FI.mjs → _projectId-D8FHe0gr.mjs} +2 -2
- package/dist/client/{_projectId-w-tZz0FI.mjs.map → _projectId-D8FHe0gr.mjs.map} +1 -1
- package/dist/client/{_projectId-qvINx3Dx.mjs → _projectId-Ig3QqYzt.mjs} +2 -2
- package/dist/client/{_projectId-qvINx3Dx.mjs.map → _projectId-Ig3QqYzt.mjs.map} +1 -1
- package/dist/client/{_projectId-BOaPmCuz.mjs → _projectId-b4NGeECR.mjs} +3 -3
- package/dist/client/{_projectId-BOaPmCuz.mjs.map → _projectId-b4NGeECR.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-B-RYPDDc.mjs → _securityGroupId-BVSsCus9.mjs} +2 -2
- package/dist/client/{_securityGroupId-B-RYPDDc.mjs.map → _securityGroupId-BVSsCus9.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-BC3KC6h5.mjs → _securityGroupId-gwV4eB0s.mjs} +16 -16
- package/dist/client/{_securityGroupId-BC3KC6h5.mjs.map → _securityGroupId-gwV4eB0s.mjs.map} +1 -1
- package/dist/client/{_storageType-ZFnIALny.mjs → _storageType-CH2khFcZ.mjs} +2 -2
- package/dist/client/{_storageType-ZFnIALny.mjs.map → _storageType-CH2khFcZ.mjs.map} +1 -1
- package/dist/client/{_storageType-MgntkZb6.mjs → _storageType-D-1H6SX1.mjs} +856 -856
- package/dist/client/{_storageType-MgntkZb6.mjs.map → _storageType-D-1H6SX1.mjs.map} +1 -1
- package/dist/client/{aurora-AAy9BJE7.mjs → aurora-Owys0YMN.mjs} +2 -2
- package/dist/client/{aurora-AAy9BJE7.mjs.map → aurora-Owys0YMN.mjs.map} +1 -1
- package/dist/client/build-DgeVmENN.mjs.map +1 -1
- package/dist/client/{floatingips-Bkk5-I_p.mjs → floatingips-DyBEotB8.mjs} +10 -10
- package/dist/client/{floatingips-Bkk5-I_p.mjs.map → floatingips-DyBEotB8.mjs.map} +1 -1
- package/dist/client/hooks-iGiEkLTp.mjs +12 -0
- package/dist/client/hooks-iGiEkLTp.mjs.map +1 -0
- package/dist/client/{images-FE3vJ6pP.mjs → images-BklbSacK.mjs} +2 -2
- package/dist/client/{images-FE3vJ6pP.mjs.map → images-BklbSacK.mjs.map} +1 -1
- package/dist/client/{images-DBLfzuJA.mjs → images-C3voJ3B1.mjs} +259 -259
- package/dist/client/{images-DBLfzuJA.mjs.map → images-C3voJ3B1.mjs.map} +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.js +370 -414
- package/dist/client/index.js.map +1 -1
- package/dist/client/md-CyCflQee.mjs.map +1 -1
- package/dist/client/{objects-DpgXMFrG.mjs → objects-B3Z8h4RU.mjs} +2 -2
- package/dist/client/{objects-DpgXMFrG.mjs.map → objects-B3Z8h4RU.mjs.map} +1 -1
- package/dist/client/{objects-Deo1Ic1A.mjs → objects-CGOfO00N.mjs} +499 -475
- package/dist/client/objects-CGOfO00N.mjs.map +1 -0
- package/dist/client/{pca-BkAJ5jvX.mjs → pca-72YR_Pk0.mjs} +3 -3
- package/dist/client/pca-72YR_Pk0.mjs.map +1 -0
- package/dist/client/pca-CsBx_IDO.mjs +251 -0
- package/dist/client/pca-CsBx_IDO.mjs.map +1 -0
- package/dist/client/pcaAccess-Br4kVjLQ.mjs +9 -0
- package/dist/client/pcaAccess-Br4kVjLQ.mjs.map +1 -0
- package/dist/client/{securitygroups-D14Jv1GQ.mjs → securitygroups-8vRbXmBL.mjs} +3 -3
- package/dist/client/{securitygroups-D14Jv1GQ.mjs.map → securitygroups-8vRbXmBL.mjs.map} +1 -1
- package/dist/client/trpcClient-BxcNKnhv.mjs +65 -0
- package/dist/client/trpcClient-BxcNKnhv.mjs.map +1 -0
- package/dist/client/trpcClient.d.ts +3014 -0
- package/dist/server/index.d.ts +3058 -1
- package/dist/server/index.js +53 -23
- package/package.json +4 -2
- package/dist/client/AuthProvider-BQSJk5R4.mjs +0 -63
- package/dist/client/AuthProvider-BQSJk5R4.mjs.map +0 -1
- package/dist/client/_pcaId-CPLb5J6d.mjs +0 -479
- package/dist/client/_pcaId-CPLb5J6d.mjs.map +0 -1
- package/dist/client/_pcaId-Hx_72pnp.mjs +0 -36
- package/dist/client/_pcaId-Hx_72pnp.mjs.map +0 -1
- package/dist/client/constants-BAqOfvr0.mjs +0 -153
- package/dist/client/constants-BAqOfvr0.mjs.map +0 -1
- package/dist/client/hooks-CnX5q5wN.mjs +0 -2
- package/dist/client/objects-Deo1Ic1A.mjs.map +0 -1
- package/dist/client/pca-BkAJ5jvX.mjs.map +0 -1
- package/dist/client/pca-P0ud1PA9.mjs +0 -202
- package/dist/client/pca-P0ud1PA9.mjs.map +0 -1
- package/dist/client/pcaAccess-BYUY700H.mjs +0 -9
- package/dist/client/pcaAccess-BYUY700H.mjs.map +0 -1
- package/dist/client/trpcClient-Dy_MP_Pv.mjs +0 -57
- package/dist/client/trpcClient-Dy_MP_Pv.mjs.map +0 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import t, { useCallback as n, useEffect as r, useRef as i } from "react";
|
|
3
|
+
//#region src/client/store/AuthProvider.tsx
|
|
4
|
+
var a = /*#__PURE__*/ t.createContext(null);
|
|
5
|
+
function o({ children: o, router: s }) {
|
|
6
|
+
let [c, l] = t.useState(null), [u, d] = t.useState(void 0), f = i(null), p = !!c, m = n(() => {
|
|
7
|
+
f.current &&= (clearTimeout(f.current), null);
|
|
8
|
+
}, []), h = n(async () => {
|
|
9
|
+
m(), l(null), d(void 0);
|
|
10
|
+
let e = window.location.pathname === "/" ? null : window.location.pathname + window.location.search;
|
|
11
|
+
s.navigate({
|
|
12
|
+
to: "/",
|
|
13
|
+
search: e ? { redirect: e } : void 0
|
|
14
|
+
}), s.invalidate();
|
|
15
|
+
}, [s, m]), g = n(async (e, t) => {
|
|
16
|
+
l(e), d(t ? new Date(t) : void 0);
|
|
17
|
+
}, []);
|
|
18
|
+
return r(() => {
|
|
19
|
+
if (m(), c && u) {
|
|
20
|
+
let e = u.getTime() - Date.now();
|
|
21
|
+
if (e <= 0) {
|
|
22
|
+
h();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
f.current = setTimeout(() => {
|
|
26
|
+
h();
|
|
27
|
+
}, e);
|
|
28
|
+
}
|
|
29
|
+
return () => {
|
|
30
|
+
m();
|
|
31
|
+
};
|
|
32
|
+
}, [
|
|
33
|
+
c,
|
|
34
|
+
u,
|
|
35
|
+
h,
|
|
36
|
+
m
|
|
37
|
+
]), /*#__PURE__*/ e(a.Provider, {
|
|
38
|
+
value: {
|
|
39
|
+
isAuthenticated: p,
|
|
40
|
+
user: c,
|
|
41
|
+
login: g,
|
|
42
|
+
logout: h,
|
|
43
|
+
expiresAt: u
|
|
44
|
+
},
|
|
45
|
+
children: o
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function s() {
|
|
49
|
+
let e = t.useContext(a);
|
|
50
|
+
if (!e) throw Error("useAuth must be used within an AuthProvider");
|
|
51
|
+
return e;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { s as n, o as t };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=AuthProvider-Cj_Btfnc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthProvider-Cj_Btfnc.mjs","names":["React","useEffect","useRef","useCallback","AuthContext","createContext","AuthProvider","children","router","user","setUser","useState","expiresAt","setExpiresAt","undefined","logoutTimerRef","isAuthenticated","clearLogoutTimer","current","clearTimeout","logout","currentPath","window","location","pathname","search","navigate","to","redirect","invalidate","login","expires_at","expiration","Date","timeUntilExpiry","getTime","now","setTimeout","Provider","value","useAuth","context","useContext","Error"],"sources":["../../src/client/store/AuthProvider.tsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback } from \"react\"\nimport { TokenData } from \"../../server/Authentication/types/models\"\n\nexport type User = TokenData[\"user\"] | null\n\nexport interface AuthContext {\n isAuthenticated: boolean\n login: (user: User, expires_at?: string) => Promise<void>\n logout: () => Promise<void>\n user?: User\n expiresAt?: Date\n}\n\ninterface RouterNavigation {\n navigate: (options: { to: string; search?: Record<string, unknown> }) => void\n invalidate: () => void\n}\n\nconst AuthContext = React.createContext<AuthContext | null>(null)\n\nexport function AuthProvider({ children, router }: { children: React.ReactNode; router: RouterNavigation }) {\n const [user, setUser] = React.useState<User | null>(null)\n const [expiresAt, setExpiresAt] = React.useState<Date | undefined>(undefined)\n\n const logoutTimerRef = useRef<NodeJS.Timeout | null>(null)\n\n const isAuthenticated = !!user\n\n const clearLogoutTimer = useCallback(() => {\n if (logoutTimerRef.current) {\n clearTimeout(logoutTimerRef.current)\n logoutTimerRef.current = null\n }\n }, [])\n\n const logout = useCallback(async () => {\n clearLogoutTimer()\n\n setUser(null)\n setExpiresAt(undefined)\n\n // Navigate to login page; include a redirect back to the current path when not already on \"/\"\n const currentPath = window.location.pathname !== \"/\" ? window.location.pathname + window.location.search : null\n\n router.navigate({\n to: \"/\",\n search: currentPath ? { redirect: currentPath } : undefined,\n })\n\n router.invalidate()\n }, [router, clearLogoutTimer])\n\n const login = useCallback(async (user: User, expires_at?: string) => {\n setUser(user)\n\n if (expires_at) {\n const expiration = new Date(expires_at)\n setExpiresAt(expiration)\n } else {\n setExpiresAt(undefined)\n }\n }, [])\n\n useEffect(() => {\n clearLogoutTimer()\n\n if (user && expiresAt) {\n const timeUntilExpiry = expiresAt.getTime() - Date.now()\n\n if (timeUntilExpiry <= 0) {\n logout()\n return\n }\n\n logoutTimerRef.current = setTimeout(() => {\n logout()\n }, timeUntilExpiry)\n }\n\n return () => {\n clearLogoutTimer()\n }\n }, [user, expiresAt, logout, clearLogoutTimer])\n\n return (\n <AuthContext.Provider\n value={{\n isAuthenticated,\n user,\n login,\n logout,\n expiresAt,\n }}\n >\n {children}\n </AuthContext.Provider>\n )\n}\n\nexport function useAuth() {\n const context = React.useContext(AuthContext)\n if (!context) {\n throw new Error(\"useAuth must be used within an AuthProvider\")\n }\n return context\n}\n"],"mappings":";;;AAkBA,IAAMI,IAAcJ,gBAAMK,cAAkC,IAAA;AAE5D,SAAgBC,EAAa,EAAEC,aAAUC,aAAiE;CACxG,IAAM,CAACC,GAAMC,KAAWV,EAAMW,SAAsB,IAAA,GAC9C,CAACC,GAAWC,KAAgBb,EAAMW,SAA2BG,KAAAA,CAAAA,GAE7DC,IAAiBb,EAA8B,IAAA,GAE/Cc,IAAkB,CAAC,CAACP,GAEpBQ,IAAmBd,QAAY;EACnC,AAEEY,EAAeG,aADfC,aAAaJ,EAAeG,OAAO,GACV;CAE7B,GAAG,CAAA,CAAE,GAECE,IAASjB,EAAY,YAAA;EAIzBU,AAHAI,EAAAA,GAEAP,EAAQ,IAAA,GACRG,EAAaC,KAAAA,CAAAA;EAGb,IAAMO,IAAcC,OAAOC,SAASC,aAAa,MAA0D,OAApDF,OAAOC,SAASC,WAAWF,OAAOC,SAASE;EAOlGjB,AALAA,EAAOkB,SAAS;GACdC,IAAI;GACJF,QAAQJ,IAAc,EAAEO,UAAUP,EAAY,IAAIP,KAAAA;EACpD,CAAA,GAEAN,EAAOqB,WAAU;CACnB,GAAG,CAACrB,GAAQS,CAAAA,CAAiB,GAEvBa,IAAQ3B,EAAY,OAAOM,GAAYsB,MAAAA;EAG3C,AAFArB,EAAQD,CAAAA,GAINI,EAFEkB,IAEWC,IADUC,KAAKF,CACfC,IAEAlB,KAAAA,CAAAA;CAEjB,GAAG,CAAA,CAAE;CAuBL,OArBAb,QAAU;EAGR,IAFAgB,EAAAA,GAEIR,KAAQG,GAAW;GACrB,IAAMsB,IAAkBtB,EAAUuB,QAAO,IAAKF,KAAKG,IAAG;GAEtD,IAAIF,KAAmB,GAAG;IACxBd,EAAAA;IACA;GACF;GAEAL,EAAeG,UAAUmB,iBAAW;IAClCjB,EAAAA;GACF,GAAGc,CAAAA;EACL;EAEA,aAAO;GACLjB,EAAAA;EACF;CACF,GAAG;EAACR;EAAMG;EAAWQ;EAAQH;EAAiB,GAG5C,gBAACb,EAAYkC,UAAQ;EACnBC,OAAO;GACLvB;GACAP;GACAqB;GACAV;GACAR;EACF;EAECL;;AAGP;AAEA,SAAgBiC,IAAAA;CACd,IAAMC,IAAUzC,EAAM0C,WAAWtC,CAAAA;CACjC,IAAI,CAACqC,GACH,MAAUE,MAAM,6CAAA;CAElB,OAAOF;AACT"}
|
package/dist/client/{BucketToastNotifications-D2Cq2VrV.mjs → BucketToastNotifications-BGd2wVmh.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { B as e, K as t, U as n, g as r, lt as i, r as a, tt as o, ut as s, y as c } from "./build-DgeVmENN.mjs";
|
|
2
|
-
import { r as l } from "./trpcClient-
|
|
2
|
+
import { r as l } from "./trpcClient-BxcNKnhv.mjs";
|
|
3
3
|
import { t as u } from "./useProjectId-DBc5lpoU.mjs";
|
|
4
4
|
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
5
5
|
import { useEffect as m, useRef as h, useState as g } from "react";
|
|
@@ -610,4 +610,4 @@ var C = ({ isOpen: e, bucket: r, onClose: s, onSuccess: c, onError: d }) => {
|
|
|
610
610
|
//#endregion
|
|
611
611
|
export { w as _, O as a, x as b, L as c, N as d, I as f, T as g, z as h, A as i, M as l, B as m, E as n, k as o, F as p, j as r, R as s, D as t, P as u, C as v, b as x, S as y };
|
|
612
612
|
|
|
613
|
-
//# sourceMappingURL=BucketToastNotifications-
|
|
613
|
+
//# sourceMappingURL=BucketToastNotifications-BGd2wVmh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BucketToastNotifications-D2Cq2VrV.mjs","names":["useEffect","useRef","useRouteContext","useModalTracking","isOpen","actionPrefix","onTrackEvent","strict","hasTrackedOpen","hasSubmitted","current","source","action","trackClose","markSubmitted","resetTracking","useEffect","trpcReact","Modal","Stack","Spinner","Message","useProjectId","useModalTracking","DeleteBucketPolicyModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","data","policyData","isLoading","isPolicyLoading","error","policyError","storage","ceph","bucketPolicy","get","useQuery","project_id","enabled","retry","deleteMutation","delete","useMutation","invalidate","name","handleClose","message","reset","handleDelete","mutate","hasPolicy","policy","isDeleting","isPending","title","t","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","div","className","variant","p","strong","isError","calculateBucketState","allVersions","isVersioningEnabled","bucketObjectCount","currentVersions","filter","v","isLatest","isDeleteMarker","realVersions","hasOnlyDeleteMarkers","length","hasOldVersionsOrDeleteMarkers","some","effectiveCurrentObjectCount","isBucketEmpty","useState","trpcReact","Modal","TextInput","Stack","Checkbox","Spinner","useProjectId","calculateBucketState","useModalTracking","EmptyBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","deleteVersionsAndMarkers","setDeleteVersionsAndMarkers","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","error","versioningError","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","staleTime","versionCheckData","isLoadingVersionCheck","versionCheckError","objects","list","containerName","maxKeys","delimiter","showVersions","status","isVersioningEnabled","allVersions","versions","bucketObjectCount","count","isBucketEmpty","hasOnlyDeleteMarkers","isBucketEmptyWithVersions","emptyBucketMutation","deleteAll","useMutation","onSettled","containers","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","shouldDeleteVersions","mutate","includeVersionsAndDeleteMarkers","deletedCount","message","handleKeyDown","key","hasQueryError","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","div","className","p","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","alignment","span","checked","useState","useEffect","trpcReact","Modal","ModalFooter","ButtonRow","TextInput","Stack","Spinner","Button","useProjectId","calculateBucketState","useModalTracking","DeleteBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","isVersioningEnabled","status","objects","isLoadingObjects","error","objectsError","list","containerName","maxKeys","delimiter","showVersions","deleteBucketMutation","containers","delete","useMutation","onSettled","invalidate","reset","handleClose","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","mutate","message","handleKeyDown","key","currentObjectCount","length","allVersions","versions","effectiveCurrentObjectCount","hasOldVersionsOrDeleteMarkers","hasCurrentObjects","hasVersionsInVersionedBucket","cannotDelete","errorMessage","title","open","onCancel","confirmButtonLabel","undefined","confirmButtonVariant","onConfirm","cancelButtonLabel","modalFooter","className","variant","onClick","data-testid","size","disableConfirmButton","isPending","direction","gap","p","role","aria-live","alignment","span","div","ul","li","label","required","onChange","onKeyDown","invalid","errortext","disabled","placeholder","useState","trpcReact","Modal","TextInput","Stack","useProjectId","useModalTracking","DeleteVersionsModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","deleteVersionsMutation","storage","ceph","objects","deleteAll","useMutation","onSettled","containers","list","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","name","t","bucketName","mutate","project_id","containerName","includeVersionsAndDeleteMarkers","deletedCount","error","message","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","getBucketCreatedToast","bucketName","message","description","getBucketCreateErrorToast","errorMessage","getBucketEmptiedToast","deletedCount","getBucketEmptyErrorToast","getBucketDeletedToast","getBucketDeleteErrorToast","getBucketsEmptyCompleteToast","emptiedCount","totalDeleted","errors","hasErrors","length","totalBuckets","errorsLength","getVersioningEnabledToast","getVersioningEnableErrorToast","getVersioningSuspendedToast","getVersioningSuspendErrorToast","getBucketPolicyDeletedToast","getBucketPolicyDeleteErrorToast","getVersionsDeletedToast","getVersionsDeleteErrorToast"],"sources":["../../src/client/hooks/useModalTracking.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/bucketStateHelpers.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/EmptyBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteVersionsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketToastNotifications.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { useRouteContext } from \"@tanstack/react-router\"\n\ninterface UseModalTrackingOptions {\n isOpen: boolean\n actionPrefix: string // e.g., \"storage.ceph.bucket.create\"\n}\n\ninterface UseModalTrackingReturn {\n trackClose: () => void\n markSubmitted: () => void\n resetTracking: () => void\n}\n\n/**\n * Custom hook to handle modal open/close analytics tracking.\n *\n * Tracks:\n * - `.open` event when modal opens (once per modal open)\n * - `.close` event when modal closes without submission (cancelled)\n *\n * @example\n * const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n * isOpen,\n * actionPrefix: \"storage.ceph.bucket.create\"\n * })\n *\n * // In handleClose:\n * trackClose()\n *\n * // In handleSubmit:\n * markSubmitted()\n *\n * // In cleanup/reset:\n * resetTracking()\n */\nexport const useModalTracking = ({ isOpen, actionPrefix }: UseModalTrackingOptions): UseModalTrackingReturn => {\n const { onTrackEvent } = useRouteContext({ strict: false })\n const hasTrackedOpen = useRef(false)\n // Use useRef instead of useState to avoid timing race with synchronous close paths\n // See: https://github.com/... - setState doesn't apply until next render, so trackClose()\n // could read stale hasSubmitted === false even after markSubmitted() was called\n const hasSubmitted = useRef(false)\n\n // Track when user opens the modal (once per modal open)\n useEffect(() => {\n if (isOpen && !hasTrackedOpen.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.open`,\n })\n hasTrackedOpen.current = true\n }\n }, [isOpen, onTrackEvent, actionPrefix])\n\n /**\n * Track close event if user didn't submit.\n * Call this at the start of your handleClose function.\n */\n const trackClose = () => {\n if (isOpen && !hasSubmitted.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.close`,\n })\n }\n }\n\n /**\n * Mark that the user submitted the form.\n * Call this in your handleSubmit function before the mutation.\n */\n const markSubmitted = () => {\n hasSubmitted.current = true\n }\n\n /**\n * Reset tracking state.\n * Call this in handleClose after tracking close event.\n */\n const resetTracking = () => {\n hasSubmitted.current = false\n hasTrackedOpen.current = false\n }\n\n return {\n trackClose,\n markSubmitted,\n resetTracking,\n }\n}\n","import { useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Spinner, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketPolicyModal = ({\n isOpen,\n bucketName,\n onClose,\n onSuccess,\n onError,\n}: DeleteBucketPolicyModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.policy.delete\",\n })\n\n // Query to verify policy exists\n const {\n data: policyData,\n isLoading: isPolicyLoading,\n error: policyError,\n } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Delete mutation\n const deleteMutation = trpcReact.storage.ceph.bucketPolicy.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.bucketPolicy.get.invalidate()\n const name = bucketName\n onSuccess?.(name)\n handleClose()\n },\n onError: (error) => {\n const name = bucketName\n onError?.(name, error.message)\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n deleteMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleDelete = () => {\n markSubmitted()\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n }\n\n if (!isOpen) return null\n\n const hasPolicy = !!policyData?.policy\n const isDeleting = deleteMutation.isPending\n\n return (\n <Modal\n title={t`Delete Bucket Policy`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Policy`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isDeleting || isPolicyLoading || !hasPolicy || !!policyError}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && (\n <div className=\"flex items-center justify-center py-4\">\n <Spinner variant=\"primary\" size=\"large\" />\n </div>\n )}\n\n {policyError && (\n <Message variant=\"error\" title={t`Failed to load policy`}>\n {policyError.message}\n </Message>\n )}\n\n {!isPolicyLoading && !policyError && !hasPolicy && (\n <Message variant=\"warning\" title={t`No policy found`}>\n <Trans>This bucket does not have a policy attached.</Trans>\n </Message>\n )}\n\n {!isPolicyLoading && !policyError && hasPolicy && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n Are you sure you want to delete the policy for bucket <strong>{bucketName}</strong>?\n </Trans>\n </p>\n <p className=\"text-theme-default\">\n <Trans>\n Deleting the policy will remove all access restrictions defined by it. This action cannot be undone.\n </Trans>\n </p>\n </>\n )}\n\n {deleteMutation.isError && (\n <Message variant=\"error\" title={t`Failed to delete policy`}>\n {deleteMutation.error?.message}\n </Message>\n )}\n </Stack>\n </Modal>\n )\n}\n","import type { S3ObjectVersion } from \"@/server/Storage/types/ceph\"\n\n/**\n * Helper to calculate bucket state from versioning data\n *\n * @param allVersions - All versions/objects from the list query with showVersions=true\n * @param isVersioningEnabled - Whether bucket has versioning Enabled or Suspended\n * @param bucketObjectCount - Object count from bucket metadata (may be 0 even with objects due to how S3 counts)\n * @returns Calculated state flags for bucket emptiness and version status\n */\nexport function calculateBucketState(\n allVersions: S3ObjectVersion[],\n isVersioningEnabled: boolean,\n bucketObjectCount: number\n) {\n // Current objects = isLatest=true and not delete markers\n const currentVersions = allVersions.filter((v) => v.isLatest && !v.isDeleteMarker)\n\n // Real versions (not delete markers) - includes both current and old\n const realVersions = allVersions.filter((v) => !v.isDeleteMarker)\n\n // Check if there are ONLY delete markers (no real objects/versions at all)\n const hasOnlyDeleteMarkers = isVersioningEnabled && allVersions.length > 0 && realVersions.length === 0\n\n // Check if there are old versions (not current) or any delete markers\n // Used to determine if \"Delete Versions\" action is needed\n const hasOldVersionsOrDeleteMarkers =\n isVersioningEnabled && allVersions.some((v) => v.isDeleteMarker || (!v.isLatest && !v.isDeleteMarker))\n\n // Count current objects for bucket emptiness check\n // - For versioned buckets: use bucketObjectCount from metadata OR count current versions if metadata is 0\n // - For unversioned buckets: count all real versions (they are all current)\n const effectiveCurrentObjectCount = isVersioningEnabled\n ? bucketObjectCount > 0\n ? bucketObjectCount\n : currentVersions.length\n : bucketObjectCount + realVersions.length\n\n // Bucket is empty only if there are no current objects\n const isBucketEmpty = effectiveCurrentObjectCount === 0\n\n return {\n currentVersions,\n hasOnlyDeleteMarkers,\n hasOldVersionsOrDeleteMarkers,\n effectiveCurrentObjectCount,\n isBucketEmpty,\n }\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack, Checkbox, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface EmptyBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const EmptyBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: EmptyBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [deleteVersionsAndMarkers, setDeleteVersionsAndMarkers] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.empty\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Query versioning status for the bucket\n const {\n data: versioningStatus,\n isLoading: isLoadingVersioning,\n error: versioningError,\n } = trpcReact.storage.ceph.versioning.getStatus.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucket?.name ?? \"\",\n },\n {\n enabled: !!projectId && !!bucket && isOpen,\n staleTime: 30 * 1000,\n }\n )\n\n // Query to check if bucket has versions/delete markers (only when versioning is enabled/suspended)\n // Use maxKeys=100 to get enough data - with maxKeys=1 we might miss current objects\n // if the first result is a delete marker\n const {\n data: versionCheckData,\n isLoading: isLoadingVersionCheck,\n error: versionCheckError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucket?.name ?? \"\",\n maxKeys: 100,\n delimiter: \"\",\n showVersions: true,\n },\n {\n enabled: !!projectId && !!bucket && isOpen && versioningStatus?.status !== \"Unversioned\",\n staleTime: 30 * 1000,\n }\n )\n\n // Check bucket state using shared helper\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n const allVersions = versionCheckData?.versions ?? []\n const bucketObjectCount = bucket?.count ?? 0\n const { isBucketEmpty, hasOnlyDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n bucketObjectCount\n )\n const isBucketEmptyWithVersions = isBucketEmpty && hasOnlyDeleteMarkers\n\n const emptyBucketMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n setDeleteVersionsAndMarkers(false)\n emptyBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // If bucket is empty with only delete markers, always delete versions\n const shouldDeleteVersions = isBucketEmptyWithVersions || deleteVersionsAndMarkers\n\n emptyBucketMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: shouldDeleteVersions,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n const bucketName = bucket.name\n const isLoading = isLoadingVersioning || isLoadingVersionCheck\n const hasQueryError = !!versioningError || !!versionCheckError\n\n // If bucket is empty with only delete markers, show \"Delete Versions\" UI\n if (isBucketEmptyWithVersions && !isLoading) {\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n </Modal>\n )\n }\n\n // Otherwise show normal \"Empty Bucket\" UI\n return (\n <Modal\n title={t`Empty Bucket`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Empty Bucket`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n {isLoading ? (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Checking bucket contents...</Trans>\n </span>\n </Stack>\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n {versioningStatus && versioningStatus.status !== \"Unversioned\" ? (\n <Trans>\n This action will permanently delete all objects from {bucketName}. You may choose to also delete all\n versions and delete markers. This will enable you to delete the bucket. This action cannot be undone.\n </Trans>\n ) : (\n <Trans>\n This action will permanently delete all objects from {bucketName}. This action cannot be undone.\n </Trans>\n )}\n </p>\n\n {versioningStatus && versioningStatus.status !== \"Unversioned\" && (\n <Checkbox\n checked={deleteVersionsAndMarkers}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDeleteVersionsAndMarkers(e.target.checked)}\n label={t`Also delete all versions and all delete markers`}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n />\n )}\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, ModalFooter, ButtonRow, TextInput, Stack, Spinner, Button } from \"@cloudoperators/juno-ui-components\"\nimport type { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Fetch versioning status to determine if bucket has versioning enabled\n const { data: versioningStatus, isLoading: isLoadingVersioning } =\n trpcReact.storage.ceph.versioning.getStatus.useQuery(\n { project_id: projectId ?? \"\", bucket: bucket?.name ?? \"\" },\n { enabled: isOpen && bucket !== null }\n )\n\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n\n // Fetch actual objects and versions to get accurate real-time state\n // Use showVersions=true to also detect delete markers in versioned buckets\n // Use delimiter=\"\" to get ALL objects including folder markers (zero-byte objects ending in \"/\")\n // Without this, folders are returned as CommonPrefixes and we can't accurately check if bucket is empty\n // Use maxKeys=100 to get enough objects/versions to accurately determine bucket state\n // (with maxKeys=1 we might miss current objects if the first result is a delete marker)\n const {\n data: objects,\n isLoading: isLoadingObjects,\n error: objectsError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n { project_id: projectId ?? \"\", containerName: bucket?.name ?? \"\", maxKeys: 100, delimiter: \"\", showVersions: true },\n { enabled: isOpen && bucket !== null }\n )\n\n const deleteBucketMutation = trpcReact.storage.ceph.containers.delete.useMutation({\n onSettled: () => {\n utils.storage.ceph.containers.list.invalidate()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucket?.name])\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (objectsError) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n deleteBucketMutation.mutate(\n { project_id: projectId, bucketName },\n {\n onSuccess: () => {\n handleClose()\n onSuccess?.(bucketName)\n },\n onError: (error) => {\n handleClose()\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n // Calculate bucket state using shared helper\n // When showVersions=true, BFF returns all objects in \"versions\" array, not \"objects\"\n // So bucketObjectCount from objects?.objects is used only as a fallback\n const currentObjectCount = objects?.objects?.length ?? 0\n const allVersions = objects?.versions ?? []\n const { effectiveCurrentObjectCount, hasOldVersionsOrDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n currentObjectCount\n )\n\n // Bucket cannot be deleted if it has:\n // 1. Current objects (effectiveCurrentObjectCount > 0) - show \"Empty the bucket\"\n // 2. Old versions or any delete markers in a versioned bucket - show \"Delete all versions\"\n const hasCurrentObjects = effectiveCurrentObjectCount > 0\n const hasVersionsInVersionedBucket = hasOldVersionsOrDeleteMarkers\n const cannotDelete = hasCurrentObjects || hasVersionsInVersionedBucket\n const errorMessage = objectsError?.message\n const isLoading = isLoadingObjects || isLoadingVersioning\n\n return (\n <Modal\n title={t`Delete Bucket`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={cannotDelete ? undefined : t`Delete Bucket`}\n confirmButtonVariant={cannotDelete ? undefined : \"primary-danger\"}\n onConfirm={cannotDelete ? undefined : handleSubmit}\n cancelButtonLabel={cannotDelete ? undefined : t`Cancel`}\n modalFooter={\n cannotDelete ? (\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"primary\" onClick={handleClose} data-testid=\"delete-has-objects-close-button\">\n <Trans>Close</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n ) : undefined\n }\n size=\"small\"\n disableConfirmButton={\n deleteBucketMutation.isPending || isLoading || !!objectsError || confirmName.trim() !== bucket.name\n }\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {objectsError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n <Trans>Failed to check bucket contents: {errorMessage}</Trans>\n </p>\n )}\n\n {isLoading ? (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Checking bucket contents...</Trans>\n </span>\n </Stack>\n ) : cannotDelete ? (\n <div className=\"text-theme-default\">\n <p className=\"mb-4\">\n <Trans>This bucket cannot be deleted yet. Do the following to be able to delete the bucket:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5\">\n {hasCurrentObjects && (\n <li>\n <Trans>Empty the bucket</Trans>\n </li>\n )}\n {hasVersionsInVersionedBucket && (\n <li>\n <Trans>Delete all versions and delete markers</Trans>\n </li>\n )}\n </ul>\n </div>\n ) : (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n This action is irreversible. Deleting a bucket permanently removes it and cannot be undone. The bucket\n must be empty before deletion.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteBucketMutation.isPending}\n placeholder={bucket.name}\n />\n </>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteVersionsModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteVersionsModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteVersionsModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.versions.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n const deleteVersionsMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n deleteVersionsMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // Always delete all versions and delete markers (includeVersionsAndDeleteMarkers: true)\n deleteVersionsMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: true,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={deleteVersionsMutation.isPending || confirmName.trim() !== bucket.name}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteVersionsMutation.isPending}\n placeholder={bucket.name}\n autoFocus\n className=\"overflow-x-hidden [overflow-wrap:anywhere]\"\n />\n </Stack>\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural } from \"@lingui/react/macro\"\n\nexport const getBucketCreatedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Created</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully created.</Trans>,\n})\n\nexport const getBucketCreateErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Create Bucket</Trans>,\n description: (\n <Trans>\n Could not create bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketEmptiedToast = (\n bucketName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Emptied</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>Bucket \"{bucketName}\" was already empty.</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} object deleted.\n </Trans>\n ) : (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} objects deleted.\n </Trans>\n ),\n})\n\nexport const getBucketEmptyErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Empty Bucket</Trans>,\n description: (\n <Trans>\n Could not empty bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketDeletedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Deleted</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully deleted.</Trans>,\n})\n\nexport const getBucketDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Bucket</Trans>,\n description: (\n <Trans>\n Could not delete bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketsEmptyCompleteToast = (\n emptiedCount: number,\n totalDeleted: number,\n errors: string[]\n): { message: ReactNode } & NotificationOptions => {\n const hasErrors = errors.length > 0\n const totalBuckets = emptiedCount + errors.length\n const errorsLength = errors.length\n\n return {\n message: hasErrors ? <Trans>Empty All Completed with Errors</Trans> : <Trans>All Buckets Emptied</Trans>,\n description: hasErrors ? (\n <Trans>\n Successfully emptied {emptiedCount} of {totalBuckets}{\" \"}\n <Plural value={totalBuckets} one=\"bucket\" other=\"buckets\" />, deleting {totalDeleted}{\" \"}\n <Plural value={totalDeleted} one=\"object\" other=\"objects\" />. {errorsLength}{\" \"}\n <Plural value={errorsLength} one=\"bucket\" other=\"buckets\" /> failed.\n </Trans>\n ) : (\n <Trans>\n Successfully emptied {emptiedCount} <Plural value={emptiedCount} one=\"bucket\" other=\"buckets\" />, deleting{\" \"}\n {totalDeleted} <Plural value={totalDeleted} one=\"object\" other=\"objects\" />.\n </Trans>\n ),\n }\n}\n\n// ── Versioning operations ──────────────────────────────────────────────────\n\nexport const getVersioningEnabledToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versioning Enabled</Trans>,\n description: <Trans>Versioning was successfully enabled for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningEnableErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Enable Versioning</Trans>,\n description: (\n <Trans>\n Could not enable versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getVersioningSuspendedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versioning Suspended</Trans>,\n description: <Trans>Versioning was successfully suspended for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningSuspendErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Suspend Versioning</Trans>,\n description: (\n <Trans>\n Could not suspend versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Bucket policy operations ───────────────────────────────────────────────\n\nexport const getBucketPolicyDeletedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Policy Deleted</Trans>,\n description: <Trans>Bucket policy was successfully deleted from \"{bucketName}\".</Trans>,\n})\n\nexport const getBucketPolicyDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Policy</Trans>,\n description: (\n <Trans>\n Could not delete bucket policy from \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Delete versions operation ──────────────────────────────────────────────\n\nexport const getVersionsDeletedToast = (\n bucketName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versions Deleted</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>No versions to delete in bucket \"{bucketName}\".</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Successfully deleted {deletedCount} version from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>\n Successfully deleted {deletedCount} versions from bucket \"{bucketName}\".\n </Trans>\n ),\n})\n\nexport const getVersionsDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Versions</Trans>,\n description: (\n <Trans>\n Could not delete versions from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BucketToastNotifications-BGd2wVmh.mjs","names":["useEffect","useRef","useRouteContext","useModalTracking","isOpen","actionPrefix","onTrackEvent","strict","hasTrackedOpen","hasSubmitted","current","source","action","trackClose","markSubmitted","resetTracking","useEffect","trpcReact","Modal","Stack","Spinner","Message","useProjectId","useModalTracking","DeleteBucketPolicyModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","data","policyData","isLoading","isPolicyLoading","error","policyError","storage","ceph","bucketPolicy","get","useQuery","project_id","enabled","retry","deleteMutation","delete","useMutation","invalidate","name","handleClose","message","reset","handleDelete","mutate","hasPolicy","policy","isDeleting","isPending","title","t","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","div","className","variant","p","strong","isError","calculateBucketState","allVersions","isVersioningEnabled","bucketObjectCount","currentVersions","filter","v","isLatest","isDeleteMarker","realVersions","hasOnlyDeleteMarkers","length","hasOldVersionsOrDeleteMarkers","some","effectiveCurrentObjectCount","isBucketEmpty","useState","trpcReact","Modal","TextInput","Stack","Checkbox","Spinner","useProjectId","calculateBucketState","useModalTracking","EmptyBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","deleteVersionsAndMarkers","setDeleteVersionsAndMarkers","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","error","versioningError","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","staleTime","versionCheckData","isLoadingVersionCheck","versionCheckError","objects","list","containerName","maxKeys","delimiter","showVersions","status","isVersioningEnabled","allVersions","versions","bucketObjectCount","count","isBucketEmpty","hasOnlyDeleteMarkers","isBucketEmptyWithVersions","emptyBucketMutation","deleteAll","useMutation","onSettled","containers","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","shouldDeleteVersions","mutate","includeVersionsAndDeleteMarkers","deletedCount","message","handleKeyDown","key","hasQueryError","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","div","className","p","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","alignment","span","checked","useState","useEffect","trpcReact","Modal","ModalFooter","ButtonRow","TextInput","Stack","Spinner","Button","useProjectId","calculateBucketState","useModalTracking","DeleteBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","isVersioningEnabled","status","objects","isLoadingObjects","error","objectsError","list","containerName","maxKeys","delimiter","showVersions","deleteBucketMutation","containers","delete","useMutation","onSettled","invalidate","reset","handleClose","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","mutate","message","handleKeyDown","key","currentObjectCount","length","allVersions","versions","effectiveCurrentObjectCount","hasOldVersionsOrDeleteMarkers","hasCurrentObjects","hasVersionsInVersionedBucket","cannotDelete","errorMessage","title","open","onCancel","confirmButtonLabel","undefined","confirmButtonVariant","onConfirm","cancelButtonLabel","modalFooter","className","variant","onClick","data-testid","size","disableConfirmButton","isPending","direction","gap","p","role","aria-live","alignment","span","div","ul","li","label","required","onChange","onKeyDown","invalid","errortext","disabled","placeholder","useState","trpcReact","Modal","TextInput","Stack","useProjectId","useModalTracking","DeleteVersionsModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","deleteVersionsMutation","storage","ceph","objects","deleteAll","useMutation","onSettled","containers","list","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","name","t","bucketName","mutate","project_id","containerName","includeVersionsAndDeleteMarkers","deletedCount","error","message","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","getBucketCreatedToast","bucketName","message","description","getBucketCreateErrorToast","errorMessage","getBucketEmptiedToast","deletedCount","getBucketEmptyErrorToast","getBucketDeletedToast","getBucketDeleteErrorToast","getBucketsEmptyCompleteToast","emptiedCount","totalDeleted","errors","hasErrors","length","totalBuckets","errorsLength","getVersioningEnabledToast","getVersioningEnableErrorToast","getVersioningSuspendedToast","getVersioningSuspendErrorToast","getBucketPolicyDeletedToast","getBucketPolicyDeleteErrorToast","getVersionsDeletedToast","getVersionsDeleteErrorToast"],"sources":["../../src/client/hooks/useModalTracking.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/bucketStateHelpers.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/EmptyBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteVersionsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketToastNotifications.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { useRouteContext } from \"@tanstack/react-router\"\n\ninterface UseModalTrackingOptions {\n isOpen: boolean\n actionPrefix: string // e.g., \"storage.ceph.bucket.create\"\n}\n\ninterface UseModalTrackingReturn {\n trackClose: () => void\n markSubmitted: () => void\n resetTracking: () => void\n}\n\n/**\n * Custom hook to handle modal open/close analytics tracking.\n *\n * Tracks:\n * - `.open` event when modal opens (once per modal open)\n * - `.close` event when modal closes without submission (cancelled)\n *\n * @example\n * const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n * isOpen,\n * actionPrefix: \"storage.ceph.bucket.create\"\n * })\n *\n * // In handleClose:\n * trackClose()\n *\n * // In handleSubmit:\n * markSubmitted()\n *\n * // In cleanup/reset:\n * resetTracking()\n */\nexport const useModalTracking = ({ isOpen, actionPrefix }: UseModalTrackingOptions): UseModalTrackingReturn => {\n const { onTrackEvent } = useRouteContext({ strict: false })\n const hasTrackedOpen = useRef(false)\n // Use useRef instead of useState to avoid timing race with synchronous close paths\n // See: https://github.com/... - setState doesn't apply until next render, so trackClose()\n // could read stale hasSubmitted === false even after markSubmitted() was called\n const hasSubmitted = useRef(false)\n\n // Track when user opens the modal (once per modal open)\n useEffect(() => {\n if (isOpen && !hasTrackedOpen.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.open`,\n })\n hasTrackedOpen.current = true\n }\n }, [isOpen, onTrackEvent, actionPrefix])\n\n /**\n * Track close event if user didn't submit.\n * Call this at the start of your handleClose function.\n */\n const trackClose = () => {\n if (isOpen && !hasSubmitted.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.close`,\n })\n }\n }\n\n /**\n * Mark that the user submitted the form.\n * Call this in your handleSubmit function before the mutation.\n */\n const markSubmitted = () => {\n hasSubmitted.current = true\n }\n\n /**\n * Reset tracking state.\n * Call this in handleClose after tracking close event.\n */\n const resetTracking = () => {\n hasSubmitted.current = false\n hasTrackedOpen.current = false\n }\n\n return {\n trackClose,\n markSubmitted,\n resetTracking,\n }\n}\n","import { useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Spinner, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketPolicyModal = ({\n isOpen,\n bucketName,\n onClose,\n onSuccess,\n onError,\n}: DeleteBucketPolicyModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.policy.delete\",\n })\n\n // Query to verify policy exists\n const {\n data: policyData,\n isLoading: isPolicyLoading,\n error: policyError,\n } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Delete mutation\n const deleteMutation = trpcReact.storage.ceph.bucketPolicy.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.bucketPolicy.get.invalidate()\n const name = bucketName\n onSuccess?.(name)\n handleClose()\n },\n onError: (error) => {\n const name = bucketName\n onError?.(name, error.message)\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n deleteMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleDelete = () => {\n markSubmitted()\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n }\n\n if (!isOpen) return null\n\n const hasPolicy = !!policyData?.policy\n const isDeleting = deleteMutation.isPending\n\n return (\n <Modal\n title={t`Delete Bucket Policy`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Policy`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isDeleting || isPolicyLoading || !hasPolicy || !!policyError}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && (\n <div className=\"flex items-center justify-center py-4\">\n <Spinner variant=\"primary\" size=\"large\" />\n </div>\n )}\n\n {policyError && (\n <Message variant=\"error\" title={t`Failed to load policy`}>\n {policyError.message}\n </Message>\n )}\n\n {!isPolicyLoading && !policyError && !hasPolicy && (\n <Message variant=\"warning\" title={t`No policy found`}>\n <Trans>This bucket does not have a policy attached.</Trans>\n </Message>\n )}\n\n {!isPolicyLoading && !policyError && hasPolicy && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n Are you sure you want to delete the policy for bucket <strong>{bucketName}</strong>?\n </Trans>\n </p>\n <p className=\"text-theme-default\">\n <Trans>\n Deleting the policy will remove all access restrictions defined by it. This action cannot be undone.\n </Trans>\n </p>\n </>\n )}\n\n {deleteMutation.isError && (\n <Message variant=\"error\" title={t`Failed to delete policy`}>\n {deleteMutation.error?.message}\n </Message>\n )}\n </Stack>\n </Modal>\n )\n}\n","import type { S3ObjectVersion } from \"@/server/Storage/types/ceph\"\n\n/**\n * Helper to calculate bucket state from versioning data\n *\n * @param allVersions - All versions/objects from the list query with showVersions=true\n * @param isVersioningEnabled - Whether bucket has versioning Enabled or Suspended\n * @param bucketObjectCount - Object count from bucket metadata (may be 0 even with objects due to how S3 counts)\n * @returns Calculated state flags for bucket emptiness and version status\n */\nexport function calculateBucketState(\n allVersions: S3ObjectVersion[],\n isVersioningEnabled: boolean,\n bucketObjectCount: number\n) {\n // Current objects = isLatest=true and not delete markers\n const currentVersions = allVersions.filter((v) => v.isLatest && !v.isDeleteMarker)\n\n // Real versions (not delete markers) - includes both current and old\n const realVersions = allVersions.filter((v) => !v.isDeleteMarker)\n\n // Check if there are ONLY delete markers (no real objects/versions at all)\n const hasOnlyDeleteMarkers = isVersioningEnabled && allVersions.length > 0 && realVersions.length === 0\n\n // Check if there are old versions (not current) or any delete markers\n // Used to determine if \"Delete Versions\" action is needed\n const hasOldVersionsOrDeleteMarkers =\n isVersioningEnabled && allVersions.some((v) => v.isDeleteMarker || (!v.isLatest && !v.isDeleteMarker))\n\n // Count current objects for bucket emptiness check\n // - For versioned buckets: use bucketObjectCount from metadata OR count current versions if metadata is 0\n // - For unversioned buckets: count all real versions (they are all current)\n const effectiveCurrentObjectCount = isVersioningEnabled\n ? bucketObjectCount > 0\n ? bucketObjectCount\n : currentVersions.length\n : bucketObjectCount + realVersions.length\n\n // Bucket is empty only if there are no current objects\n const isBucketEmpty = effectiveCurrentObjectCount === 0\n\n return {\n currentVersions,\n hasOnlyDeleteMarkers,\n hasOldVersionsOrDeleteMarkers,\n effectiveCurrentObjectCount,\n isBucketEmpty,\n }\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack, Checkbox, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface EmptyBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const EmptyBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: EmptyBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [deleteVersionsAndMarkers, setDeleteVersionsAndMarkers] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.empty\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Query versioning status for the bucket\n const {\n data: versioningStatus,\n isLoading: isLoadingVersioning,\n error: versioningError,\n } = trpcReact.storage.ceph.versioning.getStatus.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucket?.name ?? \"\",\n },\n {\n enabled: !!projectId && !!bucket && isOpen,\n staleTime: 30 * 1000,\n }\n )\n\n // Query to check if bucket has versions/delete markers (only when versioning is enabled/suspended)\n // Use maxKeys=100 to get enough data - with maxKeys=1 we might miss current objects\n // if the first result is a delete marker\n const {\n data: versionCheckData,\n isLoading: isLoadingVersionCheck,\n error: versionCheckError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucket?.name ?? \"\",\n maxKeys: 100,\n delimiter: \"\",\n showVersions: true,\n },\n {\n enabled: !!projectId && !!bucket && isOpen && versioningStatus?.status !== \"Unversioned\",\n staleTime: 30 * 1000,\n }\n )\n\n // Check bucket state using shared helper\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n const allVersions = versionCheckData?.versions ?? []\n const bucketObjectCount = bucket?.count ?? 0\n const { isBucketEmpty, hasOnlyDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n bucketObjectCount\n )\n const isBucketEmptyWithVersions = isBucketEmpty && hasOnlyDeleteMarkers\n\n const emptyBucketMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n setDeleteVersionsAndMarkers(false)\n emptyBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // If bucket is empty with only delete markers, always delete versions\n const shouldDeleteVersions = isBucketEmptyWithVersions || deleteVersionsAndMarkers\n\n emptyBucketMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: shouldDeleteVersions,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n const bucketName = bucket.name\n const isLoading = isLoadingVersioning || isLoadingVersionCheck\n const hasQueryError = !!versioningError || !!versionCheckError\n\n // If bucket is empty with only delete markers, show \"Delete Versions\" UI\n if (isBucketEmptyWithVersions && !isLoading) {\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n </Modal>\n )\n }\n\n // Otherwise show normal \"Empty Bucket\" UI\n return (\n <Modal\n title={t`Empty Bucket`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Empty Bucket`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n {isLoading ? (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Checking bucket contents...</Trans>\n </span>\n </Stack>\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n {versioningStatus && versioningStatus.status !== \"Unversioned\" ? (\n <Trans>\n This action will permanently delete all objects from {bucketName}. You may choose to also delete all\n versions and delete markers. This will enable you to delete the bucket. This action cannot be undone.\n </Trans>\n ) : (\n <Trans>\n This action will permanently delete all objects from {bucketName}. This action cannot be undone.\n </Trans>\n )}\n </p>\n\n {versioningStatus && versioningStatus.status !== \"Unversioned\" && (\n <Checkbox\n checked={deleteVersionsAndMarkers}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDeleteVersionsAndMarkers(e.target.checked)}\n label={t`Also delete all versions and all delete markers`}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n />\n )}\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, ModalFooter, ButtonRow, TextInput, Stack, Spinner, Button } from \"@cloudoperators/juno-ui-components\"\nimport type { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Fetch versioning status to determine if bucket has versioning enabled\n const { data: versioningStatus, isLoading: isLoadingVersioning } =\n trpcReact.storage.ceph.versioning.getStatus.useQuery(\n { project_id: projectId ?? \"\", bucket: bucket?.name ?? \"\" },\n { enabled: isOpen && bucket !== null }\n )\n\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n\n // Fetch actual objects and versions to get accurate real-time state\n // Use showVersions=true to also detect delete markers in versioned buckets\n // Use delimiter=\"\" to get ALL objects including folder markers (zero-byte objects ending in \"/\")\n // Without this, folders are returned as CommonPrefixes and we can't accurately check if bucket is empty\n // Use maxKeys=100 to get enough objects/versions to accurately determine bucket state\n // (with maxKeys=1 we might miss current objects if the first result is a delete marker)\n const {\n data: objects,\n isLoading: isLoadingObjects,\n error: objectsError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n { project_id: projectId ?? \"\", containerName: bucket?.name ?? \"\", maxKeys: 100, delimiter: \"\", showVersions: true },\n { enabled: isOpen && bucket !== null }\n )\n\n const deleteBucketMutation = trpcReact.storage.ceph.containers.delete.useMutation({\n onSettled: () => {\n utils.storage.ceph.containers.list.invalidate()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucket?.name])\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (objectsError) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n deleteBucketMutation.mutate(\n { project_id: projectId, bucketName },\n {\n onSuccess: () => {\n handleClose()\n onSuccess?.(bucketName)\n },\n onError: (error) => {\n handleClose()\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n // Calculate bucket state using shared helper\n // When showVersions=true, BFF returns all objects in \"versions\" array, not \"objects\"\n // So bucketObjectCount from objects?.objects is used only as a fallback\n const currentObjectCount = objects?.objects?.length ?? 0\n const allVersions = objects?.versions ?? []\n const { effectiveCurrentObjectCount, hasOldVersionsOrDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n currentObjectCount\n )\n\n // Bucket cannot be deleted if it has:\n // 1. Current objects (effectiveCurrentObjectCount > 0) - show \"Empty the bucket\"\n // 2. Old versions or any delete markers in a versioned bucket - show \"Delete all versions\"\n const hasCurrentObjects = effectiveCurrentObjectCount > 0\n const hasVersionsInVersionedBucket = hasOldVersionsOrDeleteMarkers\n const cannotDelete = hasCurrentObjects || hasVersionsInVersionedBucket\n const errorMessage = objectsError?.message\n const isLoading = isLoadingObjects || isLoadingVersioning\n\n return (\n <Modal\n title={t`Delete Bucket`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={cannotDelete ? undefined : t`Delete Bucket`}\n confirmButtonVariant={cannotDelete ? undefined : \"primary-danger\"}\n onConfirm={cannotDelete ? undefined : handleSubmit}\n cancelButtonLabel={cannotDelete ? undefined : t`Cancel`}\n modalFooter={\n cannotDelete ? (\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"primary\" onClick={handleClose} data-testid=\"delete-has-objects-close-button\">\n <Trans>Close</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n ) : undefined\n }\n size=\"small\"\n disableConfirmButton={\n deleteBucketMutation.isPending || isLoading || !!objectsError || confirmName.trim() !== bucket.name\n }\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {objectsError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n <Trans>Failed to check bucket contents: {errorMessage}</Trans>\n </p>\n )}\n\n {isLoading ? (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Checking bucket contents...</Trans>\n </span>\n </Stack>\n ) : cannotDelete ? (\n <div className=\"text-theme-default\">\n <p className=\"mb-4\">\n <Trans>This bucket cannot be deleted yet. Do the following to be able to delete the bucket:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5\">\n {hasCurrentObjects && (\n <li>\n <Trans>Empty the bucket</Trans>\n </li>\n )}\n {hasVersionsInVersionedBucket && (\n <li>\n <Trans>Delete all versions and delete markers</Trans>\n </li>\n )}\n </ul>\n </div>\n ) : (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n This action is irreversible. Deleting a bucket permanently removes it and cannot be undone. The bucket\n must be empty before deletion.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteBucketMutation.isPending}\n placeholder={bucket.name}\n />\n </>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteVersionsModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteVersionsModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteVersionsModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.versions.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n const deleteVersionsMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n deleteVersionsMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // Always delete all versions and delete markers (includeVersionsAndDeleteMarkers: true)\n deleteVersionsMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: true,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={deleteVersionsMutation.isPending || confirmName.trim() !== bucket.name}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteVersionsMutation.isPending}\n placeholder={bucket.name}\n autoFocus\n className=\"overflow-x-hidden [overflow-wrap:anywhere]\"\n />\n </Stack>\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural } from \"@lingui/react/macro\"\n\nexport const getBucketCreatedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Created</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully created.</Trans>,\n})\n\nexport const getBucketCreateErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Create Bucket</Trans>,\n description: (\n <Trans>\n Could not create bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketEmptiedToast = (\n bucketName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Emptied</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>Bucket \"{bucketName}\" was already empty.</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} object deleted.\n </Trans>\n ) : (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} objects deleted.\n </Trans>\n ),\n})\n\nexport const getBucketEmptyErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Empty Bucket</Trans>,\n description: (\n <Trans>\n Could not empty bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketDeletedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Bucket Deleted</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully deleted.</Trans>,\n})\n\nexport const getBucketDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Bucket</Trans>,\n description: (\n <Trans>\n Could not delete bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketsEmptyCompleteToast = (\n emptiedCount: number,\n totalDeleted: number,\n errors: string[]\n): { message: ReactNode } & NotificationOptions => {\n const hasErrors = errors.length > 0\n const totalBuckets = emptiedCount + errors.length\n const errorsLength = errors.length\n\n return {\n message: hasErrors ? <Trans>Empty All Completed with Errors</Trans> : <Trans>All Buckets Emptied</Trans>,\n description: hasErrors ? (\n <Trans>\n Successfully emptied {emptiedCount} of {totalBuckets}{\" \"}\n <Plural value={totalBuckets} one=\"bucket\" other=\"buckets\" />, deleting {totalDeleted}{\" \"}\n <Plural value={totalDeleted} one=\"object\" other=\"objects\" />. {errorsLength}{\" \"}\n <Plural value={errorsLength} one=\"bucket\" other=\"buckets\" /> failed.\n </Trans>\n ) : (\n <Trans>\n Successfully emptied {emptiedCount} <Plural value={emptiedCount} one=\"bucket\" other=\"buckets\" />, deleting{\" \"}\n {totalDeleted} <Plural value={totalDeleted} one=\"object\" other=\"objects\" />.\n </Trans>\n ),\n }\n}\n\n// ── Versioning operations ──────────────────────────────────────────────────\n\nexport const getVersioningEnabledToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versioning Enabled</Trans>,\n description: <Trans>Versioning was successfully enabled for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningEnableErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Enable Versioning</Trans>,\n description: (\n <Trans>\n Could not enable versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getVersioningSuspendedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versioning Suspended</Trans>,\n description: <Trans>Versioning was successfully suspended for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningSuspendErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Suspend Versioning</Trans>,\n description: (\n <Trans>\n Could not suspend versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Bucket policy operations ───────────────────────────────────────────────\n\nexport const getBucketPolicyDeletedToast = (bucketName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Policy Deleted</Trans>,\n description: <Trans>Bucket policy was successfully deleted from \"{bucketName}\".</Trans>,\n})\n\nexport const getBucketPolicyDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Policy</Trans>,\n description: (\n <Trans>\n Could not delete bucket policy from \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Delete versions operation ──────────────────────────────────────────────\n\nexport const getVersionsDeletedToast = (\n bucketName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Versions Deleted</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>No versions to delete in bucket \"{bucketName}\".</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Successfully deleted {deletedCount} version from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>\n Successfully deleted {deletedCount} versions from bucket \"{bucketName}\".\n </Trans>\n ),\n})\n\nexport const getVersionsDeleteErrorToast = (\n bucketName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Versions</Trans>,\n description: (\n <Trans>\n Could not delete versions from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n"],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { B as e, H as t, K as n, U as r, o as i, r as a, tt as o } from "./build-DgeVmENN.mjs";
|
|
2
|
+
import { r as s } from "./trpcClient-BxcNKnhv.mjs";
|
|
3
|
+
import { t as c } from "./useProjectId-DBc5lpoU.mjs";
|
|
4
|
+
import "./hooks-iGiEkLTp.mjs";
|
|
5
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
6
|
+
import { Trans as d, useLingui as f } from "@lingui/react";
|
|
7
|
+
import { z as p } from "zod";
|
|
8
|
+
import { useForm as m, useStore as h } from "@tanstack/react-form";
|
|
9
|
+
//#region src/client/routes/_auth/projects/$projectId/services/pca/-components/-modals/DeletePcaModal.tsx
|
|
10
|
+
var g = ({ pca: g, open: _, onClose: v, onSuccess: y }) => {
|
|
11
|
+
let { i18n: b, _: x } = f(), S = c(), C = s.useUtils(), { isPending: w, ...T } = s.services.pca.delete.useMutation({ onSettled: () => C.services.pca.list.invalidate() }), E = m({
|
|
12
|
+
defaultValues: { delete: "" },
|
|
13
|
+
validators: { onSubmit: p.object({ delete: p.string().refine((e) => e === "delete", { message: b._({ id: "fnCEAB" }) }) }) },
|
|
14
|
+
onSubmit: async () => {
|
|
15
|
+
w || (await T.mutateAsync({
|
|
16
|
+
project_id: S,
|
|
17
|
+
certificate_authority_id: g.id
|
|
18
|
+
}), O(), y?.());
|
|
19
|
+
}
|
|
20
|
+
}), D = h(E.store, (e) => e.isSubmitting || e.values.delete !== "delete"), O = () => {
|
|
21
|
+
E.reset(), v();
|
|
22
|
+
};
|
|
23
|
+
return /*#__PURE__*/ u(a, {
|
|
24
|
+
open: _,
|
|
25
|
+
size: "large",
|
|
26
|
+
title: b._({ id: "Blsc/x" }),
|
|
27
|
+
onCancel: O,
|
|
28
|
+
cancelButtonLabel: b._({ id: "dEgA5A" }),
|
|
29
|
+
confirmButtonLabel: b._({ id: "cnGeoo" }),
|
|
30
|
+
onConfirm: E.handleSubmit,
|
|
31
|
+
disableConfirmButton: w || D,
|
|
32
|
+
children: [
|
|
33
|
+
T.error?.message && /*#__PURE__*/ l(e, {
|
|
34
|
+
dismissible: !1,
|
|
35
|
+
variant: "error",
|
|
36
|
+
className: "mb-4",
|
|
37
|
+
children: T.error.message
|
|
38
|
+
}),
|
|
39
|
+
w && /*#__PURE__*/ u("div", {
|
|
40
|
+
className: "mb-4 flex items-center justify-center gap-2",
|
|
41
|
+
children: [/*#__PURE__*/ l(n, { variant: "primary" }), /*#__PURE__*/ l("span", {
|
|
42
|
+
className: "text-theme-high text-sm",
|
|
43
|
+
children: /*#__PURE__*/ l(d, { id: "nWNviN" })
|
|
44
|
+
})]
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ u(o, {
|
|
47
|
+
gap: "2.5",
|
|
48
|
+
direction: "vertical",
|
|
49
|
+
className: "mb-2.5",
|
|
50
|
+
children: [/*#__PURE__*/ l("p", { children: /*#__PURE__*/ l(d, { id: "nNKXt7" }) }), /*#__PURE__*/ l("p", { children: /*#__PURE__*/ l(d, {
|
|
51
|
+
id: "go9U+C",
|
|
52
|
+
components: { 0: /*#__PURE__*/ l("strong", {}) }
|
|
53
|
+
}) })]
|
|
54
|
+
}),
|
|
55
|
+
!w && /*#__PURE__*/ l(i, {
|
|
56
|
+
className: "mb-0",
|
|
57
|
+
id: "delete-pca-form",
|
|
58
|
+
onSubmit: (e) => {
|
|
59
|
+
e.preventDefault(), E.handleSubmit();
|
|
60
|
+
},
|
|
61
|
+
children: /*#__PURE__*/ l(t, { children: /*#__PURE__*/ l(E.Field, {
|
|
62
|
+
name: "delete",
|
|
63
|
+
children: (e) => /*#__PURE__*/ l(r, {
|
|
64
|
+
id: e.name,
|
|
65
|
+
name: e.name,
|
|
66
|
+
value: e.state.value,
|
|
67
|
+
onChange: (t) => e.handleChange(t.target.value),
|
|
68
|
+
placeholder: b._({ id: "QytzQr" }),
|
|
69
|
+
helptext: b._({ id: "VMh1t1" }),
|
|
70
|
+
required: !0
|
|
71
|
+
})
|
|
72
|
+
}) })
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { g as t };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=DeletePcaModal-BU6kbKsw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeletePcaModal-BU6kbKsw.mjs","names":["z","useForm","useStore","Modal","Form","FormSection","Spinner","Message","TextInput","Stack","trpcReact","useProjectId","DeletePcaModal","pca","open","onClose","onSuccess","useLingui","projectId","utils","useUtils","isPending","deletePcaMutation","services","delete","useMutation","onSettled","list","invalidate","formSchema","object","string","refine","value","message","t","form","defaultValues","validators","onSubmit","mutateAsync","project_id","certificate_authority_id","id","handleClose","canDelete","store","state","isSubmitting","values","reset","size","title","onCancel","cancelButtonLabel","confirmButtonLabel","onConfirm","handleSubmit","disableConfirmButton","error","dismissible","variant","className","div","span","gap","direction","p","strong","e","preventDefault","Field","name","children","field","onChange","handleChange","target","placeholder","helptext","required"],"sources":["../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-modals/DeletePcaModal.tsx"],"sourcesContent":["import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Form, FormSection, Spinner, Message, TextInput, Stack } from \"@cloudoperators/juno-ui-components\"\nimport type { CertificateAuthority } from \"@/server/Services/types/pca\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks\"\n\nexport interface DeletePcaModalProps {\n pca: CertificateAuthority\n open: boolean\n onClose: () => void\n onSuccess?: () => void\n}\n\nexport const DeletePcaModal = ({ pca, open, onClose, onSuccess }: DeletePcaModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { isPending, ...deletePcaMutation } = trpcReact.services.pca.delete.useMutation({\n onSettled: () => utils.services.pca.list.invalidate(),\n })\n\n const formSchema = z.object({\n delete: z.string().refine((value) => value === \"delete\", {\n message: t`Type “delete” to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n delete: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (isPending) return\n\n await deletePcaMutation.mutateAsync({\n project_id: projectId,\n certificate_authority_id: pca.id,\n })\n handleClose()\n onSuccess?.()\n },\n })\n\n // creates a reactive subscription so the component re-renders, which allows the confirm button to enable once the user types \"delete\".\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.delete !== \"delete\")\n\n const handleClose = () => {\n form.reset()\n onClose()\n }\n\n return (\n <Modal\n open={open}\n size=\"large\"\n title={t`Delete Certificate Authority`}\n onCancel={handleClose}\n cancelButtonLabel={t`Cancel`}\n confirmButtonLabel={t`Delete`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || canDelete}\n >\n {deletePcaMutation.error?.message && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {deletePcaMutation.error.message}\n </Message>\n )}\n\n {isPending && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Deleting certificate authority...</Trans>\n </span>\n </div>\n )}\n\n <Stack gap=\"2.5\" direction=\"vertical\" className=\"mb-2.5\">\n <p>\n <Trans>\n Deleting this Certificate Authority is permanent, and all the associated certificates will no longer apply\n to entities.\n </Trans>\n </p>\n <p>\n <Trans>\n To confirm, type <strong>\"delete\"</strong> in the field below.\n </Trans>\n </p>\n </Stack>\n\n {!isPending && (\n <Form\n className=\"mb-0\"\n id=\"delete-pca-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"delete\"\n children={(field) => (\n <TextInput\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder={t`Type \"delete\" to confirm`}\n helptext={t`The text must match “delete” in lowercase.`}\n required\n />\n )}\n />\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n"],"mappings":";;;;;;;;;AAeA,IAAaY,KAAkB,EAAEC,QAAKC,SAAMC,YAASC,mBAAgC;CACnF,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAYP,EAAAA,GACZQ,IAAQT,EAAUU,SAAQ,GAE1B,EAAEC,cAAW,GAAGC,MAAsBZ,EAAUa,SAASV,IAAIW,OAAOC,YAAY,EACpFC,iBAAiBP,EAAMI,SAASV,IAAIc,KAAKC,WAAU,EACrD,CAAA,GAQMQ,IAAOnC,EAAQ;EACnBoC,eAAe,EACbb,QAAQ,GACV;EACAc,YAAY,EACVC,UAXevC,EAAE8B,OAAO,EAC1BN,QAAQxB,EAAE+B,OAAM,EAAGC,QAAQC,MAAUA,MAAU,UAAU,EACvDC,SAASC,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA,EACrC,CAAA,EACF,CAOcN,EACZ;EACAU,UAAU,YAAA;GACJlB,MAEJ,MAAMC,EAAkBkB,YAAY;IAClCC,YAAYvB;IACZwB,0BAA0B7B,EAAI8B;GAChC,CAAA,GACAC,EAAAA,GACA5B,IAAAA;EACF;CACF,CAAA,GAGM6B,IAAY3C,EAASkC,EAAKU,QAAQC,MAAUA,EAAMC,gBAAgBD,EAAME,OAAOzB,WAAW,QAAA,GAE1FoB,UAAc;EAElB7B,AADAqB,EAAKc,MAAK,GACVnC,EAAAA;CACF;CAEA,OACE,gBAACZ,GAAAA;EACOW;EACNqC,MAAK;EACLC,OAAOjB,EAAAA,EAAC,EAAA,IAAA,SAA6B,CAAA;EACrCkB,UAAUT;EACVU,mBAAmBnB,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC3BoB,oBAAoBpB,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC5BqB,WAAWpB,EAAKqB;EAChBC,sBAAsBrC,KAAawB;;GAElCvB,EAAkBqC,OAAOzB,WACxB,gBAAC3B,GAAAA;IAAQqD,aAAa;IAAOC,SAAQ;IAAQC,WAAU;cACpDxC,EAAkBqC,MAAMzB;;GAI5Bb,KACC,gBAAC0C,OAAAA;IAAID,WAAU;eACb,gBAACxD,GAAAA,EAAQuD,SAAQ,UAAA,CAAA,GACjB,gBAACG,QAAAA;KAAKF,WAAU;eACd,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;GAKN,gBAACrD,GAAAA;IAAMwD,KAAI;IAAMC,WAAU;IAAWJ,WAAU;eAC9C,gBAACK,KAAAA,EAAAA,UACC,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA,GAKF,gBAACA,KAAAA,EAAAA,UACC,gBAAA,GAAA;;sCACoBC,UAAAA,CAAAA,CAAAA,EAAAA;;;GAKvB,CAAC/C,KACA,gBAACjB,GAAAA;IACC0D,WAAU;IACVnB,IAAG;IACHJ,WAAW8B,MAAAA;KAETjC,AADAiC,EAAEC,eAAc,GAChBlC,EAAKqB,aAAY;IACnB;cAEA,gBAACpD,GAAAA,EAAAA,UACC,gBAAC+B,EAAKmC,OAAK;KACTC,MAAK;KACLC,WAAWC,MACT,gBAAClE,GAAAA;MACCmC,IAAI+B,EAAMF;MACVA,MAAME,EAAMF;MACZvC,OAAOyC,EAAM3B,MAAMd;MACnB0C,WAAWN,MAAMK,EAAME,aAAaP,EAAEQ,OAAO5C,KAAK;MAClD6C,aAAa3C,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA;MACvC4C,UAAU5C,EAAAA,EAAC,EAAA,IAAA,SAA2C,CAAA;MACtD6C,UAAQ;;;;;;AAS1B"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { D as e, F as t, W as n, q as r, tt as i } from "./build-DgeVmENN.mjs";
|
|
2
|
+
import { t as a } from "./helpers-1PpYf-fC.mjs";
|
|
3
|
+
import { t as o } from "./pcaAccess-Br4kVjLQ.mjs";
|
|
4
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
|
+
import { Fragment as l } from "react";
|
|
6
|
+
import { createFileRoute as u, lazyRouteComponent as d, redirect as f } from "@tanstack/react-router";
|
|
7
|
+
var p = u("/_auth/projects/$projectId/services/pca/$pcaId/")({
|
|
8
|
+
staticData: {
|
|
9
|
+
section: "services",
|
|
10
|
+
service: "pca",
|
|
11
|
+
isDetail: !0,
|
|
12
|
+
analytics: { name: "services.pca.detail" },
|
|
13
|
+
sectionCrumb: { labelKey: "Services" },
|
|
14
|
+
crumb: {
|
|
15
|
+
labelKey: "PCA (Clavis)",
|
|
16
|
+
to: "/projects/$projectId/services/pca"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
loader: async ({ context: e, params: t }) => {
|
|
20
|
+
let n = await e.trpcClient?.services.pca.getById.query({
|
|
21
|
+
project_id: t.projectId,
|
|
22
|
+
certificate_authority_id: t.pcaId
|
|
23
|
+
});
|
|
24
|
+
return { pcaTitle: n?.configuration?.subject?.named_attributes?.cn || n?.id || null };
|
|
25
|
+
},
|
|
26
|
+
head: ({ loaderData: e }) => ({ meta: [{ title: e?.pcaTitle ?? "Certificate Authority" }] }),
|
|
27
|
+
component: d(() => import("./_pcaId-B7j0sXnY.mjs"), "component"),
|
|
28
|
+
beforeLoad: async ({ context: e, params: t }) => {
|
|
29
|
+
let { trpcClient: n } = e;
|
|
30
|
+
if (!o(a(await n?.auth.getAvailableServices.query() || []), e.enabledServices)) throw f({
|
|
31
|
+
to: "/projects/$projectId",
|
|
32
|
+
params: { projectId: t.projectId }
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}), m = ({ basicInfo: a, heading: o, content: u }) => /*#__PURE__*/ c(i, {
|
|
36
|
+
gap: "4",
|
|
37
|
+
className: "grid grid-cols-2 items-start",
|
|
38
|
+
children: [/*#__PURE__*/ s(t, {
|
|
39
|
+
alignTerms: "right",
|
|
40
|
+
className: "w-full",
|
|
41
|
+
children: a.map(({ label: t, value: n }) => /*#__PURE__*/ c(l, { children: [/*#__PURE__*/ s(r, { children: t }), /*#__PURE__*/ s(e, { children: n || "—" })] }, t))
|
|
42
|
+
}), /*#__PURE__*/ s(n, {
|
|
43
|
+
heading: o,
|
|
44
|
+
content: u,
|
|
45
|
+
className: "w-full [&_pre_code]:block [&_pre_code]:w-full",
|
|
46
|
+
wrap: !0
|
|
47
|
+
})]
|
|
48
|
+
});
|
|
49
|
+
//#endregion
|
|
50
|
+
export { p as n, m as t };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=DetailsInfo-BUyuYpJj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DetailsInfo-BUyuYpJj.mjs","names":["createFileRoute","redirect","getServiceIndex","canAccessClavisPca","Route","staticData","section","service","isDetail","analytics","name","sectionCrumb","labelKey","crumb","to","RouteInfo","loader","context","params","pca","trpcClient","services","getById","query","project_id","projectId","certificate_authority_id","pcaId","pcaTitle","configuration","subject","named_attributes","cn","id","head","loaderData","meta","title","component","lazyRouteComponent","$$splitComponentImporter","beforeLoad","availableServices","auth","getAvailableServices","serviceIndex","enabledServices","Fragment","Stack","DescriptionList","DescriptionTerm","DescriptionDefinition","CodeBlock","DetailsInfo","basicInfo","heading","content","gap","className","alignTerms","map","label","value","wrap"],"sources":["../../src/client/routes/_auth/projects/$projectId/services/pca/$pcaId/index.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/$pcaId/-components/DetailsInfo.tsx"],"sourcesContent":["import { createFileRoute, redirect, useNavigate } from \"@tanstack/react-router\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { Button, Spinner, Stack } from \"@cloudoperators/juno-ui-components/index\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { canAccessClavisPca } from \"../-components/pcaAccess\"\nimport { PcaDetailsView } from \"./-components/PcaDetailsView\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services/pca/$pcaId/\")({\n staticData: {\n section: \"services\",\n service: \"pca\",\n isDetail: true,\n analytics: {\n name: \"services.pca.detail\",\n },\n sectionCrumb: { labelKey: \"Services\" },\n crumb: { labelKey: \"PCA (Clavis)\", to: \"/projects/$projectId/services/pca\" },\n } satisfies RouteInfo,\n loader: async ({ context, params }) => {\n const pca = await context.trpcClient?.services.pca.getById.query({\n project_id: params.projectId,\n certificate_authority_id: params.pcaId,\n })\n return { pcaTitle: pca?.configuration?.subject?.named_attributes?.cn || pca?.id || null }\n },\n head: ({ loaderData }) => ({\n meta: [{ title: loaderData?.pcaTitle ?? \"Certificate Authority\" }],\n }),\n component: RouteComponent,\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = (await trpcClient?.auth.getAvailableServices.query()) || []\n const serviceIndex = getServiceIndex(availableServices)\n\n if (!canAccessClavisPca(serviceIndex, context.enabledServices)) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId: params.projectId },\n })\n }\n },\n})\n\nfunction RouteComponent() {\n const navigate = useNavigate()\n const projectId = useProjectId()\n const { pcaId } = Route.useParams()\n\n const {\n isLoading,\n isError,\n error,\n data: pca,\n } = trpcReact.services.pca.getById.useQuery({\n project_id: projectId,\n certificate_authority_id: pcaId,\n })\n\n // Loading state\n if (isLoading) {\n return (\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Certificate Authority Details...</Trans>\n </Stack>\n )\n }\n\n const handleBack = () =>\n navigate({\n to: \"/projects/$projectId/services/pca\",\n params: { projectId },\n })\n\n if (isError) {\n const errorMessage = error?.message || \"Unknown error\"\n return (\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\" gap=\"5\">\n <p className=\"text-theme-error font-semibold\">\n <Trans>Error loading Certificate Authority</Trans>\n </p>\n <p className=\"text-theme-highest\">{errorMessage}</p>\n <Button onClick={handleBack} variant=\"primary\">\n <Trans>Back to Certificate Authorities</Trans>\n </Button>\n </Stack>\n )\n }\n\n if (!pca) {\n return (\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\" gap=\"5\">\n <p className=\"text-theme-secondary\">\n <Trans>Certificate Authority not found</Trans>\n </p>\n <Button onClick={handleBack} variant=\"primary\">\n <Trans>Back to Certificate Authorities</Trans>\n </Button>\n </Stack>\n )\n }\n\n return <PcaDetailsView pca={pca} />\n}\n","import { Fragment } from \"react\"\nimport {\n Stack,\n DescriptionList,\n DescriptionTerm,\n DescriptionDefinition,\n CodeBlock,\n} from \"@cloudoperators/juno-ui-components/index\"\n\ninterface DetailsInfoProps {\n basicInfo: ReadonlyArray<{ label: string; value: string | undefined }>\n heading: string\n content: string\n}\n\nexport const DetailsInfo = ({ basicInfo, heading, content }: DetailsInfoProps) => (\n <Stack gap=\"4\" className=\"grid grid-cols-2 items-start\">\n <DescriptionList alignTerms=\"right\" className=\"w-full\">\n {basicInfo.map(({ label, value }) => (\n <Fragment key={label}>\n <DescriptionTerm>{label}</DescriptionTerm>\n <DescriptionDefinition>{value || \"—\"}</DescriptionDefinition>\n </Fragment>\n ))}\n </DescriptionList>\n\n <CodeBlock heading={heading} content={content} className=\"w-full [&_pre_code]:block [&_pre_code]:w-full\" wrap />\n </Stack>\n)\n"],"mappings":";;;;;;AAUA,IAAaI,IAAQJ,EAAgB,iDAAA,EAAmD;CACtFK,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,UAAU;EACVC,WAAW,EACTC,MAAM,sBACR;EACAC,cAAc,EAAEC,UAAU,WAAW;EACrCC,OAAO;GAAED,UAAU;GAAgBE,IAAI;EAAoC;CAC7E;CACAE,QAAQ,OAAO,EAAEC,YAASC,gBAAQ;EAChC,IAAMC,IAAM,MAAMF,EAAQG,YAAYC,SAASF,IAAIG,QAAQC,MAAM;GAC/DC,YAAYN,EAAOO;GACnBC,0BAA0BR,EAAOS;EACnC,CAAA;EACA,OAAO,EAAEC,UAAUT,GAAKU,eAAeC,SAASC,kBAAkBC,MAAMb,GAAKc,MAAM,KAAK;CAC1F;CACAC,OAAO,EAAEC,qBAAkB,EACzBC,MAAM,CAAC,EAAEC,OAAOF,GAAYP,YAAY,wBAAwB,CAAA,EAClE;CACAU,WAASC,yCAAA,WAAA;CACTE,YAAY,OAAO,EAAExB,YAASC,gBAAQ;EACpC,IAAM,EAAEE,kBAAeH;EAIvB,IAAI,CAACd,EAFgBD,EADK,MAAOkB,GAAYuB,KAAKC,qBAAqBrB,MAAAA,KAAY,CAAA,CAG3DsB,GAAc5B,EAAQ6B,eAAe,GAC3D,MAAM7C,EAAS;GACba,IAAI;GACJI,QAAQ,EAAEO,WAAWP,EAAOO,UAAU;EACxC,CAAA;CAEJ;AACF,CAAA,GC7Ba4B,KAAe,EAAEC,cAAWC,YAASC,iBAChD,gBAACR,GAAAA;CAAMS,KAAI;CAAIC,WAAU;YACvB,gBAACT,GAAAA;EAAgBU,YAAW;EAAQD,WAAU;YAC3CJ,EAAUM,KAAK,EAAEC,UAAOC,eACvB,gBAACf,GAAAA,EAAAA,UAAAA,CACC,gBAACG,GAAAA,EAAAA,UAAiBW,EAAAA,CAAAA,GAClB,gBAACV,GAAAA,EAAAA,UAAuBW,KAAS,IAAA,CAAA,CAAA,EAAA,GAFpBD,CAAAA,CAAAA;KAOnB,gBAACT,GAAAA;EAAmBG;EAAkBC;EAASE,WAAU;EAAgDK,MAAI"}
|