@cobaltcore-dev/aurora 1.1.0 → 1.3.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/README.md +59 -9
- package/dist/client/App.d.ts +2 -2
- package/dist/client/AuroraApp.d.ts +33 -13
- package/dist/client/{AuthProvider-BS5OVv8n.mjs → AuthProvider-CVSAwW9f.mjs} +22 -8
- package/dist/client/AuthProvider-CVSAwW9f.mjs.map +1 -0
- package/dist/client/{ContentHeader-BHMUzd9H.mjs → ContentHeader-CPJbgYWn.mjs} +18 -18
- package/dist/client/{ContentHeader-BHMUzd9H.mjs.map → ContentHeader-CPJbgYWn.mjs.map} +1 -1
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +773 -0
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +1 -0
- package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs +26 -0
- package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs.map +1 -0
- package/dist/client/{FiltersInput-B8CNBg1L.mjs → FiltersInput-CKI6zWnm.mjs} +18 -18
- package/dist/client/{FiltersInput-B8CNBg1L.mjs.map → FiltersInput-CKI6zWnm.mjs.map} +1 -1
- package/dist/client/FloatingIpActionModals-Ch8uozH9.mjs +466 -0
- package/dist/client/FloatingIpActionModals-Ch8uozH9.mjs.map +1 -0
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +1152 -0
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +1 -0
- package/dist/client/SortInput-4g7nSTHW.mjs +34 -0
- package/dist/client/SortInput-4g7nSTHW.mjs.map +1 -0
- package/dist/client/{TwoColumnDescriptionList-DiDx3PnH.mjs → TwoColumnDescriptionList-DKS42RKa.mjs} +10 -4
- package/dist/client/TwoColumnDescriptionList-DKS42RKa.mjs.map +1 -0
- package/dist/client/_-CAsCx-Ay.mjs +6 -0
- package/dist/client/_-CAsCx-Ay.mjs.map +1 -0
- package/dist/client/_auth-SrDjHL6j.mjs +12 -0
- package/dist/client/_auth-SrDjHL6j.mjs.map +1 -0
- package/dist/client/{_flavorId-BN_qessZ.mjs → _flavorId-Dg7MS0Af.mjs} +3 -9
- package/dist/client/_flavorId-Dg7MS0Af.mjs.map +1 -0
- package/dist/client/_flavorId-kHl-b8rI.mjs +232 -0
- package/dist/client/_flavorId-kHl-b8rI.mjs.map +1 -0
- package/dist/client/{_floatingIpId-CwDGHkWm.mjs → _floatingIpId-C9xfRWot.mjs} +3 -9
- package/dist/client/_floatingIpId-C9xfRWot.mjs.map +1 -0
- package/dist/client/_floatingIpId-DNn6ABCB.mjs +196 -0
- package/dist/client/_floatingIpId-DNn6ABCB.mjs.map +1 -0
- package/dist/client/_imageId-8JIbFmGB.mjs +39 -0
- package/dist/client/_imageId-8JIbFmGB.mjs.map +1 -0
- package/dist/client/{_imageId-BtJ7GmYB.mjs → _imageId-BBAlRioC.mjs} +217 -201
- package/dist/client/_imageId-BBAlRioC.mjs.map +1 -0
- package/dist/client/{_projectId-Byt3GQDW.mjs → _projectId-7Nl1MQTJ.mjs} +5 -5
- package/dist/client/_projectId-7Nl1MQTJ.mjs.map +1 -0
- package/dist/client/_projectId-B3wmSala.mjs +281 -0
- package/dist/client/_projectId-B3wmSala.mjs.map +1 -0
- package/dist/client/_projectId-DPzv0CCp.mjs +77 -0
- package/dist/client/_projectId-DPzv0CCp.mjs.map +1 -0
- package/dist/client/_projectId-DfeVJy0G.mjs +30 -0
- package/dist/client/_projectId-DfeVJy0G.mjs.map +1 -0
- package/dist/client/{_securityGroupId-BcbkRhsN.mjs → _securityGroupId-C6eHmrx_.mjs} +3 -9
- package/dist/client/_securityGroupId-C6eHmrx_.mjs.map +1 -0
- package/dist/client/_securityGroupId-DmplhDgt.mjs +1810 -0
- package/dist/client/_securityGroupId-DmplhDgt.mjs.map +1 -0
- package/dist/client/_serviceType-DS8DxsrP.mjs +20 -0
- package/dist/client/_serviceType-DS8DxsrP.mjs.map +1 -0
- package/dist/client/_serviceType-M8d9rOT6.mjs +6 -0
- package/dist/client/_serviceType-M8d9rOT6.mjs.map +1 -0
- package/dist/client/_storageType-BRWWJtow.mjs +14 -0
- package/dist/client/_storageType-BRWWJtow.mjs.map +1 -0
- package/dist/client/_storageType-C5gS9eut.mjs +845 -0
- package/dist/client/_storageType-C5gS9eut.mjs.map +1 -0
- package/dist/client/_storageType-CzZ4u9x_.mjs +12 -0
- package/dist/client/_storageType-CzZ4u9x_.mjs.map +1 -0
- package/dist/client/_storageType-zeSZe--V.mjs.map +1 -1
- package/dist/client/{about-_73VmpTB.mjs → about-BmQTyLWc.mjs} +2 -2
- package/dist/client/{about-_73VmpTB.mjs.map → about-BmQTyLWc.mjs.map} +1 -1
- package/dist/client/{aurora-EbwGRLLf.mjs → aurora-CIml-f2f.mjs} +2 -2
- package/dist/client/{aurora-EbwGRLLf.mjs.map → aurora-CIml-f2f.mjs.map} +1 -1
- package/dist/client/{build-C_4vRMCq.mjs → build-WuxXRAqf.mjs} +121 -24
- package/dist/client/{build-C_4vRMCq.mjs.map → build-WuxXRAqf.mjs.map} +1 -1
- package/dist/client/components/Breadcrumbs.d.ts +1 -0
- package/dist/client/components/ListToolbar/SortInput.d.ts +3 -0
- package/dist/client/context/BreadcrumbExtensionContext.d.ts +9 -0
- package/dist/client/context/DynamicBreadcrumbContext.d.ts +9 -0
- package/dist/client/{flavors-CiHCYrtZ.mjs → flavors-B1SDOPDu.mjs} +3 -5
- package/dist/client/flavors-B1SDOPDu.mjs.map +1 -0
- package/dist/client/flavors-D8_PzQUB.mjs +628 -0
- package/dist/client/flavors-D8_PzQUB.mjs.map +1 -0
- package/dist/client/flavors-DWMZ6TuJ.mjs.map +1 -1
- package/dist/client/floatingips-Cz9k80cc.mjs +8 -0
- package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -0
- package/dist/client/floatingips-DrCvtXtT.mjs +551 -0
- package/dist/client/floatingips-DrCvtXtT.mjs.map +1 -0
- package/dist/client/hooks/useBreadcrumbs.d.ts +16 -0
- package/dist/client/hooks/usePushBreadcrumbs.d.ts +10 -0
- package/dist/client/hooks/useSetBreadcrumb.d.ts +11 -0
- package/dist/client/{hooks-LutR2Yg3.mjs → hooks-D0yKIumu.mjs} +2 -2
- package/dist/client/{hooks-LutR2Yg3.mjs.map → hooks-D0yKIumu.mjs.map} +1 -1
- package/dist/client/images-BGQv9kKT.mjs +1983 -0
- package/dist/client/images-BGQv9kKT.mjs.map +1 -0
- package/dist/client/{images-CS4kZQyu.mjs → images-CPmMa4SQ.mjs} +3 -5
- package/dist/client/images-CPmMa4SQ.mjs.map +1 -0
- package/dist/client/images-NBf2bV43.mjs.map +1 -1
- package/dist/client/index.d.ts +7 -3
- package/dist/client/index.js +549 -535
- package/dist/client/index.js.map +1 -1
- package/dist/client/objects-AERkhfiM.mjs +66 -0
- package/dist/client/objects-AERkhfiM.mjs.map +1 -0
- package/dist/client/{objects-C3azvW8m.mjs → objects-BR3eeSNH.mjs} +7087 -4211
- package/dist/client/objects-BR3eeSNH.mjs.map +1 -0
- package/dist/client/objects-DVccbrL1.mjs +66 -0
- package/dist/client/objects-DVccbrL1.mjs.map +1 -0
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/routeInfo-DP3v74Wg.mjs +19 -0
- package/dist/client/routeInfo-DP3v74Wg.mjs.map +1 -0
- package/dist/client/router.d.ts +2 -2
- package/dist/client/{routes-CdDm-hhO.mjs → routes-CJj7SR_K.mjs} +2 -2
- package/dist/client/routes-CJj7SR_K.mjs.map +1 -0
- package/dist/client/routes-xofA3ksU.mjs +110 -0
- package/dist/client/routes-xofA3ksU.mjs.map +1 -0
- package/dist/client/securitygroups-BjhgLBHm.mjs +620 -0
- package/dist/client/securitygroups-BjhgLBHm.mjs.map +1 -0
- package/dist/client/securitygroups-CtKne8UQ.mjs +8 -0
- package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -0
- package/dist/client/{securitygroups-Byte-iSp.mjs → securitygroups-DEJQBcxm.mjs} +3 -5
- package/dist/client/securitygroups-DEJQBcxm.mjs.map +1 -0
- package/dist/client/trpcClient.d.ts +135 -3
- package/dist/client/useBreadcrumbs-ha3IlaxX.mjs +54 -0
- package/dist/client/useBreadcrumbs-ha3IlaxX.mjs.map +1 -0
- package/dist/client/useModalTracking-BcOKTYRN.mjs +33 -0
- package/dist/client/useModalTracking-BcOKTYRN.mjs.map +1 -0
- package/dist/client/{useSecurityGroupPermissions-C29mzb3b.mjs → useSecurityGroupPermissions-BOyLQLdC.mjs} +85 -19
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +1 -0
- package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs +19 -0
- package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs.map +1 -0
- package/dist/client/utils/formatSwiftDate.d.ts +30 -0
- package/dist/server/index.d.ts +136 -4
- package/dist/server/index.js +845 -260
- package/package.json +37 -36
- package/dist/client/AuthProvider-BS5OVv8n.mjs.map +0 -1
- package/dist/client/DeleteFlavorModal-BP83t9zX.mjs +0 -721
- package/dist/client/DeleteFlavorModal-BP83t9zX.mjs.map +0 -1
- package/dist/client/FloatingIpActionModals-BraiJWBi.mjs +0 -417
- package/dist/client/FloatingIpActionModals-BraiJWBi.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-BXMHJaIH.mjs +0 -1131
- package/dist/client/ImageToastNotifications-BXMHJaIH.mjs.map +0 -1
- package/dist/client/RouteError-hAF8_jbe.mjs +0 -25
- package/dist/client/RouteError-hAF8_jbe.mjs.map +0 -1
- package/dist/client/SortInput-Cqs2poV3.mjs +0 -34
- package/dist/client/SortInput-Cqs2poV3.mjs.map +0 -1
- package/dist/client/StatusError-C5KodQOq.mjs +0 -39
- package/dist/client/StatusError-C5KodQOq.mjs.map +0 -1
- package/dist/client/TwoColumnDescriptionList-DiDx3PnH.mjs.map +0 -1
- package/dist/client/_auth-DJ9wHZaj.mjs +0 -11
- package/dist/client/_auth-DJ9wHZaj.mjs.map +0 -1
- package/dist/client/_flavorId-BN_qessZ.mjs.map +0 -1
- package/dist/client/_flavorId-CJjEB_Ao.mjs +0 -210
- package/dist/client/_flavorId-CJjEB_Ao.mjs.map +0 -1
- package/dist/client/_floatingIpId-CwDGHkWm.mjs.map +0 -1
- package/dist/client/_floatingIpId-foMIwbE4.mjs +0 -215
- package/dist/client/_floatingIpId-foMIwbE4.mjs.map +0 -1
- package/dist/client/_imageId-BtJ7GmYB.mjs.map +0 -1
- package/dist/client/_projectId-BmtCuzJu.mjs +0 -29
- package/dist/client/_projectId-BmtCuzJu.mjs.map +0 -1
- package/dist/client/_projectId-Byt3GQDW.mjs.map +0 -1
- package/dist/client/_projectId-NYk1IN_a.mjs +0 -291
- package/dist/client/_projectId-NYk1IN_a.mjs.map +0 -1
- package/dist/client/_projectId-QueiFczy.mjs +0 -46
- package/dist/client/_projectId-QueiFczy.mjs.map +0 -1
- package/dist/client/_securityGroupId-BcbkRhsN.mjs.map +0 -1
- package/dist/client/_securityGroupId-pPtJsCoe.mjs +0 -1797
- package/dist/client/_securityGroupId-pPtJsCoe.mjs.map +0 -1
- package/dist/client/_storageType-BmqrU06i.mjs +0 -2202
- package/dist/client/_storageType-BmqrU06i.mjs.map +0 -1
- package/dist/client/components/Error/StatusError.d.ts +0 -11
- package/dist/client/components/ProjectView/ProjectInfoBox.d.ts +0 -12
- package/dist/client/flavors-CiHCYrtZ.mjs.map +0 -1
- package/dist/client/flavors-DY-bDc8l.mjs +0 -650
- package/dist/client/flavors-DY-bDc8l.mjs.map +0 -1
- package/dist/client/floatingips-Ci4jHkaG.mjs +0 -591
- package/dist/client/floatingips-Ci4jHkaG.mjs.map +0 -1
- package/dist/client/images-91U7tr9Y2.mjs +0 -1976
- package/dist/client/images-91U7tr9Y2.mjs.map +0 -1
- package/dist/client/images-CS4kZQyu.mjs.map +0 -1
- package/dist/client/objects-C3azvW8m.mjs.map +0 -1
- package/dist/client/objects-CM265S6b.mjs +0 -56
- package/dist/client/objects-CM265S6b.mjs.map +0 -1
- package/dist/client/objects-EE9Cd1wI.mjs +0 -56
- package/dist/client/objects-EE9Cd1wI.mjs.map +0 -1
- package/dist/client/routeInfo-DXqB2HCf.mjs +0 -32
- package/dist/client/routeInfo-DXqB2HCf.mjs.map +0 -1
- package/dist/client/routes-CBd8CCuM.mjs +0 -115
- package/dist/client/routes-CBd8CCuM.mjs.map +0 -1
- package/dist/client/routes-CdDm-hhO.mjs.map +0 -1
- package/dist/client/securitygroups-Bd_uV4S9.mjs +0 -595
- package/dist/client/securitygroups-Bd_uV4S9.mjs.map +0 -1
- package/dist/client/securitygroups-Byte-iSp.mjs.map +0 -1
- package/dist/client/useSecurityGroupPermissions-C29mzb3b.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securitygroups-BjhgLBHm.mjs","names":["z","useForm","useStore","React","Modal","Stack","Message","Form","FormSection","TextInput","useModalTracking","DeleteSecurityGroupDialog","isOpen","onClose","securityGroup","onDelete","isDeleting","error","useLingui","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","id","canDelete","store","state","isSubmitting","values","securityGroupName","name","handleClose","reset","open","onCancel","size","title","confirmButtonLabel","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","p","className","e","preventDefault","Field","children","field","label","onChange","handleChange","target","placeholder","disabled","autoComplete","autoFocus","data-testid","required","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","Checkbox","SecurityGroupTableRow","securityGroup","sg","permissions","onEdit","onDelete","onViewDetails","isReadOnly","showSelectColumn","isSelected","onSelect","useLingui","BooleanValue","value","span","t","handleShowDetails","data-testid","id","onClick","className","e","stopPropagation","checked","onChange","div","p","name","description","shared","project_id","stateful","label","canUpdate","canDelete","useState","useEffect","useRef","DataGrid","DataGridCell","DataGridHeadCell","DataGridRow","Status","useNavigate","useProjectId","EditSecurityGroupModal","DeleteSecurityGroupDialog","SecurityGroupTableRow","SecurityGroupListContainer","securityGroups","isLoading","isError","error","permissions","onDeleteSecurityGroup","isDeletingSecurityGroup","deleteError","onUpdateSecurityGroup","isUpdatingSecurityGroup","updateError","currentProjectId","hasAnyBulkAction","onClearUpdateError","useLingui","navigate","projectId","selectedSecurityGroup","setSelectedSecurityGroup","editModalOpen","setEditModalOpen","deleteDialogOpen","setDeleteDialogOpen","prevIsDeletingRef","prevIsUpdatingRef","handleEdit","sg","id","handleDelete","handleViewDetails","to","params","securityGroupId","closeEditModal","closeDeleteDialog","deletionJustFinished","current","updateJustFinished","status","title","t","message","columns","minContentColumns","map","label","length","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","showSelectColumn","isSelected","onSelect","colSpan","body","open","onClose","onUpdate","data","Promise","resolve","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","helptext","parseFiltersFromUrl","searchParams","filters","shared","push","name","value","buildFilterParams","selectedFilters","filterDefinitions","params","length","filterGroups","filter","sf","inactive","reduce","acc","Object","entries","forEach","filterName","values","filterDef","find","f","supportsMultiValue","join","applyFilterSelection","current","selected","alreadySelected","some","supportsMulti","buildUrlSearchParams","baseParams","newParams","search","sortBy","sortDirection","useState","useEffect","useNavigate","useSearch","Button","Stack","DataGridToolbar","SearchInput","toast","Status","ContentHeader","trpcReact","SortInput","SelectedFilters","FiltersInput","SecurityGroupListContainer","CreateSecurityGroupModal","useSecurityGroupPermissions","parseFiltersFromUrl","buildFilterParams","buildUrlSearchParams","applyFilterSelection","getSecurityGroupDeletedToast","getSecurityGroupDeleteErrorToast","getSecurityGroupUpdatedToast","getSecurityGroupUpdateErrorToast","SecurityGroups","project","projectId","useLingui","navigate","searchParams","strict","sortSettings","setSortSettings","options","label","t","value","sortBy","sortDirection","filterSettings","setFilterSettings","filters","displayName","filterName","values","supportsMultiValue","selectedFilters","searchTerm","setSearchTerm","search","createModalOpen","setCreateModalOpen","deleteError","setDeleteError","createError","setCreateError","updateError","setUpdateError","utils","useUtils","prev","shared","urlFilters","urlSortBy","urlSortDirection","urlSearchTerm","data","securityGroupsData","isLoading","isError","error","network","securityGroup","list","useQuery","project_id","sort_key","sort_dir","refetchOnWindowFocus","securityGroups","listError","code","permissions","createSecurityGroupMutation","create","useMutation","onSuccess","createdSecurityGroup","invalidate","getById","to","params","securityGroupId","id","onError","message","deleteSecurityGroupMutation","deleteById","updateSecurityGroupMutation","update","handleCreateSecurityGroup","securityGroupData","mutateAsync","handleDeleteSecurityGroup","sgName","find","sg","name","mutate","success","handleUpdateSecurityGroup","handleClearUpdateError","handleSortChange","newSortSettings","settings","toString","replace","handleFilterChange","newFilterSettings","handleSearchChange","term","searchValue","undefined","status","title","length","className","distribution","alignment","direction","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","variant","comboboxClassName","onChange","selected","newSelected","placeholder","data-testid","onInput","e","currentTarget","onSearch","onClear","onDelete","filterToRemove","filter","f","onCreateClick","onDeleteSecurityGroup","isDeletingSecurityGroup","isPending","onUpdateSecurityGroup","isUpdatingSecurityGroup","currentProjectId","hasAnyBulkAction","onClearUpdateError","isOpen","onClose","onCreate","SecurityGroups","Route","RouteComponent","projectId","useParams","trpcClient","useRouteContext","Error","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/urlHelpers.ts","../../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 { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport React from \"react\"\nimport { Modal, Stack, Message, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\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\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"network.securitygroup.delete\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"delete\", {\n message: t`Type \"delete\" to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (isDeleting) return\n\n markSubmitted()\n onDelete(securityGroup.id)\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n const securityGroupName = securityGroup.name || securityGroup.id\n\n const handleClose = () => {\n trackClose()\n form.reset()\n resetTracking()\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 confirmButtonLabel={isDeleting ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={form.handleSubmit}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={canDelete || isDeleting}\n disableCancelButton={isDeleting}\n disableCloseButton={isDeleting}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {error && <Message variant=\"error\">{error}</Message>}\n\n <p className=\"text-theme-default\">\n <Trans>This action cannot be undone. The security group will be permanently deleted.</Trans>\n </p>\n\n <Form\n className=\"mb-0\"\n id=\"delete-security-group-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n children={(field) => (\n <TextInput\n label={t`Type \"delete\" to confirm`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder=\"delete\"\n disabled={isDeleting}\n autoComplete=\"off\"\n autoFocus\n data-testid=\"delete-confirmation-input\"\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n </Modal>\n )\n}\n","import {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Checkbox,\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 canView: boolean\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n canCreateRule: boolean\n canDeleteRule: boolean\n canManageAccess: boolean\n canViewRBAC: 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 showSelectColumn?: boolean\n isSelected?: boolean\n onSelect?: (sg: SecurityGroup) => void\n}\n\nexport function SecurityGroupTableRow({\n securityGroup: sg,\n permissions,\n onEdit,\n onDelete,\n onViewDetails,\n isReadOnly = false,\n showSelectColumn = false,\n isSelected = false,\n onSelect,\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 {showSelectColumn && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <Checkbox checked={isSelected} onChange={() => onSelect?.(sg)} />\n </DataGridCell>\n )}\n <DataGridCell>\n <div>\n <p className=\"text-md\">{sg.name}</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, DataGridCell, DataGridHeadCell, DataGridRow, Status } from \"@cloudoperators/juno-ui-components\"\nimport { 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 ) => Promise<void>\n isUpdatingSecurityGroup?: boolean\n updateError?: string | null\n currentProjectId?: string\n hasAnyBulkAction?: boolean\n onClearUpdateError?: () => void\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 hasAnyBulkAction = false,\n onClearUpdateError,\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 // Clear error when selecting a different security group\n if (selectedSecurityGroup && selectedSecurityGroup.id !== sg.id && onClearUpdateError) {\n onClearUpdateError()\n }\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 <Status status=\"progress\" title={t`Loading...`} />\n }\n\n // Error state\n if (isError) {\n return <Status status=\"error\" title={error?.message ?? t`Failed to load security groups`} />\n }\n\n return (\n <>\n <DataGrid columns={hasAnyBulkAction ? 6 : 5} minContentColumns={hasAnyBulkAction ? [5] : [4]}>\n <DataGridRow>\n {hasAnyBulkAction && <DataGridHeadCell />}\n {[t`Name`, t`Description`, t`Shared`, t`Stateful`, \"\"].map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n\n {securityGroups && securityGroups.length > 0 ? (\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 showSelectColumn={hasAnyBulkAction}\n isSelected={false}\n onSelect={() => {}}\n />\n )\n })\n ) : (\n <DataGridRow>\n <DataGridCell colSpan={hasAnyBulkAction ? 6 : 5}>\n <Status\n status=\"empty\"\n title={t`No security groups found`}\n body={t`There are no security groups available for this project with the current filters applied. Try adjusting your filter criteria or create a new security group to get started.`}\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n\n {selectedSecurityGroup && (\n <>\n <EditSecurityGroupModal\n securityGroup={selectedSecurityGroup}\n open={editModalOpen}\n onClose={closeEditModal}\n onUpdate={(id, data) => {\n if (onUpdateSecurityGroup) {\n return onUpdateSecurityGroup(id, data)\n }\n return Promise.resolve()\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 helptext={t`Stateful security groups track connection state. This setting cannot be changed after creation.`}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { SelectedFilter, Filter } from \"@/client/components/ListToolbar/types\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n}\n\n/**\n * Parses URL search params into SelectedFilter array for ListToolbar\n */\nexport const parseFiltersFromUrl = (searchParams: SecurityGroupsSearchParams): SelectedFilter[] => {\n const filters: SelectedFilter[] = []\n\n // Shared filter\n if (searchParams.shared) {\n filters.push({ name: \"shared\", value: searchParams.shared })\n }\n\n return filters\n}\n\n/**\n * Builds filter parameters for API request from SelectedFilter array\n */\nexport const buildFilterParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[]\n): Record<string, string> => {\n const params: Record<string, string> = {}\n\n if (!selectedFilters?.length) return params\n\n // Group selected filters by filter name\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n // Build parameters based on whether filter supports multiple values\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n params[filterName] = `in:${values.join(\",\")}`\n } else {\n params[filterName] = values[0]\n }\n })\n\n return params\n}\n\n/**\n * Merges a newly selected filter into the current list.\n * - Ignores duplicates (same name + value).\n * - For single-value filters, replaces any existing entry with the same name.\n * - For multi-value filters, appends.\n */\nexport const applyFilterSelection = (\n current: SelectedFilter[],\n selected: SelectedFilter,\n filterDefinitions: Filter[]\n): SelectedFilter[] => {\n const alreadySelected = current.some((f) => f.name === selected.name && f.value === selected.value)\n if (alreadySelected) return current\n\n const supportsMulti = filterDefinitions.find((f) => f.filterName === selected.name)?.supportsMultiValue\n return supportsMulti ? [...current, selected] : [...current.filter((f) => f.name !== selected.name), selected]\n}\n\n/**\n * Builds URL search params object from filter settings for navigation\n */\nexport const buildUrlSearchParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[],\n baseParams: {\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n }\n): SecurityGroupsSearchParams => {\n const newParams: SecurityGroupsSearchParams = {\n search: baseParams.search,\n sortBy: baseParams.sortBy,\n sortDirection: baseParams.sortDirection,\n }\n\n if (!selectedFilters?.length) return newParams\n\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n // Type assertion needed because we're dynamically setting filter fields\n ;(newParams as Record<string, string>)[filterName] = `in:${values.join(\",\")}`\n } else {\n ;(newParams as Record<string, string>)[filterName] = values[0]\n }\n })\n\n return newParams\n}\n","import { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\nimport { Button, Stack, DataGridToolbar, SearchInput, toast, Status } from \"@cloudoperators/juno-ui-components\"\nimport { CreateSecurityGroupInput, UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SelectedFilters } from \"@/client/components/ListToolbar/SelectedFilters\"\nimport { FiltersInput } from \"@/client/components/ListToolbar/FiltersInput\"\nimport { FilterSettings, SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { SecurityGroupListContainer } from \"./SecurityGroupListContainer\"\nimport { CreateSecurityGroupModal } from \"./-modals/CreateSecurityGroupModal\"\nimport { useSecurityGroupPermissions } from \"../-hooks/useSecurityGroupPermissions\"\nimport { parseFiltersFromUrl, buildFilterParams, buildUrlSearchParams, applyFilterSelection } from \"../urlHelpers\"\nimport {\n getSecurityGroupDeletedToast,\n getSecurityGroupDeleteErrorToast,\n getSecurityGroupUpdatedToast,\n getSecurityGroupUpdateErrorToast,\n} from \"./SecurityGroupToastNotifications\"\n\ntype SecurityGroupSortKey = \"name\" | \"project_id\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n}\n\ntype RequiredSortSettings = {\n options: SortSettings[\"options\"]\n sortBy: string\n sortDirection: \"asc\" | \"desc\"\n}\n\ninterface SecurityGroupsProps {\n project: string\n}\n\nexport const SecurityGroups = ({ project: projectId }: SecurityGroupsProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const searchParams = useSearch({ strict: false }) as SecurityGroupsSearchParams\n\n const [sortSettings, setSortSettings] = useState<RequiredSortSettings>({\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`Project id`, value: \"project_id\" },\n ],\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n })\n\n const [filterSettings, setFilterSettings] = useState<FilterSettings>({\n filters: [\n {\n displayName: t`Shared`,\n filterName: \"shared\",\n values: [\"true\", \"false\"],\n supportsMultiValue: false,\n },\n ],\n selectedFilters: parseFiltersFromUrl(searchParams),\n })\n\n const [searchTerm, setSearchTerm] = useState(searchParams.search || \"\")\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 utils = trpcReact.useUtils()\n\n useEffect(() => {\n setSortSettings((prev) => ({\n ...prev,\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n }))\n setFilterSettings((prev) => ({\n ...prev,\n selectedFilters: parseFiltersFromUrl(searchParams),\n }))\n setSearchTerm(searchParams.search || \"\")\n }, [searchParams.sortBy, searchParams.sortDirection, searchParams.search, searchParams.shared])\n\n const urlFilters = parseFiltersFromUrl(searchParams)\n const urlSortBy = (searchParams.sortBy || \"name\") as SecurityGroupSortKey\n const urlSortDirection = searchParams.sortDirection || \"asc\"\n const urlSearchTerm = searchParams.search || \"\"\n\n const {\n data: securityGroupsData,\n isLoading,\n isError,\n error,\n } = trpcReact.network.securityGroup.list.useQuery(\n {\n project_id: projectId || \"\",\n sort_key: urlSortBy,\n sort_dir: urlSortDirection,\n ...buildFilterParams(urlFilters, filterSettings.filters),\n ...(urlSearchTerm ? { searchTerm: urlSearchTerm } : {}),\n },\n {\n refetchOnWindowFocus: false,\n }\n )\n\n const securityGroups = securityGroupsData || []\n const listError =\n isError && error?.data?.code === \"FORBIDDEN\" ? t`You do not have permission to view security groups` : null\n\n const { permissions } = useSecurityGroupPermissions(projectId)\n\n const createSecurityGroupMutation = trpcReact.network.securityGroup.create.useMutation({\n onSuccess: (createdSecurityGroup) => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setCreateError(null)\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: {\n projectId,\n securityGroupId: createdSecurityGroup.id,\n },\n })\n },\n onError: (error) => {\n setCreateError(error.message || t`Failed to create security group`)\n },\n })\n\n const deleteSecurityGroupMutation = trpcReact.network.securityGroup.deleteById.useMutation({\n onSuccess: () => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setDeleteError(null)\n },\n onError: (error) => {\n setDeleteError(error.message || t`Failed to delete security group`)\n const { message, ...options } = getSecurityGroupDeleteErrorToast(error.message)\n toast.error(message, options)\n },\n })\n\n const updateSecurityGroupMutation = trpcReact.network.securityGroup.update.useMutation({\n onSuccess: () => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setUpdateError(null)\n },\n onError: (error) => {\n setUpdateError(error.message || t`Failed to update security group`)\n const { message, ...options } = getSecurityGroupUpdateErrorToast(error.message)\n toast.error(message, options)\n },\n })\n\n const handleCreateSecurityGroup = async (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => {\n setCreateError(null)\n try {\n await createSecurityGroupMutation.mutateAsync({ project_id: projectId, ...securityGroupData })\n } catch {\n // onError handles error state and UI feedback\n }\n }\n\n const handleDeleteSecurityGroup = (securityGroupId: string) => {\n setDeleteError(null)\n const sgName = securityGroups.find((sg) => sg.id === securityGroupId)?.name || securityGroupId\n deleteSecurityGroupMutation.mutate(\n { project_id: projectId, securityGroupId },\n {\n onSuccess: () => {\n const { message, ...options } = getSecurityGroupDeletedToast(sgName)\n toast.success(message, options)\n },\n }\n )\n }\n\n const handleUpdateSecurityGroup = async (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => {\n setUpdateError(null)\n const sgName = data.name || securityGroups.find((sg) => sg.id === securityGroupId)?.name || securityGroupId\n try {\n await updateSecurityGroupMutation.mutateAsync({ project_id: projectId, securityGroupId, ...data })\n const { message, ...options } = getSecurityGroupUpdatedToast(sgName)\n toast.success(message, options)\n } catch {\n // onError handles error state and UI feedback\n }\n }\n\n const handleClearUpdateError = () => {\n setUpdateError(null)\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: RequiredSortSettings = {\n options: newSortSettings.options,\n sortBy: newSortSettings.sortBy?.toString() || \"name\",\n sortDirection: newSortSettings.sortDirection || \"asc\",\n }\n setSortSettings(settings)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) => ({\n ...prev,\n sortBy: settings.sortBy,\n sortDirection: settings.sortDirection,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleFilterChange = (newFilterSettings: FilterSettings) => {\n setFilterSettings(newFilterSettings)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) =>\n buildUrlSearchParams(newFilterSettings.selectedFilters || [], newFilterSettings.filters, {\n search: prev.search,\n sortBy: prev.sortBy,\n sortDirection: prev.sortDirection,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n setSearchTerm(searchValue)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) => ({\n ...prev,\n search: searchValue || undefined,\n })) as unknown as true,\n replace: true,\n })\n }\n\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Security Groups...`} />\n }\n\n if (isError && !securityGroups.length) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {listError || t`Failed to load security groups`}\n </Stack>\n )\n }\n\n return (\n <>\n <ContentHeader title={t`Security Groups`} projectId={projectId} />\n\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"2\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-40\"\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n {permissions.canCreate && (\n <Button onClick={() => setCreateModalOpen(true)} variant=\"primary\" className=\"whitespace-nowrap\">\n <Trans>Create Security Group</Trans>\n </Button>\n )}\n </Stack>\n </Stack>\n\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"between\" alignment=\"center\">\n <FiltersInput\n filters={filterSettings.filters}\n selectClassName=\"sm:min-w-40\"\n comboboxClassName=\"sm:min-w-40\"\n onChange={(selected) => {\n const newSelected = applyFilterSelection(\n filterSettings.selectedFilters || [],\n selected,\n filterSettings.filters\n )\n if (newSelected === (filterSettings.selectedFilters || [])) return\n handleFilterChange({ ...filterSettings, selectedFilters: newSelected })\n }}\n />\n <SearchInput\n placeholder={t`Search security groups...`}\n data-testid=\"searchbar\"\n value={searchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setSearchTerm(v)\n }}\n onSearch={(v) => {\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n setSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n {filterSettings.selectedFilters && filterSettings.selectedFilters.length > 0 && (\n <SelectedFilters\n selectedFilters={filterSettings.selectedFilters}\n onDelete={(filterToRemove) =>\n handleFilterChange({\n ...filterSettings,\n selectedFilters: (filterSettings.selectedFilters || []).filter(\n (f) => !(f.name === filterToRemove.name && f.value === filterToRemove.value)\n ),\n })\n }\n onClear={() => handleFilterChange({ ...filterSettings, selectedFilters: [] })}\n />\n )}\n </Stack>\n </DataGridToolbar>\n\n <SecurityGroupListContainer\n securityGroups={securityGroups}\n isLoading={false}\n isError={false}\n error={null}\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 hasAnyBulkAction={false}\n onClearUpdateError={handleClearUpdateError}\n />\n\n <CreateSecurityGroupModal\n isOpen={createModalOpen}\n onClose={() => {\n setCreateError(null)\n setCreateModalOpen(false)\n }}\n onCreate={handleCreateSecurityGroup}\n isLoading={createSecurityGroupMutation.isPending}\n error={createError}\n />\n </>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\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 } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return <SecurityGroups project={projectId} />\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { Outlet as t } from "@tanstack/react-router";
|
|
3
|
+
//#region src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=component
|
|
4
|
+
var n = () => /*#__PURE__*/ e(t, {});
|
|
5
|
+
//#endregion
|
|
6
|
+
export { n as component };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=securitygroups-CtKne8UQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securitygroups-CtKne8UQ.mjs","names":["Outlet","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\nimport { msg } from \"@lingui/core/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n crumb: { text: msg`Security Groups` },\n } satisfies RouteInfo,\n component: () => <Outlet />,\n})\n"],"mappings":";;;AAAgE,IAAAC,UAU7C,gBAAC,GAAA,CAAA,CAAA"}
|
|
@@ -4,14 +4,12 @@ var r = e("/_auth/projects/$projectId/network/securitygroups/")({
|
|
|
4
4
|
staticData: {
|
|
5
5
|
section: "network",
|
|
6
6
|
service: "securitygroups",
|
|
7
|
-
analytics: { name: "network.securitygroups.list" }
|
|
8
|
-
sectionCrumb: { labelKey: "Network" },
|
|
9
|
-
crumb: { labelKey: "Security Groups" }
|
|
7
|
+
analytics: { name: "network.securitygroups.list" }
|
|
10
8
|
},
|
|
11
9
|
head: () => ({ meta: [{ title: n._({ id: "4opp4r" }) }] }),
|
|
12
|
-
component: t(() => import("./securitygroups-
|
|
10
|
+
component: t(() => import("./securitygroups-BjhgLBHm.mjs"), "component")
|
|
13
11
|
});
|
|
14
12
|
//#endregion
|
|
15
13
|
export { r as t };
|
|
16
14
|
|
|
17
|
-
//# sourceMappingURL=securitygroups-
|
|
15
|
+
//# sourceMappingURL=securitygroups-DEJQBcxm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securitygroups-DEJQBcxm.mjs","names":["createFileRoute","t","Route","staticData","section","service","analytics","name","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\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 } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return <SecurityGroups project={projectId} />\n}\n"],"mappings":";;AAKA,IAAaE,IAAQF,EAAgB,oDAAA,CAAA,CAAsD;CACzFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,WAAW,EACTC,MAAM,8BACR;CACF;CACAE,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOV,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAkB,CAAC,EAAE;CACrDW,WAASC,iDAAA,WAAA;AACX,CAAA"}
|
|
@@ -125,7 +125,6 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
125
125
|
create: import('@trpc/server').TRPCMutationProcedure<{
|
|
126
126
|
input: {
|
|
127
127
|
project_id: string;
|
|
128
|
-
tenant_id: string;
|
|
129
128
|
floating_network_id: string;
|
|
130
129
|
fixed_ip_address?: string | undefined;
|
|
131
130
|
floating_ip_address?: string | undefined;
|
|
@@ -1745,6 +1744,137 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
1745
1744
|
meta: object;
|
|
1746
1745
|
}>;
|
|
1747
1746
|
}>>;
|
|
1747
|
+
lifecycle: import('@trpc/server').TRPCBuiltRouter<{
|
|
1748
|
+
ctx: import('../server/context').AuroraPortalContext;
|
|
1749
|
+
meta: object;
|
|
1750
|
+
errorShape: import('@trpc/server').TRPCDefaultErrorShape;
|
|
1751
|
+
transformer: false;
|
|
1752
|
+
}, import('@trpc/server').TRPCDecorateCreateRouterOptions<{
|
|
1753
|
+
get: import('@trpc/server').TRPCQueryProcedure<{
|
|
1754
|
+
input: {
|
|
1755
|
+
project_id: string;
|
|
1756
|
+
bucketName: string;
|
|
1757
|
+
};
|
|
1758
|
+
output: {
|
|
1759
|
+
rules: {
|
|
1760
|
+
Status: string;
|
|
1761
|
+
ID?: string | undefined;
|
|
1762
|
+
Prefix?: string | undefined;
|
|
1763
|
+
Filter?: {
|
|
1764
|
+
[x: string]: unknown;
|
|
1765
|
+
Prefix?: string | undefined;
|
|
1766
|
+
Tag?: {
|
|
1767
|
+
Key: string;
|
|
1768
|
+
Value: string;
|
|
1769
|
+
} | undefined;
|
|
1770
|
+
ObjectSizeGreaterThan?: number | undefined;
|
|
1771
|
+
ObjectSizeLessThan?: number | undefined;
|
|
1772
|
+
And?: {
|
|
1773
|
+
Prefix?: string | undefined;
|
|
1774
|
+
Tags?: {
|
|
1775
|
+
Key: string;
|
|
1776
|
+
Value: string;
|
|
1777
|
+
}[] | undefined;
|
|
1778
|
+
ObjectSizeGreaterThan?: number | undefined;
|
|
1779
|
+
ObjectSizeLessThan?: number | undefined;
|
|
1780
|
+
} | undefined;
|
|
1781
|
+
} | undefined;
|
|
1782
|
+
Expiration?: {
|
|
1783
|
+
[x: string]: unknown;
|
|
1784
|
+
Days?: number | undefined;
|
|
1785
|
+
Date?: string | Date | undefined;
|
|
1786
|
+
ExpiredObjectDeleteMarker?: boolean | undefined;
|
|
1787
|
+
} | undefined;
|
|
1788
|
+
Transitions?: {
|
|
1789
|
+
[x: string]: unknown;
|
|
1790
|
+
StorageClass: string;
|
|
1791
|
+
Days?: number | undefined;
|
|
1792
|
+
Date?: string | Date | undefined;
|
|
1793
|
+
}[] | undefined;
|
|
1794
|
+
NoncurrentVersionExpiration?: {
|
|
1795
|
+
[x: string]: unknown;
|
|
1796
|
+
NoncurrentDays?: number | undefined;
|
|
1797
|
+
NewerNoncurrentVersions?: number | undefined;
|
|
1798
|
+
} | undefined;
|
|
1799
|
+
NoncurrentVersionTransitions?: {
|
|
1800
|
+
[x: string]: unknown;
|
|
1801
|
+
StorageClass: string;
|
|
1802
|
+
NoncurrentDays?: number | undefined;
|
|
1803
|
+
NewerNoncurrentVersions?: number | undefined;
|
|
1804
|
+
}[] | undefined;
|
|
1805
|
+
AbortIncompleteMultipartUpload?: {
|
|
1806
|
+
[x: string]: unknown;
|
|
1807
|
+
DaysAfterInitiation?: number | undefined;
|
|
1808
|
+
} | undefined;
|
|
1809
|
+
}[] | null;
|
|
1810
|
+
skippedRuleCount: number;
|
|
1811
|
+
};
|
|
1812
|
+
meta: object;
|
|
1813
|
+
}>;
|
|
1814
|
+
set: import('@trpc/server').TRPCMutationProcedure<{
|
|
1815
|
+
input: {
|
|
1816
|
+
project_id: string;
|
|
1817
|
+
bucketName: string;
|
|
1818
|
+
lifecycleConfiguration: {
|
|
1819
|
+
Rules: {
|
|
1820
|
+
Status: "Enabled" | "Disabled";
|
|
1821
|
+
ID?: string | undefined;
|
|
1822
|
+
Prefix?: string | undefined;
|
|
1823
|
+
Filter?: {
|
|
1824
|
+
Prefix?: string | undefined;
|
|
1825
|
+
Tag?: {
|
|
1826
|
+
Key: string;
|
|
1827
|
+
Value: string;
|
|
1828
|
+
} | undefined;
|
|
1829
|
+
ObjectSizeGreaterThan?: number | undefined;
|
|
1830
|
+
ObjectSizeLessThan?: number | undefined;
|
|
1831
|
+
And?: {
|
|
1832
|
+
Prefix?: string | undefined;
|
|
1833
|
+
Tags?: {
|
|
1834
|
+
Key: string;
|
|
1835
|
+
Value: string;
|
|
1836
|
+
}[] | undefined;
|
|
1837
|
+
ObjectSizeGreaterThan?: number | undefined;
|
|
1838
|
+
ObjectSizeLessThan?: number | undefined;
|
|
1839
|
+
} | undefined;
|
|
1840
|
+
} | undefined;
|
|
1841
|
+
Expiration?: {
|
|
1842
|
+
Days?: number | undefined;
|
|
1843
|
+
Date?: string | undefined;
|
|
1844
|
+
ExpiredObjectDeleteMarker?: boolean | undefined;
|
|
1845
|
+
} | undefined;
|
|
1846
|
+
Transitions?: {
|
|
1847
|
+
StorageClass: string;
|
|
1848
|
+
Days?: number | undefined;
|
|
1849
|
+
Date?: string | undefined;
|
|
1850
|
+
}[] | undefined;
|
|
1851
|
+
NoncurrentVersionExpiration?: {
|
|
1852
|
+
NoncurrentDays: number;
|
|
1853
|
+
NewerNoncurrentVersions?: number | undefined;
|
|
1854
|
+
} | undefined;
|
|
1855
|
+
NoncurrentVersionTransitions?: {
|
|
1856
|
+
NoncurrentDays: number;
|
|
1857
|
+
StorageClass: string;
|
|
1858
|
+
NewerNoncurrentVersions?: number | undefined;
|
|
1859
|
+
}[] | undefined;
|
|
1860
|
+
AbortIncompleteMultipartUpload?: {
|
|
1861
|
+
DaysAfterInitiation: number;
|
|
1862
|
+
} | undefined;
|
|
1863
|
+
}[];
|
|
1864
|
+
};
|
|
1865
|
+
};
|
|
1866
|
+
output: boolean;
|
|
1867
|
+
meta: object;
|
|
1868
|
+
}>;
|
|
1869
|
+
delete: import('@trpc/server').TRPCMutationProcedure<{
|
|
1870
|
+
input: {
|
|
1871
|
+
project_id: string;
|
|
1872
|
+
bucketName: string;
|
|
1873
|
+
};
|
|
1874
|
+
output: boolean;
|
|
1875
|
+
meta: object;
|
|
1876
|
+
}>;
|
|
1877
|
+
}>>;
|
|
1748
1878
|
}>>;
|
|
1749
1879
|
};
|
|
1750
1880
|
}> & import('@trpc/server').TRPCDecorateCreateRouterOptions<{
|
|
@@ -1881,6 +2011,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
1881
2011
|
first?: string | undefined;
|
|
1882
2012
|
next?: string | undefined;
|
|
1883
2013
|
schema?: string | undefined;
|
|
2014
|
+
totalCount?: number | undefined;
|
|
1884
2015
|
};
|
|
1885
2016
|
meta: object;
|
|
1886
2017
|
}>;
|
|
@@ -1964,6 +2095,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
1964
2095
|
first?: string | undefined;
|
|
1965
2096
|
next?: string | undefined;
|
|
1966
2097
|
schema?: string | undefined;
|
|
2098
|
+
totalCount?: number | undefined;
|
|
1967
2099
|
};
|
|
1968
2100
|
meta: object;
|
|
1969
2101
|
}>;
|
|
@@ -2755,7 +2887,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
2755
2887
|
domain: {
|
|
2756
2888
|
id?: string;
|
|
2757
2889
|
name?: string;
|
|
2758
|
-
}
|
|
2890
|
+
};
|
|
2759
2891
|
} | {
|
|
2760
2892
|
project: {
|
|
2761
2893
|
domain?: {
|
|
@@ -2764,7 +2896,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
|
|
|
2764
2896
|
};
|
|
2765
2897
|
id?: string;
|
|
2766
2898
|
name?: string;
|
|
2767
|
-
}
|
|
2899
|
+
};
|
|
2768
2900
|
domain: {
|
|
2769
2901
|
id?: string;
|
|
2770
2902
|
name?: string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { t as e } from "./routeInfo-DP3v74Wg.mjs";
|
|
2
|
+
import { t } from "./DynamicBreadcrumbContext-CVcUQFou.mjs";
|
|
3
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
+
import { createContext as r, useContext as i, useMemo as a, useState as o } from "react";
|
|
5
|
+
import { useMatches as s, useNavigate as c } from "@tanstack/react-router";
|
|
6
|
+
import { useLingui as l } from "@lingui/react";
|
|
7
|
+
//#region src/client/context/BreadcrumbExtensionContext.tsx
|
|
8
|
+
var u = /*#__PURE__*/ r({
|
|
9
|
+
breadcrumbs: [],
|
|
10
|
+
setBreadcrumbs: () => {}
|
|
11
|
+
});
|
|
12
|
+
function d({ children: e }) {
|
|
13
|
+
let [t, r] = o([]);
|
|
14
|
+
return /*#__PURE__*/ n(u.Provider, {
|
|
15
|
+
value: {
|
|
16
|
+
breadcrumbs: t,
|
|
17
|
+
setBreadcrumbs: r
|
|
18
|
+
},
|
|
19
|
+
children: e
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/client/hooks/useBreadcrumbs.ts
|
|
24
|
+
function f() {
|
|
25
|
+
let { i18n: n, _: r } = l(), o = c(), u = s(), { crumbs: d } = i(t);
|
|
26
|
+
return a(() => {
|
|
27
|
+
let t = u.filter((t) => e(t.staticData) && t.staticData.crumb || d.has(t.routeId));
|
|
28
|
+
return t.map((r, i) => {
|
|
29
|
+
let a = d.get(r.routeId), s = e(r.staticData) ? r.staticData.crumb : void 0, c = a?.text ? p(a.text, n) : s?.text ? p(s.text, n) : void 0, l = a?.to ?? s?.to, u = a?.icon ?? s?.icon, f = i === t.length - 1;
|
|
30
|
+
return {
|
|
31
|
+
label: c,
|
|
32
|
+
icon: u,
|
|
33
|
+
onClick: f ? void 0 : () => o({
|
|
34
|
+
to: l ?? r.pathname,
|
|
35
|
+
params: r.params
|
|
36
|
+
}),
|
|
37
|
+
active: f
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}, [
|
|
41
|
+
u,
|
|
42
|
+
d,
|
|
43
|
+
o,
|
|
44
|
+
n,
|
|
45
|
+
n.locale
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
function p(e, t) {
|
|
49
|
+
return typeof e == "string" ? e : t._(e);
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { u as n, d as r, f as t };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=useBreadcrumbs-ha3IlaxX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBreadcrumbs-ha3IlaxX.mjs","names":["createContext","useState","BreadcrumbExtensionContext","breadcrumbs","setBreadcrumbs","BreadcrumbExtensionProvider","children","Provider","value","useMatches","useNavigate","useMemo","useContext","isRouteInfo","DynamicBreadcrumbContext","useBreadcrumbs","i18n","useLingui","navigate","matches","crumbs","dynamicCrumbs","crumbMatches","filter","m","staticData","crumb","has","routeId","map","match","i","dynamic","get","staticCrumb","undefined","crumbText","text","resolveCrumbText","crumbTo","to","crumbIcon","icon","isLast","length","label","onClick","pathname","params","active","locale","_"],"sources":["../../src/client/context/BreadcrumbExtensionContext.tsx","../../src/client/hooks/useBreadcrumbs.ts"],"sourcesContent":["import { createContext, useState } from \"react\"\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\"\nimport type { BreadcrumbItem } from \"@/client/hooks/useBreadcrumbs\"\n\nexport const BreadcrumbExtensionContext = createContext<{\n breadcrumbs: BreadcrumbItem[]\n setBreadcrumbs: Dispatch<SetStateAction<BreadcrumbItem[]>>\n}>({ breadcrumbs: [], setBreadcrumbs: () => {} })\n\nexport function BreadcrumbExtensionProvider({ children }: { children: ReactNode }) {\n const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([])\n return (\n <BreadcrumbExtensionContext.Provider value={{ breadcrumbs, setBreadcrumbs }}>\n {children}\n </BreadcrumbExtensionContext.Provider>\n )\n}\n","import { useMatches, useNavigate } from \"@tanstack/react-router\"\nimport { useMemo, useContext } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { I18n } from \"@lingui/core\"\nimport type { MessageDescriptor } from \"@lingui/core\"\nimport { isRouteInfo, type RouteInfo } from \"@/client/routes/routeInfo\"\nimport { DynamicBreadcrumbContext } from \"@/client/context/DynamicBreadcrumbContext\"\n\n/**\n * Returns the ordered breadcrumb chain for the current route.\n * Reads static crumbs from route staticData and dynamic crumbs from useSetBreadcrumb.\n * Works with any TanStack Router instance — suitable for embedded sub-apps (e.g. SCI services).\n *\n * Requirements:\n * - Must be rendered inside DynamicBreadcrumbProvider and a lingui I18nProvider\n * - To include SCI extension crumbs in OSS, use the Breadcrumbs component which merges BreadcrumbExtensionContext\n */\nexport type BreadcrumbItem = {\n label?: string\n icon?: string\n onClick?: () => void\n active?: boolean\n}\n\nexport function useBreadcrumbs(): BreadcrumbItem[] {\n const { i18n } = useLingui()\n const navigate = useNavigate()\n const matches = useMatches()\n const { crumbs: dynamicCrumbs } = useContext(DynamicBreadcrumbContext)\n\n return useMemo(() => {\n const crumbMatches = matches.filter(\n (m) => (isRouteInfo(m.staticData) && (m.staticData as RouteInfo).crumb) || dynamicCrumbs.has(m.routeId)\n )\n\n return crumbMatches.map((match, i) => {\n const dynamic = dynamicCrumbs.get(match.routeId)\n const staticCrumb = isRouteInfo(match.staticData) ? (match.staticData as RouteInfo).crumb : undefined\n const crumbText = dynamic?.text\n ? resolveCrumbText(dynamic.text, i18n)\n : staticCrumb?.text\n ? resolveCrumbText(staticCrumb.text, i18n)\n : undefined\n const crumbTo = dynamic?.to ?? staticCrumb?.to\n const crumbIcon = dynamic?.icon ?? staticCrumb?.icon\n const isLast = i === crumbMatches.length - 1\n return {\n label: crumbText,\n icon: crumbIcon,\n onClick: isLast\n ? undefined\n : () => navigate({ to: (crumbTo ?? match.pathname) as never, params: match.params as never }),\n active: isLast,\n }\n })\n }, [matches, dynamicCrumbs, navigate, i18n, i18n.locale])\n}\n\nfunction resolveCrumbText(text: string | MessageDescriptor, i18n: I18n): string {\n return typeof text === \"string\" ? text : i18n._(text)\n}\n"],"mappings":";;;;;;;AAIA,IAAaE,IAA6BF,gBAGvC;CAAEG,aAAa,CAAA;CAAIC,sBAAgB,CAAO;AAAE,CAAA;AAE/C,SAAgBC,EAA4B,EAAEC,eAAmC;CAC/E,IAAM,CAACH,GAAaC,KAAkBH,EAA2B,CAAA,CAAE;CACnE,OACE,gBAACC,EAA2BK,UAAQ;EAACC,OAAO;GAAEL;GAAaC;EAAe;EACvEE;;AAGP;;;ACQA,SAAgBS,IAAAA;CACd,IAAM,EAAEC,SAAI,GAAA,MAAKC,EAAAA,GACXC,IAAWR,EAAAA,GACXS,IAAUV,EAAAA,GACV,EAAEW,QAAQC,MAAkBT,EAAWE,CAAAA;CAE7C,OAAOH,QAAQ;EACb,IAAMW,IAAeH,EAAQI,QAC1BC,MAAM,EAAaA,EAAEC,UAAU,KAAK,EAAGA,WAAyBC,SAAUL,EAAcM,IAAIH,EAAEI,OAAO,CAAA;EAGxG,OAAON,EAAaO,KAAKC,GAAOC,MAAAA;GAC9B,IAAMC,IAAUX,EAAcY,IAAIH,EAAMF,OAAO,GACzCM,IAAcrB,EAAYiB,EAAML,UAAU,IAAI,EAAOA,WAAyBC,QAAQS,KAAAA,GACtFC,IAAYJ,GAASK,OACvBC,EAAiBN,EAAQK,MAAMrB,CAAAA,IAC/BkB,GAAaG,OACXC,EAAiBJ,EAAYG,MAAMrB,CAAAA,IACnCmB,KAAAA,GACAI,IAAUP,GAASQ,MAAMN,GAAaM,IACtCC,IAAYT,GAASU,QAAQR,GAAaQ,MAC1CC,IAASZ,MAAMT,EAAasB,SAAS;GAC3C,OAAO;IACLC,OAAOT;IACPM,MAAMD;IACNK,SAASH,IACLR,KAAAA,UACMjB,EAAS;KAAEsB,IAAKD,KAAWT,EAAMiB;KAAoBC,QAAQlB,EAAMkB;IAAgB,CAAA;IAC7FC,QAAQN;GACV;EACF,CAAA;CACF,GAAG;EAACxB;EAASE;EAAeH;EAAUF;EAAMA,EAAKkC;CAAO,CAAA;AAC1D;AAEA,SAASZ,EAAiBD,GAAkCrB,GAAU;CACpE,OAAO,OAAOqB,KAAS,WAAWA,IAAOrB,EAAKmC,EAAEd,CAAAA;AAClD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect as e, useRef as t } from "react";
|
|
2
|
+
import { useRouteContext as n } from "@tanstack/react-router";
|
|
3
|
+
//#region src/client/hooks/useModalTracking.ts
|
|
4
|
+
var r = ({ isOpen: r, actionPrefix: i }) => {
|
|
5
|
+
let { onTrackEvent: a } = n({ strict: !1 }), o = t(!1), s = t(!1);
|
|
6
|
+
return e(() => {
|
|
7
|
+
r && !o.current && (a?.({
|
|
8
|
+
source: "modal",
|
|
9
|
+
action: `${i}.open`
|
|
10
|
+
}), o.current = !0);
|
|
11
|
+
}, [
|
|
12
|
+
r,
|
|
13
|
+
a,
|
|
14
|
+
i
|
|
15
|
+
]), {
|
|
16
|
+
trackClose: () => {
|
|
17
|
+
r && !s.current && a?.({
|
|
18
|
+
source: "modal",
|
|
19
|
+
action: `${i}.close`
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
markSubmitted: () => {
|
|
23
|
+
s.current = !0;
|
|
24
|
+
},
|
|
25
|
+
resetTracking: () => {
|
|
26
|
+
s.current = !1, o.current = !1;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { r as t };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=useModalTracking-BcOKTYRN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModalTracking-BcOKTYRN.mjs","names":["useEffect","useRef","useRouteContext","useModalTracking","isOpen","actionPrefix","onTrackEvent","strict","hasTrackedOpen","hasSubmitted","current","source","action","trackClose","markSubmitted","resetTracking"],"sources":["../../src/client/hooks/useModalTracking.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { useRouteContext } from \"@tanstack/react-router\"\n\ninterface UseModalTrackingOptions {\n isOpen: boolean\n actionPrefix: string // e.g., \"storage.ceph.bucket.create\"\n}\n\ninterface UseModalTrackingReturn {\n trackClose: () => void\n markSubmitted: () => void\n resetTracking: () => void\n}\n\n/**\n * Custom hook to handle modal open/close analytics tracking.\n *\n * Tracks:\n * - `.open` event when modal opens (once per modal open)\n * - `.close` event when modal closes without submission (cancelled)\n *\n * @example\n * const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n * isOpen,\n * actionPrefix: \"storage.ceph.bucket.create\"\n * })\n *\n * // In handleClose:\n * trackClose()\n *\n * // In handleSubmit:\n * markSubmitted()\n *\n * // In cleanup/reset:\n * resetTracking()\n */\nexport const useModalTracking = ({ isOpen, actionPrefix }: UseModalTrackingOptions): UseModalTrackingReturn => {\n const { onTrackEvent } = useRouteContext({ strict: false })\n const hasTrackedOpen = useRef(false)\n // Use useRef instead of useState to avoid timing race with synchronous close paths\n // See: https://github.com/... - setState doesn't apply until next render, so trackClose()\n // could read stale hasSubmitted === false even after markSubmitted() was called\n const hasSubmitted = useRef(false)\n\n // Track when user opens the modal (once per modal open)\n useEffect(() => {\n if (isOpen && !hasTrackedOpen.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.open`,\n })\n hasTrackedOpen.current = true\n }\n }, [isOpen, onTrackEvent, actionPrefix])\n\n /**\n * Track close event if user didn't submit.\n * Call this at the start of your handleClose function.\n */\n const trackClose = () => {\n if (isOpen && !hasSubmitted.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.close`,\n })\n }\n }\n\n /**\n * Mark that the user submitted the form.\n * Call this in your handleSubmit function before the mutation.\n */\n const markSubmitted = () => {\n hasSubmitted.current = true\n }\n\n /**\n * Reset tracking state.\n * Call this in handleClose after tracking close event.\n */\n const resetTracking = () => {\n hasSubmitted.current = false\n hasTrackedOpen.current = false\n }\n\n return {\n trackClose,\n markSubmitted,\n resetTracking,\n }\n}\n"],"mappings":";;;AAoCA,IAAaG,KAAoB,EAAEC,WAAQC,sBAAuC;CAChF,IAAM,EAAEC,oBAAiBJ,EAAgB,EAAEK,QAAQ,GAAM,CAAA,GACnDC,IAAiBP,EAAO,EAAA,GAIxBQ,IAAeR,EAAO,EAAA;CA2C5B,OAxCAD,QAAU;EACR,AAAII,KAAU,CAACI,EAAeE,YAC5BJ,IAAe;GACbK,QAAQ;GACRC,QAAQ,GAAGP,EAAa;EAC1B,CAAA,GACAG,EAAeE,UAAU;CAE7B,GAAG;EAACN;EAAQE;EAAcD;CAAa,CAAA,GAgChC;EACLQ,kBA3BiB;GACjB,AAAIT,KAAU,CAACK,EAAaC,WAC1BJ,IAAe;IACbK,QAAQ;IACRC,QAAQ,GAAGP,EAAa;GAC1B,CAAA;EAEJ;EAqBES,qBAfoB;GACpBL,EAAaC,UAAU;EACzB;EAcEK,qBARoB;GAEpBP,AADAC,EAAaC,UAAU,IACvBF,EAAeE,UAAU;EAC3B;CAMA;AACF"}
|