@cobaltcore-dev/aurora 0.19.0 → 0.20.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/App.d.ts +12 -0
- package/dist/client/{DeletePcaModal-BU6kbKsw.mjs → DeletePcaModal-YUlNw8cw.mjs} +2 -2
- package/dist/client/{DeletePcaModal-BU6kbKsw.mjs.map → DeletePcaModal-YUlNw8cw.mjs.map} +1 -1
- package/dist/client/{DetailsInfo-BUyuYpJj.mjs → DetailsInfo-Cv3oke-R.mjs} +2 -2
- package/dist/client/{DetailsInfo-BUyuYpJj.mjs.map → DetailsInfo-Cv3oke-R.mjs.map} +1 -1
- package/dist/client/{FloatingIpActionModals-DAtZoYGS.mjs → FloatingIpActionModals-PLN6CWZ9.mjs} +2 -2
- package/dist/client/{FloatingIpActionModals-DAtZoYGS.mjs.map → FloatingIpActionModals-PLN6CWZ9.mjs.map} +1 -1
- package/dist/client/{ImageToastNotifications-BhjU1bfT.mjs → ImageToastNotifications-BQM7HOyE.mjs} +2 -2
- package/dist/client/{ImageToastNotifications-BhjU1bfT.mjs.map → ImageToastNotifications-BQM7HOyE.mjs.map} +1 -1
- package/dist/client/_auth-BtRCgHQe.mjs.map +1 -1
- package/dist/client/{_floatingIpId-BHZGh8U8.mjs → _floatingIpId-DFCaWI9K.mjs} +2 -2
- package/dist/client/{_floatingIpId-BHZGh8U8.mjs.map → _floatingIpId-DFCaWI9K.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-CR3aD38l2.mjs → _floatingIpId-De0hCSSN2.mjs} +4 -4
- package/dist/client/{_floatingIpId-CR3aD38l2.mjs.map → _floatingIpId-De0hCSSN2.mjs.map} +1 -1
- package/dist/client/{_imageId-Cf-Xdksv.mjs → _imageId-D8HiDS3P.mjs} +2 -2
- package/dist/client/{_imageId-Cf-Xdksv.mjs.map → _imageId-D8HiDS3P.mjs.map} +1 -1
- package/dist/client/{_pcaId-B7j0sXnY.mjs → _pcaId-CNbmhUF8.mjs} +4 -4
- package/dist/client/{_pcaId-B7j0sXnY.mjs.map → _pcaId-CNbmhUF8.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-BVSsCus9.mjs → _securityGroupId-a46ExjsA.mjs} +2 -2
- package/dist/client/{_securityGroupId-BVSsCus9.mjs.map → _securityGroupId-a46ExjsA.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-gwV4eB0s.mjs → _securityGroupId-ju2ZSIYe.mjs} +3 -3
- package/dist/client/{_securityGroupId-gwV4eB0s.mjs.map → _securityGroupId-ju2ZSIYe.mjs.map} +1 -1
- package/dist/client/analytics/setupRouterAnalytics.d.ts +20 -0
- package/dist/client/assets/__mocks__/svgMock.d.ts +3 -0
- package/dist/client/components/Auth/SessionExpirationTimer.d.ts +4 -0
- package/dist/client/components/ClipboardText.d.ts +10 -0
- package/dist/client/components/ContentHeader/ContentHeader.d.ts +10 -0
- package/dist/client/components/Error/RouteError.d.ts +9 -0
- package/dist/client/components/Error/StatusError.d.ts +11 -0
- package/dist/client/components/JsonEditor.d.ts +39 -0
- package/dist/client/components/ListToolbar/FiltersInput.d.ts +6 -0
- package/dist/client/components/ListToolbar/SelectedFilters.d.ts +24 -0
- package/dist/client/components/ListToolbar/SortInput.d.ts +11 -0
- package/dist/client/components/ListToolbar/index.d.ts +26 -0
- package/dist/client/components/ListToolbar/types.d.ts +116 -0
- package/dist/client/components/ProjectView/ProjectInfoBox.d.ts +12 -0
- package/dist/client/components/Slot.d.ts +7 -0
- package/dist/client/components/navigation/LanguageSelect.d.ts +3 -0
- package/dist/client/components/navigation/MainNavigation.d.ts +10 -0
- package/dist/client/components/navigation/UserMenu.d.ts +1 -0
- package/dist/client/components/navigation/types.d.ts +4 -0
- package/dist/client/{floatingips-DyBEotB8.mjs → floatingips-D98DrjA0.mjs} +3 -3
- package/dist/client/{floatingips-DyBEotB8.mjs.map → floatingips-D98DrjA0.mjs.map} +1 -1
- package/dist/client/hooks/index.d.ts +18 -0
- package/dist/client/hooks/useDomainId.d.ts +21 -0
- package/dist/client/hooks/useModalTracking.d.ts +33 -0
- package/dist/client/hooks/useProjectId.d.ts +22 -0
- package/dist/client/hooks/useScope.d.ts +4 -0
- package/dist/client/{hooks-iGiEkLTp.mjs → hooks-BsbKkpZc.mjs} +13 -3
- package/dist/client/hooks-BsbKkpZc.mjs.map +1 -0
- package/dist/client/{images-C3voJ3B1.mjs → images-CkW8zNjs.mjs} +4 -4
- package/dist/client/{images-C3voJ3B1.mjs.map → images-CkW8zNjs.mjs.map} +1 -1
- package/dist/client/{images-BklbSacK.mjs → images-sNuJa6ce.mjs} +2 -2
- package/dist/client/{images-BklbSacK.mjs.map → images-sNuJa6ce.mjs.map} +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +254 -258
- package/dist/client/index.js.map +1 -1
- package/dist/client/{pca-72YR_Pk0.mjs → pca-B4_2DqT2.mjs} +2 -2
- package/dist/client/{pca-72YR_Pk0.mjs.map → pca-B4_2DqT2.mjs.map} +1 -1
- package/dist/client/{pca-CsBx_IDO.mjs → pca-BClYQElh.mjs} +4 -4
- package/dist/client/{pca-CsBx_IDO.mjs.map → pca-BClYQElh.mjs.map} +1 -1
- package/dist/client/router.d.ts +7 -0
- package/dist/client/{securitygroups-8vRbXmBL.mjs → securitygroups-BwhVyNmZ.mjs} +2 -2
- package/dist/client/{securitygroups-8vRbXmBL.mjs.map → securitygroups-BwhVyNmZ.mjs.map} +1 -1
- package/dist/client/store/AuthProvider.d.ts +23 -0
- package/dist/client/utils/buildFilterParams.d.ts +5 -0
- package/dist/client/utils/cn.d.ts +27 -0
- package/dist/client/utils/formatBytes.d.ts +40 -0
- package/dist/client/utils/formatFloatingIpStatus.d.ts +6 -0
- package/dist/client/utils/languageDetection.d.ts +11 -0
- package/dist/client/utils/trpcErrors.d.ts +13 -0
- package/dist/client/utils/useErrorTranslation.d.ts +4 -0
- package/dist/client/utils/useListWithFiltering.d.ts +84 -0
- package/dist/client/utils/useModal.d.ts +3 -0
- package/package.json +1 -1
- package/dist/client/hooks-iGiEkLTp.mjs.map +0 -1
|
@@ -17,9 +17,9 @@ var o = n("/_auth/projects/$projectId/services/pca/")({
|
|
|
17
17
|
params: { projectId: r.projectId }
|
|
18
18
|
});
|
|
19
19
|
},
|
|
20
|
-
component: r(() => import("./pca-
|
|
20
|
+
component: r(() => import("./pca-BClYQElh.mjs"), "component")
|
|
21
21
|
});
|
|
22
22
|
//#endregion
|
|
23
23
|
export { o as t };
|
|
24
24
|
|
|
25
|
-
//# sourceMappingURL=pca-
|
|
25
|
+
//# sourceMappingURL=pca-B4_2DqT2.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pca-
|
|
1
|
+
{"version":3,"file":"pca-B4_2DqT2.mjs","names":["createFileRoute","redirect","t","getServiceIndex","canAccessClavisPca","Route","staticData","section","service","analytics","name","sectionCrumb","labelKey","crumb","RouteInfo","head","meta","title","beforeLoad","context","params","availableServices","trpcClient","auth","getAvailableServices","query","serviceIndex","enabledServices","to","projectId","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/services/pca/index.tsx"],"sourcesContent":["import { createFileRoute, redirect } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { canAccessClavisPca } from \"./-components/pcaAccess\"\nimport { PcaListContainer } from \"./-components/-table/PcaListContainer\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services/pca/\")({\n staticData: {\n section: \"services\",\n service: \"pca\",\n analytics: {\n name: \"services.pca.list\",\n },\n sectionCrumb: { labelKey: \"Services\" },\n crumb: { labelKey: \"PCA (Clavis)\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`PCA` }] }),\n beforeLoad: async ({ context, params }) => {\n const availableServices = (await context.trpcClient?.auth.getAvailableServices.query()) || []\n const serviceIndex = getServiceIndex(availableServices)\n\n if (!canAccessClavisPca(serviceIndex, context.enabledServices)) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId: params.projectId },\n })\n }\n },\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n\n return (\n <>\n <ContentHeader title={t`PCA`} projectId={projectId} />\n <PcaListContainer />\n </>\n )\n}\n"],"mappings":";;;;AASA,IAAaK,IAAQL,EAAgB,0CAAA,EAA4C;CAC/EM,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,WAAW,EACTC,MAAM,oBACR;EACAC,cAAc,EAAEC,UAAU,WAAW;EACrCC,OAAO,EAAED,UAAU,eAAe;CACpC;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOf,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAM,CAAA,EAAG;CACzCgB,YAAY,OAAO,EAAEC,YAASC,gBAAQ;EAIpC,IAAI,CAAChB,EAFgBD,EADK,MAAOgB,EAAQG,YAAYC,KAAKC,qBAAqBC,MAAAA,KAAY,CAAA,CAGnEC,GAAcP,EAAQQ,eAAe,GAC3D,MAAM1B,EAAS;GACb2B,IAAI;GACJR,QAAQ,EAAES,WAAWT,EAAOS,UAAU;EACxC,CAAA;CAEJ;CACAC,WAASC,sCAAA,WAAA;AACX,CAAA"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { A as e, B as t, C as n, E as r, G as i, H as a, K as o, P as s, R as c, U as l, Y as u, at as d, o as f, r as p, rt as m, tt as h, y as g } from "./build-DgeVmENN.mjs";
|
|
2
2
|
import { r as _ } from "./trpcClient-BxcNKnhv.mjs";
|
|
3
|
-
import { t as v } from "./pca-
|
|
3
|
+
import { t as v } from "./pca-B4_2DqT2.mjs";
|
|
4
4
|
import { t as y } from "./useProjectId-DBc5lpoU.mjs";
|
|
5
|
-
import "./hooks-
|
|
5
|
+
import "./hooks-BsbKkpZc.mjs";
|
|
6
6
|
import { t as b } from "./ContentHeader-BIScbvb4.mjs";
|
|
7
7
|
import { t as x } from "./useModal-DCs1OJh7.mjs";
|
|
8
8
|
import { d as S, h as C, n as w, r as T, u as E } from "./md-CyCflQee.mjs";
|
|
9
|
-
import { t as D } from "./DeletePcaModal-
|
|
9
|
+
import { t as D } from "./DeletePcaModal-YUlNw8cw.mjs";
|
|
10
10
|
import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
11
11
|
import { useState as j } from "react";
|
|
12
12
|
import { useNavigate as M } from "@tanstack/react-router";
|
|
@@ -248,4 +248,4 @@ function W() {
|
|
|
248
248
|
//#endregion
|
|
249
249
|
export { W as component };
|
|
250
250
|
|
|
251
|
-
//# sourceMappingURL=pca-
|
|
251
|
+
//# sourceMappingURL=pca-BClYQElh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pca-CsBx_IDO.mjs","names":["MdAutorenew","MdCheckCircle","MdHelpOutline","MdHourglassEmpty","MdReportProblem","useNavigate","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","useModal","useProjectId","DeletePcaModal","PcaTableRow","pca","useLingui","navigate","projectId","deletePcaModalOpen","toggleDeletePcaModal","navigateToDetailsPage","to","params","pcaId","id","STATE_CONFIG","CREATING","text","t","icon","size","color","fill","AWAITING_CERTIFICATE","READY","FAILED","UNEXPECTED","data-testid","onClick","div","className","state","display_subject","e","stopPropagation","label","open","onClose","z","useForm","useStore","useNavigate","Modal","Form","FormSection","Spinner","TextInput","Message","trpcReact","useProjectId","csrRegex","isValidCommonName","value","test","CreatePcaModal","open","onClose","useLingui","navigate","projectId","utils","useUtils","isPending","createPcaMutation","services","pca","create","useMutation","onSettled","list","invalidate","formSchema","object","common_name","string","trim","min","t","refine","message","form","defaultValues","validators","onSubmit","createdPca","mutateAsync","project_id","configuration","subject","named_attributes","cn","handleClose","to","params","pcaId","id","reset","isCreateDisabled","store","state","isSubmitting","values","length","size","title","onCancel","cancelButtonLabel","confirmButtonLabel","onConfirm","handleSubmit","disableConfirmButton","error","dismissible","variant","className","div","span","e","preventDefault","Field","name","children","field","onBlur","handleBlur","onChange","handleChange","target","label","placeholder","helptext","errortext","meta","errors","map","join","disabled","useState","Stack","Spinner","DataGrid","DataGridRow","DataGridCell","ContentHeading","DataGridHeadCell","Button","Pagination","trpcReact","useProjectId","useModal","PcaTableRow","CreatePcaModal","ITEMS_PER_PAGE","PcaListContainer","useLingui","projectId","createCaOpen","toggleCreateCa","pageMarkers","setPageMarkers","undefined","currentPage","setCurrentPage","currentMarker","data","isLoading","isError","error","services","pca","list","useQuery","project_id","limit","next_page_marker","pcas","certificate_authorities","nextMarker","computedTotal","totalPages","Math","max","length","goToPage","page","prev","updated","className","distribution","alignment","direction","variant","size","message","t","TABLE_COLUMNS","columnsLength","div","label","onClick","columns","data-testid","colSpan","p","map","id","pages","onPressPrevious","onPressNext","open","onClose","useLingui","ContentHeader","PcaListContainer","Route","RouteComponent","t","projectId","useParams","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-table/PcaTableRow.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-modals/CreatePcaModal.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-table/PcaListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/index.tsx?tsr-split=component"],"sourcesContent":["import { MdAutorenew, MdCheckCircle, MdHelpOutline, MdHourglassEmpty, MdReportProblem } from \"react-icons/md\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CertificateAuthority } from \"@/server/Services/types/pca\"\nimport { useModal } from \"@/client/utils/useModal\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { DeletePcaModal } from \"../-modals/DeletePcaModal\"\n\ninterface PcaTableRowProps {\n pca: CertificateAuthority\n}\n\nexport const PcaTableRow = ({ pca }: PcaTableRowProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const [deletePcaModalOpen, toggleDeletePcaModal] = useModal(false)\n\n const navigateToDetailsPage = () =>\n navigate({\n to: \"/projects/$projectId/services/pca/$pcaId\",\n params: { projectId, pcaId: pca.id },\n })\n\n const STATE_CONFIG = {\n CREATING: {\n text: t`Creating`,\n icon: <MdAutorenew size={20} color=\"white\" fill=\"#1976D2\" />,\n },\n AWAITING_CERTIFICATE: {\n text: t`Awaiting Certificate`,\n icon: <MdHourglassEmpty size={20} color=\"white\" fill=\"#FBC02D\" />,\n },\n READY: {\n text: t`Ready`,\n icon: <MdCheckCircle size={20} color=\"white\" fill=\"#4FB81C\" />,\n },\n FAILED: {\n text: t`Failed`,\n icon: <MdReportProblem size={20} color=\"white\" fill=\"#D32F2F\" />,\n },\n UNEXPECTED: {\n text: t`Unexpected`,\n icon: <MdHelpOutline size={20} color=\"white\" fill=\"#757575\" />,\n },\n } as const\n\n return (\n <>\n <DataGridRow key={pca.id} data-testid={`pca-row-${pca.id}`} onClick={navigateToDetailsPage}>\n <DataGridCell>\n <div className=\"flex items-center gap-2\">\n {STATE_CONFIG[pca.state].icon}\n {STATE_CONFIG[pca.state].text}\n </div>\n </DataGridCell>\n <DataGridCell>{pca.id}</DataGridCell>\n <DataGridCell>{pca.display_subject || \"—\"}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={navigateToDetailsPage} />\n <PopupMenuItem label={t`Delete CA`} onClick={toggleDeletePcaModal} />\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n\n {deletePcaModalOpen && <DeletePcaModal pca={pca} open={deletePcaModalOpen} onClose={toggleDeletePcaModal} />}\n </>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Form, FormSection, Spinner, TextInput, Message } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks\"\n\ninterface CreatePcaModalProps {\n open: boolean\n onClose: () => void\n}\n\nconst csrRegex = /^(?=.{1,253}$)(?:\\*\\.)?(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$/\nconst isValidCommonName = (value: string) => csrRegex.test(value)\n\nexport const CreatePcaModal = ({ open, onClose }: CreatePcaModalProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { isPending, ...createPcaMutation } = trpcReact.services.pca.create.useMutation({\n onSettled: () => utils.services.pca.list.invalidate(),\n })\n\n const formSchema = z.object({\n common_name: z\n .string()\n .trim()\n .min(1, t`Common name is required.`)\n .refine((value) => isValidCommonName(value), { message: t`Must be a valid common name (FQDN).` }),\n })\n\n const form = useForm({\n defaultValues: {\n common_name: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async ({ value }) => {\n if (isPending) return\n\n const createdPca = await createPcaMutation.mutateAsync({\n project_id: projectId,\n configuration: {\n subject: {\n named_attributes: {\n cn: value.common_name,\n },\n },\n },\n })\n handleClose()\n\n await navigate({\n to: \"/projects/$projectId/services/pca/$pcaId\",\n params: { projectId, pcaId: createdPca.id },\n })\n },\n })\n\n const handleClose = () => {\n if (isPending) return\n\n form.reset()\n createPcaMutation.reset()\n onClose()\n }\n\n // Reactive subscription used to control create action disabled state.\n const isCreateDisabled = useStore(\n form.store,\n (state) => state.isSubmitting || state.values.common_name.trim().length === 0\n )\n\n return (\n <Modal\n open={open}\n size=\"large\"\n title={t`Create Certificate Authority`}\n onCancel={handleClose}\n cancelButtonLabel={t`Cancel`}\n confirmButtonLabel={t`Save`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || isCreateDisabled}\n >\n {createPcaMutation.error?.message && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {createPcaMutation.error.message}\n </Message>\n )}\n\n {isPending && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Creating Certificate Authority...</Trans>\n </span>\n </div>\n )}\n\n {!isPending && (\n <Form\n className=\"mb-0\"\n id=\"create-certificate-authority-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection className=\"mb-4\">\n <form.Field\n name=\"common_name\"\n children={(field) => (\n <TextInput\n id={field.name}\n name={field.name}\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(e) => field.handleChange(e.target.value)}\n label={t`Common name`}\n placeholder={t`Enter Common name (e.g., demo-ca.test.sci)`}\n helptext={t`Enter a valid common name in FQDN format (e.g., demo-ca.test.sci).`}\n errortext={field.state.meta.errors.map((e) => e?.message).join(\", \")}\n disabled={isPending}\n />\n )}\n />\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useState } from \"react\"\nimport {\n Stack,\n Spinner,\n DataGrid,\n DataGridRow,\n DataGridCell,\n ContentHeading,\n DataGridHeadCell,\n Button,\n Pagination,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { useModal } from \"@/client/utils/useModal\"\nimport { PcaTableRow } from \"./PcaTableRow\"\nimport { CreatePcaModal } from \"../-modals/CreatePcaModal\"\n\nconst ITEMS_PER_PAGE = 50\n\nexport const PcaListContainer = () => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [createCaOpen, toggleCreateCa] = useModal(false)\n const [pageMarkers, setPageMarkers] = useState<(string | undefined)[]>([undefined])\n const [currentPage, setCurrentPage] = useState(1)\n const currentMarker = pageMarkers[currentPage - 1]\n\n const { data, isLoading, isError, error } = trpcReact.services.pca.list.useQuery({\n project_id: projectId,\n limit: ITEMS_PER_PAGE,\n next_page_marker: currentMarker,\n })\n\n const pcas = data?.certificate_authorities ?? []\n const nextMarker = data?.next_page_marker\n const computedTotal = nextMarker ? currentPage + 1 : currentPage\n const totalPages = Math.max(computedTotal, pageMarkers.length)\n\n const goToPage = (page: number) => {\n if (page < 1 || page > totalPages) return\n if (page > currentPage && nextMarker) {\n setPageMarkers((prev) => {\n const updated = [...prev]\n updated[page - 1] = nextMarker\n return updated\n })\n }\n setCurrentPage(page)\n }\n\n if (isLoading) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading...</Trans>\n </Stack>\n )\n }\n\n if (isError) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {error?.message ?? t`Failed to load PCAs`}\n </Stack>\n )\n }\n\n const TABLE_COLUMNS = [\n t`State`,\n t`ID`,\n t`Subject information`,\n \"\", // empty column for item-action with context menu containing \"Delete CA\" button\n ] as const\n const columnsLength = TABLE_COLUMNS.length\n\n return (\n <div className=\"relative\">\n <Stack className=\"pt-3 pb-2\" distribution=\"end\">\n <Button variant=\"primary\" label={t`Create Certificate Authority`} onClick={toggleCreateCa} />\n </Stack>\n\n {pcas.length === 0 && currentPage === 1 ? (\n <DataGrid columns={columnsLength} className=\"pca\" data-testid=\"no-pcas\">\n <DataGridRow>\n <DataGridCell colSpan={columnsLength}>\n <ContentHeading>\n <Trans>No PCAs found</Trans>\n </ContentHeading>\n <p>\n <Trans>There are no PCAs available for this project.</Trans>\n </p>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n ) : (\n <>\n <DataGrid columns={columnsLength}>\n <DataGridRow>\n {TABLE_COLUMNS.map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n {pcas.map((pca) => (\n <PcaTableRow key={pca.id} pca={pca} />\n ))}\n </DataGrid>\n\n {totalPages > 1 && (\n <div className=\"flex justify-center py-4\">\n <Pagination\n variant=\"input\"\n currentPage={currentPage}\n pages={totalPages}\n onPressPrevious={() => goToPage(currentPage - 1)}\n onPressNext={() => goToPage(currentPage + 1)}\n />\n </div>\n )}\n </>\n )}\n\n {createCaOpen && <CreatePcaModal open={createCaOpen} onClose={toggleCreateCa} />}\n </div>\n )\n}\n","import { createFileRoute, redirect } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { canAccessClavisPca } from \"./-components/pcaAccess\"\nimport { PcaListContainer } from \"./-components/-table/PcaListContainer\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services/pca/\")({\n staticData: {\n section: \"services\",\n service: \"pca\",\n analytics: {\n name: \"services.pca.list\",\n },\n sectionCrumb: { labelKey: \"Services\" },\n crumb: { labelKey: \"PCA (Clavis)\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`PCA` }] }),\n beforeLoad: async ({ context, params }) => {\n const availableServices = (await context.trpcClient?.auth.getAvailableServices.query()) || []\n const serviceIndex = getServiceIndex(availableServices)\n\n if (!canAccessClavisPca(serviceIndex, context.enabledServices)) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId: params.projectId },\n })\n }\n },\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n\n return (\n <>\n <ContentHeader title={t`PCA`} projectId={projectId} />\n <PcaListContainer />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pca-BClYQElh.mjs","names":["MdAutorenew","MdCheckCircle","MdHelpOutline","MdHourglassEmpty","MdReportProblem","useNavigate","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","useModal","useProjectId","DeletePcaModal","PcaTableRow","pca","useLingui","navigate","projectId","deletePcaModalOpen","toggleDeletePcaModal","navigateToDetailsPage","to","params","pcaId","id","STATE_CONFIG","CREATING","text","t","icon","size","color","fill","AWAITING_CERTIFICATE","READY","FAILED","UNEXPECTED","data-testid","onClick","div","className","state","display_subject","e","stopPropagation","label","open","onClose","z","useForm","useStore","useNavigate","Modal","Form","FormSection","Spinner","TextInput","Message","trpcReact","useProjectId","csrRegex","isValidCommonName","value","test","CreatePcaModal","open","onClose","useLingui","navigate","projectId","utils","useUtils","isPending","createPcaMutation","services","pca","create","useMutation","onSettled","list","invalidate","formSchema","object","common_name","string","trim","min","t","refine","message","form","defaultValues","validators","onSubmit","createdPca","mutateAsync","project_id","configuration","subject","named_attributes","cn","handleClose","to","params","pcaId","id","reset","isCreateDisabled","store","state","isSubmitting","values","length","size","title","onCancel","cancelButtonLabel","confirmButtonLabel","onConfirm","handleSubmit","disableConfirmButton","error","dismissible","variant","className","div","span","e","preventDefault","Field","name","children","field","onBlur","handleBlur","onChange","handleChange","target","label","placeholder","helptext","errortext","meta","errors","map","join","disabled","useState","Stack","Spinner","DataGrid","DataGridRow","DataGridCell","ContentHeading","DataGridHeadCell","Button","Pagination","trpcReact","useProjectId","useModal","PcaTableRow","CreatePcaModal","ITEMS_PER_PAGE","PcaListContainer","useLingui","projectId","createCaOpen","toggleCreateCa","pageMarkers","setPageMarkers","undefined","currentPage","setCurrentPage","currentMarker","data","isLoading","isError","error","services","pca","list","useQuery","project_id","limit","next_page_marker","pcas","certificate_authorities","nextMarker","computedTotal","totalPages","Math","max","length","goToPage","page","prev","updated","className","distribution","alignment","direction","variant","size","message","t","TABLE_COLUMNS","columnsLength","div","label","onClick","columns","data-testid","colSpan","p","map","id","pages","onPressPrevious","onPressNext","open","onClose","useLingui","ContentHeader","PcaListContainer","Route","RouteComponent","t","projectId","useParams","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-table/PcaTableRow.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-modals/CreatePcaModal.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/-components/-table/PcaListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/services/pca/index.tsx?tsr-split=component"],"sourcesContent":["import { MdAutorenew, MdCheckCircle, MdHelpOutline, MdHourglassEmpty, MdReportProblem } from \"react-icons/md\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CertificateAuthority } from \"@/server/Services/types/pca\"\nimport { useModal } from \"@/client/utils/useModal\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { DeletePcaModal } from \"../-modals/DeletePcaModal\"\n\ninterface PcaTableRowProps {\n pca: CertificateAuthority\n}\n\nexport const PcaTableRow = ({ pca }: PcaTableRowProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const [deletePcaModalOpen, toggleDeletePcaModal] = useModal(false)\n\n const navigateToDetailsPage = () =>\n navigate({\n to: \"/projects/$projectId/services/pca/$pcaId\",\n params: { projectId, pcaId: pca.id },\n })\n\n const STATE_CONFIG = {\n CREATING: {\n text: t`Creating`,\n icon: <MdAutorenew size={20} color=\"white\" fill=\"#1976D2\" />,\n },\n AWAITING_CERTIFICATE: {\n text: t`Awaiting Certificate`,\n icon: <MdHourglassEmpty size={20} color=\"white\" fill=\"#FBC02D\" />,\n },\n READY: {\n text: t`Ready`,\n icon: <MdCheckCircle size={20} color=\"white\" fill=\"#4FB81C\" />,\n },\n FAILED: {\n text: t`Failed`,\n icon: <MdReportProblem size={20} color=\"white\" fill=\"#D32F2F\" />,\n },\n UNEXPECTED: {\n text: t`Unexpected`,\n icon: <MdHelpOutline size={20} color=\"white\" fill=\"#757575\" />,\n },\n } as const\n\n return (\n <>\n <DataGridRow key={pca.id} data-testid={`pca-row-${pca.id}`} onClick={navigateToDetailsPage}>\n <DataGridCell>\n <div className=\"flex items-center gap-2\">\n {STATE_CONFIG[pca.state].icon}\n {STATE_CONFIG[pca.state].text}\n </div>\n </DataGridCell>\n <DataGridCell>{pca.id}</DataGridCell>\n <DataGridCell>{pca.display_subject || \"—\"}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={navigateToDetailsPage} />\n <PopupMenuItem label={t`Delete CA`} onClick={toggleDeletePcaModal} />\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n\n {deletePcaModalOpen && <DeletePcaModal pca={pca} open={deletePcaModalOpen} onClose={toggleDeletePcaModal} />}\n </>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Form, FormSection, Spinner, TextInput, Message } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks\"\n\ninterface CreatePcaModalProps {\n open: boolean\n onClose: () => void\n}\n\nconst csrRegex = /^(?=.{1,253}$)(?:\\*\\.)?(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,63}$/\nconst isValidCommonName = (value: string) => csrRegex.test(value)\n\nexport const CreatePcaModal = ({ open, onClose }: CreatePcaModalProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { isPending, ...createPcaMutation } = trpcReact.services.pca.create.useMutation({\n onSettled: () => utils.services.pca.list.invalidate(),\n })\n\n const formSchema = z.object({\n common_name: z\n .string()\n .trim()\n .min(1, t`Common name is required.`)\n .refine((value) => isValidCommonName(value), { message: t`Must be a valid common name (FQDN).` }),\n })\n\n const form = useForm({\n defaultValues: {\n common_name: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async ({ value }) => {\n if (isPending) return\n\n const createdPca = await createPcaMutation.mutateAsync({\n project_id: projectId,\n configuration: {\n subject: {\n named_attributes: {\n cn: value.common_name,\n },\n },\n },\n })\n handleClose()\n\n await navigate({\n to: \"/projects/$projectId/services/pca/$pcaId\",\n params: { projectId, pcaId: createdPca.id },\n })\n },\n })\n\n const handleClose = () => {\n if (isPending) return\n\n form.reset()\n createPcaMutation.reset()\n onClose()\n }\n\n // Reactive subscription used to control create action disabled state.\n const isCreateDisabled = useStore(\n form.store,\n (state) => state.isSubmitting || state.values.common_name.trim().length === 0\n )\n\n return (\n <Modal\n open={open}\n size=\"large\"\n title={t`Create Certificate Authority`}\n onCancel={handleClose}\n cancelButtonLabel={t`Cancel`}\n confirmButtonLabel={t`Save`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || isCreateDisabled}\n >\n {createPcaMutation.error?.message && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {createPcaMutation.error.message}\n </Message>\n )}\n\n {isPending && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Creating Certificate Authority...</Trans>\n </span>\n </div>\n )}\n\n {!isPending && (\n <Form\n className=\"mb-0\"\n id=\"create-certificate-authority-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection className=\"mb-4\">\n <form.Field\n name=\"common_name\"\n children={(field) => (\n <TextInput\n id={field.name}\n name={field.name}\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(e) => field.handleChange(e.target.value)}\n label={t`Common name`}\n placeholder={t`Enter Common name (e.g., demo-ca.test.sci)`}\n helptext={t`Enter a valid common name in FQDN format (e.g., demo-ca.test.sci).`}\n errortext={field.state.meta.errors.map((e) => e?.message).join(\", \")}\n disabled={isPending}\n />\n )}\n />\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useState } from \"react\"\nimport {\n Stack,\n Spinner,\n DataGrid,\n DataGridRow,\n DataGridCell,\n ContentHeading,\n DataGridHeadCell,\n Button,\n Pagination,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { useModal } from \"@/client/utils/useModal\"\nimport { PcaTableRow } from \"./PcaTableRow\"\nimport { CreatePcaModal } from \"../-modals/CreatePcaModal\"\n\nconst ITEMS_PER_PAGE = 50\n\nexport const PcaListContainer = () => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [createCaOpen, toggleCreateCa] = useModal(false)\n const [pageMarkers, setPageMarkers] = useState<(string | undefined)[]>([undefined])\n const [currentPage, setCurrentPage] = useState(1)\n const currentMarker = pageMarkers[currentPage - 1]\n\n const { data, isLoading, isError, error } = trpcReact.services.pca.list.useQuery({\n project_id: projectId,\n limit: ITEMS_PER_PAGE,\n next_page_marker: currentMarker,\n })\n\n const pcas = data?.certificate_authorities ?? []\n const nextMarker = data?.next_page_marker\n const computedTotal = nextMarker ? currentPage + 1 : currentPage\n const totalPages = Math.max(computedTotal, pageMarkers.length)\n\n const goToPage = (page: number) => {\n if (page < 1 || page > totalPages) return\n if (page > currentPage && nextMarker) {\n setPageMarkers((prev) => {\n const updated = [...prev]\n updated[page - 1] = nextMarker\n return updated\n })\n }\n setCurrentPage(page)\n }\n\n if (isLoading) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading...</Trans>\n </Stack>\n )\n }\n\n if (isError) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {error?.message ?? t`Failed to load PCAs`}\n </Stack>\n )\n }\n\n const TABLE_COLUMNS = [\n t`State`,\n t`ID`,\n t`Subject information`,\n \"\", // empty column for item-action with context menu containing \"Delete CA\" button\n ] as const\n const columnsLength = TABLE_COLUMNS.length\n\n return (\n <div className=\"relative\">\n <Stack className=\"pt-3 pb-2\" distribution=\"end\">\n <Button variant=\"primary\" label={t`Create Certificate Authority`} onClick={toggleCreateCa} />\n </Stack>\n\n {pcas.length === 0 && currentPage === 1 ? (\n <DataGrid columns={columnsLength} className=\"pca\" data-testid=\"no-pcas\">\n <DataGridRow>\n <DataGridCell colSpan={columnsLength}>\n <ContentHeading>\n <Trans>No PCAs found</Trans>\n </ContentHeading>\n <p>\n <Trans>There are no PCAs available for this project.</Trans>\n </p>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n ) : (\n <>\n <DataGrid columns={columnsLength}>\n <DataGridRow>\n {TABLE_COLUMNS.map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n {pcas.map((pca) => (\n <PcaTableRow key={pca.id} pca={pca} />\n ))}\n </DataGrid>\n\n {totalPages > 1 && (\n <div className=\"flex justify-center py-4\">\n <Pagination\n variant=\"input\"\n currentPage={currentPage}\n pages={totalPages}\n onPressPrevious={() => goToPage(currentPage - 1)}\n onPressNext={() => goToPage(currentPage + 1)}\n />\n </div>\n )}\n </>\n )}\n\n {createCaOpen && <CreatePcaModal open={createCaOpen} onClose={toggleCreateCa} />}\n </div>\n )\n}\n","import { createFileRoute, redirect } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { canAccessClavisPca } from \"./-components/pcaAccess\"\nimport { PcaListContainer } from \"./-components/-table/PcaListContainer\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services/pca/\")({\n staticData: {\n section: \"services\",\n service: \"pca\",\n analytics: {\n name: \"services.pca.list\",\n },\n sectionCrumb: { labelKey: \"Services\" },\n crumb: { labelKey: \"PCA (Clavis)\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`PCA` }] }),\n beforeLoad: async ({ context, params }) => {\n const availableServices = (await context.trpcClient?.auth.getAvailableServices.query()) || []\n const serviceIndex = getServiceIndex(availableServices)\n\n if (!canAccessClavisPca(serviceIndex, context.enabledServices)) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId: params.projectId },\n })\n }\n },\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n\n return (\n <>\n <ContentHeader title={t`PCA`} projectId={projectId} />\n <PcaListContainer />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TrpcReact, TrpcClient } from './trpcClient';
|
|
2
|
+
export declare function createAuroraRouter(trpcReact: TrpcReact, trpcClient: TrpcClient): import('@tanstack/router-core').RouterCore<import('@tanstack/router-core').Route<import('@tanstack/react-router').Register, any, "/", "/", string, "__root__", undefined, {}, import('./routes/__root').RouterContext, import('@tanstack/router-core').AnyContext, import('@tanstack/router-core').AnyContext, {}, undefined, import('./routeTree.gen').RootRouteChildren, import('./routeTree.gen').FileRouteTypes, unknown, unknown, undefined>, "never", false, import('@tanstack/history').RouterHistory, Record<string, any>>;
|
|
3
|
+
declare module "@tanstack/react-router" {
|
|
4
|
+
interface Register {
|
|
5
|
+
router: ReturnType<typeof createAuroraRouter>;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { A as e, B as t, E as n, G as r, H as i, K as a, P as o, R as s, U as c, Y as l, at as u, c as d, et as f, g as p, lt as m, o as h, r as g, rt as _, tt as v, ut as y, y as b } from "./build-DgeVmENN.mjs";
|
|
2
2
|
import { r as x } from "./trpcClient-BxcNKnhv.mjs";
|
|
3
3
|
import { t as S } from "./useProjectId-DBc5lpoU.mjs";
|
|
4
|
-
import "./hooks-
|
|
4
|
+
import "./hooks-BsbKkpZc.mjs";
|
|
5
5
|
import { n as C, t as w } from "./useListWithFiltering-BuhE81I6.mjs";
|
|
6
6
|
import { t as T } from "./buildFilterParams-DoZzMKX9.mjs";
|
|
7
7
|
import { t as E } from "./EditSecurityGroupModal-BGPXglju.mjs";
|
|
@@ -437,4 +437,4 @@ function U() {
|
|
|
437
437
|
//#endregion
|
|
438
438
|
export { U as component };
|
|
439
439
|
|
|
440
|
-
//# sourceMappingURL=securitygroups-
|
|
440
|
+
//# sourceMappingURL=securitygroups-BwhVyNmZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"securitygroups-8vRbXmBL.mjs","names":["React","useState","Modal","Button","ModalFooter","ButtonRow","Message","TextInput","DeleteSecurityGroupDialog","isOpen","onClose","securityGroup","onDelete","isDeleting","error","useLingui","confirmationText","setConfirmationText","deleteWord","t","isDeleteEnabled","toLowerCase","securityGroupName","name","id","handleDelete","e","preventDefault","handleClose","open","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","div","dismissible","p","strong","value","onChange","target","placeholder","autoComplete","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","SecurityGroupTableRow","securityGroup","sg","permissions","onEdit","onDelete","onViewDetails","isReadOnly","useLingui","BooleanValue","value","span","t","handleShowDetails","data-testid","id","onClick","className","div","p","name","description","shared","project_id","stateful","e","stopPropagation","label","canUpdate","canDelete","useState","useEffect","useRef","DataGrid","DataGridHeadCell","DataGridRow","Stack","Spinner","useNavigate","useProjectId","EditSecurityGroupModal","DeleteSecurityGroupDialog","SecurityGroupTableRow","SecurityGroupListContainer","securityGroups","isLoading","isError","error","permissions","onDeleteSecurityGroup","isDeletingSecurityGroup","deleteError","onUpdateSecurityGroup","isUpdatingSecurityGroup","updateError","currentProjectId","useLingui","navigate","projectId","selectedSecurityGroup","setSelectedSecurityGroup","editModalOpen","setEditModalOpen","deleteDialogOpen","setDeleteDialogOpen","prevIsDeletingRef","prevIsUpdatingRef","handleEdit","sg","handleDelete","handleViewDetails","to","params","securityGroupId","id","closeEditModal","closeDeleteDialog","deletionJustFinished","current","updateJustFinished","className","distribution","alignment","direction","variant","size","message","t","length","columns","map","label","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","open","onClose","onUpdate","data","isOpen","isDeleting","React","useState","Modal","Form","FormRow","FormSection","TextInput","Checkbox","Button","ButtonRow","Spinner","ModalFooter","Textarea","Message","defaultSecurityGroupValues","name","description","stateful","CreateSecurityGroupModal","isOpen","onClose","onCreate","isLoading","error","useLingui","properties","setProperties","errors","setErrors","handleInputChange","e","value","type","target","checked","prev","newErrors","validateForm","trim","t","Object","keys","length","handleSubmit","preventDefault","securityGroupData","undefined","handleClose","open","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","dismissible","div","span","id","label","onChange","required","errortext","placeholder","rows","useState","useNavigate","Button","trpcReact","ListToolbar","buildFilterParams","useListWithFiltering","useProjectId","SecurityGroupListContainer","CreateSecurityGroupModal","SECURITY_GROUP_SHARED","TRUE","FALSE","SecurityGroups","useLingui","navigate","projectId","createModalOpen","setCreateModalOpen","deleteError","setDeleteError","createError","setCreateError","updateError","setUpdateError","searchTerm","sortSettings","filterSettings","handleSearchChange","handleSortChange","handleFilterChange","defaultSortKey","defaultSortDir","sortOptions","label","t","value","filters","displayName","filterName","values","Object","supportsMultiValue","utils","useUtils","permissions","canCreate","canUpdate","canDelete","canManageAccess","data","securityGroups","isLoading","isError","error","network","securityGroup","list","useQuery","project_id","sort_key","sortBy","sort_dir","sortDirection","enabled","createSecurityGroupMutation","create","useMutation","onSuccess","createdSecurityGroup","invalidate","to","params","securityGroupId","id","onError","message","deleteSecurityGroupMutation","deleteById","updateSecurityGroupMutation","update","handleCreateSecurityGroup","securityGroupData","mutateAsync","handleDeleteSecurityGroup","mutate","handleUpdateSecurityGroup","div","className","onSort","onFilter","onSearch","actions","onClick","variant","onCreateClick","onDeleteSecurityGroup","isDeletingSecurityGroup","isPending","onUpdateSecurityGroup","isUpdatingSecurityGroup","currentProjectId","isOpen","onClose","onCreate","useLingui","SecurityGroups","ContentHeading","Route","RouteComponent","t","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/DeleteSecurityGroupDialog.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupTableRow.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/CreateSecurityGroupModal.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupsList.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/index.tsx?tsr-split=component"],"sourcesContent":["import React, { useState } from \"react\"\nimport { Modal, Button, ModalFooter, ButtonRow, Message, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\n\ninterface DeleteSecurityGroupDialogProps {\n isOpen: boolean\n securityGroup: SecurityGroup\n onClose: () => void\n onDelete: (securityGroupId: string) => void\n isDeleting?: boolean\n error?: string | null\n}\n\nexport const DeleteSecurityGroupDialog: React.FC<DeleteSecurityGroupDialogProps> = ({\n isOpen,\n onClose,\n securityGroup,\n onDelete,\n isDeleting = false,\n error = null,\n}) => {\n const { t } = useLingui()\n const [confirmationText, setConfirmationText] = useState(\"\")\n\n const deleteWord = t`delete`\n const isDeleteEnabled = confirmationText.toLowerCase() === deleteWord.toLowerCase()\n const securityGroupName = securityGroup.name || securityGroup.id\n\n const handleDelete = (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault()\n if (isDeleteEnabled && !isDeleting) {\n onDelete(securityGroup.id)\n }\n }\n\n const handleClose = () => {\n setConfirmationText(\"\")\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"small\"\n title={t`Delete Security Group \"${securityGroupName}\"`}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={handleClose} disabled={isDeleting}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary-danger\"\n onClick={handleDelete}\n disabled={!isDeleteEnabled || isDeleting}\n data-testid=\"confirm-delete-button\"\n >\n {isDeleting ? <Trans>Deleting...</Trans> : <Trans>Delete</Trans>}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n <div>\n {/* Error Message */}\n {error && (\n <Message dismissible={false} variant=\"error\" className=\"mt-4\">\n {error}\n </Message>\n )}\n\n {/* Warning */}\n <Trans>This action cannot be undone. The security group will be permanently deleted.</Trans>\n\n {/* Confirmation Input */}\n <div className=\"mt-4\">\n <p className=\"mb-2 text-sm\">\n <Trans>\n Type <strong>{deleteWord}</strong> to confirm:\n </Trans>\n </p>\n <TextInput\n id=\"confirmation\"\n name=\"confirmation\"\n value={confirmationText}\n onChange={(e) => setConfirmationText(e.target.value)}\n placeholder={deleteWord}\n disabled={isDeleting}\n autoComplete=\"off\"\n data-testid=\"delete-confirmation-input\"\n />\n </div>\n </div>\n </Modal>\n )\n}\n","import {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\n\nexport interface SecurityGroupPermissions {\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n canManageAccess: boolean\n}\n\ninterface SecurityGroupTableRowProps {\n securityGroup: SecurityGroup\n permissions: SecurityGroupPermissions\n onEdit: (sg: SecurityGroup) => void\n onDelete: (sg: SecurityGroup) => void\n onViewDetails?: (sg: SecurityGroup) => void\n isReadOnly?: boolean\n}\n\nexport function SecurityGroupTableRow({\n securityGroup: sg,\n permissions,\n onEdit,\n onDelete,\n onViewDetails,\n isReadOnly = false,\n}: SecurityGroupTableRowProps) {\n const { t } = useLingui()\n\n const BooleanValue = ({ value }: { value: boolean | undefined }) => <span>{value ? t`Yes` : t`No`}</span>\n\n const handleShowDetails = () => {\n if (onViewDetails) {\n onViewDetails(sg)\n }\n }\n\n return (\n <DataGridRow\n key={sg.id}\n data-testid={`security-group-row-${sg.id}`}\n onClick={handleShowDetails}\n className=\"hover:bg-theme-background-lvl-2 cursor-pointer\"\n >\n <DataGridCell>\n <div>\n <p className=\"text-md\">{sg.name}</p>\n <p className=\"text-theme-light text-xs\">{sg.id}</p>\n </div>\n </DataGridCell>\n <DataGridCell>{sg.description || t`—`}</DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.shared} />\n {sg.shared && (\n <p>\n <Trans>Owner</Trans>: <span className=\"text-theme-light text-xs\">{sg.project_id}</span>\n </p>\n )}\n </DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.stateful} />\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end justify-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={() => handleShowDetails()} />\n {permissions.canUpdate && !isReadOnly && <PopupMenuItem label={t`Edit`} onClick={() => onEdit(sg)} />}\n {permissions.canDelete && !isReadOnly && <PopupMenuItem label={t`Delete`} onClick={() => onDelete(sg)} />}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n}\n","import { useState, useEffect, useRef } from \"react\"\nimport { DataGrid, DataGridHeadCell, DataGridRow, Stack, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { useProjectId } from \"@/client/hooks\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport type { UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { EditSecurityGroupModal } from \"./-modals/EditSecurityGroupModal\"\nimport { DeleteSecurityGroupDialog } from \"./-modals/DeleteSecurityGroupDialog\"\nimport { SecurityGroupTableRow, type SecurityGroupPermissions } from \"./SecurityGroupTableRow\"\n\ninterface SecurityGroupListContainerProps {\n securityGroups: SecurityGroup[]\n isLoading: boolean\n isError: boolean\n error: { message?: string } | null\n permissions: SecurityGroupPermissions\n onCreateClick?: () => void\n onDeleteSecurityGroup?: (securityGroupId: string) => void\n isDeletingSecurityGroup?: boolean\n deleteError?: string | null\n onUpdateSecurityGroup?: (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => void\n isUpdatingSecurityGroup?: boolean\n updateError?: string | null\n currentProjectId?: string\n}\n\nexport const SecurityGroupListContainer = ({\n securityGroups,\n isLoading,\n isError,\n error,\n permissions,\n onDeleteSecurityGroup,\n isDeletingSecurityGroup = false,\n deleteError = null,\n onUpdateSecurityGroup,\n isUpdatingSecurityGroup = false,\n updateError = null,\n currentProjectId,\n}: SecurityGroupListContainerProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const [selectedSecurityGroup, setSelectedSecurityGroup] = useState<SecurityGroup | null>(null)\n const [editModalOpen, setEditModalOpen] = useState(false)\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)\n const prevIsDeletingRef = useRef<boolean>(false)\n const prevIsUpdatingRef = useRef<boolean>(false)\n\n const handleEdit = (sg: SecurityGroup) => {\n setSelectedSecurityGroup(sg)\n setEditModalOpen(true)\n }\n\n const handleDelete = (sg: SecurityGroup) => {\n setSelectedSecurityGroup(sg)\n setDeleteDialogOpen(true)\n }\n\n const handleViewDetails = (sg: SecurityGroup) => {\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: { projectId, securityGroupId: sg.id },\n })\n }\n\n const closeEditModal = () => {\n setSelectedSecurityGroup(null)\n setEditModalOpen(false)\n }\n\n const closeDeleteDialog = () => {\n setSelectedSecurityGroup(null)\n setDeleteDialogOpen(false)\n }\n\n // Close delete dialog when deletion completes successfully\n useEffect(() => {\n // Check if deletion just finished (was deleting before, now not deleting)\n const deletionJustFinished = prevIsDeletingRef.current && !isDeletingSecurityGroup\n\n // Close dialog if deletion just finished and there's no error\n if (deletionJustFinished && deleteDialogOpen && !deleteError) {\n closeDeleteDialog()\n }\n\n // Update the ref for next render\n prevIsDeletingRef.current = isDeletingSecurityGroup\n }, [isDeletingSecurityGroup, deleteError, deleteDialogOpen])\n\n // Close edit modal when update completes successfully\n useEffect(() => {\n // Check if update just finished (was updating before, now not updating)\n const updateJustFinished = prevIsUpdatingRef.current && !isUpdatingSecurityGroup\n\n // Close modal if update just finished and there's no error\n if (updateJustFinished && editModalOpen && !updateError) {\n closeEditModal()\n }\n\n // Update the ref for next render\n prevIsUpdatingRef.current = isUpdatingSecurityGroup\n }, [isUpdatingSecurityGroup, updateError, editModalOpen])\n\n // Loading state\n if (isLoading) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading...</Trans>\n </Stack>\n )\n }\n\n // Error state\n if (isError) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {error?.message ?? t`Failed to load security groups`}\n </Stack>\n )\n }\n\n // Empty state\n if (securityGroups.length === 0) {\n return <Trans>There are no groups</Trans>\n }\n\n return (\n <>\n <DataGrid columns={5}>\n <DataGridRow>\n {[t`Name`, t`Description`, t`Shared`, t`Stateful`, \"\"].map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n {securityGroups.map((sg) => {\n // Compute isReadOnly only when the security group has an explicit project owner\n const isReadOnly = Boolean(currentProjectId && sg.project_id && sg.project_id !== currentProjectId)\n\n return (\n <SecurityGroupTableRow\n key={sg.id}\n securityGroup={sg}\n permissions={permissions}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onViewDetails={handleViewDetails}\n isReadOnly={isReadOnly}\n />\n )\n })}\n </DataGrid>\n\n {selectedSecurityGroup && (\n <>\n <EditSecurityGroupModal\n securityGroup={selectedSecurityGroup}\n open={editModalOpen}\n onClose={closeEditModal}\n onUpdate={async (id, data) => {\n if (onUpdateSecurityGroup) {\n await onUpdateSecurityGroup(id, data)\n }\n }}\n isLoading={isUpdatingSecurityGroup}\n error={updateError}\n />\n <DeleteSecurityGroupDialog\n securityGroup={selectedSecurityGroup}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onDelete={(id) => {\n if (onDeleteSecurityGroup) {\n onDeleteSecurityGroup(id)\n }\n }}\n isDeleting={isDeletingSecurityGroup}\n error={deleteError}\n />\n </>\n )}\n </>\n )\n}\n","import React, { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Checkbox,\n Button,\n ButtonRow,\n Spinner,\n ModalFooter,\n Textarea,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CreateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\ninterface CreateSecurityGroupModalProps {\n isOpen: boolean\n onClose: () => void\n onCreate: (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => Promise<void>\n isLoading?: boolean\n error?: string | null\n}\n\ninterface SecurityGroupProperties {\n name: string\n description: string\n stateful: boolean\n}\n\nconst defaultSecurityGroupValues: SecurityGroupProperties = {\n name: \"\",\n description: \"\",\n stateful: true,\n}\n\nexport const CreateSecurityGroupModal: React.FC<CreateSecurityGroupModalProps> = ({\n isOpen,\n onClose,\n onCreate,\n isLoading = false,\n error = null,\n}) => {\n const { t } = useLingui()\n\n const [properties, setProperties] = useState<SecurityGroupProperties>({ ...defaultSecurityGroupValues })\n const [errors, setErrors] = useState<{ [key: string]: string }>({})\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value, type } = e.target\n const checked = (e.target as HTMLInputElement).checked\n\n setProperties((prev) => ({\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }))\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: { [key: string]: string } = {}\n\n if (!properties.name || properties.name.trim() === \"\") {\n newErrors.name = t`Security group name is required`\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n const securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\"> = {\n name: properties.name.trim(),\n description: properties.description.trim() || undefined,\n stateful: properties.stateful,\n }\n\n await onCreate(securityGroupData)\n handleClose()\n }\n\n const handleClose = () => {\n setProperties({ ...defaultSecurityGroupValues })\n setErrors({})\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"large\"\n title={t`Create Security Group`}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={handleClose} disabled={isLoading}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary\"\n onClick={(e) => {\n handleSubmit(e)\n }}\n disabled={isLoading}\n data-testid=\"create-security-group-button\"\n >\n {isLoading ? <Spinner size=\"small\" /> : <Trans>Create Security Group</Trans>}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {/* Error Message */}\n {error && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {error}\n </Message>\n )}\n\n {isLoading && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Creating security group...</Trans>\n </span>\n </div>\n )}\n\n {!isLoading && (\n <Form className=\"mb-6\">\n <FormSection className=\"mb-6\">\n <FormRow className=\"mb-6\">\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Name`}\n value={properties.name}\n onChange={handleInputChange}\n required\n errortext={errors.name}\n placeholder={t`Type name`}\n disabled={isLoading}\n />\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <Textarea\n id=\"description\"\n name=\"description\"\n label={t`Description`}\n value={properties.description}\n onChange={handleInputChange}\n placeholder={t`Description`}\n disabled={isLoading}\n rows={3}\n />\n </FormRow>\n\n <FormRow className=\"mb-0\">\n <Checkbox\n id=\"stateful\"\n name=\"stateful\"\n label={t`Stateful`}\n checked={properties.stateful}\n onChange={handleInputChange}\n disabled={isLoading}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { buildFilterParams } from \"@/client/utils/buildFilterParams\"\nimport { useListWithFiltering } from \"@/client/utils/useListWithFiltering\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { SecurityGroupListContainer } from \"./SecurityGroupListContainer\"\nimport { CreateSecurityGroupModal } from \"./-modals/CreateSecurityGroupModal\"\nimport { CreateSecurityGroupInput, UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\n// Security group shared filter constants\nconst SECURITY_GROUP_SHARED = {\n TRUE: \"true\",\n FALSE: \"false\",\n} as const\n\ntype SecurityGroupSortKey = \"name\" | \"project_id\"\n\nexport const SecurityGroups = () => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n const [createError, setCreateError] = useState<string | null>(null)\n const [updateError, setUpdateError] = useState<string | null>(null)\n\n const { searchTerm, sortSettings, filterSettings, handleSearchChange, handleSortChange, handleFilterChange } =\n useListWithFiltering<SecurityGroupSortKey>({\n defaultSortKey: \"name\",\n defaultSortDir: \"asc\",\n sortOptions: [\n { label: t`Name`, value: \"name\" },\n { label: t`Project id`, value: \"project_id\" },\n ],\n filterSettings: {\n filters: [\n {\n displayName: t`Shared`,\n filterName: \"shared\",\n values: Object.values(SECURITY_GROUP_SHARED),\n supportsMultiValue: false,\n },\n ],\n },\n })\n\n const utils = trpcReact.useUtils()\n\n // TODO: replace with trpc.network.canUser when security group permissions are available\n const permissions = {\n canCreate: true,\n canUpdate: true,\n canDelete: true,\n canManageAccess: true,\n }\n\n const {\n data: securityGroups = [],\n isLoading,\n isError,\n error,\n } = trpcReact.network.securityGroup.list.useQuery(\n {\n project_id: projectId || \"\",\n sort_key: sortSettings.sortBy,\n sort_dir: sortSettings.sortDirection,\n ...buildFilterParams(filterSettings),\n ...(searchTerm ? { searchTerm } : {}),\n },\n {\n enabled: !!projectId,\n }\n )\n\n const createSecurityGroupMutation = trpcReact.network.securityGroup.create.useMutation({\n onSuccess: (createdSecurityGroup) => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setCreateError(null)\n\n // Navigate to the details page of the newly created security group\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: {\n projectId,\n securityGroupId: createdSecurityGroup.id,\n },\n })\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setCreateError(error.message || t`Failed to create security group`)\n },\n })\n\n const deleteSecurityGroupMutation = trpcReact.network.securityGroup.deleteById.useMutation({\n onSuccess: () => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setDeleteError(null)\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setDeleteError(error.message || t`Failed to delete security group`)\n },\n })\n\n const updateSecurityGroupMutation = trpcReact.network.securityGroup.update.useMutation({\n onSuccess: () => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setUpdateError(null)\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setUpdateError(error.message || t`Failed to update security group`)\n },\n })\n\n const handleCreateSecurityGroup = async (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => {\n setCreateError(null)\n await createSecurityGroupMutation.mutateAsync({ project_id: projectId, ...securityGroupData })\n }\n\n const handleDeleteSecurityGroup = (securityGroupId: string) => {\n setDeleteError(null)\n deleteSecurityGroupMutation.mutate({ project_id: projectId, securityGroupId })\n }\n\n const handleUpdateSecurityGroup = async (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => {\n setUpdateError(null)\n await updateSecurityGroupMutation.mutateAsync({ project_id: projectId, securityGroupId, ...data })\n }\n\n return (\n <div className=\"relative\">\n <ListToolbar\n sortSettings={sortSettings}\n filterSettings={filterSettings}\n searchTerm={searchTerm}\n onSort={handleSortChange}\n onFilter={handleFilterChange}\n onSearch={handleSearchChange}\n actions={\n permissions.canCreate && (\n <Button onClick={() => setCreateModalOpen(true)} variant=\"primary\">\n <Trans>Create Security Group</Trans>\n </Button>\n )\n }\n />\n\n <SecurityGroupListContainer\n securityGroups={securityGroups}\n isLoading={isLoading}\n isError={isError}\n error={error}\n permissions={permissions}\n onCreateClick={() => setCreateModalOpen(true)}\n onDeleteSecurityGroup={handleDeleteSecurityGroup}\n isDeletingSecurityGroup={deleteSecurityGroupMutation.isPending}\n deleteError={deleteError}\n onUpdateSecurityGroup={handleUpdateSecurityGroup}\n isUpdatingSecurityGroup={updateSecurityGroupMutation.isPending}\n updateError={updateError}\n currentProjectId={projectId}\n />\n\n <CreateSecurityGroupModal\n isOpen={createModalOpen}\n onClose={() => setCreateModalOpen(false)}\n onCreate={handleCreateSecurityGroup}\n isLoading={createSecurityGroupMutation.isPending}\n error={createError}\n />\n </div>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeading } from \"@cloudoperators/juno-ui-components\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups/\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n analytics: {\n name: \"network.securitygroups.list\",\n },\n sectionCrumb: { labelKey: \"Network\" },\n crumb: { labelKey: \"Security Groups\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n return (\n <>\n <ContentHeading>{t`Security Groups`}</ContentHeading>\n <SecurityGroups />\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"securitygroups-BwhVyNmZ.mjs","names":["React","useState","Modal","Button","ModalFooter","ButtonRow","Message","TextInput","DeleteSecurityGroupDialog","isOpen","onClose","securityGroup","onDelete","isDeleting","error","useLingui","confirmationText","setConfirmationText","deleteWord","t","isDeleteEnabled","toLowerCase","securityGroupName","name","id","handleDelete","e","preventDefault","handleClose","open","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","div","dismissible","p","strong","value","onChange","target","placeholder","autoComplete","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","SecurityGroupTableRow","securityGroup","sg","permissions","onEdit","onDelete","onViewDetails","isReadOnly","useLingui","BooleanValue","value","span","t","handleShowDetails","data-testid","id","onClick","className","div","p","name","description","shared","project_id","stateful","e","stopPropagation","label","canUpdate","canDelete","useState","useEffect","useRef","DataGrid","DataGridHeadCell","DataGridRow","Stack","Spinner","useNavigate","useProjectId","EditSecurityGroupModal","DeleteSecurityGroupDialog","SecurityGroupTableRow","SecurityGroupListContainer","securityGroups","isLoading","isError","error","permissions","onDeleteSecurityGroup","isDeletingSecurityGroup","deleteError","onUpdateSecurityGroup","isUpdatingSecurityGroup","updateError","currentProjectId","useLingui","navigate","projectId","selectedSecurityGroup","setSelectedSecurityGroup","editModalOpen","setEditModalOpen","deleteDialogOpen","setDeleteDialogOpen","prevIsDeletingRef","prevIsUpdatingRef","handleEdit","sg","handleDelete","handleViewDetails","to","params","securityGroupId","id","closeEditModal","closeDeleteDialog","deletionJustFinished","current","updateJustFinished","className","distribution","alignment","direction","variant","size","message","t","length","columns","map","label","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","open","onClose","onUpdate","data","isOpen","isDeleting","React","useState","Modal","Form","FormRow","FormSection","TextInput","Checkbox","Button","ButtonRow","Spinner","ModalFooter","Textarea","Message","defaultSecurityGroupValues","name","description","stateful","CreateSecurityGroupModal","isOpen","onClose","onCreate","isLoading","error","useLingui","properties","setProperties","errors","setErrors","handleInputChange","e","value","type","target","checked","prev","newErrors","validateForm","trim","t","Object","keys","length","handleSubmit","preventDefault","securityGroupData","undefined","handleClose","open","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","dismissible","div","span","id","label","onChange","required","errortext","placeholder","rows","useState","useNavigate","Button","trpcReact","ListToolbar","buildFilterParams","useListWithFiltering","useProjectId","SecurityGroupListContainer","CreateSecurityGroupModal","SECURITY_GROUP_SHARED","TRUE","FALSE","SecurityGroups","useLingui","navigate","projectId","createModalOpen","setCreateModalOpen","deleteError","setDeleteError","createError","setCreateError","updateError","setUpdateError","searchTerm","sortSettings","filterSettings","handleSearchChange","handleSortChange","handleFilterChange","defaultSortKey","defaultSortDir","sortOptions","label","t","value","filters","displayName","filterName","values","Object","supportsMultiValue","utils","useUtils","permissions","canCreate","canUpdate","canDelete","canManageAccess","data","securityGroups","isLoading","isError","error","network","securityGroup","list","useQuery","project_id","sort_key","sortBy","sort_dir","sortDirection","enabled","createSecurityGroupMutation","create","useMutation","onSuccess","createdSecurityGroup","invalidate","to","params","securityGroupId","id","onError","message","deleteSecurityGroupMutation","deleteById","updateSecurityGroupMutation","update","handleCreateSecurityGroup","securityGroupData","mutateAsync","handleDeleteSecurityGroup","mutate","handleUpdateSecurityGroup","div","className","onSort","onFilter","onSearch","actions","onClick","variant","onCreateClick","onDeleteSecurityGroup","isDeletingSecurityGroup","isPending","onUpdateSecurityGroup","isUpdatingSecurityGroup","currentProjectId","isOpen","onClose","onCreate","useLingui","SecurityGroups","ContentHeading","Route","RouteComponent","t","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/DeleteSecurityGroupDialog.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupTableRow.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/CreateSecurityGroupModal.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupsList.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/index.tsx?tsr-split=component"],"sourcesContent":["import React, { useState } from \"react\"\nimport { Modal, Button, ModalFooter, ButtonRow, Message, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\n\ninterface DeleteSecurityGroupDialogProps {\n isOpen: boolean\n securityGroup: SecurityGroup\n onClose: () => void\n onDelete: (securityGroupId: string) => void\n isDeleting?: boolean\n error?: string | null\n}\n\nexport const DeleteSecurityGroupDialog: React.FC<DeleteSecurityGroupDialogProps> = ({\n isOpen,\n onClose,\n securityGroup,\n onDelete,\n isDeleting = false,\n error = null,\n}) => {\n const { t } = useLingui()\n const [confirmationText, setConfirmationText] = useState(\"\")\n\n const deleteWord = t`delete`\n const isDeleteEnabled = confirmationText.toLowerCase() === deleteWord.toLowerCase()\n const securityGroupName = securityGroup.name || securityGroup.id\n\n const handleDelete = (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault()\n if (isDeleteEnabled && !isDeleting) {\n onDelete(securityGroup.id)\n }\n }\n\n const handleClose = () => {\n setConfirmationText(\"\")\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"small\"\n title={t`Delete Security Group \"${securityGroupName}\"`}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={handleClose} disabled={isDeleting}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary-danger\"\n onClick={handleDelete}\n disabled={!isDeleteEnabled || isDeleting}\n data-testid=\"confirm-delete-button\"\n >\n {isDeleting ? <Trans>Deleting...</Trans> : <Trans>Delete</Trans>}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n <div>\n {/* Error Message */}\n {error && (\n <Message dismissible={false} variant=\"error\" className=\"mt-4\">\n {error}\n </Message>\n )}\n\n {/* Warning */}\n <Trans>This action cannot be undone. The security group will be permanently deleted.</Trans>\n\n {/* Confirmation Input */}\n <div className=\"mt-4\">\n <p className=\"mb-2 text-sm\">\n <Trans>\n Type <strong>{deleteWord}</strong> to confirm:\n </Trans>\n </p>\n <TextInput\n id=\"confirmation\"\n name=\"confirmation\"\n value={confirmationText}\n onChange={(e) => setConfirmationText(e.target.value)}\n placeholder={deleteWord}\n disabled={isDeleting}\n autoComplete=\"off\"\n data-testid=\"delete-confirmation-input\"\n />\n </div>\n </div>\n </Modal>\n )\n}\n","import {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\n\nexport interface SecurityGroupPermissions {\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n canManageAccess: boolean\n}\n\ninterface SecurityGroupTableRowProps {\n securityGroup: SecurityGroup\n permissions: SecurityGroupPermissions\n onEdit: (sg: SecurityGroup) => void\n onDelete: (sg: SecurityGroup) => void\n onViewDetails?: (sg: SecurityGroup) => void\n isReadOnly?: boolean\n}\n\nexport function SecurityGroupTableRow({\n securityGroup: sg,\n permissions,\n onEdit,\n onDelete,\n onViewDetails,\n isReadOnly = false,\n}: SecurityGroupTableRowProps) {\n const { t } = useLingui()\n\n const BooleanValue = ({ value }: { value: boolean | undefined }) => <span>{value ? t`Yes` : t`No`}</span>\n\n const handleShowDetails = () => {\n if (onViewDetails) {\n onViewDetails(sg)\n }\n }\n\n return (\n <DataGridRow\n key={sg.id}\n data-testid={`security-group-row-${sg.id}`}\n onClick={handleShowDetails}\n className=\"hover:bg-theme-background-lvl-2 cursor-pointer\"\n >\n <DataGridCell>\n <div>\n <p className=\"text-md\">{sg.name}</p>\n <p className=\"text-theme-light text-xs\">{sg.id}</p>\n </div>\n </DataGridCell>\n <DataGridCell>{sg.description || t`—`}</DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.shared} />\n {sg.shared && (\n <p>\n <Trans>Owner</Trans>: <span className=\"text-theme-light text-xs\">{sg.project_id}</span>\n </p>\n )}\n </DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.stateful} />\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end justify-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={() => handleShowDetails()} />\n {permissions.canUpdate && !isReadOnly && <PopupMenuItem label={t`Edit`} onClick={() => onEdit(sg)} />}\n {permissions.canDelete && !isReadOnly && <PopupMenuItem label={t`Delete`} onClick={() => onDelete(sg)} />}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n}\n","import { useState, useEffect, useRef } from \"react\"\nimport { DataGrid, DataGridHeadCell, DataGridRow, Stack, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { useProjectId } from \"@/client/hooks\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport type { UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { EditSecurityGroupModal } from \"./-modals/EditSecurityGroupModal\"\nimport { DeleteSecurityGroupDialog } from \"./-modals/DeleteSecurityGroupDialog\"\nimport { SecurityGroupTableRow, type SecurityGroupPermissions } from \"./SecurityGroupTableRow\"\n\ninterface SecurityGroupListContainerProps {\n securityGroups: SecurityGroup[]\n isLoading: boolean\n isError: boolean\n error: { message?: string } | null\n permissions: SecurityGroupPermissions\n onCreateClick?: () => void\n onDeleteSecurityGroup?: (securityGroupId: string) => void\n isDeletingSecurityGroup?: boolean\n deleteError?: string | null\n onUpdateSecurityGroup?: (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => void\n isUpdatingSecurityGroup?: boolean\n updateError?: string | null\n currentProjectId?: string\n}\n\nexport const SecurityGroupListContainer = ({\n securityGroups,\n isLoading,\n isError,\n error,\n permissions,\n onDeleteSecurityGroup,\n isDeletingSecurityGroup = false,\n deleteError = null,\n onUpdateSecurityGroup,\n isUpdatingSecurityGroup = false,\n updateError = null,\n currentProjectId,\n}: SecurityGroupListContainerProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const [selectedSecurityGroup, setSelectedSecurityGroup] = useState<SecurityGroup | null>(null)\n const [editModalOpen, setEditModalOpen] = useState(false)\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)\n const prevIsDeletingRef = useRef<boolean>(false)\n const prevIsUpdatingRef = useRef<boolean>(false)\n\n const handleEdit = (sg: SecurityGroup) => {\n setSelectedSecurityGroup(sg)\n setEditModalOpen(true)\n }\n\n const handleDelete = (sg: SecurityGroup) => {\n setSelectedSecurityGroup(sg)\n setDeleteDialogOpen(true)\n }\n\n const handleViewDetails = (sg: SecurityGroup) => {\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: { projectId, securityGroupId: sg.id },\n })\n }\n\n const closeEditModal = () => {\n setSelectedSecurityGroup(null)\n setEditModalOpen(false)\n }\n\n const closeDeleteDialog = () => {\n setSelectedSecurityGroup(null)\n setDeleteDialogOpen(false)\n }\n\n // Close delete dialog when deletion completes successfully\n useEffect(() => {\n // Check if deletion just finished (was deleting before, now not deleting)\n const deletionJustFinished = prevIsDeletingRef.current && !isDeletingSecurityGroup\n\n // Close dialog if deletion just finished and there's no error\n if (deletionJustFinished && deleteDialogOpen && !deleteError) {\n closeDeleteDialog()\n }\n\n // Update the ref for next render\n prevIsDeletingRef.current = isDeletingSecurityGroup\n }, [isDeletingSecurityGroup, deleteError, deleteDialogOpen])\n\n // Close edit modal when update completes successfully\n useEffect(() => {\n // Check if update just finished (was updating before, now not updating)\n const updateJustFinished = prevIsUpdatingRef.current && !isUpdatingSecurityGroup\n\n // Close modal if update just finished and there's no error\n if (updateJustFinished && editModalOpen && !updateError) {\n closeEditModal()\n }\n\n // Update the ref for next render\n prevIsUpdatingRef.current = isUpdatingSecurityGroup\n }, [isUpdatingSecurityGroup, updateError, editModalOpen])\n\n // Loading state\n if (isLoading) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading...</Trans>\n </Stack>\n )\n }\n\n // Error state\n if (isError) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {error?.message ?? t`Failed to load security groups`}\n </Stack>\n )\n }\n\n // Empty state\n if (securityGroups.length === 0) {\n return <Trans>There are no groups</Trans>\n }\n\n return (\n <>\n <DataGrid columns={5}>\n <DataGridRow>\n {[t`Name`, t`Description`, t`Shared`, t`Stateful`, \"\"].map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n {securityGroups.map((sg) => {\n // Compute isReadOnly only when the security group has an explicit project owner\n const isReadOnly = Boolean(currentProjectId && sg.project_id && sg.project_id !== currentProjectId)\n\n return (\n <SecurityGroupTableRow\n key={sg.id}\n securityGroup={sg}\n permissions={permissions}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onViewDetails={handleViewDetails}\n isReadOnly={isReadOnly}\n />\n )\n })}\n </DataGrid>\n\n {selectedSecurityGroup && (\n <>\n <EditSecurityGroupModal\n securityGroup={selectedSecurityGroup}\n open={editModalOpen}\n onClose={closeEditModal}\n onUpdate={async (id, data) => {\n if (onUpdateSecurityGroup) {\n await onUpdateSecurityGroup(id, data)\n }\n }}\n isLoading={isUpdatingSecurityGroup}\n error={updateError}\n />\n <DeleteSecurityGroupDialog\n securityGroup={selectedSecurityGroup}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onDelete={(id) => {\n if (onDeleteSecurityGroup) {\n onDeleteSecurityGroup(id)\n }\n }}\n isDeleting={isDeletingSecurityGroup}\n error={deleteError}\n />\n </>\n )}\n </>\n )\n}\n","import React, { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Checkbox,\n Button,\n ButtonRow,\n Spinner,\n ModalFooter,\n Textarea,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CreateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\ninterface CreateSecurityGroupModalProps {\n isOpen: boolean\n onClose: () => void\n onCreate: (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => Promise<void>\n isLoading?: boolean\n error?: string | null\n}\n\ninterface SecurityGroupProperties {\n name: string\n description: string\n stateful: boolean\n}\n\nconst defaultSecurityGroupValues: SecurityGroupProperties = {\n name: \"\",\n description: \"\",\n stateful: true,\n}\n\nexport const CreateSecurityGroupModal: React.FC<CreateSecurityGroupModalProps> = ({\n isOpen,\n onClose,\n onCreate,\n isLoading = false,\n error = null,\n}) => {\n const { t } = useLingui()\n\n const [properties, setProperties] = useState<SecurityGroupProperties>({ ...defaultSecurityGroupValues })\n const [errors, setErrors] = useState<{ [key: string]: string }>({})\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value, type } = e.target\n const checked = (e.target as HTMLInputElement).checked\n\n setProperties((prev) => ({\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }))\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: { [key: string]: string } = {}\n\n if (!properties.name || properties.name.trim() === \"\") {\n newErrors.name = t`Security group name is required`\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n const securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\"> = {\n name: properties.name.trim(),\n description: properties.description.trim() || undefined,\n stateful: properties.stateful,\n }\n\n await onCreate(securityGroupData)\n handleClose()\n }\n\n const handleClose = () => {\n setProperties({ ...defaultSecurityGroupValues })\n setErrors({})\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"large\"\n title={t`Create Security Group`}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={handleClose} disabled={isLoading}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary\"\n onClick={(e) => {\n handleSubmit(e)\n }}\n disabled={isLoading}\n data-testid=\"create-security-group-button\"\n >\n {isLoading ? <Spinner size=\"small\" /> : <Trans>Create Security Group</Trans>}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {/* Error Message */}\n {error && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {error}\n </Message>\n )}\n\n {isLoading && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Creating security group...</Trans>\n </span>\n </div>\n )}\n\n {!isLoading && (\n <Form className=\"mb-6\">\n <FormSection className=\"mb-6\">\n <FormRow className=\"mb-6\">\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Name`}\n value={properties.name}\n onChange={handleInputChange}\n required\n errortext={errors.name}\n placeholder={t`Type name`}\n disabled={isLoading}\n />\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <Textarea\n id=\"description\"\n name=\"description\"\n label={t`Description`}\n value={properties.description}\n onChange={handleInputChange}\n placeholder={t`Description`}\n disabled={isLoading}\n rows={3}\n />\n </FormRow>\n\n <FormRow className=\"mb-0\">\n <Checkbox\n id=\"stateful\"\n name=\"stateful\"\n label={t`Stateful`}\n checked={properties.stateful}\n onChange={handleInputChange}\n disabled={isLoading}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { buildFilterParams } from \"@/client/utils/buildFilterParams\"\nimport { useListWithFiltering } from \"@/client/utils/useListWithFiltering\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { SecurityGroupListContainer } from \"./SecurityGroupListContainer\"\nimport { CreateSecurityGroupModal } from \"./-modals/CreateSecurityGroupModal\"\nimport { CreateSecurityGroupInput, UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\n// Security group shared filter constants\nconst SECURITY_GROUP_SHARED = {\n TRUE: \"true\",\n FALSE: \"false\",\n} as const\n\ntype SecurityGroupSortKey = \"name\" | \"project_id\"\n\nexport const SecurityGroups = () => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n const [createError, setCreateError] = useState<string | null>(null)\n const [updateError, setUpdateError] = useState<string | null>(null)\n\n const { searchTerm, sortSettings, filterSettings, handleSearchChange, handleSortChange, handleFilterChange } =\n useListWithFiltering<SecurityGroupSortKey>({\n defaultSortKey: \"name\",\n defaultSortDir: \"asc\",\n sortOptions: [\n { label: t`Name`, value: \"name\" },\n { label: t`Project id`, value: \"project_id\" },\n ],\n filterSettings: {\n filters: [\n {\n displayName: t`Shared`,\n filterName: \"shared\",\n values: Object.values(SECURITY_GROUP_SHARED),\n supportsMultiValue: false,\n },\n ],\n },\n })\n\n const utils = trpcReact.useUtils()\n\n // TODO: replace with trpc.network.canUser when security group permissions are available\n const permissions = {\n canCreate: true,\n canUpdate: true,\n canDelete: true,\n canManageAccess: true,\n }\n\n const {\n data: securityGroups = [],\n isLoading,\n isError,\n error,\n } = trpcReact.network.securityGroup.list.useQuery(\n {\n project_id: projectId || \"\",\n sort_key: sortSettings.sortBy,\n sort_dir: sortSettings.sortDirection,\n ...buildFilterParams(filterSettings),\n ...(searchTerm ? { searchTerm } : {}),\n },\n {\n enabled: !!projectId,\n }\n )\n\n const createSecurityGroupMutation = trpcReact.network.securityGroup.create.useMutation({\n onSuccess: (createdSecurityGroup) => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setCreateError(null)\n\n // Navigate to the details page of the newly created security group\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: {\n projectId,\n securityGroupId: createdSecurityGroup.id,\n },\n })\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setCreateError(error.message || t`Failed to create security group`)\n },\n })\n\n const deleteSecurityGroupMutation = trpcReact.network.securityGroup.deleteById.useMutation({\n onSuccess: () => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setDeleteError(null)\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setDeleteError(error.message || t`Failed to delete security group`)\n },\n })\n\n const updateSecurityGroupMutation = trpcReact.network.securityGroup.update.useMutation({\n onSuccess: () => {\n // Invalidate and refetch the security groups list\n utils.network.securityGroup.list.invalidate()\n setUpdateError(null)\n },\n onError: (error) => {\n // Backend handles error parsing, just display the message\n setUpdateError(error.message || t`Failed to update security group`)\n },\n })\n\n const handleCreateSecurityGroup = async (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => {\n setCreateError(null)\n await createSecurityGroupMutation.mutateAsync({ project_id: projectId, ...securityGroupData })\n }\n\n const handleDeleteSecurityGroup = (securityGroupId: string) => {\n setDeleteError(null)\n deleteSecurityGroupMutation.mutate({ project_id: projectId, securityGroupId })\n }\n\n const handleUpdateSecurityGroup = async (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => {\n setUpdateError(null)\n await updateSecurityGroupMutation.mutateAsync({ project_id: projectId, securityGroupId, ...data })\n }\n\n return (\n <div className=\"relative\">\n <ListToolbar\n sortSettings={sortSettings}\n filterSettings={filterSettings}\n searchTerm={searchTerm}\n onSort={handleSortChange}\n onFilter={handleFilterChange}\n onSearch={handleSearchChange}\n actions={\n permissions.canCreate && (\n <Button onClick={() => setCreateModalOpen(true)} variant=\"primary\">\n <Trans>Create Security Group</Trans>\n </Button>\n )\n }\n />\n\n <SecurityGroupListContainer\n securityGroups={securityGroups}\n isLoading={isLoading}\n isError={isError}\n error={error}\n permissions={permissions}\n onCreateClick={() => setCreateModalOpen(true)}\n onDeleteSecurityGroup={handleDeleteSecurityGroup}\n isDeletingSecurityGroup={deleteSecurityGroupMutation.isPending}\n deleteError={deleteError}\n onUpdateSecurityGroup={handleUpdateSecurityGroup}\n isUpdatingSecurityGroup={updateSecurityGroupMutation.isPending}\n updateError={updateError}\n currentProjectId={projectId}\n />\n\n <CreateSecurityGroupModal\n isOpen={createModalOpen}\n onClose={() => setCreateModalOpen(false)}\n onCreate={handleCreateSecurityGroup}\n isLoading={createSecurityGroupMutation.isPending}\n error={createError}\n />\n </div>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeading } from \"@cloudoperators/juno-ui-components\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups/\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n analytics: {\n name: \"network.securitygroups.list\",\n },\n sectionCrumb: { labelKey: \"Network\" },\n crumb: { labelKey: \"Security Groups\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n return (\n <>\n <ContentHeading>{t`Security Groups`}</ContentHeading>\n <SecurityGroups />\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAcA,IAAaQ,KAAuE,EAClFC,WACAC,YACAC,kBACAC,aACAC,gBAAa,IACbC,WAAQ,WACT;CACC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACR,CAACC,GAAkBC,KAAuBhB,EAAS,EAAA,GAEnDiB,IAAaC,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA,GACrBC,IAAkBJ,EAAiBK,YAAW,MAAOH,EAAWG,YAAW,GAC3EC,IAAoBX,EAAcY,QAAQZ,EAAca,IAExDC,KAAgBC,MAAAA;EAEpB,AADAA,EAAEC,eAAc,GACZP,KAAmB,CAACP,KACtBD,EAASD,EAAca,EAAE;CAE7B,GAEMI,UAAc;EAElBlB,AADAO,EAAoB,EAAA,GACpBP,EAAAA;CACF;CAEA,OACE,gBAACR,GAAAA;EACC2B,MAAMpB;EACNqB,UAAUF;EACVG,MAAK;EACLC,OAAOb,EAAAA,EAAC;;aAA0BG,qBAAAA;EAAmB,CAAA;EACrDW,aACE,gBAAC7B,GAAAA;GAAY8B,WAAU;aACrB,gBAAC7B,GAAAA,EAAAA,UAAAA,CACC,gBAACF,GAAAA;IAAOgC,SAAQ;IAAUC,SAASR;IAAaS,UAAUxB;cACxD,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;OAEF,gBAACV,GAAAA;IACCgC,SAAQ;IACRC,SAASX;IACTY,UAAU,CAACjB,KAAmBP;IAC9ByB,eAAY;cAEXzB,IAAa,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,IAA6B,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;YAMnD,gBAAC0B,OAAAA,EAAAA,UAAAA;GAEEzB,KACC,gBAACR,GAAAA;IAAQkC,aAAa;IAAOL,SAAQ;IAAQD,WAAU;cACpDpB;;GAKL,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;GAGA,gBAACyB,OAAAA;IAAIL,WAAU;eACb,gBAACO,KAAAA;KAAEP,WAAU;eACX,gBAAA,GAAA;;gBACgBhB,cAAAA;uCAARwB,UAAAA,CAAAA,CAAAA,EAAAA;;QAGV,gBAACnC,GAAAA;KACCiB,IAAG;KACHD,MAAK;KACLoB,OAAO3B;KACP4B,WAAWlB,MAAMT,EAAoBS,EAAEmB,OAAOF,KAAK;KACnDG,aAAa5B;KACbmB,UAAUxB;KACVkC,cAAa;KACbT,eAAY;;;;;AAMxB;;;ACvEA,SAAgBe,EAAsB,EACpCC,eAAeC,GACfC,gBACAC,WACAC,aACAC,kBACAC,gBAAa,MACc;CAC3B,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GAERC,KAAgB,EAAEC,eAA4C,gBAACC,QAAAA,EAAAA,UAAMD,IAAQE,EAAAA,EAAC,EAAA,IAAA,SAAI,CAAA,IAAIA,EAAAA,EAAC,EAAA,IAAA,SAAG,CAAA,EAAA,CAAA,GAE1FC,UAAoB;EACxB,AAAIP,KACFA,EAAcJ,CAAAA;CAElB;CAEA,OACE,gBAACN,GAAAA;EAECkB,eAAa,sBAAsBZ,EAAGa;EACtCC,SAASH;EACTI,WAAU;;GAEV,gBAACtB,GAAAA,EAAAA,UACC,gBAACuB,OAAAA,EAAAA,UAAAA,CACC,gBAACC,KAAAA;IAAEF,WAAU;cAAWf,EAAGkB;OAC3B,gBAACD,KAAAA;IAAEF,WAAU;cAA4Bf,EAAGa;;GAGhD,gBAACpB,GAAAA,EAAAA,UAAcO,EAAGmB,eAAeT,EAAAA,EAAC,EAAA,IAAA,SAAE,CAAA,EAAA,CAAA;GACpC,gBAACjB,GAAAA,EAAAA,UAAAA,CACC,gBAACc,GAAAA,EAAaC,OAAOR,EAAGoB,OAAAA,CAAAA,GACvBpB,EAAGoB,UACF,gBAACH,KAAAA,EAAAA,UAAAA;IACC,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;IAAoB;IAAE,gBAACR,QAAAA;KAAKM,WAAU;eAA4Bf,EAAGqB;;;GAI3E,gBAAC5B,GAAAA,EAAAA,UACC,gBAACc,GAAAA,EAAaC,OAAOR,EAAGsB,SAAAA,CAAAA,EAAAA,CAAAA;GAE1B,gBAAC7B,GAAAA;IAAaqB,UAAUS,MAAMA,EAAEC,gBAAe;IAAIT,WAAU;cAC3D,gBAACpB,GAAAA,EAAAA,UACC,gBAACE,GAAAA,EAAAA,UAAAA;KACC,gBAACD,GAAAA;MAAc6B,OAAOf,EAAAA,EAAC,EAAA,IAAA,SAAa,CAAA;MAAGI,eAAeH,EAAAA;;KACrDV,EAAYyB,aAAa,CAACrB,KAAc,gBAACT,GAAAA;MAAc6B,OAAOf,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;MAAGI,eAAeZ,EAAOF,CAAAA;;KAC7FC,EAAY0B,aAAa,CAACtB,KAAc,gBAACT,GAAAA;MAAc6B,OAAOf,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;MAAGI,eAAeX,EAASH,CAAAA;;;;;IA5BnGA,EAAGa,EAAE;AAkChB;;;AClDA,IAAa4B,KAA8B,EACzCC,mBACAC,cACAC,YACAC,UACAC,gBACAC,0BACAC,6BAA0B,IAC1BC,iBAAc,MACdC,0BACAC,6BAA0B,IAC1BC,iBAAc,MACdC,0BACgC;CAChC,IAAM,EAAA,MAAA,GAAA,MAAQC,EAAAA,GACRC,IAAWnB,EAAAA,GACXoB,IAAYnB,EAAAA,GACZ,CAACoB,GAAuBC,KAA4B9B,EAA+B,IAAA,GACnF,CAAC+B,GAAeC,KAAoBhC,EAAS,EAAA,GAC7C,CAACiC,GAAkBC,KAAuBlC,EAAS,EAAA,GACnDmC,IAAoBjC,EAAgB,EAAA,GACpCkC,IAAoBlC,EAAgB,EAAA,GAEpCmC,KAAcC,MAAAA;EAElBN,AADAF,EAAyBQ,CAAAA,GACzBN,EAAiB,EAAA;CACnB,GAEMO,KAAgBD,MAAAA;EAEpBJ,AADAJ,EAAyBQ,CAAAA,GACzBJ,EAAoB,EAAA;CACtB,GAEMM,KAAqBF,MAAAA;EACzBX,EAAS;GACPc,IAAI;GACJC,QAAQ;IAAEd;IAAWe,iBAAiBL,EAAGM;GAAG;EAC9C,CAAA;CACF,GAEMC,UAAiB;EAErBb,AADAF,EAAyB,IAAA,GACzBE,EAAiB,EAAA;CACnB,GAEMc,UAAoB;EAExBZ,AADAJ,EAAyB,IAAA,GACzBI,EAAoB,EAAA;CACtB;CAsDA,OAnDAjC,QAAU;EAURkC,AAR6BA,EAAkBa,WAAW,CAAC5B,KAG/Ba,KAAoB,CAACZ,KAC/CyB,EAAAA,GAIFX,EAAkBa,UAAU5B;CAC9B,GAAG;EAACA;EAAyBC;EAAaY;EAAiB,GAG3DhC,QAAU;EAURmC,AAR2BA,EAAkBY,WAAW,CAACzB,KAG/BQ,KAAiB,CAACP,KAC1CqB,EAAAA,GAIFT,EAAkBY,UAAUzB;CAC9B,GAAG;EAACA;EAAyBC;EAAaO;EAAc,GAGpDhB,IAEA,gBAACT,GAAAA;EAAM4C,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;aACzE,gBAAC9C,GAAAA;GAAQ+C,SAAQ;GAAUC,MAAK;GAAQL,WAAU;MAClD,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,CAAA;MAMFlC,IAEA,gBAACV,GAAAA;EAAM4C,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;YACxEpC,GAAOuC,WAAWC,EAAAA,EAAC,EAAA,IAAA,SAA+B,CAAA;MAMrD3C,EAAe4C,WAAW,IACrB,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,IAIP,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACvD,GAAAA;EAASwD,SAAS;aACjB,gBAACtD,GAAAA,EAAAA,UACE;GAACoD,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;GAAGA,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA;GAAGA,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;GAAGA,EAAAA,EAAC,EAAA,IAAA,SAAS,CAAA;GAAG;IAAIG,KAAKC,MAC1D,gBAACzD,GAAAA,EAAAA,UAA8ByD,EAAAA,GAARA,CAAAA,CAAAA,EAAAA,CAAAA,GAG1B/C,EAAe8C,KAAKtB,MAKjB,gBAAC1B,GAAAA;GAECqD,eAAe3B;GACFpB;GACbgD,QAAQ7B;GACR8B,UAAU5B;GACV6B,eAAe5B;GACHsB,YAVGC,GAAQtC,KAAoBa,EAAG0B,cAAc1B,EAAG0B,eAAevC;KAIzEa,EAAGM,EAAE,CAShB,CAAA;KAGDf,KACC,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACnB,GAAAA;EACCuD,eAAepC;EACfwC,MAAMtC;EACNuC,SAASzB;EACT0B,UAAU,OAAO3B,GAAI4B,MAAAA;GACnB,AAAIlD,KACF,MAAMA,EAAsBsB,GAAI4B,CAAAA;EAEpC;EACAzD,WAAWQ;EACXN,OAAOO;KAET,gBAACb,GAAAA;EACCsD,eAAepC;EACf4C,QAAQxC;EACRqC,SAASxB;EACTqB,WAAWvB,MAAAA;GACT,AAAIzB,KACFA,EAAsByB,CAAAA;EAE1B;EACA8B,YAAYtD;EACZH,OAAOI;;AAMnB,GC5JMoE,IAAsD;CAC1DC,MAAM;CACNC,aAAa;CACbC,UAAU;AACZ,GAEaC,KAAqE,EAChFC,WACAC,YACAC,aACAC,eAAY,IACZC,WAAQ,WACT;CACC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GAER,CAACC,GAAYC,KAAiBzB,EAAkC,EAAE,GAAGa,EAA2B,CAAA,GAChG,CAACa,GAAQC,KAAa3B,EAAoC,CAAC,CAAA,GAE3D4B,KAAqBC,MAAAA;EACzB,IAAM,EAAEf,SAAMgB,UAAOC,YAASF,EAAEG,QAC1BC,IAAU,EAAGD,OAA4BC;EAO/C,AALAR,GAAeS,OAAU;GACvB,GAAGA;IACFpB,IAAOiB,MAAS,aAAaE,IAAUH;EAC1C,EAAA,GAEIJ,EAAOZ,MACTa,GAAWO,MAAAA;GACT,IAAMC,IAAY,EAAE,GAAGD,EAAK;GAE5B,OADA,OAAOC,EAAUrB,IACVqB;EACT,CAAA;CAEJ,GAEMC,UAAe;EACnB,IAAMD,IAAuC,CAAC;EAO9C,QALI,CAACX,EAAWV,QAAQU,EAAWV,KAAKuB,KAAI,MAAO,QACjDF,EAAUrB,OAAOwB,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,IAGpDX,EAAUQ,CAAAA,GACHI,OAAOC,KAAKL,CAAAA,EAAWM,WAAW;CAC3C,GAEMC,IAAe,OAAOb,MAAAA;EAC1BA,EAAEc,eAAc,GAEXP,EAAAA,MAUL,MAAMhB,EAASwB;GALb9B,MAAMU,EAAWV,KAAKuB,KAAI;GAC1BtB,aAAaS,EAAWT,YAAYsB,KAAI,KAAMQ,KAAAA;GAC9C7B,UAAUQ,EAAWR;EAGR4B,CAAAA,GACfE,EAAAA;CACF,GAEMA,UAAc;EAGlB3B,AAFAM,EAAc,EAAE,GAAGZ,EAA2B,CAAA,GAC9Cc,EAAU,CAAC,CAAA,GACXR,EAAAA;CACF;CAEA,OACE,gBAAClB,GAAAA;EACC8C,MAAM7B;EACN8B,UAAUF;EACVG,MAAK;EACLC,OAAOZ,EAAAA,EAAC,EAAA,IAAA,SAAsB,CAAA;EAC9Ba,aACE,gBAACzC,GAAAA;GAAY0C,WAAU;aACrB,gBAAC5C,GAAAA,EAAAA,UAAAA,CACC,gBAACD,GAAAA;IAAO8C,SAAQ;IAAUC,SAASR;IAAaS,UAAUlC;cACxD,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;OAEF,gBAACd,GAAAA;IACC8C,SAAQ;IACRC,UAAUzB,MAAAA;KACRa,EAAab,CAAAA;IACf;IACA0B,UAAUlC;IACVmC,eAAY;cAEXnC,IAAY,gBAACZ,GAAAA,EAAQwC,MAAK,QAAA,CAAA,IAAa,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;;GAO/C3B,KACC,gBAACV,GAAAA;IAAQ6C,aAAa;IAAOJ,SAAQ;IAAQD,WAAU;cACpD9B;;GAIJD,KACC,gBAACqC,OAAAA;IAAIN,WAAU;eACb,gBAAC3C,GAAAA,EAAQ4C,SAAQ,UAAA,CAAA,GACjB,gBAACM,QAAAA;KAAKP,WAAU;eACd,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;GAKL,CAAC/B,KACA,gBAACnB,GAAAA;IAAKkD,WAAU;cACd,gBAAChD,GAAAA;KAAYgD,WAAU;;MACrB,gBAACjD,GAAAA;OAAQiD,WAAU;iBACjB,gBAAC/C,GAAAA;QACCuD,IAAG;QACH9C,MAAK;QACL+C,OAAOvB,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;QACbR,OAAON,EAAWV;QAClBgD,UAAUlC;QACVmC,UAAQ;QACRC,WAAWtC,EAAOZ;QAClBmD,aAAa3B,EAAAA,EAAC,EAAA,IAAA,SAAU,CAAA;QACxBiB,UAAUlC;;;MAId,gBAAClB,GAAAA;OAAQiD,WAAU;iBACjB,gBAACzC,GAAAA;QACCiD,IAAG;QACH9C,MAAK;QACL+C,OAAOvB,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA;QACpBR,OAAON,EAAWT;QAClB+C,UAAUlC;QACVqC,aAAa3B,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA;QAC1BiB,UAAUlC;QACV6C,MAAM;;;MAIV,gBAAC/D,GAAAA;OAAQiD,WAAU;iBACjB,gBAAC9C,GAAAA;QACCsD,IAAG;QACH9C,MAAK;QACL+C,OAAOvB,EAAAA,EAAC,EAAA,IAAA,SAAS,CAAA;QACjBL,SAAST,EAAWR;QACpB8C,UAAUlC;QACV2B,UAAUlC;;;;;;;;AAQ1B,GC/KMwD,IAAwB;CAC5BC,MAAM;CACNC,OAAO;AACT,GAIaC,UAAiB;CAC5B,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAWd,EAAAA,GACXe,IAAYT,EAAAA,GAEZ,CAACU,GAAiBC,KAAsBlB,EAAS,EAAA,GACjD,CAACmB,GAAaC,KAAkBpB,EAAwB,IAAA,GACxD,CAACqB,GAAaC,KAAkBtB,EAAwB,IAAA,GACxD,CAACuB,GAAaC,KAAkBxB,EAAwB,IAAA,GAExD,EAAEyB,eAAYC,iBAAcC,mBAAgBC,uBAAoBC,qBAAkBC,0BACtFxB,EAA2C;EACzCyB,gBAAgB;EAChBC,gBAAgB;EAChBC,aAAa,CACX;GAAEC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;GAAGC,OAAO;EAAO,GAChC;GAAEF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAW,CAAA;GAAGC,OAAO;EAAa,CAAA;EAE9CT,gBAAgB,EACdU,SAAS,CACP;GACEC,aAAaH,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;GACrBI,YAAY;GACZC,QAAQC,OAAOD,OAAO9B,CAAAA;GACtBgC,oBAAoB;EACtB,CAAA,EAEJ;CACF,CAAA,GAEIC,IAAQxC,EAAUyC,SAAQ,GAG1BC,IAAc;EAClBC,WAAW;EACXC,WAAW;EACXC,WAAW;EACXC,iBAAiB;CACnB,GAEM,EACJC,MAAMC,IAAiB,CAAA,GACvBC,cACAC,YACAC,aACEnD,EAAUoD,QAAQC,cAAcC,KAAKC,SACvC;EACEC,YAAY3C,KAAa;EACzB4C,UAAUlC,EAAamC;EACvBC,UAAUpC,EAAaqC;EACvB,GAAG1D,EAAkBsB,CAAAA;EACrB,GAAIF,IAAa,EAAEA,cAAW,IAAI,CAAC;CACrC,GACA,EACEuC,SAAS,CAAC,CAAChD,EACb,CAAA,GAGIiD,IAA8B9D,EAAUoD,QAAQC,cAAcU,OAAOC,YAAY;EACrFC,YAAYC,MAAAA;GAMVtD,AAJA4B,EAAMY,QAAQC,cAAcC,KAAKa,WAAU,GAC3ChD,EAAe,IAAA,GAGfP,EAAS;IACPwD,IAAI;IACJC,QAAQ;KACNxD;KACAyD,iBAAiBJ,EAAqBK;IACxC;GACF,CAAA;EACF;EACAC,UAAUrB,MAAAA;GAERhC,EAAegC,EAAMsB,WAAWzC,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA,GAEM0C,IAA8B1E,EAAUoD,QAAQC,cAAcsB,WAAWX,YAAY;EACzFC,iBAAW;GAGThD,AADAuB,EAAMY,QAAQC,cAAcC,KAAKa,WAAU,GAC3ClD,EAAe,IAAA;EACjB;EACAuD,UAAUrB,MAAAA;GAERlC,EAAekC,EAAMsB,WAAWzC,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA,GAEM4C,IAA8B5E,EAAUoD,QAAQC,cAAcwB,OAAOb,YAAY;EACrFC,iBAAW;GAGT5C,AADAmB,EAAMY,QAAQC,cAAcC,KAAKa,WAAU,GAC3C9C,EAAe,IAAA;EACjB;EACAmD,UAAUrB,MAAAA;GAER9B,EAAe8B,EAAMsB,WAAWzC,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA;CAoBA,OACE,gBAACoD,OAAAA;EAAIC,WAAU;;GACb,gBAACpF,GAAAA;IACesB;IACEC;IACJF;IACZgE,QAAQ5D;IACR6D,UAAU5D;IACV6D,UAAU/D;IACVgE,SACE/C,EAAYC,aACV,gBAAC5C,GAAAA;KAAO2F,eAAe3E,EAAmB,EAAA;KAAO4E,SAAQ;eACvD,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;GAMR,gBAACtF,GAAAA;IACiB2C;IACLC;IACFC;IACFC;IACMT;IACbkD,qBAAqB7E,EAAmB,EAAA;IACxC8E,wBAtC6BvB,MAAAA;KAEjCI,AADAzD,EAAe,IAAA,GACfyD,EAA4BQ,OAAO;MAAE1B,YAAY3C;MAAWyD;KAAgB,CAAA;IAC9E;IAoCMwB,yBAAyBpB,EAA4BqB;IACxC/E;IACbgF,uBAAuBb,OAnC3Bb,GACAvB,MAAAA;KAGA,AADA1B,EAAe,IAAA,GACf,MAAMuD,EAA4BI,YAAY;MAAExB,YAAY3C;MAAWyD;MAAiB,GAAGvB;KAAK,CAAA;IAClG;IA+BMkD,yBAAyBrB,EAA4BmB;IACxC3E;IACb8E,kBAAkBrF;;GAGpB,gBAACP,GAAAA;IACC6F,QAAQrF;IACRsF,eAAerF,EAAmB,EAAA;IAClCsF,UAAUvB,OAvDyBC,MAAAA;KAEvC,AADA5D,EAAe,IAAA,GACf,MAAM2C,EAA4BkB,YAAY;MAAExB,YAAY3C;MAAW,GAAGkE;KAAkB,CAAA;IAC9F;IAqDM9B,WAAWa,EAA4BiC;IACvC5C,OAAOjC;;;;AAIf;;;ACpKA,SAASwF,IAAAA;CACP,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQJ,EAAAA;CACd,OACE,gBAAA,GAAA,EAAA,UAAA,CACE,gBAAC,GAAA,EAAA,UAAgBK,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA,GAClB,gBAAC,GAAA,CAAA,CAAA,CAAA,EAAA,CAAA;AAGP"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { TokenData } from '../../server/Authentication/types/models';
|
|
3
|
+
export type User = TokenData["user"] | null;
|
|
4
|
+
export interface AuthContext {
|
|
5
|
+
isAuthenticated: boolean;
|
|
6
|
+
login: (user: User, expires_at?: string) => Promise<void>;
|
|
7
|
+
logout: () => Promise<void>;
|
|
8
|
+
user?: User;
|
|
9
|
+
expiresAt?: Date;
|
|
10
|
+
}
|
|
11
|
+
interface RouterNavigation {
|
|
12
|
+
navigate: (options: {
|
|
13
|
+
to: string;
|
|
14
|
+
search?: Record<string, unknown>;
|
|
15
|
+
}) => void;
|
|
16
|
+
invalidate: () => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function AuthProvider({ children, router }: {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
router: RouterNavigation;
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function useAuth(): AuthContext;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
/**
|
|
3
|
+
* A utility function that combines clsx and tailwind-merge
|
|
4
|
+
*
|
|
5
|
+
* This function takes multiple class values (strings, objects, arrays, etc.)
|
|
6
|
+
* and combines them into a single string of CSS classes.
|
|
7
|
+
* It then uses tailwind-merge to resolve any Tailwind CSS conflicts.
|
|
8
|
+
*
|
|
9
|
+
* @param inputs - Class values to be combined
|
|
10
|
+
* @returns A string of CSS classes with Tailwind conflicts resolved
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* cn('text-red-500', 'bg-blue-500')
|
|
15
|
+
* // => 'text-red-500 bg-blue-500'
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // With conditionals
|
|
19
|
+
* cn('text-white', isError && 'bg-red-500', !isError && 'bg-blue-500')
|
|
20
|
+
* // => 'text-white bg-red-500' or 'text-white bg-blue-500'
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Resolving conflicts
|
|
24
|
+
* cn('text-red-500', 'text-blue-500')
|
|
25
|
+
* // => 'text-blue-500' (the latter class wins)
|
|
26
|
+
*/
|
|
27
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported unit systems for byte formatting.
|
|
3
|
+
*
|
|
4
|
+
* - `"binary"` (IEC): uses powers of 1024 → B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB
|
|
5
|
+
* - `"decimal"` (SI): uses powers of 1000 → B, KB, MB, GB, TB, PB, EB, ZB, YB
|
|
6
|
+
*
|
|
7
|
+
* Default is `"binary"`.
|
|
8
|
+
*/
|
|
9
|
+
export type ByteUnitSystem = "binary" | "decimal";
|
|
10
|
+
export interface FormatBytesOptions {
|
|
11
|
+
/** Number of decimal places to display. Defaults to `2`. */
|
|
12
|
+
decimals?: number;
|
|
13
|
+
/** Unit system to use. Defaults to `"binary"`. */
|
|
14
|
+
unitSystem?: ByteUnitSystem;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Formats a raw byte count into a human-readable string.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* formatBytes(1536) // "1.50 KiB" (binary, default)
|
|
21
|
+
* formatBytes(1500, { unitSystem: "decimal" }) // "1.50 KB"
|
|
22
|
+
* formatBytes(1073741824) // "1.00 GiB"
|
|
23
|
+
* formatBytes(0) // "0 B"
|
|
24
|
+
* formatBytes(null) // "0 B"
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatBytes(bytes: number | null | undefined, { decimals, unitSystem }?: FormatBytesOptions): string;
|
|
27
|
+
/**
|
|
28
|
+
* Convenience wrapper that always uses the decimal (SI) unit system.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* formatBytesDecimal(1500000) // "1.50 MB"
|
|
32
|
+
*/
|
|
33
|
+
export declare const formatBytesDecimal: (bytes: number | null | undefined, decimals?: number) => string;
|
|
34
|
+
/**
|
|
35
|
+
* Convenience wrapper that always uses the binary (IEC) unit system.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* formatBytesBinary(1048576) // "1.00 MiB"
|
|
39
|
+
*/
|
|
40
|
+
export declare const formatBytesBinary: (bytes: number | null | undefined, decimals?: number) => string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FloatingIpStatus } from '../../server/Network/types/floatingIp';
|
|
2
|
+
/**
|
|
3
|
+
* Formats a floating IP status value from uppercase enum to title case.
|
|
4
|
+
* Example: "ACTIVE" → "Active", "DOWN" → "Down", "ERROR" → "Error"
|
|
5
|
+
*/
|
|
6
|
+
export declare const formatFloatingIpStatus: (status: FloatingIpStatus) => string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const SUPPORTED_LOCALES: readonly ["en", "de"];
|
|
2
|
+
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
3
|
+
/**
|
|
4
|
+
* Detects the user's preferred language with fallback chain:
|
|
5
|
+
* 1. Saved preference (localStorage)
|
|
6
|
+
* 2. Browser language settings
|
|
7
|
+
* 3. Default locale
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectLanguage(): SupportedLocale;
|
|
10
|
+
export declare function saveLanguagePreference(locale: SupportedLocale): void;
|
|
11
|
+
export declare function getLanguagePreference(): SupportedLocale | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if an error is a tRPC error with UNAUTHORIZED code
|
|
3
|
+
*/
|
|
4
|
+
export declare function isTRPCUnauthorized(error: unknown): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Type guard to check if an error is a tRPC error
|
|
7
|
+
*/
|
|
8
|
+
export declare function isTRPCError(error: unknown): error is {
|
|
9
|
+
data: {
|
|
10
|
+
code: string;
|
|
11
|
+
};
|
|
12
|
+
message?: string;
|
|
13
|
+
};
|