@cobaltcore-dev/aurora 0.22.0 → 0.23.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-p1e1DuKU.mjs → AuthProvider-CQ6Yppoh.mjs} +2 -2
- package/dist/client/{AuthProvider-p1e1DuKU.mjs.map → AuthProvider-CQ6Yppoh.mjs.map} +1 -1
- package/dist/client/{BucketToastNotifications-BGd2wVmh.mjs → BucketToastNotifications-BhPi4WWw.mjs} +3 -3
- package/dist/client/{BucketToastNotifications-BGd2wVmh.mjs.map → BucketToastNotifications-BhPi4WWw.mjs.map} +1 -1
- package/dist/client/{ContentHeader-BIScbvb4.mjs → ContentHeader-9KZdhOoA.mjs} +2 -2
- package/dist/client/{ContentHeader-BIScbvb4.mjs.map → ContentHeader-9KZdhOoA.mjs.map} +1 -1
- package/dist/client/{DeleteFlavorModal-lFMExcq_.mjs → DeleteFlavorModal-Be2qZo4w.mjs} +2 -2
- package/dist/client/{DeleteFlavorModal-lFMExcq_.mjs.map → DeleteFlavorModal-Be2qZo4w.mjs.map} +1 -1
- package/dist/client/{DeletePcaModal-Dg9dej-H.mjs → DeletePcaModal-CIFsGWyj.mjs} +4 -4
- package/dist/client/{DeletePcaModal-Dg9dej-H.mjs.map → DeletePcaModal-CIFsGWyj.mjs.map} +1 -1
- package/dist/client/{DetailsInfo-DwCo9P1o.mjs → DetailsInfo-CHVD7d-W.mjs} +3 -3
- package/dist/client/{DetailsInfo-DwCo9P1o.mjs.map → DetailsInfo-CHVD7d-W.mjs.map} +1 -1
- package/dist/client/{FiltersInput-cOaaRpcQ.mjs → FiltersInput-DqT08Ib-.mjs} +2 -2
- package/dist/client/{FiltersInput-cOaaRpcQ.mjs.map → FiltersInput-DqT08Ib-.mjs.map} +1 -1
- package/dist/client/{FloatingIpActionModals-CDF8LVtX.mjs → FloatingIpActionModals-BcceUHcg.mjs} +4 -4
- package/dist/client/{FloatingIpActionModals-CDF8LVtX.mjs.map → FloatingIpActionModals-BcceUHcg.mjs.map} +1 -1
- package/dist/client/{ImageToastNotifications-Dzq6jNTm.mjs → ImageToastNotifications-BGyX2J6j.mjs} +5 -5
- package/dist/client/ImageToastNotifications-BGyX2J6j.mjs.map +1 -0
- package/dist/client/{RouteError-BmZRk_ss.mjs → RouteError-Rm08PcxN.mjs} +2 -2
- package/dist/client/{RouteError-BmZRk_ss.mjs.map → RouteError-Rm08PcxN.mjs.map} +1 -1
- package/dist/client/{SortInput-DjaEHvcO.mjs → SortInput-D_q_jDfe.mjs} +2 -2
- package/dist/client/{SortInput-DjaEHvcO.mjs.map → SortInput-D_q_jDfe.mjs.map} +1 -1
- package/dist/client/{StatusError-CLB026fg.mjs → StatusError-2ZU1gFpu.mjs} +2 -2
- package/dist/client/{StatusError-CLB026fg.mjs.map → StatusError-2ZU1gFpu.mjs.map} +1 -1
- package/dist/client/{_auth-Dut7CaMR.mjs → _auth-D5_QNUos.mjs} +2 -2
- package/dist/client/{_auth-Dut7CaMR.mjs.map → _auth-D5_QNUos.mjs.map} +1 -1
- package/dist/client/{_flavorId-DUWdFEMH.mjs → _flavorId-BsmqS9hP.mjs} +7 -7
- package/dist/client/{_flavorId-DUWdFEMH.mjs.map → _flavorId-BsmqS9hP.mjs.map} +1 -1
- package/dist/client/{_flavorId-BMJcnI7H.mjs → _flavorId-CFmkmg2Y.mjs} +2 -2
- package/dist/client/{_flavorId-BMJcnI7H.mjs.map → _flavorId-CFmkmg2Y.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-KcWWq9ZW2.mjs → _floatingIpId-Bb9ZEJ6b.mjs} +6 -6
- package/dist/client/_floatingIpId-Bb9ZEJ6b.mjs.map +1 -0
- package/dist/client/{_floatingIpId-CjQLzpC5.mjs → _floatingIpId-Dzh6_JCI.mjs} +2 -2
- package/dist/client/{_floatingIpId-CjQLzpC5.mjs.map → _floatingIpId-Dzh6_JCI.mjs.map} +1 -1
- package/dist/client/{_imageId-BkEpwbCr.mjs → _imageId-C3As7sHE.mjs} +5 -5
- package/dist/client/{_imageId-BkEpwbCr.mjs.map → _imageId-C3As7sHE.mjs.map} +1 -1
- package/dist/client/{_pcaId-BcwGho7g.mjs → _pcaId-n0q0aDb6.mjs} +6 -6
- package/dist/client/{_pcaId-BcwGho7g.mjs.map → _pcaId-n0q0aDb6.mjs.map} +1 -1
- package/dist/client/{_projectId-hMtrqW6m.mjs → _projectId-BuBIFdgG.mjs} +3 -3
- package/dist/client/{_projectId-hMtrqW6m.mjs.map → _projectId-BuBIFdgG.mjs.map} +1 -1
- package/dist/client/{_projectId-CoMD6nq6.mjs → _projectId-CAQkJHZ4.mjs} +3 -3
- package/dist/client/{_projectId-CoMD6nq6.mjs.map → _projectId-CAQkJHZ4.mjs.map} +1 -1
- package/dist/client/_projectId-D-b7paXE.mjs +29 -0
- package/dist/client/_projectId-D-b7paXE.mjs.map +1 -0
- package/dist/client/{_projectId-D8FHe0gr.mjs → _projectId-DNZsNxJw.mjs} +3 -3
- package/dist/client/{_projectId-D8FHe0gr.mjs.map → _projectId-DNZsNxJw.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-B5-gJe1u.mjs → _securityGroupId-DFdNKa2l.mjs} +641 -504
- package/dist/client/_securityGroupId-DFdNKa2l.mjs.map +1 -0
- package/dist/client/{_securityGroupId-fPJWtDPU.mjs → _securityGroupId-DRkY3Gt6.mjs} +2 -2
- package/dist/client/_securityGroupId-DRkY3Gt6.mjs.map +1 -0
- package/dist/client/{_storageType-CI5f4CsI.mjs → _storageType-BKfQcpgp.mjs} +2 -2
- package/dist/client/{_storageType-CI5f4CsI.mjs.map → _storageType-BKfQcpgp.mjs.map} +1 -1
- package/dist/client/{_storageType-DePX1Aah.mjs → _storageType-sMj9NEJz.mjs} +7 -7
- package/dist/client/{_storageType-DePX1Aah.mjs.map → _storageType-sMj9NEJz.mjs.map} +1 -1
- package/dist/client/{about-B4sGnxeW.mjs → about-C8tTrQaW.mjs} +2 -2
- package/dist/client/{about-B4sGnxeW.mjs.map → about-C8tTrQaW.mjs.map} +1 -1
- package/dist/client/assets/objectDownload.worker-BAc5Au4B.js.map +1 -0
- package/dist/client/{aurora-Dp_NPGe8.mjs → aurora-jyvXcI4T.mjs} +2 -2
- package/dist/client/{aurora-Dp_NPGe8.mjs.map → aurora-jyvXcI4T.mjs.map} +1 -1
- package/dist/client/{build-DgeVmENN.mjs → build-CRLQyqu2.mjs} +2616 -3346
- package/dist/client/{build-DgeVmENN.mjs.map → build-CRLQyqu2.mjs.map} +1 -1
- package/dist/client/{flavors-DkGuWvge.mjs → flavors-BfTXqmoD.mjs} +6 -6
- package/dist/client/{flavors-DkGuWvge.mjs.map → flavors-BfTXqmoD.mjs.map} +1 -1
- package/dist/client/{flavors-DLxUiBhE.mjs → flavors-Dy-2mRGv.mjs} +2 -2
- package/dist/client/{flavors-DLxUiBhE.mjs.map → flavors-Dy-2mRGv.mjs.map} +1 -1
- package/dist/client/floatingips-zhNK6Xxn.mjs +562 -0
- package/dist/client/floatingips-zhNK6Xxn.mjs.map +1 -0
- package/dist/client/{hooks-D0wGUhRF.mjs → hooks-Bw3sHHOg.mjs} +2 -2
- package/dist/client/{hooks-D0wGUhRF.mjs.map → hooks-Bw3sHHOg.mjs.map} +1 -1
- package/dist/client/{images-h9i7S4LN.mjs → images-DPKUXryV.mjs} +2 -2
- package/dist/client/{images-h9i7S4LN.mjs.map → images-DPKUXryV.mjs.map} +1 -1
- package/dist/client/{images-D9nfOtSC.mjs → images-DhZnqUG_.mjs} +29 -29
- package/dist/client/images-DhZnqUG_.mjs.map +1 -0
- package/dist/client/images-NBf2bV43.mjs.map +1 -1
- package/dist/client/index.js +303 -312
- package/dist/client/index.js.map +1 -1
- package/dist/client/{objects-CGOfO00N.mjs → objects-BG1saVLZ.mjs} +1153 -862
- package/dist/client/objects-BG1saVLZ.mjs.map +1 -0
- package/dist/client/{objects-B3Z8h4RU.mjs → objects-Dahys529.mjs} +2 -2
- package/dist/client/{objects-B3Z8h4RU.mjs.map → objects-Dahys529.mjs.map} +1 -1
- package/dist/client/{pca-Nppb8aVa.mjs → pca-B60iWWfG.mjs} +7 -7
- package/dist/client/{pca-Nppb8aVa.mjs.map → pca-B60iWWfG.mjs.map} +1 -1
- package/dist/client/{pca-C7cMT8fW.mjs → pca-D0kKxHp4.mjs} +2 -2
- package/dist/client/{pca-C7cMT8fW.mjs.map → pca-D0kKxHp4.mjs.map} +1 -1
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/{routes-CaqfgBYu.mjs → routes-BOf-GDMM.mjs} +4 -4
- package/dist/client/{routes-CaqfgBYu.mjs.map → routes-BOf-GDMM.mjs.map} +1 -1
- package/dist/client/{routes-Bz4zb2H4.mjs → routes-CtfnI-aY.mjs} +2 -2
- package/dist/client/{routes-Bz4zb2H4.mjs.map → routes-CtfnI-aY.mjs.map} +1 -1
- package/dist/client/securitygroups-B8aLyFK7.mjs +17 -0
- package/dist/client/securitygroups-B8aLyFK7.mjs.map +1 -0
- package/dist/client/securitygroups-DRhFle2O.mjs +589 -0
- package/dist/client/securitygroups-DRhFle2O.mjs.map +1 -0
- package/dist/client/trpcClient-Di56hpVv.mjs +71 -0
- package/dist/client/trpcClient-Di56hpVv.mjs.map +1 -0
- package/dist/client/trpcClient.d.ts +40 -4
- package/dist/client/useListWithFiltering-aPTUNRaW.mjs +32 -0
- package/dist/client/useListWithFiltering-aPTUNRaW.mjs.map +1 -0
- package/dist/client/useSecurityGroupPermissions-BPS1ibWq.mjs +161 -0
- package/dist/client/useSecurityGroupPermissions-BPS1ibWq.mjs.map +1 -0
- package/dist/server/index.d.ts +56 -53
- package/dist/server/index.js +297 -20
- package/package.json +15 -15
- package/dist/client/EditSecurityGroupModal-BGPXglju.mjs +0 -137
- package/dist/client/EditSecurityGroupModal-BGPXglju.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-Dzq6jNTm.mjs.map +0 -1
- package/dist/client/_floatingIpId-KcWWq9ZW2.mjs.map +0 -1
- package/dist/client/_projectId-MjFv839t.mjs +0 -25
- package/dist/client/_projectId-MjFv839t.mjs.map +0 -1
- package/dist/client/_securityGroupId-B5-gJe1u.mjs.map +0 -1
- package/dist/client/_securityGroupId-fPJWtDPU.mjs.map +0 -1
- package/dist/client/buildFilterParams-DoZzMKX9.mjs +0 -15
- package/dist/client/buildFilterParams-DoZzMKX9.mjs.map +0 -1
- package/dist/client/floatingips-DC5OrR8h.mjs +0 -434
- package/dist/client/floatingips-DC5OrR8h.mjs.map +0 -1
- package/dist/client/images-B5ktfqg6.mjs +0 -8
- package/dist/client/images-B5ktfqg6.mjs.map +0 -1
- package/dist/client/images-D9nfOtSC.mjs.map +0 -1
- package/dist/client/objects-CGOfO00N.mjs.map +0 -1
- package/dist/client/projects-DvSiI5Vg.mjs +0 -12
- package/dist/client/projects-DvSiI5Vg.mjs.map +0 -1
- package/dist/client/securitygroups-JMvcJLpb.mjs +0 -440
- package/dist/client/securitygroups-JMvcJLpb.mjs.map +0 -1
- package/dist/client/trpcClient-BxcNKnhv.mjs +0 -65
- package/dist/client/trpcClient-BxcNKnhv.mjs.map +0 -1
- package/dist/client/useListWithFiltering-BuhE81I6.mjs +0 -157
- package/dist/client/useListWithFiltering-BuhE81I6.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as e } from "./trpcClient-Di56hpVv.mjs";
|
|
2
2
|
import { jsx as t } from "react/jsx-runtime";
|
|
3
3
|
import n, { useEffect as r, useState as i } from "react";
|
|
4
4
|
//#region src/client/store/AuthProvider.tsx
|
|
@@ -66,4 +66,4 @@ function s() {
|
|
|
66
66
|
//#endregion
|
|
67
67
|
export { s as n, o as t };
|
|
68
68
|
|
|
69
|
-
//# sourceMappingURL=AuthProvider-
|
|
69
|
+
//# sourceMappingURL=AuthProvider-CQ6Yppoh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthProvider-
|
|
1
|
+
{"version":3,"file":"AuthProvider-CQ6Yppoh.mjs","names":["React","useEffect","useState","trpcClient","AuthContext","createContext","AuthProvider","children","user","setUser","isLoading","setIsLoading","error","setError","expiresAt","setExpiresAt","redirectToLogin","saveReturnUrl","window","location","pathname","returnUrl","encodeURIComponent","search","href","clearLocalSession","auth","getCurrentUserSession","query","then","session","expires_at","catch","err","Error","message","finally","timeUntilExpiry","Date","getTime","now","handleExpiry","timer","setTimeout","clearTimeout","login","domain","password","createUserSession","mutate","domainName","success","logout","terminateUserSession","Provider","value","isAuthenticated","undefined","useAuth","context","useContext"],"sources":["../../src/client/store/AuthProvider.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\"\nimport { TokenData } from \"../../server/Authentication/types/models\"\nimport { trpcClient } from \"../trpcClient\"\n\nexport type User = TokenData[\"user\"] | null\n\nexport interface AuthContext {\n isAuthenticated: boolean\n isLoading: boolean\n error: string | null\n login: (credentials: { domain: string; user: string; password: string }) => Promise<{ success: boolean }>\n logout: () => Promise<void>\n user?: User\n expiresAt?: Date\n}\n\nconst AuthContext = React.createContext<AuthContext | null>(null)\n\nexport function AuthProvider({ children }: { children: React.ReactNode }) {\n const [user, setUser] = useState<User | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [expiresAt, setExpiresAt] = useState<string | null>(null)\n\n // Redirect to login, optionally with return URL\n const redirectToLogin = (saveReturnUrl: boolean = false) => {\n if (window.location.pathname !== \"/\") {\n const returnUrl = saveReturnUrl\n ? `/?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`\n : \"/\"\n window.location.href = returnUrl\n }\n }\n\n // Clear local session state\n const clearLocalSession = () => {\n setUser(null)\n setExpiresAt(null)\n }\n\n // Get current session on mount\n useEffect(() => {\n trpcClient.auth.getCurrentUserSession\n .query()\n .then((session) => {\n if (session) {\n setUser(session.user)\n setExpiresAt(session.expires_at)\n }\n })\n .catch((err) => {\n setError(err instanceof Error ? err.message : \"Could not load session\")\n })\n .finally(() => setIsLoading(false))\n }, [])\n\n // Auto-logout when session expires\n useEffect(() => {\n if (!user || !expiresAt) return\n\n const timeUntilExpiry = new Date(expiresAt).getTime() - Date.now()\n\n const handleExpiry = () => {\n clearLocalSession()\n redirectToLogin(true)\n }\n\n if (timeUntilExpiry <= 0) {\n handleExpiry()\n return\n }\n\n const timer = setTimeout(handleExpiry, timeUntilExpiry)\n return () => clearTimeout(timer)\n }, [user, expiresAt])\n\n const login = async ({ domain, user, password }: { domain: string; user: string; password: string }) => {\n setError(null)\n setIsLoading(true)\n try {\n const session = await trpcClient.auth.createUserSession.mutate({ domainName: domain, user, password })\n setUser(session.user)\n setExpiresAt(session.expires_at)\n return { success: true }\n } catch (err) {\n setError(err instanceof Error ? err.message : `Could not create session: ${err}`)\n return { success: false }\n } finally {\n setIsLoading(false)\n }\n }\n\n const logout = async () => {\n setIsLoading(true)\n await trpcClient.auth.terminateUserSession.mutate().catch(() => {})\n clearLocalSession()\n redirectToLogin(false) // Don't save return URL on manual logout\n // If already on login page, no redirect happens - reset loading state\n if (window.location.pathname === \"/\") {\n setIsLoading(false)\n }\n }\n\n return (\n <AuthContext.Provider\n value={{\n user,\n isAuthenticated: !!user,\n isLoading,\n error,\n login,\n logout,\n expiresAt: expiresAt ? new Date(expiresAt) : undefined,\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":";;;;AAgBA,IAAMI,IAAcJ,gBAAMK,cAAkC,IAAA;AAE5D,SAAgBC,EAAa,EAAEC,eAAyC;CACtE,IAAM,CAACC,GAAMC,KAAWP,EAAsB,IAAA,GACxC,CAACQ,GAAWC,KAAgBT,EAAS,EAAA,GACrC,CAACU,GAAOC,KAAYX,EAAwB,IAAA,GAC5C,CAACY,GAAWC,KAAgBb,EAAwB,IAAA,GAGpDc,KAAmBC,IAAyB,OAAK;EACrD,IAAIC,OAAOC,SAASC,aAAa,KAAK;GACpC,IAAMC,IAAYJ,IACd,cAAcK,mBAAmBJ,OAAOC,SAASC,WAAWF,OAAOC,SAASI,MAAM,MAClF;GACJL,OAAOC,SAASK,OAAOH;EACzB;CACF,GAGMI,UAAoB;EAExBV,AADAN,EAAQ,IAAA,GACRM,EAAa,IAAA;CACf;CAiEA,OA9DAd,QAAU;EACRE,EAAWuB,KAAKC,sBACbC,MAAK,EACLC,MAAMC,MAAAA;GACL,AAAIA,MACFrB,EAAQqB,EAAQtB,IAAI,GACpBO,EAAae,EAAQC,UAAU;EAEnC,CAAA,EACCC,OAAOC,MAAAA;GACNpB,EAASoB,aAAeC,QAAQD,EAAIE,UAAU,wBAAA;EAChD,CAAA,EACCC,cAAczB,EAAa,EAAA,CAAA;CAChC,GAAG,CAAA,CAAE,GAGLV,QAAU;EACR,IAAI,CAACO,KAAQ,CAACM,GAAW;EAEzB,IAAMuB,IAAkB,IAAIC,KAAKxB,CAAAA,EAAWyB,QAAO,IAAKD,KAAKE,IAAG,GAE1DC,UAAe;GAEnBzB,AADAS,EAAAA,GACAT,EAAgB,EAAA;EAClB;EAEA,IAAIqB,KAAmB,GAAG;GACxBI,EAAAA;GACA;EACF;EAEA,IAAMC,IAAQC,WAAWF,GAAcJ,CAAAA;EACvC,aAAaO,aAAaF,CAAAA;CAC5B,GAAG,CAAClC,GAAMM,CAAAA,CAAU,GA8BlB,gBAACV,EAAYkD,UAAQ;EACnBC,OAAO;GACL/C;GACAgD,iBAAiB,CAAC,CAAChD;GACnBE;GACAE;GACAiC,cAlCe,EAAEC,WAAQtC,SAAMuC,kBAA8D;IAEjGpC,AADAE,EAAS,IAAA,GACTF,EAAa,EAAA;IACb,IAAI;KACF,IAAMmB,IAAU,MAAM3B,EAAWuB,KAAKsB,kBAAkBC,OAAO;MAAEC,YAAYJ;MAAQtC;MAAMuC;KAAS,CAAA;KAGpG,OAFAtC,EAAQqB,EAAQtB,IAAI,GACpBO,EAAae,EAAQC,UAAU,GACxB,EAAEoB,SAAS,GAAK;IACzB,SAASlB,GAAK;KAEZ,OADApB,EAASoB,aAAeC,QAAQD,EAAIE,UAAU,6BAA6BF,GAAK,GACzE,EAAEkB,SAAS,GAAM;IAC1B,UAAU;KACRxC,EAAa,EAAA;IACf;GACF;GAqBMyC,oBAnBS;IAMb,AALAzC,EAAa,EAAA,GACb,MAAMR,EAAWuB,KAAK2B,qBAAqBJ,OAAM,EAAGjB,YAAM,CAAO,CAAA,GACjEP,EAAAA,GACAT,EAAgB,EAAA,GAEZE,OAAOC,SAASC,aAAa,OAC/BT,EAAa,EAAA;GAEjB;GAWMG,WAAWA,IAAY,IAAIwB,KAAKxB,CAAAA,IAAa2C,KAAAA;EAC/C;EAEClD;;AAGP;AAEA,SAAgBmD,IAAAA;CACd,IAAMC,IAAU3D,EAAM4D,WAAWxD,CAAAA;CACjC,IAAI,CAACuD,GACH,MAAUzB,MAAM,6CAAA;CAElB,OAAOyB;AACT"}
|
package/dist/client/{BucketToastNotifications-BGd2wVmh.mjs → BucketToastNotifications-BhPi4WWw.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
2
|
-
import {
|
|
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-CRLQyqu2.mjs";
|
|
2
|
+
import { a as l } from "./trpcClient-Di56hpVv.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-BhPi4WWw.mjs.map
|
|
@@ -1 +1 @@
|
|
|
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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"}
|
|
1
|
+
{"version":3,"file":"BucketToastNotifications-BhPi4WWw.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,4 +1,4 @@
|
|
|
1
|
-
import { Y as e, f as t, j as n, l as r, ot as i, s as a, tt as o } from "./build-
|
|
1
|
+
import { Y as e, f as t, j as n, l as r, ot as i, s as a, tt as o } from "./build-CRLQyqu2.mjs";
|
|
2
2
|
import { t as s } from "./Slot-CWb612-_.mjs";
|
|
3
3
|
import { t as c } from "./routeInfo-CdTRlSxv.mjs";
|
|
4
4
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
@@ -111,4 +111,4 @@ function v({ title: t, projectId: r, description: i, actions: a, badges: o }) {
|
|
|
111
111
|
//#endregion
|
|
112
112
|
export { _ as n, v as t };
|
|
113
113
|
|
|
114
|
-
//# sourceMappingURL=ContentHeader-
|
|
114
|
+
//# sourceMappingURL=ContentHeader-9KZdhOoA.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentHeader-
|
|
1
|
+
{"version":3,"file":"ContentHeader-9KZdhOoA.mjs","names":["React","useState","Tooltip","TooltipTrigger","TooltipContent","Icon","Stack","ClipboardText","text","tooltipContent","className","truncateAt","showTooltip","props","useLingui","copied","setCopied","isHovering","setIsHovering","combinedClassName","handleCopy","e","preventDefault","stopPropagation","navigator","clipboard","writeText","setTimeout","err","console","error","displayText","length","slice","getTooltipContent","t","tooltipIsOpen","div","open","onClick","onMouseEnter","onMouseLeave","aria-label","asChild","data-testid","direction","gap","span","icon","size","Divider","ContentHeading","useRouteContext","useMatches","useParams","ClipboardText","Slot","isRouteInfo","ContentHeader","title","projectId","description","actions","badges","slots","strict","matches","provider","activeMatch","reverse","find","m","staticData","routeService","service","undefined","currentService","slotActions","servicePageActions","component","useShadowDOM","serviceBanner","projectOverviewBanner","header","className","div","span","text","truncateAt","p"],"sources":["../../src/client/components/ClipboardText.tsx","../../src/client/components/ContentHeader/ContentHeader.tsx"],"sourcesContent":["import React, { useState } from \"react\"\nimport { Tooltip, TooltipTrigger, TooltipContent, Icon, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\n\nexport interface ClipboardTextProps extends React.HTMLAttributes<HTMLDivElement> {\n tooltipContent?: string\n text: string\n className?: string\n truncateAt?: number\n showTooltip?: boolean\n}\n\nconst ClipboardText: React.FC<ClipboardTextProps> = ({\n text,\n tooltipContent,\n className,\n truncateAt,\n showTooltip = true,\n ...props\n}) => {\n const { t } = useLingui()\n const [copied, setCopied] = useState(false)\n const [isHovering, setIsHovering] = useState(false)\n\n const combinedClassName = `copyableTooltip inline-flex items-center ${className || \"\"}`\n\n const handleCopy = async (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setIsHovering(false)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error(\"Failed to copy text:\", err)\n }\n }\n\n const displayText = truncateAt && text.length > truncateAt ? `${text.slice(0, truncateAt)}...` : text\n\n // Determine tooltip content based on state\n const getTooltipContent = () => {\n if (copied) {\n return tooltipContent || t`Copied to clipboard!`\n }\n return t`Copy`\n }\n\n const tooltipIsOpen = (copied && showTooltip) || (isHovering && showTooltip)\n\n return (\n <div {...props} className={combinedClassName}>\n <Tooltip open={tooltipIsOpen}>\n <TooltipTrigger\n onClick={handleCopy}\n onMouseEnter={() => !copied && setIsHovering(true)}\n onMouseLeave={() => setIsHovering(false)}\n aria-label={t`Copy ${text} to clipboard`}\n className=\"cursor-pointer\"\n asChild\n data-testid=\"clipboard-copy-trigger\"\n >\n <div className=\"group\">\n <Stack direction=\"horizontal\" gap=\"1\" className=\"items-center hover:underline\">\n <span className=\"select-none\">{displayText}</span>\n <Icon icon={copied ? \"check\" : \"contentCopy\"} size=\"18\" />\n </Stack>\n </div>\n </TooltipTrigger>\n <TooltipContent>{getTooltipContent()}</TooltipContent>\n </Tooltip>\n </div>\n )\n}\n\nexport default ClipboardText\n","import type { ReactNode } from \"react\"\nimport { Divider, ContentHeading } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useRouteContext, useMatches, useParams } from \"@tanstack/react-router\"\nimport ClipboardText from \"../ClipboardText\"\nimport { Slot } from \"../Slot\"\nimport { isRouteInfo } from \"@/client/routes/routeInfo\"\n\ninterface ContentHeaderProps {\n title: string\n projectId: string\n description?: string | null\n actions?: ReactNode\n badges?: ReactNode\n}\n\nexport function ContentHeader({ title, projectId, description, actions, badges }: ContentHeaderProps) {\n const { slots } = useRouteContext({ strict: false })\n const matches = useMatches()\n const { provider } = useParams({ strict: false }) as { provider?: string }\n\n const activeMatch = [...matches].reverse().find((m) => isRouteInfo(m.staticData))\n const routeService = activeMatch && isRouteInfo(activeMatch.staticData) ? activeMatch.staticData.service : undefined\n\n // Storage routes share service: \"containers\" for both Swift and Ceph.\n // Distinguish them by the $provider param.\n const currentService = routeService === \"containers\" && provider === \"ceph\" ? \"ceph-containers\" : routeService\n\n const slotActions =\n slots?.servicePageActions && currentService ? (\n <Slot component={slots.servicePageActions} useShadowDOM={false} currentService={currentService} />\n ) : null\n\n const serviceBanner =\n slots?.serviceBanner && currentService ? (\n <Slot component={slots.serviceBanner} useShadowDOM={false} currentService={currentService} />\n ) : null\n\n const projectOverviewBanner =\n slots?.projectOverviewBanner && !currentService ? (\n <Slot component={slots.projectOverviewBanner} useShadowDOM={false} />\n ) : null\n\n return (\n <header className=\"mb-8\">\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <ContentHeading>{title}</ContentHeading>\n {slotActions}\n </div>\n <div className=\"text-theme-light flex shrink-0 items-center gap-1 text-sm\">\n <span className=\"font-semibold\">\n <Trans>Project ID</Trans>:{\" \"}\n </span>\n <ClipboardText text={projectId} truncateAt={15} />\n </div>\n </div>\n {description && <p className=\"text-sm font-normal\">{description}</p>}\n {serviceBanner}\n {projectOverviewBanner}\n <Divider className=\"mt-4\" />\n {(badges || actions) && (\n <div className=\"mt-3 flex items-start justify-between\">\n <div className=\"flex items-center gap-2\">{badges} </div>\n {actions && <div className=\"flex gap-2\">{actions}</div>}\n </div>\n )}\n </header>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as e, E as t, G as n, K as r, P as i, R as a, U as o, g as s, r as c, tt as l, ut as u, y as d } from "./build-
|
|
1
|
+
import { B as e, E as t, G as n, K as r, P as i, R as a, U as o, g as s, r as c, tt as l, ut as u, y as d } from "./build-CRLQyqu2.mjs";
|
|
2
2
|
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
3
3
|
import h, { Suspense as g, startTransition as _, use as v, useEffect as y, useMemo as b, useState as x } from "react";
|
|
4
4
|
import { Trans as S, useLingui as C } from "@lingui/react";
|
|
@@ -710,4 +710,4 @@ var B = ({ client: t, isOpen: n, onClose: r, project: i, flavor: a }) => {
|
|
|
710
710
|
//#endregion
|
|
711
711
|
export { T as i, B as n, N as r, V as t };
|
|
712
712
|
|
|
713
|
-
//# sourceMappingURL=DeleteFlavorModal-
|
|
713
|
+
//# sourceMappingURL=DeleteFlavorModal-Be2qZo4w.mjs.map
|