@cobaltcore-dev/aurora 0.23.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/App.d.ts +3 -2
- package/dist/client/AuroraApp.d.ts +25 -0
- package/dist/client/{AuthProvider-CQ6Yppoh.mjs → AuthProvider-BS5OVv8n.mjs} +4 -4
- package/dist/client/AuthProvider-BS5OVv8n.mjs.map +1 -0
- package/dist/client/{ContentHeader-9KZdhOoA.mjs → ContentHeader-BHMUzd9H.mjs} +27 -26
- package/dist/client/ContentHeader-BHMUzd9H.mjs.map +1 -0
- package/dist/client/DeleteFlavorModal-BP83t9zX.mjs +721 -0
- package/dist/client/DeleteFlavorModal-BP83t9zX.mjs.map +1 -0
- package/dist/client/FiltersInput-B8CNBg1L.mjs +82 -0
- package/dist/client/FiltersInput-B8CNBg1L.mjs.map +1 -0
- package/dist/client/{FloatingIpActionModals-BcceUHcg.mjs → FloatingIpActionModals-BraiJWBi.mjs} +66 -66
- package/dist/client/{FloatingIpActionModals-BcceUHcg.mjs.map → FloatingIpActionModals-BraiJWBi.mjs.map} +1 -1
- package/dist/client/ImageToastNotifications-BXMHJaIH.mjs +1131 -0
- package/dist/client/ImageToastNotifications-BXMHJaIH.mjs.map +1 -0
- package/dist/client/{RouteError-Rm08PcxN.mjs → RouteError-hAF8_jbe.mjs} +2 -2
- package/dist/client/{RouteError-Rm08PcxN.mjs.map → RouteError-hAF8_jbe.mjs.map} +1 -1
- package/dist/client/Slot-CWb612-_.mjs.map +1 -1
- package/dist/client/{SortInput-D_q_jDfe.mjs → SortInput-Cqs2poV3.mjs} +9 -9
- package/dist/client/{SortInput-D_q_jDfe.mjs.map → SortInput-Cqs2poV3.mjs.map} +1 -1
- package/dist/client/{StatusError-2ZU1gFpu.mjs → StatusError-C5KodQOq.mjs} +7 -7
- package/dist/client/{StatusError-2ZU1gFpu.mjs.map → StatusError-C5KodQOq.mjs.map} +1 -1
- package/dist/client/TwoColumnDescriptionList-DiDx3PnH.mjs +22 -0
- package/dist/client/TwoColumnDescriptionList-DiDx3PnH.mjs.map +1 -0
- package/dist/client/{_auth-D5_QNUos.mjs → _auth-DJ9wHZaj.mjs} +2 -2
- package/dist/client/_auth-DJ9wHZaj.mjs.map +1 -0
- package/dist/client/{_flavorId-CFmkmg2Y.mjs → _flavorId-BN_qessZ.mjs} +4 -4
- package/dist/client/{_flavorId-CFmkmg2Y.mjs.map → _flavorId-BN_qessZ.mjs.map} +1 -1
- package/dist/client/_flavorId-CJjEB_Ao.mjs +210 -0
- package/dist/client/_flavorId-CJjEB_Ao.mjs.map +1 -0
- package/dist/client/{_floatingIpId-Dzh6_JCI.mjs → _floatingIpId-CwDGHkWm.mjs} +4 -4
- package/dist/client/{_floatingIpId-Dzh6_JCI.mjs.map → _floatingIpId-CwDGHkWm.mjs.map} +1 -1
- package/dist/client/_floatingIpId-foMIwbE4.mjs +215 -0
- package/dist/client/_floatingIpId-foMIwbE4.mjs.map +1 -0
- package/dist/client/_imageId-BtJ7GmYB.mjs +558 -0
- package/dist/client/_imageId-BtJ7GmYB.mjs.map +1 -0
- package/dist/client/{_projectId-D-b7paXE.mjs → _projectId-BmtCuzJu.mjs} +4 -4
- package/dist/client/{_projectId-D-b7paXE.mjs.map → _projectId-BmtCuzJu.mjs.map} +1 -1
- package/dist/client/_projectId-Byt3GQDW.mjs +99 -0
- package/dist/client/_projectId-Byt3GQDW.mjs.map +1 -0
- package/dist/client/_projectId-NYk1IN_a.mjs +291 -0
- package/dist/client/_projectId-NYk1IN_a.mjs.map +1 -0
- package/dist/client/{_projectId-CAQkJHZ4.mjs → _projectId-QueiFczy.mjs} +3 -3
- package/dist/client/{_projectId-CAQkJHZ4.mjs.map → _projectId-QueiFczy.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-DRkY3Gt6.mjs → _securityGroupId-BcbkRhsN.mjs} +4 -4
- package/dist/client/{_securityGroupId-DRkY3Gt6.mjs.map → _securityGroupId-BcbkRhsN.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-DFdNKa2l.mjs → _securityGroupId-pPtJsCoe.mjs} +541 -527
- package/dist/client/_securityGroupId-pPtJsCoe.mjs.map +1 -0
- package/dist/client/_storageType-BmqrU06i.mjs +2202 -0
- package/dist/client/_storageType-BmqrU06i.mjs.map +1 -0
- package/dist/client/_storageType-zeSZe--V.mjs.map +1 -1
- package/dist/client/{about-C8tTrQaW.mjs → about-_73VmpTB.mjs} +8 -8
- package/dist/client/about-_73VmpTB.mjs.map +1 -0
- package/dist/client/assets/objectDownload.worker-CWWLPDyb.js.map +1 -0
- package/dist/client/assets/objectDownload.worker-kZlQuo3F.js.map +1 -0
- package/dist/client/{aurora-jyvXcI4T.mjs → aurora-EbwGRLLf.mjs} +2 -2
- package/dist/client/aurora-EbwGRLLf.mjs.map +1 -0
- package/dist/client/{build-CRLQyqu2.mjs → build-C_4vRMCq.mjs} +8072 -8533
- package/dist/client/build-C_4vRMCq.mjs.map +1 -0
- package/dist/client/components/Auth/LoginForm.d.ts +1 -1
- package/dist/client/components/Auth/SessionExpirationTimer.d.ts +1 -1
- package/dist/client/components/ContentHeader/ContentHeader.d.ts +1 -1
- package/dist/client/components/Error/RouteError.d.ts +1 -1
- package/dist/client/components/Error/StatusError.d.ts +1 -1
- package/dist/client/components/JsonEditor.d.ts +1 -1
- package/dist/client/components/ListToolbar/FiltersInput.d.ts +3 -1
- package/dist/client/components/ListToolbar/SelectedFilters.d.ts +1 -1
- package/dist/client/components/ListToolbar/index.d.ts +1 -1
- package/dist/client/components/ProjectView/ProjectInfoBox.d.ts +1 -1
- package/dist/client/components/Slot.d.ts +1 -1
- package/dist/client/components/TwoColumnDescriptionList.d.ts +11 -0
- package/dist/client/components/navigation/LanguageSelect.d.ts +1 -1
- package/dist/client/components/navigation/MainNavigation.d.ts +1 -1
- package/dist/client/components/navigation/UserMenu.d.ts +1 -1
- package/dist/client/{flavors-Dy-2mRGv.mjs → flavors-CiHCYrtZ.mjs} +2 -2
- package/dist/client/{flavors-Dy-2mRGv.mjs.map → flavors-CiHCYrtZ.mjs.map} +1 -1
- package/dist/client/flavors-DWMZ6TuJ.mjs.map +1 -1
- package/dist/client/{flavors-BfTXqmoD.mjs → flavors-DY-bDc8l.mjs} +196 -194
- package/dist/client/flavors-DY-bDc8l.mjs.map +1 -0
- package/dist/client/floatingips-Ci4jHkaG.mjs +591 -0
- package/dist/client/floatingips-Ci4jHkaG.mjs.map +1 -0
- package/dist/client/formatBytes-CZv_XyCY.mjs.map +1 -1
- package/dist/client/helpers-1PpYf-fC.mjs.map +1 -1
- package/dist/client/hooks/useAvailableViewportHeight.d.ts +8 -5
- package/dist/client/hooks/useVirtualizedTableBody.d.ts +1 -3
- package/dist/client/{hooks-Bw3sHHOg.mjs → hooks-LutR2Yg3.mjs} +2 -2
- package/dist/client/{hooks-Bw3sHHOg.mjs.map → hooks-LutR2Yg3.mjs.map} +1 -1
- package/dist/client/images-91U7tr9Y2.mjs +1976 -0
- package/dist/client/images-91U7tr9Y2.mjs.map +1 -0
- package/dist/client/{images-DPKUXryV.mjs → images-CS4kZQyu.mjs} +2 -2
- package/dist/client/{images-DPKUXryV.mjs.map → images-CS4kZQyu.mjs.map} +1 -1
- package/dist/client/images-NBf2bV43.mjs.map +1 -1
- package/dist/client/index.d.ts +4 -1
- package/dist/client/index.js +559 -545
- package/dist/client/index.js.map +1 -1
- package/dist/client/{md-CyCflQee.mjs → md-kvaGCNAK.mjs} +6 -78
- package/dist/client/{md-CyCflQee.mjs.map → md-kvaGCNAK.mjs.map} +1 -1
- package/dist/client/network-DuZm76BZ.mjs.map +1 -1
- package/dist/client/objects-C3azvW8m.mjs +10074 -0
- package/dist/client/objects-C3azvW8m.mjs.map +1 -0
- package/dist/client/objects-CM265S6b.mjs +56 -0
- package/dist/client/objects-CM265S6b.mjs.map +1 -0
- package/dist/client/objects-EE9Cd1wI.mjs +56 -0
- package/dist/client/objects-EE9Cd1wI.mjs.map +1 -0
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/{routeInfo-CdTRlSxv.mjs → routeInfo-DXqB2HCf.mjs} +3 -3
- package/dist/client/routeInfo-DXqB2HCf.mjs.map +1 -0
- package/dist/client/router.d.ts +2 -1
- package/dist/client/{routes-BOf-GDMM.mjs → routes-CBd8CCuM.mjs} +27 -24
- package/dist/client/routes-CBd8CCuM.mjs.map +1 -0
- package/dist/client/{routes-CtfnI-aY.mjs → routes-CdDm-hhO.mjs} +2 -2
- package/dist/client/{routes-CtfnI-aY.mjs.map → routes-CdDm-hhO.mjs.map} +1 -1
- package/dist/client/securitygroups-Bd_uV4S9.mjs +595 -0
- package/dist/client/securitygroups-Bd_uV4S9.mjs.map +1 -0
- package/dist/client/{securitygroups-B8aLyFK7.mjs → securitygroups-Byte-iSp.mjs} +2 -2
- package/dist/client/{securitygroups-B8aLyFK7.mjs.map → securitygroups-Byte-iSp.mjs.map} +1 -1
- package/dist/client/services-D1PbooD1.mjs +6 -0
- package/dist/client/services-D1PbooD1.mjs.map +1 -0
- package/dist/client/services-DEMVtFyn.mjs +9 -0
- package/dist/client/services-DEMVtFyn.mjs.map +1 -0
- package/dist/client/store/AuthProvider.d.ts +1 -1
- package/dist/client/{trpcClient-Di56hpVv.mjs → trpcClient-D7gpR7YG.mjs} +2 -2
- package/dist/client/{trpcClient-Di56hpVv.mjs.map → trpcClient-D7gpR7YG.mjs.map} +1 -1
- package/dist/client/trpcClient.d.ts +139 -374
- package/dist/client/useModal-DCs1OJh7.mjs.map +1 -1
- package/dist/client/{useSecurityGroupPermissions-BPS1ibWq.mjs → useSecurityGroupPermissions-C29mzb3b.mjs} +15 -15
- package/dist/client/{useSecurityGroupPermissions-BPS1ibWq.mjs.map → useSecurityGroupPermissions-C29mzb3b.mjs.map} +1 -1
- package/dist/server/index.d.ts +164 -376
- package/dist/server/index.js +4223 -3131
- package/package.json +7 -9
- package/dist/client/AuthProvider-CQ6Yppoh.mjs.map +0 -1
- package/dist/client/BucketToastNotifications-Dq4dudkM.mjs +0 -665
- package/dist/client/BucketToastNotifications-Dq4dudkM.mjs.map +0 -1
- package/dist/client/ContentHeader-9KZdhOoA.mjs.map +0 -1
- package/dist/client/DeleteFlavorModal-Be2qZo4w.mjs +0 -713
- package/dist/client/DeleteFlavorModal-Be2qZo4w.mjs.map +0 -1
- package/dist/client/DeletePcaModal-CIFsGWyj.mjs +0 -80
- package/dist/client/DeletePcaModal-CIFsGWyj.mjs.map +0 -1
- package/dist/client/DetailsInfo-CHVD7d-W.mjs +0 -52
- package/dist/client/DetailsInfo-CHVD7d-W.mjs.map +0 -1
- package/dist/client/FiltersInput-DqT08Ib-.mjs +0 -81
- package/dist/client/FiltersInput-DqT08Ib-.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-BGyX2J6j.mjs +0 -1219
- package/dist/client/ImageToastNotifications-BGyX2J6j.mjs.map +0 -1
- package/dist/client/_auth-D5_QNUos.mjs.map +0 -1
- package/dist/client/_flavorId-BsmqS9hP.mjs +0 -194
- package/dist/client/_flavorId-BsmqS9hP.mjs.map +0 -1
- package/dist/client/_floatingIpId-Bb9ZEJ6b.mjs +0 -228
- package/dist/client/_floatingIpId-Bb9ZEJ6b.mjs.map +0 -1
- package/dist/client/_imageId-C3As7sHE.mjs +0 -534
- package/dist/client/_imageId-C3As7sHE.mjs.map +0 -1
- package/dist/client/_pcaId-n0q0aDb6.mjs +0 -545
- package/dist/client/_pcaId-n0q0aDb6.mjs.map +0 -1
- package/dist/client/_projectId-BuBIFdgG.mjs +0 -291
- package/dist/client/_projectId-BuBIFdgG.mjs.map +0 -1
- package/dist/client/_projectId-DNZsNxJw.mjs +0 -98
- package/dist/client/_projectId-DNZsNxJw.mjs.map +0 -1
- package/dist/client/_securityGroupId-DFdNKa2l.mjs.map +0 -1
- package/dist/client/_storageType-Cn7TSOki.mjs +0 -81
- package/dist/client/_storageType-Cn7TSOki.mjs.map +0 -1
- package/dist/client/_storageType-_8Ambhxc.mjs +0 -2859
- package/dist/client/_storageType-_8Ambhxc.mjs.map +0 -1
- package/dist/client/about-C8tTrQaW.mjs.map +0 -1
- package/dist/client/assets/objectDownload.worker-BAc5Au4B.js.map +0 -1
- package/dist/client/aurora-jyvXcI4T.mjs.map +0 -1
- package/dist/client/build-CRLQyqu2.mjs.map +0 -1
- package/dist/client/flavors-BfTXqmoD.mjs.map +0 -1
- package/dist/client/floatingips-zhNK6Xxn.mjs +0 -562
- package/dist/client/floatingips-zhNK6Xxn.mjs.map +0 -1
- package/dist/client/images-DhZnqUG_.mjs +0 -1890
- package/dist/client/images-DhZnqUG_.mjs.map +0 -1
- package/dist/client/objects-B3mbk6V0.mjs +0 -6636
- package/dist/client/objects-B3mbk6V0.mjs.map +0 -1
- package/dist/client/objects-BQ8xvSW8.mjs +0 -103
- package/dist/client/objects-BQ8xvSW8.mjs.map +0 -1
- package/dist/client/objects-o2Cj_ndZ.mjs +0 -8
- package/dist/client/objects-o2Cj_ndZ.mjs.map +0 -1
- package/dist/client/pca-B60iWWfG.mjs +0 -251
- package/dist/client/pca-B60iWWfG.mjs.map +0 -1
- package/dist/client/pca-D0kKxHp4.mjs +0 -25
- package/dist/client/pca-D0kKxHp4.mjs.map +0 -1
- package/dist/client/pcaAccess-Br4kVjLQ.mjs +0 -9
- package/dist/client/pcaAccess-Br4kVjLQ.mjs.map +0 -1
- package/dist/client/routeInfo-CdTRlSxv.mjs.map +0 -1
- package/dist/client/routes-BOf-GDMM.mjs.map +0 -1
- package/dist/client/securitygroups-DRhFle2O.mjs +0 -589
- package/dist/client/securitygroups-DRhFle2O.mjs.map +0 -1
- package/dist/client/useListWithFiltering-aPTUNRaW.mjs +0 -32
- package/dist/client/useListWithFiltering-aPTUNRaW.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"securitygroups-DRhFle2O.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","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","variant","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 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 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":"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"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { startTransition as e, useState as t } from "react";
|
|
2
|
-
//#region src/client/utils/useListWithFiltering.ts
|
|
3
|
-
function n({ defaultSortKey: n, defaultSortDir: r, sortOptions: i, filterSettings: a }) {
|
|
4
|
-
let [o, s] = t(""), c = (t) => {
|
|
5
|
-
let n = typeof t == "string" ? t : "";
|
|
6
|
-
e(() => s(n));
|
|
7
|
-
}, [l, u] = t({
|
|
8
|
-
options: i,
|
|
9
|
-
sortBy: n,
|
|
10
|
-
sortDirection: r
|
|
11
|
-
}), d = (e) => {
|
|
12
|
-
u({
|
|
13
|
-
options: e.options ?? l.options,
|
|
14
|
-
sortBy: e.sortBy?.toString() || n,
|
|
15
|
-
sortDirection: e.sortDirection || r
|
|
16
|
-
});
|
|
17
|
-
}, [f, p] = t(a);
|
|
18
|
-
return {
|
|
19
|
-
searchTerm: o,
|
|
20
|
-
sortSettings: l,
|
|
21
|
-
filterSettings: f,
|
|
22
|
-
handleSearchChange: c,
|
|
23
|
-
handleSortChange: d,
|
|
24
|
-
handleFilterChange: (t) => {
|
|
25
|
-
e(() => p(t));
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { n as t };
|
|
31
|
-
|
|
32
|
-
//# sourceMappingURL=useListWithFiltering-aPTUNRaW.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useListWithFiltering-aPTUNRaW.mjs","names":["startTransition","useState","useListWithFiltering","defaultSortKey","defaultSortDir","sortOptions","filterSettings","initialFilterSettings","searchTerm","setSearchTerm","handleSearchChange","term","searchValue","sortSettings","setSortSettings","options","sortBy","sortDirection","handleSortChange","newSortSettings","settings","toString","setFilterSettings","handleFilterChange","newFilterSettings"],"sources":["../../src/client/utils/useListWithFiltering.ts"],"sourcesContent":["import { startTransition, useState } from \"react\"\nimport { FilterSettings, SortOption, SortSettings } from \"@/client/components/ListToolbar/types\"\n\n/**\n * Sort direction enumeration\n * Used across all sort-enabled list views\n */\nexport type SortDirection = \"asc\" | \"desc\"\n\n/**\n * Generic required sort settings with guaranteed non-optional properties\n * Used by components to maintain a fully-defined sort state\n *\n * Type parameter K is the sort key type (string literal union of allowed sort fields)\n *\n * @example\n * // For floating IPs\n * type FloatingIpListSortSettings = ListSortConfig<FloatingIpsSortKey>\n *\n * // For security groups\n * type SecurityGroupListSortSettings = ListSortConfig<\"name\" | \"project_id\">\n */\nexport type ListSortConfig<T extends string = string> = {\n /**\n * Array of available sort options to display in the UI\n */\n options: SortOption[]\n /**\n * The currently selected sort field (guaranteed to be one of the available options)\n */\n sortBy: T\n /**\n * The currently active sort direction (guaranteed to be either \"asc\" or \"desc\")\n */\n sortDirection: SortDirection\n}\n\n/**\n * Configuration options for the useListWithFiltering hook\n */\nexport interface UseListWithFilteringOptions<T extends string> {\n /** Default sort key to use on initial render */\n defaultSortKey: T\n /** Default sort direction to use on initial render */\n defaultSortDir: SortDirection\n /** Available sort options to display in the sort dropdown */\n sortOptions: Array<{ label: string; value: string }>\n /** Initial filter settings configuration */\n filterSettings: FilterSettings\n}\n\n/**\n * Return value from the useListWithFiltering hook\n */\nexport interface UseListWithFilteringReturn<T extends string> {\n // State\n searchTerm: string\n sortSettings: ListSortConfig<T>\n filterSettings: FilterSettings\n\n // Handlers\n handleSearchChange: (term: string | number | string[] | undefined) => void\n handleSortChange: (newSortSettings: SortSettings) => void\n handleFilterChange: (newFilterSettings: FilterSettings) => void\n}\n\n/**\n * Custom hook to manage common list view state: search, sort, and filter\n *\n * Extracts shared logic from list components to ensure consistent behavior\n * across all list pages and reduce code duplication.\n *\n * @example\n * ```tsx\n * const listState = useListWithFiltering({\n * defaultSortKey: \"name\",\n * defaultSortDir: \"asc\",\n * sortOptions: [\n * { label: t`Name`, value: \"name\" },\n * { label: t`Created`, value: \"created_at\" },\n * ],\n * filterSettings: {\n * filters: [\n * { displayName: t`Status`, filterName: \"status\", values: [\"active\", \"inactive\"] }\n * ]\n * }\n * })\n * ```\n */\nexport function useListWithFiltering<T extends string>({\n defaultSortKey,\n defaultSortDir,\n sortOptions,\n filterSettings: initialFilterSettings,\n}: UseListWithFilteringOptions<T>): UseListWithFilteringReturn<T> {\n // Search\n const [searchTerm, setSearchTerm] = useState(\"\")\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n startTransition(() => setSearchTerm(searchValue))\n }\n\n // Sort\n const [sortSettings, setSortSettings] = useState<ListSortConfig<T>>({\n options: sortOptions,\n sortBy: defaultSortKey,\n sortDirection: defaultSortDir,\n })\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: ListSortConfig<T> = {\n options: newSortSettings.options ?? sortSettings.options,\n sortBy: (newSortSettings.sortBy?.toString() as T) || defaultSortKey,\n sortDirection: (newSortSettings.sortDirection as SortDirection) || defaultSortDir,\n }\n setSortSettings(settings)\n }\n\n // Filter\n const [filterSettings, setFilterSettings] = useState<FilterSettings>(initialFilterSettings)\n const handleFilterChange = (newFilterSettings: FilterSettings) => {\n startTransition(() => setFilterSettings(newFilterSettings))\n }\n\n return {\n searchTerm,\n sortSettings,\n filterSettings,\n handleSearchChange,\n handleSortChange,\n handleFilterChange,\n }\n}\n"],"mappings":";;AAyFA,SAAgBE,EAAuC,EACrDC,mBACAC,mBACAC,gBACAC,gBAAgBC,KACe;CAE/B,IAAM,CAACC,GAAYC,KAAiBR,EAAS,EAAA,GACvCS,KAAsBC,MAAAA;EAC1B,IAAMC,IAAc,OAAOD,KAAS,WAAWA,IAAO;EACtDX,QAAsBS,EAAcG,CAAAA,CAAAA;CACtC,GAGM,CAACC,GAAcC,KAAmBb,EAA4B;EAClEc,SAASV;EACTW,QAAQb;EACRc,eAAeb;CACjB,CAAA,GACMc,KAAoBC,MAAAA;EAMxBL,EAAgBM;GAJdL,SAASI,EAAgBJ,WAAWF,EAAaE;GACjDC,QAAQ,EAAiBA,QAAQK,SAAAA,KAAoBlB;GACrDc,eAAe,EAAiBA,iBAAmCb;EAErDgB,CAAAA;CAClB,GAGM,CAACd,GAAgBgB,KAAqBrB,EAAyBM,CAAAA;CAKrE,OAAO;EACLC;EACAK;EACAP;EACAI;EACAQ;EACAK,qBAV0BC,MAAAA;GAC1BxB,QAAsBsB,EAAkBE,CAAAA,CAAAA;EAC1C;CASA;AACF"}
|