@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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"securitygroups-Bd_uV4S9.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","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","DataGridHeadCell","DataGridRow","Stack","Spinner","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","className","distribution","alignment","direction","variant","size","message","t","length","columns","map","label","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","showSelectColumn","isSelected","onSelect","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","trpcReact","SortInput","SelectedFilters","FiltersInput","SecurityGroupListContainer","CreateSecurityGroupModal","parseFiltersFromUrl","buildFilterParams","buildUrlSearchParams","applyFilterSelection","useSecurityGroupPermissions","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","mutate","handleUpdateSecurityGroup","handleClearUpdateError","handleSortChange","newSortSettings","settings","toString","replace","handleFilterChange","newFilterSettings","handleSearchChange","term","searchValue","undefined","className","distribution","alignment","direction","length","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","name","onCreateClick","onDeleteSecurityGroup","isDeletingSecurityGroup","isPending","onUpdateSecurityGroup","isUpdatingSecurityGroup","currentProjectId","hasAnyBulkAction","onClearUpdateError","isOpen","onClose","onCreate","useLingui","SecurityGroups","ContentHeading","Route","RouteComponent","t","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 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 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 <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 ) => 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 (\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={hasAnyBulkAction ? 6 : 5}>\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 {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 </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 } from \"@cloudoperators/juno-ui-components\"\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 { CreateSecurityGroupInput, UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { parseFiltersFromUrl, buildFilterParams, buildUrlSearchParams, applyFilterSelection } from \"../urlHelpers\"\nimport { useSecurityGroupPermissions } from \"../-hooks/useSecurityGroupPermissions\"\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 },\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 },\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 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 (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Trans>Loading...</Trans>\n </Stack>\n )\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 <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 { 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 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 (\n <>\n <ContentHeading>{t`Security Groups`}</ContentHeading>\n <SecurityGroups project={projectId} />\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;;GAA0BG,QAAAA,EAAAA,qBAAAA;EAAmB,CAAA;EACrDW,aACE,gBAAC7B,GAAAA;GAAY8B,WAAU;GACrB,UAAA,gBAAC7B,GAAAA,EAAAA,UAAAA,CACC,gBAACF,GAAAA;IAAOgC,SAAQ;IAAUC,SAASR;IAAaS,UAAUxB;IACxD,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;GAEF,CAAA,GAAA,gBAACV,GAAAA;IACCgC,SAAQ;IACRC,SAASX;IACTY,UAAU,CAACjB,KAAmBP;IAC9ByB,eAAY;IAEXzB,UAAAA,IAAa,gBAAA,GAAA,EAAA,IAAA,SAA6B,CAAA,IAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;EAMnD,UAAA,gBAAC0B,OAAAA,EAAAA,UAAAA;GAEEzB,KACC,gBAACR,GAAAA;IAAQkC,aAAa;IAAOL,SAAQ;IAAQD,WAAU;IACpDpB,UAAAA;;GAKL,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;GAGA,gBAACyB,OAAAA;IAAIL,WAAU;IACb,UAAA,CAAA,gBAACO,KAAAA;KAAEP,WAAU;KACX,UAAA,gBAAA,GAAA;;MACgBhB,QAAAA,EAAAA,cAAAA;MAARwB,YAAAA,EAAAA,GAAAA,gBAAAA,UAAAA,CAAAA,CAAAA,EAAAA;;IAGV,CAAA,GAAA,gBAACnC,GAAAA;KACCiB,IAAG;KACHD,MAAK;KACLoB,OAAO3B;KACP4B,WAAWlB,MAAMT,EAAoBS,EAAEmB,OAAOF,KAAK;KACnDG,aAAa5B;KACbmB,UAAUxB;KACVkC,cAAa;KACbT,eAAY;;;;;AAMxB;;;AC/DA,SAAgBgB,EAAsB,EACpCC,eAAeC,GACfC,gBACAC,WACAC,aACAC,kBACAC,gBAAa,IACbC,sBAAmB,IACnBC,gBAAa,IACbC,eAC2B;CAC3B,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GAERC,KAAgB,EAAEC,eAA4C,gBAACC,QAAAA,EAAMD,UAAAA,IAAQE,EAAAA,EAAC,EAAA,IAAA,SAAI,CAAA,IAAIA,EAAAA,EAAC,EAAA,IAAA,SAAG,CAAA,EAAA,CAAA,GAE1FC,UAAoB;EACxB,AAAIV,KACFA,EAAcJ,CAAAA;CAElB;CAEA,OACE,gBAACP,GAAAA;EAECsB,eAAa,sBAAsBf,EAAGgB;EACtCC,SAASH;EACTI,WAAU;;GAETZ,KACC,gBAACd,GAAAA;IAAayB,UAAUE,MAAMA,EAAEC,gBAAe;IAC7C,UAAA,gBAACvB,GAAAA;KAASwB,SAASd;KAAYe,gBAAgBd,IAAWR,CAAAA;;;GAG9D,gBAACR,GAAAA,EACC,UAAA,gBAAC+B,OAAAA,EAAAA,UAAAA,CACC,gBAACC,KAAAA;IAAEN,WAAU;IAAWlB,UAAAA,EAAGyB;GAC3B,CAAA,GAAA,gBAACD,KAAAA;IAAEN,WAAU;IAA4BlB,UAAAA,EAAGgB;;GAGhD,gBAACxB,GAAAA,EAAcQ,UAAAA,EAAG0B,eAAeb,EAAAA,EAAC,EAAA,IAAA,SAAE,CAAA,EAAA,CAAA;GACpC,gBAACrB,GAAAA,EAAAA,UAAAA,CACC,gBAACkB,GAAAA,EAAaC,OAAOX,EAAG2B,OAAAA,CAAAA,GACvB3B,EAAG2B,UACF,gBAACH,KAAAA,EAAAA,UAAAA;IACC,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;IAAoB;IAAE,gBAACZ,QAAAA;KAAKM,WAAU;KAA4BlB,UAAAA,EAAG4B;;;GAI3E,gBAACpC,GAAAA,EACC,UAAA,gBAACkB,GAAAA,EAAaC,OAAOX,EAAG6B,SAAAA,CAAAA,EAAAA,CAAAA;GAE1B,gBAACrC,GAAAA;IAAayB,UAAUE,MAAMA,EAAEC,gBAAe;IAAIF,WAAU;IAC3D,UAAA,gBAACxB,GAAAA,EACC,UAAA,gBAACE,GAAAA,EAAAA,UAAAA;KACC,gBAACD,GAAAA;MAAcmC,OAAOjB,EAAAA,EAAC,EAAA,IAAA,SAAa,CAAA;MAAGI,eAAeH,EAAAA;;KACrDb,EAAY8B,aAAa,CAAC1B,KAAc,gBAACV,GAAAA;MAAcmC,OAAOjB,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;MAAGI,eAAef,EAAOF,CAAAA;;KAC7FC,EAAY+B,aAAa,CAAC3B,KAAc,gBAACV,GAAAA;MAAcmC,OAAOjB,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;MAAGI,eAAed,EAASH,CAAAA;;;;;CAjCnGA,GAAAA,EAAGgB,EAAE;AAuChB;;;AChEA,IAAa8B,KAA8B,EACzCC,mBACAC,cACAC,YACAC,UACAC,gBACAC,0BACAC,6BAA0B,IAC1BC,iBAAc,MACdC,0BACAC,6BAA0B,IAC1BC,iBAAc,MACdC,qBACAC,sBAAmB,IACnBC,4BACgC;CAChC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAWrB,GAAAA,GACXsB,IAAYrB,EAAAA,GACZ,CAACsB,GAAuBC,KAA4BhC,EAA+B,IAAA,GACnF,CAACiC,GAAeC,KAAoBlC,EAAS,EAAA,GAC7C,CAACmC,GAAkBC,KAAuBpC,EAAS,EAAA,GACnDqC,IAAoBnC,EAAgB,EAAA,GACpCoC,IAAoBpC,EAAgB,EAAA,GAEpCqC,KAAcC,MAAAA;EAMlBN,AAJIH,KAAyBA,EAAsBU,OAAOD,EAAGC,MAAMd,KACjEA,EAAAA,GAEFK,EAAyBQ,CAAAA,GACzBN,EAAiB,EAAA;CACnB,GAEMQ,KAAgBF,MAAAA;EAEpBJ,AADAJ,EAAyBQ,CAAAA,GACzBJ,EAAoB,EAAA;CACtB,GAEMO,KAAqBH,MAAAA;EACzBX,EAAS;GACPe,IAAI;GACJC,QAAQ;IAAEf;IAAWgB,iBAAiBN,EAAGC;GAAG;EAC9C,CAAA;CACF,GAEMM,UAAiB;EAErBb,AADAF,EAAyB,IAAA,GACzBE,EAAiB,EAAA;CACnB,GAEMc,UAAoB;EAExBZ,AADAJ,EAAyB,IAAA,GACzBI,EAAoB,EAAA;CACtB;CAsDA,OAnDAnC,QAAU;EAURoC,AAR6BA,EAAkBa,WAAW,CAAC9B,KAG/Be,KAAoB,CAACd,KAC/C2B,EAAAA,GAIFX,EAAkBa,UAAU9B;CAC9B,GAAG;EAACA;EAAyBC;EAAac;CAAiB,CAAA,GAG3DlC,QAAU;EAURqC,AAR2BA,EAAkBY,WAAW,CAAC3B,KAG/BU,KAAiB,CAACT,KAC1CuB,EAAAA,GAIFT,EAAkBY,UAAU3B;CAC9B,GAAG;EAACA;EAAyBC;EAAaS;CAAc,CAAA,GAGpDlB,IAEA,gBAACT,GAAAA;EAAM8C,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;EACzE,UAAA,CAAA,gBAAChD,GAAAA;GAAQiD,SAAQ;GAAUC,MAAK;GAAQL,WAAU;EAClD,CAAA,GAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,CAAA;MAMFpC,IAEA,gBAACV,GAAAA;EAAM8C,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;EACxEtC,UAAAA,GAAOyC,WAAWC,EAAAA,EAAC,EAAA,IAAA,SAA+B,CAAA;MAMrD7C,EAAe8C,WAAW,IACrB,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA,IAIP,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACzD,GAAAA;EAAS0D,SAASnC,IAAmB,IAAI;EACxC,UAAA,CAAA,gBAACrB,GAAAA,EAAAA,UAAAA,CACEqB,KAAoB,gBAACtB,GAAAA,CAAAA,CAAAA,GACrB;GAACuD,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;EAAG,CAAA,CAACG,KAAKC,MAC1D,gBAAC3D,GAAAA,EAA8B2D,UAAAA,EAARA,GAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,GAG1BjD,EAAegD,KAAKtB,MAAAA;GAEnB,IAAMwB,IAAaC,GAAQxC,KAAoBe,EAAG0B,cAAc1B,EAAG0B,eAAezC;GAElF,OACE,gBAACb,GAAAA;IAECuD,eAAe3B;IACFtB;IACbkD,QAAQ7B;IACR8B,UAAU3B;IACV4B,eAAe3B;IACHqB;IACZO,kBAAkB7C;IAClB8C,YAAY;IACZC,gBAAU,CAAO;GATZjC,GAAAA,EAAGC,EAAE;EAYhB,CAAA,CAAA;CAGDV,CAAAA,GAAAA,KACC,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACrB,GAAAA;EACCyD,eAAepC;EACf2C,MAAMzC;EACN0C,SAAS5B;EACT6B,WAAWnC,GAAIoC,MACTvD,IACKA,EAAsBmB,GAAIoC,CAAAA,IAE5BC,QAAQC,QAAO;EAExBhE,WAAWQ;EACXN,OAAOO;CAET,CAAA,GAAA,gBAACb,GAAAA;EACCwD,eAAepC;EACfiD,QAAQ7C;EACRwC,SAAS3B;EACTqB,WAAW5B,MAAAA;GACT,AAAItB,KACFA,EAAsBsB,CAAAA;EAE1B;EACAwC,YAAY7D;EACZH,OAAOI;;AAMnB,GCzKM2E,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,CAAAA,CAAWM,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;GACrB,UAAA,gBAAC5C,GAAAA,EAAAA,UAAAA,CACC,gBAACD,GAAAA;IAAO8C,SAAQ;IAAUC,SAASR;IAAaS,UAAUlC;IACxD,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;GAEF,CAAA,GAAA,gBAACd,GAAAA;IACC8C,SAAQ;IACRC,UAAUzB,MAAAA;KACRa,EAAab,CAAAA;IACf;IACA0B,UAAUlC;IACVmC,eAAY;IAEXnC,UAAAA,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;IACpD9B,UAAAA;;GAIJD,KACC,gBAACqC,OAAAA;IAAIN,WAAU;IACb,UAAA,CAAA,gBAAC3C,GAAAA,EAAQ4C,SAAQ,UAAA,CAAA,GACjB,gBAACM,QAAAA;KAAKP,WAAU;KACd,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;GAKL,CAAC/B,KACA,gBAACnB,GAAAA;IAAKkD,WAAU;IACd,UAAA,gBAAChD,GAAAA;KAAYgD,WAAU;;MACrB,gBAACjD,GAAAA;OAAQiD,WAAU;OACjB,UAAA,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;OACjB,UAAA,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;OACjB,UAAA,gBAAC9C,GAAAA;QACCsD,IAAG;QACH9C,MAAK;QACL+C,OAAOvB,EAAAA,EAAC,EAAA,IAAA,SAAS,CAAA;QACjBL,SAAST,EAAWR;QACpB8C,UAAUlC;QACV2B,UAAUlC;QACV8C,UAAU7B,EAAAA,EAAC,EAAA,IAAA,SAAgG,CAAA;;;;;;;;AAQ3H,GClLa8B,KAAuBC,MAAAA;CAClC,IAAMC,IAA4B,CAAA;CAOlC,OAJID,EAAaE,UACfD,EAAQE,KAAK;EAAEC,MAAM;EAAUC,OAAOL,EAAaE;CAAO,CAAA,GAGrDD;AACT,GAKaK,KACXC,GACAC,MAAAA;CAEA,IAAMC,IAAiC,CAAC;CAExC,IAAI,CAACF,GAAiBG,QAAQ,OAAOD;CAGrC,IAAME,IAAeJ,EAClBK,QAAQC,MAAO,CAACA,EAAGC,QAAQ,CAAA,CAC3BC,QACEC,GAAKH,OACCG,EAAIH,EAAGT,UAAOY,EAAIH,EAAGT,QAAQ,CAAA,IAClCY,EAAIH,EAAGT,KAAK,CAACD,KAAKU,EAAGR,KAAK,GACnBW,IAET,CAAC,CAAA;CAcL,OAVAC,OAAOC,QAAQP,CAAAA,CAAAA,CAAcQ,SAAS,CAACC,GAAYC,OAAO;EAGxD,AAFkBb,EAAkBe,MAAMC,MAAMA,EAAEJ,eAAeA,CAE7DE,CAAAA,EAAWG,sBAAsBJ,EAAOX,SAAS,IACnDD,EAAOW,KAAc,MAAMC,EAAOK,KAAK,GAAA,MAEvCjB,EAAOW,KAAcC,EAAO;CAEhC,CAAA,GAEOZ;AACT,GAQakB,KACXC,GACAC,GACArB,MAEwBoB,EAAQG,MAAMP,MAAMA,EAAEpB,SAASyB,EAASzB,QAAQoB,EAAEnB,UAAUwB,EAASxB,KACzFyB,IAAwBF,IAENpB,EAAkBe,MAAMC,MAAMA,EAAEJ,eAAeS,EAASzB,IAAI,CAAA,EAAGqB,qBAC9D,CAAIG,GAAAA,GAASC,CAAS,IAAG,CAAID,GAAAA,EAAQhB,QAAQY,MAAMA,EAAEpB,SAASyB,EAASzB,IAAI,GAAGyB,CAAS,GAMnGI,MACX1B,GACAC,GACA0B,MAAAA;CAMA,IAAMC,IAAwC;EAC5CC,QAAQF,EAAWE;EACnBC,QAAQH,EAAWG;EACnBC,eAAeJ,EAAWI;CAC5B;CAEA,IAAI,CAAC/B,GAAiBG,QAAQ,OAAOyB;CAErC,IAAMxB,IAAeJ,EAClBK,QAAQC,MAAO,CAACA,EAAGC,QAAQ,CAAA,CAC3BC,QACEC,GAAKH,OACCG,EAAIH,EAAGT,UAAOY,EAAIH,EAAGT,QAAQ,CAAA,IAClCY,EAAIH,EAAGT,KAAK,CAACD,KAAKU,EAAGR,KAAK,GACnBW,IAET,CAAC,CAAA;CAcL,OAXAC,OAAOC,QAAQP,CAAAA,CAAAA,CAAcQ,SAAS,CAACC,GAAYC,OAAO;EAGxD,AAFkBb,EAAkBe,MAAMC,MAAMA,EAAEJ,eAAeA,CAE7DE,CAAAA,EAAWG,sBAAsBJ,EAAOX,SAAS,IAEjDyB,EAAqCf,KAAc,MAAMC,EAAOK,KAAK,GAAA,MAErES,EAAqCf,KAAcC,EAAO;CAEhE,CAAA,GAEOc;AACT,GCvFauB,KAAkB,EAAEC,SAASC,QAAgC;CACxE,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAWrB,GAAAA,GACXsB,IAAerB,EAAU,EAAEsB,QAAQ,GAAM,CAAA,GAEzC,CAACC,GAAcC,KAAmB3B,EAA+B;EACrE4B,SAAS,CACP;GAAEC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA;GAAGC,OAAO;EAAO,GAChC;GAAEF,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAW,CAAA;GAAGC,OAAO;EAAa,CAC7C;EACDC,QAAQR,EAAaQ,UAAU;EAC/BC,eAAeT,EAAaS,iBAAiB;CAC/C,CAAA,GAEM,CAACC,GAAgBC,KAAqBnC,EAAyB;EACnEoC,SAAS,CACP;GACEC,aAAaP,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;GACrBQ,YAAY;GACZC,QAAQ,CAAC,QAAQ,OAAQ;GACzBC,oBAAoB;EACtB,CACD;EACDC,iBAAiB3B,EAAoBU,CAAAA;CACvC,CAAA,GAEM,CAACkB,GAAYC,KAAiB3C,EAASwB,EAAaoB,UAAU,EAAA,GAC9D,CAACC,GAAiBC,KAAsB9C,EAAS,EAAA,GACjD,CAAC+C,GAAaC,KAAkBhD,EAAwB,IAAA,GACxD,CAACiD,GAAaC,KAAkBlD,EAAwB,IAAA,GACxD,CAACmD,GAAaC,KAAkBpD,EAAwB,IAAA,GAExDqD,IAAQ7C,EAAU8C,SAAQ;CAEhCrD,QAAU;EAUR0C,AATAhB,GAAiB4B,OAAU;GACzB,GAAGA;GACHvB,QAAQR,EAAaQ,UAAU;GAC/BC,eAAeT,EAAaS,iBAAiB;EAC/C,EAAA,GACAE,GAAmBoB,OAAU;GAC3B,GAAGA;GACHd,iBAAiB3B,EAAoBU,CAAAA;EACvC,EAAA,GACAmB,EAAcnB,EAAaoB,UAAU,EAAA;CACvC,GAAG;EAACpB,EAAaQ;EAAQR,EAAaS;EAAeT,EAAaoB;EAAQpB,EAAagC;CAAO,CAAA;CAE9F,IAAMC,IAAa3C,EAAoBU,CAAAA,GACjCkC,IAAalC,EAAaQ,UAAU,QACpC2B,IAAmBnC,EAAaS,iBAAiB,OACjD2B,IAAgBpC,EAAaoB,UAAU,IAEvC,EACJiB,MAAMC,GACNC,cACAC,YACAC,aACEzD,EAAU0D,QAAQC,cAAcC,KAAKC,SACvC;EACEC,YAAYjD,KAAa;EACzBkD,UAAUb;EACVc,UAAUb;EACV,GAAG5C,EAAkB0C,GAAYvB,EAAeE,OAAO;EACvD,GAAIwB,IAAgB,EAAElB,YAAYkB,EAAc,IAAI,CAAC;CACvD,GACA,EACEa,sBAAsB,GACxB,CAAA,GAGIC,IAAiBZ,KAAsB,CAAA,GACvCa,KACJX,KAAWC,GAAOJ,MAAMe,SAAS,cAAc9C,EAAAA,EAAC,EAAA,IAAA,SAAmD,CAAA,IAAI,MAEnG,EAAE+C,mBAAgB3D,EAA4BG,CAAAA,GAE9CyD,IAA8BtE,EAAU0D,QAAQC,cAAcY,OAAOC,YAAY;EACrFC,YAAYC,MAAAA;GAIV3D,AAHA8B,EAAMa,QAAQC,cAAcC,KAAKe,WAAU,GAC3C9B,EAAMa,QAAQC,cAAciB,QAAQD,WAAU,GAC9CjC,EAAe,IAAA,GACf3B,EAAS;IACP8D,IAAI;IACJC,QAAQ;KACNjE;KACAkE,iBAAiBL,EAAqBM;IACxC;GACF,CAAA;EACF;EACAC,UAAUxB,MAAAA;GACRf,EAAee,EAAMyB,WAAW5D,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA,GAEM6D,KAA8BnF,EAAU0D,QAAQC,cAAcyB,WAAWZ,YAAY;EACzFC,iBAAW;GAGTjC,AAFAK,EAAMa,QAAQC,cAAcC,KAAKe,WAAU,GAC3C9B,EAAMa,QAAQC,cAAciB,QAAQD,WAAU,GAC9CnC,EAAe,IAAA;EACjB;EACAyC,UAAUxB,MAAAA;GACRjB,EAAeiB,EAAMyB,WAAW5D,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA,GAEM+D,KAA8BrF,EAAU0D,QAAQC,cAAc2B,OAAOd,YAAY;EACrFC,iBAAW;GAGT7B,AAFAC,EAAMa,QAAQC,cAAcC,KAAKe,WAAU,GAC3C9B,EAAMa,QAAQC,cAAciB,QAAQD,WAAU,GAC9C/B,EAAe,IAAA;EACjB;EACAqC,UAAUxB,MAAAA;GACRb,EAAea,EAAMyB,WAAW5D,EAAAA,EAAC,EAAA,IAAA,SAAgC,CAAA,CAAA;EACnE;CACF,CAAA,GAEMiE,KAA4B,OAAOC,MAAAA;EAEvC,AADA9C,EAAe,IAAA,GACf,MAAM4B,EAA4BmB,YAAY;GAAE3B,YAAYjD;GAAW,GAAG2E;EAAkB,CAAA;CAC9F,GAEME,MAA6BX,MAAAA;EAEjCI,AADA3C,EAAe,IAAA,GACf2C,GAA4BQ,OAAO;GAAE7B,YAAYjD;GAAWkE;EAAgB,CAAA;CAC9E,GAEMa,KAA4B,OAChCb,GACA1B,MAAAA;EAGA,AADAT,EAAe,IAAA,GACf,MAAMyC,GAA4BI,YAAY;GAAE3B,YAAYjD;GAAWkE;GAAiB,GAAG1B;EAAK,CAAA;CAClG,GAEMwC,WAAyB;EAC7BjD,EAAe,IAAA;CACjB,GAEMkD,MAAoBC,MAAAA;EACxB,IAAMC,IAAiC;GACrC5E,SAAS2E,EAAgB3E;GACzBI,QAAQuE,EAAgBvE,QAAQyE,SAAAA,KAAc;GAC9CxE,eAAesE,EAAgBtE,iBAAiB;EAClD;EAEAV,AADAI,EAAgB6E,CAAAA,GAChBjF,EAAS;GACPqB,SAAUW,OAAsC;IAC9C,GAAGA;IACHvB,QAAQwE,EAASxE;IACjBC,eAAeuE,EAASvE;GAC1B;GACAyE,SAAS;EACX,CAAA;CACF,GAEMC,KAAsBC,MAAAA;EAE1BrF,AADAY,EAAkByE,CAAAA,GAClBrF,EAAS;GACPqB,SAAUW,MACRvC,GAAqB4F,EAAkBnE,mBAAmB,CAAA,GAAImE,EAAkBxE,SAAS;IACvFQ,QAAQW,EAAKX;IACbZ,QAAQuB,EAAKvB;IACbC,eAAesB,EAAKtB;GACtB,CAAA;GACFyE,SAAS;EACX,CAAA;CACF,GAEMG,MAAsBC,MAAAA;EAC1B,IAAMC,IAAc,OAAOD,KAAS,WAAWA,IAAO;EAEtDvF,AADAoB,EAAcoE,CAAAA,GACdxF,EAAS;GACPqB,SAAUW,OAAsC;IAC9C,GAAGA;IACHX,QAAQmE,KAAeC,KAAAA;GACzB;GACAN,SAAS;EACX,CAAA;CACF;CAkBA,OAhBI3C,IAEA,gBAAC1D,GAAAA;EAAM4G,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;EACzE,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;MAKFpD,KAAW,CAACU,EAAe2C,SAE3B,gBAAChH,GAAAA;EAAM4G,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;EACxEzC,UAAAA,MAAa7C,EAAAA,EAAC,EAAA,IAAA,SAA+B,CAAA;MAMlD,gBAAA,GAAA,EAAA,UAAA;EACE,gBAACzB,GAAAA;GAAM6G,cAAa;GAAMC,WAAU;GAASG,KAAI;GAAIL,WAAU;GAC7D,UAAA,gBAAC5G,GAAAA;IAAMiH,KAAI;IACT,UAAA,CAAA,gBAAC7G,GAAAA;KACCmB,SAASF,EAAaE;KACtBI,QAAQN,EAAaM;KACrBC,eAAeP,EAAaO,iBAAiB;KAC7CsF,iBAAgB;KAChBC,iBAAiBC,MACfnB,GAAiB;MAAE,GAAG5E;MAAcM,QAAQyF;MAAGxF,eAAeP,EAAaO;KAAc,CAAA;KAE3FyF,wBAAwBC,MAAQrB,GAAiB;MAAE,GAAG5E;MAAcO,eAAe0F;KAAI,CAAA;IAExF9C,CAAAA,GAAAA,EAAY+C,aACX,gBAACxH,GAAAA;KAAOyH,eAAe/E,EAAmB,EAAA;KAAOgF,SAAQ;KAAUb,WAAU;KAC3E,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;;EAMR,gBAAC3G,GAAAA,EACC,UAAA,gBAACD,GAAAA;GAAM+G,WAAU;GAAWE,KAAI;GAC9B,UAAA,CAAA,gBAACjH,GAAAA;IAAM6G,cAAa;IAAUC,WAAU;IACtC,UAAA,CAAA,gBAACxG,GAAAA;KACCyB,SAASF,EAAeE;KACxBmF,iBAAgB;KAChBQ,mBAAkB;KAClBC,WAAWC,MAAAA;MACT,IAAMC,IAAcjH,EAClBiB,EAAeO,mBAAmB,CAAA,GAClCwF,GACA/F,EAAeE,OAAO;MAEpB8F,OAAiBhG,EAAeO,mBAAmB,CAAA,MACvDkE,EAAmB;OAAE,GAAGzE;OAAgBO,iBAAiByF;MAAY,CAAA;KACvE;IAEF,CAAA,GAAA,gBAAC3H,GAAAA;KACC4H,aAAarG,EAAAA,EAAC,EAAA,IAAA,SAA0B,CAAA;KACxCsG,eAAY;KACZrG,OAAOW;KACP2F,UAAUC,MAAAA;MACR,IAAMb,IAAIa,EAAEC,cAAcxG;MAC1BY,EAAc8E,CAAAA;KAChB;KACAe,WAAWf,MAAAA;MACTZ,GAAmB,OAAOY,KAAM,WAAWA,IAAI,EAAA;KACjD;KACAgB,eAAS;MAEP5B,AADAlE,EAAc,EAAA,GACdkE,GAAmB,EAAA;KACrB;;GAGH3E,CAAAA,GAAAA,EAAeO,mBAAmBP,EAAeO,gBAAgB4E,SAAS,KACzE,gBAAC3G,GAAAA;IACC+B,iBAAiBP,EAAeO;IAChCiG,WAAWC,MACThC,EAAmB;KACjB,GAAGzE;KACHO,kBAAkBP,EAAeO,mBAAmB,CAAA,EAAA,CAAImG,QACrDC,MAAQA,EAAEC,SAASH,EAAeG,QAAQD,EAAE9G,UAAU4G,EAAe5G,KAAI;IAE9E,CAAA;IAEF0G,eAAe9B,EAAmB;KAAE,GAAGzE;KAAgBO,iBAAiB,CAAA;IAAG,CAAA;;;EAMnF,gBAAC7B,GAAAA;GACiB8D;GAChBX,WAAW;GACXC,SAAS;GACTC,OAAO;GACMY;GACbkE,qBAAqBjG,EAAmB,EAAA;GACxCkG,uBAAuB9C;GACvB+C,yBAAyBtD,GAA4BuD;GACxCnG;GACboG,uBAAuB/C;GACvBgD,yBAAyBvD,GAA4BqD;GACxC/F;GACbkG,kBAAkBhI;GAClBiI,kBAAkB;GAClBC,oBAAoBlD;;EAGtB,gBAACxF,GAAAA;GACC2I,QAAQ3G;GACR4G,eAAS;IAEP3G,AADAI,EAAe,IAAA,GACfJ,EAAmB,EAAA;GACrB;GACA4G,UAAU3D;GACVhC,WAAWe,EAA4BoE;GACvCjF,OAAOhB;;;AAIf;;;ACxTA,SAAS8G,IAAAA;CACP,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQJ,EAAAA,GACR,EAAEM,iBAAcH,EAAMI,UAAS,GAC/B,EAAEC,kBAAeL,EAAMM,gBAAe;CAE5C,IAAI,CAACD,GACH,MAAUE,MAAM,8CAAA;CAGlB,OACE,gBAAA,GAAA,EAAA,UAAA,CACE,gBAAC,GAAA,EAAgBL,UAAAA,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAA,CAAA,GAClB,gBAAC,GAAA,EAAe,SAASC,EAAAA,CAAAA,CAAAA,EAAAA,CAAAA;AAG/B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"securitygroups-Byte-iSp.mjs","names":["createFileRoute","t","Route","staticData","section","service","analytics","name","sectionCrumb","labelKey","crumb","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 { 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 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 (\n <>\n <ContentHeading>{t`Security Groups`}</ContentHeading>\n <SecurityGroups project={projectId} />\n </>\n )\n}\n"],"mappings":";;AAOA,IAAaE,IAAQF,EAAgB,oDAAA,CAAA,CAAsD;CACzFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,WAAW,EACTC,MAAM,8BACR;EACAC,cAAc,EAAEC,UAAU,UAAU;EACpCC,OAAO,EAAED,UAAU,kBAAkB;CACvC;CACAG,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOb,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAkB,CAAC,EAAE;CACrDc,WAASC,iDAAA,WAAA;AACX,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useSecurityGroupPermissions-C29mzb3b.mjs","names":["React","useState","useEffect","Modal","Form","FormRow","FormSection","TextInput","Button","ButtonRow","Spinner","ModalFooter","Textarea","Message","EditSecurityGroupModal","securityGroup","open","onClose","onUpdate","isLoading","error","useLingui","properties","setProperties","name","description","errors","setErrors","handleInputChange","e","value","type","target","checked","prev","newErrors","validateForm","trim","t","Object","keys","length","handleSubmit","preventDefault","updateData","undefined","id","handleClose","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","dismissible","div","span","label","onChange","required","errortext","placeholder","rows","trpcReact","useSecurityGroupPermissions","projectId","data","permissions","canView","canCreate","canUpdate","canDelete","canCreateRule","canDeleteRule","canManageAccess","canViewRBAC","isLoading","isError","network","canUser","useQuery","project_id","permission","enabled","Boolean","select","canCreateRBAC","canDeleteRBAC","staleTime","Infinity","gcTime"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/EditSecurityGroupModal.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-hooks/useSecurityGroupPermissions.ts"],"sourcesContent":["import React, { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Button,\n ButtonRow,\n Spinner,\n ModalFooter,\n Textarea,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport { UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\ninterface EditSecurityGroupModalProps {\n securityGroup: SecurityGroup\n open: boolean\n onClose: () => void\n onUpdate?: (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => Promise<void>\n isLoading?: boolean\n error?: string | null\n}\n\ninterface SecurityGroupProperties {\n name: string\n description: string\n}\n\nexport const EditSecurityGroupModal: React.FC<EditSecurityGroupModalProps> = ({\n securityGroup,\n open,\n onClose,\n onUpdate,\n isLoading = false,\n error = null,\n}) => {\n const { t } = useLingui()\n\n const [properties, setProperties] = useState<SecurityGroupProperties>({\n name: securityGroup.name || \"\",\n description: securityGroup.description || \"\",\n })\n const [errors, setErrors] = useState<{ [key: string]: string }>({})\n\n // Update properties when securityGroup changes\n useEffect(() => {\n setProperties({\n name: securityGroup.name || \"\",\n description: securityGroup.description || \"\",\n })\n }, [securityGroup])\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 if (onUpdate) {\n // Prepare base update data without stateful\n const updateData: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\"> = {\n name: properties.name.trim(),\n description: properties.description.trim() || undefined,\n }\n\n // Note: We deliberately do NOT include 'stateful' field here\n // because it requires special 'update_security_group:stateful' permission\n // which needs cloud admin role. Regular users can only update name/description.\n\n await onUpdate(securityGroup.id, updateData)\n }\n }\n\n const handleClose = () => {\n setErrors({})\n onClose()\n }\n\n return (\n <Modal\n open={open}\n onCancel={handleClose}\n size=\"large\"\n title={t`Edit 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=\"update-security-group-button\"\n >\n {isLoading ? <Spinner size=\"small\" /> : <Trans>Update 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>Updating 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 {/* Note: Stateful checkbox is not shown here because it requires 'update_security_group:stateful' permission (cloud admin only) */}\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { trpcReact } from \"@/client/trpcClient\"\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\n/**\n * Hook to fetch security group permissions for the current user\n * Uses React Query with infinite cache since permissions don't change during session\n */\nexport function useSecurityGroupPermissions(projectId: string) {\n const {\n data: permissions = {\n canView: false,\n canCreate: false,\n canUpdate: false,\n canDelete: false,\n canCreateRule: false,\n canDeleteRule: false,\n canManageAccess: false,\n canViewRBAC: false,\n },\n isLoading,\n isError,\n } = trpcReact.network.canUser.useQuery(\n {\n project_id: projectId || \"\",\n permission: [\n \"network:security_groups:read\",\n \"network:security_groups:create\",\n \"network:security_groups:update\",\n \"network:security_groups:delete\",\n \"network:security_group_rules:create\",\n \"network:security_group_rules:delete\",\n \"network:rbac_policies:create\",\n \"network:rbac_policies:delete\",\n \"network:rbac_policies:read\",\n ],\n },\n {\n enabled: Boolean(projectId), // Only fetch if we have a project ID\n select: ([\n canView,\n canCreate,\n canUpdate,\n canDelete,\n canCreateRule,\n canDeleteRule,\n canCreateRBAC,\n canDeleteRBAC,\n canViewRBAC,\n ]) => ({\n canView,\n canCreate,\n canUpdate,\n canDelete,\n canCreateRule,\n canDeleteRule,\n canManageAccess: canCreateRBAC && canDeleteRBAC,\n canViewRBAC,\n }),\n staleTime: Infinity, // Permissions don't change during session\n gcTime: Infinity, // Keep in cache forever (previously cacheTime)\n }\n )\n\n return {\n permissions,\n isLoading,\n isError,\n }\n}\n"],"mappings":"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"}
|