@cobaltcore-dev/aurora 1.1.0 → 1.2.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.
Files changed (183) hide show
  1. package/README.md +59 -9
  2. package/dist/client/App.d.ts +2 -2
  3. package/dist/client/AuroraApp.d.ts +33 -13
  4. package/dist/client/{AuthProvider-BS5OVv8n.mjs → AuthProvider-CVSAwW9f.mjs} +22 -8
  5. package/dist/client/AuthProvider-CVSAwW9f.mjs.map +1 -0
  6. package/dist/client/{ContentHeader-BHMUzd9H.mjs → ContentHeader-CPJbgYWn.mjs} +18 -18
  7. package/dist/client/{ContentHeader-BHMUzd9H.mjs.map → ContentHeader-CPJbgYWn.mjs.map} +1 -1
  8. package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +773 -0
  9. package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +1 -0
  10. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs +26 -0
  11. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs.map +1 -0
  12. package/dist/client/{FiltersInput-B8CNBg1L.mjs → FiltersInput-CKI6zWnm.mjs} +18 -18
  13. package/dist/client/{FiltersInput-B8CNBg1L.mjs.map → FiltersInput-CKI6zWnm.mjs.map} +1 -1
  14. package/dist/client/FloatingIpActionModals-CwEC5GR-.mjs +460 -0
  15. package/dist/client/FloatingIpActionModals-CwEC5GR-.mjs.map +1 -0
  16. package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +1152 -0
  17. package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +1 -0
  18. package/dist/client/SortInput-4g7nSTHW.mjs +34 -0
  19. package/dist/client/SortInput-4g7nSTHW.mjs.map +1 -0
  20. package/dist/client/{TwoColumnDescriptionList-DiDx3PnH.mjs → TwoColumnDescriptionList-NvgvErua.mjs} +2 -2
  21. package/dist/client/{TwoColumnDescriptionList-DiDx3PnH.mjs.map → TwoColumnDescriptionList-NvgvErua.mjs.map} +1 -1
  22. package/dist/client/_-CAsCx-Ay.mjs +6 -0
  23. package/dist/client/_-CAsCx-Ay.mjs.map +1 -0
  24. package/dist/client/_auth-SrDjHL6j.mjs +12 -0
  25. package/dist/client/_auth-SrDjHL6j.mjs.map +1 -0
  26. package/dist/client/_flavorId-9PcBBW52.mjs +231 -0
  27. package/dist/client/_flavorId-9PcBBW52.mjs.map +1 -0
  28. package/dist/client/{_flavorId-BN_qessZ.mjs → _flavorId-a9Gu66R1.mjs} +3 -9
  29. package/dist/client/_flavorId-a9Gu66R1.mjs.map +1 -0
  30. package/dist/client/_floatingIpId-AE9Fu8l6.mjs +210 -0
  31. package/dist/client/_floatingIpId-AE9Fu8l6.mjs.map +1 -0
  32. package/dist/client/{_floatingIpId-CwDGHkWm.mjs → _floatingIpId-AZ11Ksmu.mjs} +3 -9
  33. package/dist/client/_floatingIpId-AZ11Ksmu.mjs.map +1 -0
  34. package/dist/client/{_imageId-BtJ7GmYB.mjs → _imageId-BtAql2Kr.mjs} +104 -92
  35. package/dist/client/_imageId-BtAql2Kr.mjs.map +1 -0
  36. package/dist/client/_imageId-D76BxvFY.mjs +39 -0
  37. package/dist/client/_imageId-D76BxvFY.mjs.map +1 -0
  38. package/dist/client/{_projectId-Byt3GQDW.mjs → _projectId-7Nl1MQTJ.mjs} +5 -5
  39. package/dist/client/_projectId-7Nl1MQTJ.mjs.map +1 -0
  40. package/dist/client/_projectId-B3wmSala.mjs +281 -0
  41. package/dist/client/_projectId-B3wmSala.mjs.map +1 -0
  42. package/dist/client/_projectId-DPzv0CCp.mjs +77 -0
  43. package/dist/client/_projectId-DPzv0CCp.mjs.map +1 -0
  44. package/dist/client/_projectId-DfeVJy0G.mjs +30 -0
  45. package/dist/client/_projectId-DfeVJy0G.mjs.map +1 -0
  46. package/dist/client/_securityGroupId-C5huJNfO.mjs +1810 -0
  47. package/dist/client/_securityGroupId-C5huJNfO.mjs.map +1 -0
  48. package/dist/client/{_securityGroupId-BcbkRhsN.mjs → _securityGroupId-D85mSigA.mjs} +3 -9
  49. package/dist/client/_securityGroupId-D85mSigA.mjs.map +1 -0
  50. package/dist/client/_serviceType-DS8DxsrP.mjs +20 -0
  51. package/dist/client/_serviceType-DS8DxsrP.mjs.map +1 -0
  52. package/dist/client/_serviceType-M8d9rOT6.mjs +6 -0
  53. package/dist/client/_serviceType-M8d9rOT6.mjs.map +1 -0
  54. package/dist/client/_storageType-BRWWJtow.mjs +14 -0
  55. package/dist/client/_storageType-BRWWJtow.mjs.map +1 -0
  56. package/dist/client/_storageType-CzZ4u9x_.mjs +12 -0
  57. package/dist/client/_storageType-CzZ4u9x_.mjs.map +1 -0
  58. package/dist/client/_storageType-Dy9uCVXr.mjs +845 -0
  59. package/dist/client/_storageType-Dy9uCVXr.mjs.map +1 -0
  60. package/dist/client/_storageType-zeSZe--V.mjs.map +1 -1
  61. package/dist/client/{about-_73VmpTB.mjs → about-BmQTyLWc.mjs} +2 -2
  62. package/dist/client/{about-_73VmpTB.mjs.map → about-BmQTyLWc.mjs.map} +1 -1
  63. package/dist/client/{aurora-EbwGRLLf.mjs → aurora-CIml-f2f.mjs} +2 -2
  64. package/dist/client/{aurora-EbwGRLLf.mjs.map → aurora-CIml-f2f.mjs.map} +1 -1
  65. package/dist/client/{build-C_4vRMCq.mjs → build-WuxXRAqf.mjs} +121 -24
  66. package/dist/client/{build-C_4vRMCq.mjs.map → build-WuxXRAqf.mjs.map} +1 -1
  67. package/dist/client/components/Breadcrumbs.d.ts +1 -0
  68. package/dist/client/components/ListToolbar/SortInput.d.ts +3 -0
  69. package/dist/client/context/BreadcrumbExtensionContext.d.ts +9 -0
  70. package/dist/client/context/DynamicBreadcrumbContext.d.ts +9 -0
  71. package/dist/client/{flavors-CiHCYrtZ.mjs → flavors-B0rbqffG.mjs} +3 -5
  72. package/dist/client/flavors-B0rbqffG.mjs.map +1 -0
  73. package/dist/client/flavors-DWMZ6TuJ.mjs.map +1 -1
  74. package/dist/client/flavors-Rl20bxVU.mjs +628 -0
  75. package/dist/client/flavors-Rl20bxVU.mjs.map +1 -0
  76. package/dist/client/floatingips-Cz9k80cc.mjs +8 -0
  77. package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -0
  78. package/dist/client/floatingips-xbO_mu4f.mjs +576 -0
  79. package/dist/client/floatingips-xbO_mu4f.mjs.map +1 -0
  80. package/dist/client/hooks/useBreadcrumbs.d.ts +16 -0
  81. package/dist/client/hooks/usePushBreadcrumbs.d.ts +10 -0
  82. package/dist/client/hooks/useSetBreadcrumb.d.ts +11 -0
  83. package/dist/client/{hooks-LutR2Yg3.mjs → hooks-D0yKIumu.mjs} +2 -2
  84. package/dist/client/{hooks-LutR2Yg3.mjs.map → hooks-D0yKIumu.mjs.map} +1 -1
  85. package/dist/client/images-BGQv9kKT.mjs +1983 -0
  86. package/dist/client/images-BGQv9kKT.mjs.map +1 -0
  87. package/dist/client/{images-CS4kZQyu.mjs → images-CPmMa4SQ.mjs} +3 -5
  88. package/dist/client/images-CPmMa4SQ.mjs.map +1 -0
  89. package/dist/client/images-NBf2bV43.mjs.map +1 -1
  90. package/dist/client/index.d.ts +7 -3
  91. package/dist/client/index.js +549 -535
  92. package/dist/client/index.js.map +1 -1
  93. package/dist/client/{objects-C3azvW8m.mjs → objects-BE_u5yRt.mjs} +7087 -4211
  94. package/dist/client/objects-BE_u5yRt.mjs.map +1 -0
  95. package/dist/client/objects-BN-59Th0.mjs +66 -0
  96. package/dist/client/objects-BN-59Th0.mjs.map +1 -0
  97. package/dist/client/objects-D9Luf9KB.mjs +66 -0
  98. package/dist/client/objects-D9Luf9KB.mjs.map +1 -0
  99. package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
  100. package/dist/client/routeInfo-DP3v74Wg.mjs +19 -0
  101. package/dist/client/routeInfo-DP3v74Wg.mjs.map +1 -0
  102. package/dist/client/router.d.ts +2 -2
  103. package/dist/client/{routes-CdDm-hhO.mjs → routes-CJj7SR_K.mjs} +2 -2
  104. package/dist/client/routes-CJj7SR_K.mjs.map +1 -0
  105. package/dist/client/routes-xofA3ksU.mjs +110 -0
  106. package/dist/client/routes-xofA3ksU.mjs.map +1 -0
  107. package/dist/client/securitygroups-BjhgLBHm.mjs +620 -0
  108. package/dist/client/securitygroups-BjhgLBHm.mjs.map +1 -0
  109. package/dist/client/securitygroups-CtKne8UQ.mjs +8 -0
  110. package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -0
  111. package/dist/client/{securitygroups-Byte-iSp.mjs → securitygroups-DEJQBcxm.mjs} +3 -5
  112. package/dist/client/securitygroups-DEJQBcxm.mjs.map +1 -0
  113. package/dist/client/trpcClient.d.ts +135 -3
  114. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs +54 -0
  115. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs.map +1 -0
  116. package/dist/client/useModalTracking-BcOKTYRN.mjs +33 -0
  117. package/dist/client/useModalTracking-BcOKTYRN.mjs.map +1 -0
  118. package/dist/client/{useSecurityGroupPermissions-C29mzb3b.mjs → useSecurityGroupPermissions-BOyLQLdC.mjs} +85 -19
  119. package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +1 -0
  120. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs +19 -0
  121. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs.map +1 -0
  122. package/dist/client/utils/formatSwiftDate.d.ts +30 -0
  123. package/dist/server/index.d.ts +136 -4
  124. package/dist/server/index.js +845 -260
  125. package/package.json +37 -36
  126. package/dist/client/AuthProvider-BS5OVv8n.mjs.map +0 -1
  127. package/dist/client/DeleteFlavorModal-BP83t9zX.mjs +0 -721
  128. package/dist/client/DeleteFlavorModal-BP83t9zX.mjs.map +0 -1
  129. package/dist/client/FloatingIpActionModals-BraiJWBi.mjs +0 -417
  130. package/dist/client/FloatingIpActionModals-BraiJWBi.mjs.map +0 -1
  131. package/dist/client/ImageToastNotifications-BXMHJaIH.mjs +0 -1131
  132. package/dist/client/ImageToastNotifications-BXMHJaIH.mjs.map +0 -1
  133. package/dist/client/RouteError-hAF8_jbe.mjs +0 -25
  134. package/dist/client/RouteError-hAF8_jbe.mjs.map +0 -1
  135. package/dist/client/SortInput-Cqs2poV3.mjs +0 -34
  136. package/dist/client/SortInput-Cqs2poV3.mjs.map +0 -1
  137. package/dist/client/StatusError-C5KodQOq.mjs +0 -39
  138. package/dist/client/StatusError-C5KodQOq.mjs.map +0 -1
  139. package/dist/client/_auth-DJ9wHZaj.mjs +0 -11
  140. package/dist/client/_auth-DJ9wHZaj.mjs.map +0 -1
  141. package/dist/client/_flavorId-BN_qessZ.mjs.map +0 -1
  142. package/dist/client/_flavorId-CJjEB_Ao.mjs +0 -210
  143. package/dist/client/_flavorId-CJjEB_Ao.mjs.map +0 -1
  144. package/dist/client/_floatingIpId-CwDGHkWm.mjs.map +0 -1
  145. package/dist/client/_floatingIpId-foMIwbE4.mjs +0 -215
  146. package/dist/client/_floatingIpId-foMIwbE4.mjs.map +0 -1
  147. package/dist/client/_imageId-BtJ7GmYB.mjs.map +0 -1
  148. package/dist/client/_projectId-BmtCuzJu.mjs +0 -29
  149. package/dist/client/_projectId-BmtCuzJu.mjs.map +0 -1
  150. package/dist/client/_projectId-Byt3GQDW.mjs.map +0 -1
  151. package/dist/client/_projectId-NYk1IN_a.mjs +0 -291
  152. package/dist/client/_projectId-NYk1IN_a.mjs.map +0 -1
  153. package/dist/client/_projectId-QueiFczy.mjs +0 -46
  154. package/dist/client/_projectId-QueiFczy.mjs.map +0 -1
  155. package/dist/client/_securityGroupId-BcbkRhsN.mjs.map +0 -1
  156. package/dist/client/_securityGroupId-pPtJsCoe.mjs +0 -1797
  157. package/dist/client/_securityGroupId-pPtJsCoe.mjs.map +0 -1
  158. package/dist/client/_storageType-BmqrU06i.mjs +0 -2202
  159. package/dist/client/_storageType-BmqrU06i.mjs.map +0 -1
  160. package/dist/client/components/Error/StatusError.d.ts +0 -11
  161. package/dist/client/components/ProjectView/ProjectInfoBox.d.ts +0 -12
  162. package/dist/client/flavors-CiHCYrtZ.mjs.map +0 -1
  163. package/dist/client/flavors-DY-bDc8l.mjs +0 -650
  164. package/dist/client/flavors-DY-bDc8l.mjs.map +0 -1
  165. package/dist/client/floatingips-Ci4jHkaG.mjs +0 -591
  166. package/dist/client/floatingips-Ci4jHkaG.mjs.map +0 -1
  167. package/dist/client/images-91U7tr9Y2.mjs +0 -1976
  168. package/dist/client/images-91U7tr9Y2.mjs.map +0 -1
  169. package/dist/client/images-CS4kZQyu.mjs.map +0 -1
  170. package/dist/client/objects-C3azvW8m.mjs.map +0 -1
  171. package/dist/client/objects-CM265S6b.mjs +0 -56
  172. package/dist/client/objects-CM265S6b.mjs.map +0 -1
  173. package/dist/client/objects-EE9Cd1wI.mjs +0 -56
  174. package/dist/client/objects-EE9Cd1wI.mjs.map +0 -1
  175. package/dist/client/routeInfo-DXqB2HCf.mjs +0 -32
  176. package/dist/client/routeInfo-DXqB2HCf.mjs.map +0 -1
  177. package/dist/client/routes-CBd8CCuM.mjs +0 -115
  178. package/dist/client/routes-CBd8CCuM.mjs.map +0 -1
  179. package/dist/client/routes-CdDm-hhO.mjs.map +0 -1
  180. package/dist/client/securitygroups-Bd_uV4S9.mjs +0 -595
  181. package/dist/client/securitygroups-Bd_uV4S9.mjs.map +0 -1
  182. package/dist/client/securitygroups-Byte-iSp.mjs.map +0 -1
  183. package/dist/client/useSecurityGroupPermissions-C29mzb3b.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securitygroups-BjhgLBHm.mjs","names":["z","useForm","useStore","React","Modal","Stack","Message","Form","FormSection","TextInput","useModalTracking","DeleteSecurityGroupDialog","isOpen","onClose","securityGroup","onDelete","isDeleting","error","useLingui","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","id","canDelete","store","state","isSubmitting","values","securityGroupName","name","handleClose","reset","open","onCancel","size","title","confirmButtonLabel","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","p","className","e","preventDefault","Field","children","field","label","onChange","handleChange","target","placeholder","disabled","autoComplete","autoFocus","data-testid","required","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","Checkbox","SecurityGroupTableRow","securityGroup","sg","permissions","onEdit","onDelete","onViewDetails","isReadOnly","showSelectColumn","isSelected","onSelect","useLingui","BooleanValue","value","span","t","handleShowDetails","data-testid","id","onClick","className","e","stopPropagation","checked","onChange","div","p","name","description","shared","project_id","stateful","label","canUpdate","canDelete","useState","useEffect","useRef","DataGrid","DataGridCell","DataGridHeadCell","DataGridRow","Status","useNavigate","useProjectId","EditSecurityGroupModal","DeleteSecurityGroupDialog","SecurityGroupTableRow","SecurityGroupListContainer","securityGroups","isLoading","isError","error","permissions","onDeleteSecurityGroup","isDeletingSecurityGroup","deleteError","onUpdateSecurityGroup","isUpdatingSecurityGroup","updateError","currentProjectId","hasAnyBulkAction","onClearUpdateError","useLingui","navigate","projectId","selectedSecurityGroup","setSelectedSecurityGroup","editModalOpen","setEditModalOpen","deleteDialogOpen","setDeleteDialogOpen","prevIsDeletingRef","prevIsUpdatingRef","handleEdit","sg","id","handleDelete","handleViewDetails","to","params","securityGroupId","closeEditModal","closeDeleteDialog","deletionJustFinished","current","updateJustFinished","status","title","t","message","columns","minContentColumns","map","label","length","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","showSelectColumn","isSelected","onSelect","colSpan","body","open","onClose","onUpdate","data","Promise","resolve","isOpen","isDeleting","React","useState","Modal","Form","FormRow","FormSection","TextInput","Checkbox","Button","ButtonRow","Spinner","ModalFooter","Textarea","Message","defaultSecurityGroupValues","name","description","stateful","CreateSecurityGroupModal","isOpen","onClose","onCreate","isLoading","error","useLingui","properties","setProperties","errors","setErrors","handleInputChange","e","value","type","target","checked","prev","newErrors","validateForm","trim","t","Object","keys","length","handleSubmit","preventDefault","securityGroupData","undefined","handleClose","open","onCancel","size","title","modalFooter","className","variant","onClick","disabled","data-testid","dismissible","div","span","id","label","onChange","required","errortext","placeholder","rows","helptext","parseFiltersFromUrl","searchParams","filters","shared","push","name","value","buildFilterParams","selectedFilters","filterDefinitions","params","length","filterGroups","filter","sf","inactive","reduce","acc","Object","entries","forEach","filterName","values","filterDef","find","f","supportsMultiValue","join","applyFilterSelection","current","selected","alreadySelected","some","supportsMulti","buildUrlSearchParams","baseParams","newParams","search","sortBy","sortDirection","useState","useEffect","useNavigate","useSearch","Button","Stack","DataGridToolbar","SearchInput","toast","Status","ContentHeader","trpcReact","SortInput","SelectedFilters","FiltersInput","SecurityGroupListContainer","CreateSecurityGroupModal","useSecurityGroupPermissions","parseFiltersFromUrl","buildFilterParams","buildUrlSearchParams","applyFilterSelection","getSecurityGroupDeletedToast","getSecurityGroupDeleteErrorToast","getSecurityGroupUpdatedToast","getSecurityGroupUpdateErrorToast","SecurityGroups","project","projectId","useLingui","navigate","searchParams","strict","sortSettings","setSortSettings","options","label","t","value","sortBy","sortDirection","filterSettings","setFilterSettings","filters","displayName","filterName","values","supportsMultiValue","selectedFilters","searchTerm","setSearchTerm","search","createModalOpen","setCreateModalOpen","deleteError","setDeleteError","createError","setCreateError","updateError","setUpdateError","utils","useUtils","prev","shared","urlFilters","urlSortBy","urlSortDirection","urlSearchTerm","data","securityGroupsData","isLoading","isError","error","network","securityGroup","list","useQuery","project_id","sort_key","sort_dir","refetchOnWindowFocus","securityGroups","listError","code","permissions","createSecurityGroupMutation","create","useMutation","onSuccess","createdSecurityGroup","invalidate","getById","to","params","securityGroupId","id","onError","message","deleteSecurityGroupMutation","deleteById","updateSecurityGroupMutation","update","handleCreateSecurityGroup","securityGroupData","mutateAsync","handleDeleteSecurityGroup","sgName","find","sg","name","mutate","success","handleUpdateSecurityGroup","handleClearUpdateError","handleSortChange","newSortSettings","settings","toString","replace","handleFilterChange","newFilterSettings","handleSearchChange","term","searchValue","undefined","status","title","length","className","distribution","alignment","direction","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","variant","comboboxClassName","onChange","selected","newSelected","placeholder","data-testid","onInput","e","currentTarget","onSearch","onClear","onDelete","filterToRemove","filter","f","onCreateClick","onDeleteSecurityGroup","isDeletingSecurityGroup","isPending","onUpdateSecurityGroup","isUpdatingSecurityGroup","currentProjectId","hasAnyBulkAction","onClearUpdateError","isOpen","onClose","onCreate","SecurityGroups","Route","RouteComponent","projectId","useParams","trpcClient","useRouteContext","Error","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/DeleteSecurityGroupDialog.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupTableRow.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupListContainer.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/-modals/CreateSecurityGroupModal.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/urlHelpers.ts","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/-components/SecurityGroupsList.tsx","../../src/client/routes/_auth/projects/$projectId/network/securitygroups/index.tsx?tsr-split=component"],"sourcesContent":["import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport React from \"react\"\nimport { Modal, Stack, Message, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteSecurityGroupDialogProps {\n isOpen: boolean\n securityGroup: SecurityGroup\n onClose: () => void\n onDelete: (securityGroupId: string) => void\n isDeleting?: boolean\n error?: string | null\n}\n\nexport const DeleteSecurityGroupDialog: React.FC<DeleteSecurityGroupDialogProps> = ({\n isOpen,\n onClose,\n securityGroup,\n onDelete,\n isDeleting = false,\n error = null,\n}) => {\n const { t } = useLingui()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"network.securitygroup.delete\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"delete\", {\n message: t`Type \"delete\" to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (isDeleting) return\n\n markSubmitted()\n onDelete(securityGroup.id)\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n const securityGroupName = securityGroup.name || securityGroup.id\n\n const handleClose = () => {\n trackClose()\n form.reset()\n resetTracking()\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"small\"\n title={t`Delete Security Group \"${securityGroupName}\"`}\n confirmButtonLabel={isDeleting ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={form.handleSubmit}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={canDelete || isDeleting}\n disableCancelButton={isDeleting}\n disableCloseButton={isDeleting}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {error && <Message variant=\"error\">{error}</Message>}\n\n <p className=\"text-theme-default\">\n <Trans>This action cannot be undone. The security group will be permanently deleted.</Trans>\n </p>\n\n <Form\n className=\"mb-0\"\n id=\"delete-security-group-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n children={(field) => (\n <TextInput\n label={t`Type \"delete\" to confirm`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder=\"delete\"\n disabled={isDeleting}\n autoComplete=\"off\"\n autoFocus\n data-testid=\"delete-confirmation-input\"\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n </Modal>\n )\n}\n","import {\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Checkbox,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useLingui, Trans } from \"@lingui/react/macro\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\n\nexport interface SecurityGroupPermissions {\n canView: boolean\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n canCreateRule: boolean\n canDeleteRule: boolean\n canManageAccess: boolean\n canViewRBAC: boolean\n}\n\ninterface SecurityGroupTableRowProps {\n securityGroup: SecurityGroup\n permissions: SecurityGroupPermissions\n onEdit: (sg: SecurityGroup) => void\n onDelete: (sg: SecurityGroup) => void\n onViewDetails?: (sg: SecurityGroup) => void\n isReadOnly?: boolean\n showSelectColumn?: boolean\n isSelected?: boolean\n onSelect?: (sg: SecurityGroup) => void\n}\n\nexport function SecurityGroupTableRow({\n securityGroup: sg,\n permissions,\n onEdit,\n onDelete,\n onViewDetails,\n isReadOnly = false,\n showSelectColumn = false,\n isSelected = false,\n onSelect,\n}: SecurityGroupTableRowProps) {\n const { t } = useLingui()\n\n const BooleanValue = ({ value }: { value: boolean | undefined }) => <span>{value ? t`Yes` : t`No`}</span>\n\n const handleShowDetails = () => {\n if (onViewDetails) {\n onViewDetails(sg)\n }\n }\n\n return (\n <DataGridRow\n key={sg.id}\n data-testid={`security-group-row-${sg.id}`}\n onClick={handleShowDetails}\n className=\"hover:bg-theme-background-lvl-2 cursor-pointer\"\n >\n {showSelectColumn && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <Checkbox checked={isSelected} onChange={() => onSelect?.(sg)} />\n </DataGridCell>\n )}\n <DataGridCell>\n <div>\n <p className=\"text-md\">{sg.name}</p>\n </div>\n </DataGridCell>\n <DataGridCell>{sg.description || t`—`}</DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.shared} />\n {sg.shared && (\n <p>\n <Trans>Owner</Trans>: <span className=\"text-theme-light text-xs\">{sg.project_id}</span>\n </p>\n )}\n </DataGridCell>\n <DataGridCell>\n <BooleanValue value={sg.stateful} />\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end justify-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={() => handleShowDetails()} />\n {permissions.canUpdate && !isReadOnly && <PopupMenuItem label={t`Edit`} onClick={() => onEdit(sg)} />}\n {permissions.canDelete && !isReadOnly && <PopupMenuItem label={t`Delete`} onClick={() => onDelete(sg)} />}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n}\n","import { useState, useEffect, useRef } from \"react\"\nimport { DataGrid, DataGridCell, DataGridHeadCell, DataGridRow, Status } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { useProjectId } from \"@/client/hooks\"\nimport type { SecurityGroup } from \"@/server/Network/types/securityGroup\"\nimport type { UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { EditSecurityGroupModal } from \"./-modals/EditSecurityGroupModal\"\nimport { DeleteSecurityGroupDialog } from \"./-modals/DeleteSecurityGroupDialog\"\nimport { SecurityGroupTableRow, type SecurityGroupPermissions } from \"./SecurityGroupTableRow\"\n\ninterface SecurityGroupListContainerProps {\n securityGroups: SecurityGroup[]\n isLoading: boolean\n isError: boolean\n error: { message?: string } | null\n permissions: SecurityGroupPermissions\n onCreateClick?: () => void\n onDeleteSecurityGroup?: (securityGroupId: string) => void\n isDeletingSecurityGroup?: boolean\n deleteError?: string | null\n onUpdateSecurityGroup?: (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => Promise<void>\n isUpdatingSecurityGroup?: boolean\n updateError?: string | null\n currentProjectId?: string\n hasAnyBulkAction?: boolean\n onClearUpdateError?: () => void\n}\n\nexport const SecurityGroupListContainer = ({\n securityGroups,\n isLoading,\n isError,\n error,\n permissions,\n onDeleteSecurityGroup,\n isDeletingSecurityGroup = false,\n deleteError = null,\n onUpdateSecurityGroup,\n isUpdatingSecurityGroup = false,\n updateError = null,\n currentProjectId,\n hasAnyBulkAction = false,\n onClearUpdateError,\n}: SecurityGroupListContainerProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const projectId = useProjectId()\n const [selectedSecurityGroup, setSelectedSecurityGroup] = useState<SecurityGroup | null>(null)\n const [editModalOpen, setEditModalOpen] = useState(false)\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)\n const prevIsDeletingRef = useRef<boolean>(false)\n const prevIsUpdatingRef = useRef<boolean>(false)\n\n const handleEdit = (sg: SecurityGroup) => {\n // Clear error when selecting a different security group\n if (selectedSecurityGroup && selectedSecurityGroup.id !== sg.id && onClearUpdateError) {\n onClearUpdateError()\n }\n setSelectedSecurityGroup(sg)\n setEditModalOpen(true)\n }\n\n const handleDelete = (sg: SecurityGroup) => {\n setSelectedSecurityGroup(sg)\n setDeleteDialogOpen(true)\n }\n\n const handleViewDetails = (sg: SecurityGroup) => {\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: { projectId, securityGroupId: sg.id },\n })\n }\n\n const closeEditModal = () => {\n setSelectedSecurityGroup(null)\n setEditModalOpen(false)\n }\n\n const closeDeleteDialog = () => {\n setSelectedSecurityGroup(null)\n setDeleteDialogOpen(false)\n }\n\n // Close delete dialog when deletion completes successfully\n useEffect(() => {\n // Check if deletion just finished (was deleting before, now not deleting)\n const deletionJustFinished = prevIsDeletingRef.current && !isDeletingSecurityGroup\n\n // Close dialog if deletion just finished and there's no error\n if (deletionJustFinished && deleteDialogOpen && !deleteError) {\n closeDeleteDialog()\n }\n\n // Update the ref for next render\n prevIsDeletingRef.current = isDeletingSecurityGroup\n }, [isDeletingSecurityGroup, deleteError, deleteDialogOpen])\n\n // Close edit modal when update completes successfully\n useEffect(() => {\n // Check if update just finished (was updating before, now not updating)\n const updateJustFinished = prevIsUpdatingRef.current && !isUpdatingSecurityGroup\n\n // Close modal if update just finished and there's no error\n if (updateJustFinished && editModalOpen && !updateError) {\n closeEditModal()\n }\n\n // Update the ref for next render\n prevIsUpdatingRef.current = isUpdatingSecurityGroup\n }, [isUpdatingSecurityGroup, updateError, editModalOpen])\n\n // Loading state\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading...`} />\n }\n\n // Error state\n if (isError) {\n return <Status status=\"error\" title={error?.message ?? t`Failed to load security groups`} />\n }\n\n return (\n <>\n <DataGrid columns={hasAnyBulkAction ? 6 : 5} minContentColumns={hasAnyBulkAction ? [5] : [4]}>\n <DataGridRow>\n {hasAnyBulkAction && <DataGridHeadCell />}\n {[t`Name`, t`Description`, t`Shared`, t`Stateful`, \"\"].map((label) => (\n <DataGridHeadCell key={label}>{label}</DataGridHeadCell>\n ))}\n </DataGridRow>\n\n {securityGroups && securityGroups.length > 0 ? (\n securityGroups.map((sg) => {\n // Compute isReadOnly only when the security group has an explicit project owner\n const isReadOnly = Boolean(currentProjectId && sg.project_id && sg.project_id !== currentProjectId)\n\n return (\n <SecurityGroupTableRow\n key={sg.id}\n securityGroup={sg}\n permissions={permissions}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onViewDetails={handleViewDetails}\n isReadOnly={isReadOnly}\n showSelectColumn={hasAnyBulkAction}\n isSelected={false}\n onSelect={() => {}}\n />\n )\n })\n ) : (\n <DataGridRow>\n <DataGridCell colSpan={hasAnyBulkAction ? 6 : 5}>\n <Status\n status=\"empty\"\n title={t`No security groups found`}\n body={t`There are no security groups available for this project with the current filters applied. Try adjusting your filter criteria or create a new security group to get started.`}\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n\n {selectedSecurityGroup && (\n <>\n <EditSecurityGroupModal\n securityGroup={selectedSecurityGroup}\n open={editModalOpen}\n onClose={closeEditModal}\n onUpdate={(id, data) => {\n if (onUpdateSecurityGroup) {\n return onUpdateSecurityGroup(id, data)\n }\n return Promise.resolve()\n }}\n isLoading={isUpdatingSecurityGroup}\n error={updateError}\n />\n <DeleteSecurityGroupDialog\n securityGroup={selectedSecurityGroup}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onDelete={(id) => {\n if (onDeleteSecurityGroup) {\n onDeleteSecurityGroup(id)\n }\n }}\n isDeleting={isDeletingSecurityGroup}\n error={deleteError}\n />\n </>\n )}\n </>\n )\n}\n","import React, { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Checkbox,\n Button,\n ButtonRow,\n Spinner,\n ModalFooter,\n Textarea,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CreateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\n\ninterface CreateSecurityGroupModalProps {\n isOpen: boolean\n onClose: () => void\n onCreate: (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => Promise<void>\n isLoading?: boolean\n error?: string | null\n}\n\ninterface SecurityGroupProperties {\n name: string\n description: string\n stateful: boolean\n}\n\nconst defaultSecurityGroupValues: SecurityGroupProperties = {\n name: \"\",\n description: \"\",\n stateful: true,\n}\n\nexport const CreateSecurityGroupModal: React.FC<CreateSecurityGroupModalProps> = ({\n isOpen,\n onClose,\n onCreate,\n isLoading = false,\n error = null,\n}) => {\n const { t } = useLingui()\n\n const [properties, setProperties] = useState<SecurityGroupProperties>({ ...defaultSecurityGroupValues })\n const [errors, setErrors] = useState<{ [key: string]: string }>({})\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value, type } = e.target\n const checked = (e.target as HTMLInputElement).checked\n\n setProperties((prev) => ({\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }))\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n\n const validateForm = (): boolean => {\n const newErrors: { [key: string]: string } = {}\n\n if (!properties.name || properties.name.trim() === \"\") {\n newErrors.name = t`Security group name is required`\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n\n if (!validateForm()) {\n return\n }\n\n const securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\"> = {\n name: properties.name.trim(),\n description: properties.description.trim() || undefined,\n stateful: properties.stateful,\n }\n\n await onCreate(securityGroupData)\n handleClose()\n }\n\n const handleClose = () => {\n setProperties({ ...defaultSecurityGroupValues })\n setErrors({})\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n size=\"large\"\n title={t`Create Security Group`}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={handleClose} disabled={isLoading}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary\"\n onClick={(e) => {\n handleSubmit(e)\n }}\n disabled={isLoading}\n data-testid=\"create-security-group-button\"\n >\n {isLoading ? <Spinner size=\"small\" /> : <Trans>Create Security Group</Trans>}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {/* Error Message */}\n {error && (\n <Message dismissible={false} variant=\"error\" className=\"mb-4\">\n {error}\n </Message>\n )}\n\n {isLoading && (\n <div className=\"mb-4 flex items-center justify-center gap-2\">\n <Spinner variant=\"primary\" />\n <span className=\"text-theme-high text-sm\">\n <Trans>Creating security group...</Trans>\n </span>\n </div>\n )}\n\n {!isLoading && (\n <Form className=\"mb-6\">\n <FormSection className=\"mb-6\">\n <FormRow className=\"mb-6\">\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Name`}\n value={properties.name}\n onChange={handleInputChange}\n required\n errortext={errors.name}\n placeholder={t`Type name`}\n disabled={isLoading}\n />\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <Textarea\n id=\"description\"\n name=\"description\"\n label={t`Description`}\n value={properties.description}\n onChange={handleInputChange}\n placeholder={t`Description`}\n disabled={isLoading}\n rows={3}\n />\n </FormRow>\n\n <FormRow className=\"mb-0\">\n <Checkbox\n id=\"stateful\"\n name=\"stateful\"\n label={t`Stateful`}\n checked={properties.stateful}\n onChange={handleInputChange}\n disabled={isLoading}\n helptext={t`Stateful security groups track connection state. This setting cannot be changed after creation.`}\n />\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import { SelectedFilter, Filter } from \"@/client/components/ListToolbar/types\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n}\n\n/**\n * Parses URL search params into SelectedFilter array for ListToolbar\n */\nexport const parseFiltersFromUrl = (searchParams: SecurityGroupsSearchParams): SelectedFilter[] => {\n const filters: SelectedFilter[] = []\n\n // Shared filter\n if (searchParams.shared) {\n filters.push({ name: \"shared\", value: searchParams.shared })\n }\n\n return filters\n}\n\n/**\n * Builds filter parameters for API request from SelectedFilter array\n */\nexport const buildFilterParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[]\n): Record<string, string> => {\n const params: Record<string, string> = {}\n\n if (!selectedFilters?.length) return params\n\n // Group selected filters by filter name\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n // Build parameters based on whether filter supports multiple values\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n params[filterName] = `in:${values.join(\",\")}`\n } else {\n params[filterName] = values[0]\n }\n })\n\n return params\n}\n\n/**\n * Merges a newly selected filter into the current list.\n * - Ignores duplicates (same name + value).\n * - For single-value filters, replaces any existing entry with the same name.\n * - For multi-value filters, appends.\n */\nexport const applyFilterSelection = (\n current: SelectedFilter[],\n selected: SelectedFilter,\n filterDefinitions: Filter[]\n): SelectedFilter[] => {\n const alreadySelected = current.some((f) => f.name === selected.name && f.value === selected.value)\n if (alreadySelected) return current\n\n const supportsMulti = filterDefinitions.find((f) => f.filterName === selected.name)?.supportsMultiValue\n return supportsMulti ? [...current, selected] : [...current.filter((f) => f.name !== selected.name), selected]\n}\n\n/**\n * Builds URL search params object from filter settings for navigation\n */\nexport const buildUrlSearchParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[],\n baseParams: {\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n }\n): SecurityGroupsSearchParams => {\n const newParams: SecurityGroupsSearchParams = {\n search: baseParams.search,\n sortBy: baseParams.sortBy,\n sortDirection: baseParams.sortDirection,\n }\n\n if (!selectedFilters?.length) return newParams\n\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n // Type assertion needed because we're dynamically setting filter fields\n ;(newParams as Record<string, string>)[filterName] = `in:${values.join(\",\")}`\n } else {\n ;(newParams as Record<string, string>)[filterName] = values[0]\n }\n })\n\n return newParams\n}\n","import { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\nimport { Button, Stack, DataGridToolbar, SearchInput, toast, Status } from \"@cloudoperators/juno-ui-components\"\nimport { CreateSecurityGroupInput, UpdateSecurityGroupInput } from \"@/server/Network/types/securityGroup\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SelectedFilters } from \"@/client/components/ListToolbar/SelectedFilters\"\nimport { FiltersInput } from \"@/client/components/ListToolbar/FiltersInput\"\nimport { FilterSettings, SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { SecurityGroupListContainer } from \"./SecurityGroupListContainer\"\nimport { CreateSecurityGroupModal } from \"./-modals/CreateSecurityGroupModal\"\nimport { useSecurityGroupPermissions } from \"../-hooks/useSecurityGroupPermissions\"\nimport { parseFiltersFromUrl, buildFilterParams, buildUrlSearchParams, applyFilterSelection } from \"../urlHelpers\"\nimport {\n getSecurityGroupDeletedToast,\n getSecurityGroupDeleteErrorToast,\n getSecurityGroupUpdatedToast,\n getSecurityGroupUpdateErrorToast,\n} from \"./SecurityGroupToastNotifications\"\n\ntype SecurityGroupSortKey = \"name\" | \"project_id\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n}\n\ntype RequiredSortSettings = {\n options: SortSettings[\"options\"]\n sortBy: string\n sortDirection: \"asc\" | \"desc\"\n}\n\ninterface SecurityGroupsProps {\n project: string\n}\n\nexport const SecurityGroups = ({ project: projectId }: SecurityGroupsProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const searchParams = useSearch({ strict: false }) as SecurityGroupsSearchParams\n\n const [sortSettings, setSortSettings] = useState<RequiredSortSettings>({\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`Project id`, value: \"project_id\" },\n ],\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n })\n\n const [filterSettings, setFilterSettings] = useState<FilterSettings>({\n filters: [\n {\n displayName: t`Shared`,\n filterName: \"shared\",\n values: [\"true\", \"false\"],\n supportsMultiValue: false,\n },\n ],\n selectedFilters: parseFiltersFromUrl(searchParams),\n })\n\n const [searchTerm, setSearchTerm] = useState(searchParams.search || \"\")\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [deleteError, setDeleteError] = useState<string | null>(null)\n const [createError, setCreateError] = useState<string | null>(null)\n const [updateError, setUpdateError] = useState<string | null>(null)\n\n const utils = trpcReact.useUtils()\n\n useEffect(() => {\n setSortSettings((prev) => ({\n ...prev,\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n }))\n setFilterSettings((prev) => ({\n ...prev,\n selectedFilters: parseFiltersFromUrl(searchParams),\n }))\n setSearchTerm(searchParams.search || \"\")\n }, [searchParams.sortBy, searchParams.sortDirection, searchParams.search, searchParams.shared])\n\n const urlFilters = parseFiltersFromUrl(searchParams)\n const urlSortBy = (searchParams.sortBy || \"name\") as SecurityGroupSortKey\n const urlSortDirection = searchParams.sortDirection || \"asc\"\n const urlSearchTerm = searchParams.search || \"\"\n\n const {\n data: securityGroupsData,\n isLoading,\n isError,\n error,\n } = trpcReact.network.securityGroup.list.useQuery(\n {\n project_id: projectId || \"\",\n sort_key: urlSortBy,\n sort_dir: urlSortDirection,\n ...buildFilterParams(urlFilters, filterSettings.filters),\n ...(urlSearchTerm ? { searchTerm: urlSearchTerm } : {}),\n },\n {\n refetchOnWindowFocus: false,\n }\n )\n\n const securityGroups = securityGroupsData || []\n const listError =\n isError && error?.data?.code === \"FORBIDDEN\" ? t`You do not have permission to view security groups` : null\n\n const { permissions } = useSecurityGroupPermissions(projectId)\n\n const createSecurityGroupMutation = trpcReact.network.securityGroup.create.useMutation({\n onSuccess: (createdSecurityGroup) => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setCreateError(null)\n navigate({\n to: \"/projects/$projectId/network/securitygroups/$securityGroupId\",\n params: {\n projectId,\n securityGroupId: createdSecurityGroup.id,\n },\n })\n },\n onError: (error) => {\n setCreateError(error.message || t`Failed to create security group`)\n },\n })\n\n const deleteSecurityGroupMutation = trpcReact.network.securityGroup.deleteById.useMutation({\n onSuccess: () => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setDeleteError(null)\n },\n onError: (error) => {\n setDeleteError(error.message || t`Failed to delete security group`)\n const { message, ...options } = getSecurityGroupDeleteErrorToast(error.message)\n toast.error(message, options)\n },\n })\n\n const updateSecurityGroupMutation = trpcReact.network.securityGroup.update.useMutation({\n onSuccess: () => {\n utils.network.securityGroup.list.invalidate()\n utils.network.securityGroup.getById.invalidate()\n setUpdateError(null)\n },\n onError: (error) => {\n setUpdateError(error.message || t`Failed to update security group`)\n const { message, ...options } = getSecurityGroupUpdateErrorToast(error.message)\n toast.error(message, options)\n },\n })\n\n const handleCreateSecurityGroup = async (securityGroupData: Omit<CreateSecurityGroupInput, \"project_id\">) => {\n setCreateError(null)\n try {\n await createSecurityGroupMutation.mutateAsync({ project_id: projectId, ...securityGroupData })\n } catch {\n // onError handles error state and UI feedback\n }\n }\n\n const handleDeleteSecurityGroup = (securityGroupId: string) => {\n setDeleteError(null)\n const sgName = securityGroups.find((sg) => sg.id === securityGroupId)?.name || securityGroupId\n deleteSecurityGroupMutation.mutate(\n { project_id: projectId, securityGroupId },\n {\n onSuccess: () => {\n const { message, ...options } = getSecurityGroupDeletedToast(sgName)\n toast.success(message, options)\n },\n }\n )\n }\n\n const handleUpdateSecurityGroup = async (\n securityGroupId: string,\n data: Omit<UpdateSecurityGroupInput, \"securityGroupId\" | \"project_id\">\n ) => {\n setUpdateError(null)\n const sgName = data.name || securityGroups.find((sg) => sg.id === securityGroupId)?.name || securityGroupId\n try {\n await updateSecurityGroupMutation.mutateAsync({ project_id: projectId, securityGroupId, ...data })\n const { message, ...options } = getSecurityGroupUpdatedToast(sgName)\n toast.success(message, options)\n } catch {\n // onError handles error state and UI feedback\n }\n }\n\n const handleClearUpdateError = () => {\n setUpdateError(null)\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: RequiredSortSettings = {\n options: newSortSettings.options,\n sortBy: newSortSettings.sortBy?.toString() || \"name\",\n sortDirection: newSortSettings.sortDirection || \"asc\",\n }\n setSortSettings(settings)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) => ({\n ...prev,\n sortBy: settings.sortBy,\n sortDirection: settings.sortDirection,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleFilterChange = (newFilterSettings: FilterSettings) => {\n setFilterSettings(newFilterSettings)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) =>\n buildUrlSearchParams(newFilterSettings.selectedFilters || [], newFilterSettings.filters, {\n search: prev.search,\n sortBy: prev.sortBy,\n sortDirection: prev.sortDirection,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n setSearchTerm(searchValue)\n navigate({\n search: ((prev: SecurityGroupsSearchParams) => ({\n ...prev,\n search: searchValue || undefined,\n })) as unknown as true,\n replace: true,\n })\n }\n\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Security Groups...`} />\n }\n\n if (isError && !securityGroups.length) {\n return (\n <Stack className=\"py-8\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n {listError || t`Failed to load security groups`}\n </Stack>\n )\n }\n\n return (\n <>\n <ContentHeader title={t`Security Groups`} projectId={projectId} />\n\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"2\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-40\"\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n {permissions.canCreate && (\n <Button onClick={() => setCreateModalOpen(true)} variant=\"primary\" className=\"whitespace-nowrap\">\n <Trans>Create Security Group</Trans>\n </Button>\n )}\n </Stack>\n </Stack>\n\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"between\" alignment=\"center\">\n <FiltersInput\n filters={filterSettings.filters}\n selectClassName=\"sm:min-w-40\"\n comboboxClassName=\"sm:min-w-40\"\n onChange={(selected) => {\n const newSelected = applyFilterSelection(\n filterSettings.selectedFilters || [],\n selected,\n filterSettings.filters\n )\n if (newSelected === (filterSettings.selectedFilters || [])) return\n handleFilterChange({ ...filterSettings, selectedFilters: newSelected })\n }}\n />\n <SearchInput\n placeholder={t`Search security groups...`}\n data-testid=\"searchbar\"\n value={searchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setSearchTerm(v)\n }}\n onSearch={(v) => {\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n setSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n {filterSettings.selectedFilters && filterSettings.selectedFilters.length > 0 && (\n <SelectedFilters\n selectedFilters={filterSettings.selectedFilters}\n onDelete={(filterToRemove) =>\n handleFilterChange({\n ...filterSettings,\n selectedFilters: (filterSettings.selectedFilters || []).filter(\n (f) => !(f.name === filterToRemove.name && f.value === filterToRemove.value)\n ),\n })\n }\n onClear={() => handleFilterChange({ ...filterSettings, selectedFilters: [] })}\n />\n )}\n </Stack>\n </DataGridToolbar>\n\n <SecurityGroupListContainer\n securityGroups={securityGroups}\n isLoading={false}\n isError={false}\n error={null}\n permissions={permissions}\n onCreateClick={() => setCreateModalOpen(true)}\n onDeleteSecurityGroup={handleDeleteSecurityGroup}\n isDeletingSecurityGroup={deleteSecurityGroupMutation.isPending}\n deleteError={deleteError}\n onUpdateSecurityGroup={handleUpdateSecurityGroup}\n isUpdatingSecurityGroup={updateSecurityGroupMutation.isPending}\n updateError={updateError}\n currentProjectId={projectId}\n hasAnyBulkAction={false}\n onClearUpdateError={handleClearUpdateError}\n />\n\n <CreateSecurityGroupModal\n isOpen={createModalOpen}\n onClose={() => {\n setCreateError(null)\n setCreateModalOpen(false)\n }}\n onCreate={handleCreateSecurityGroup}\n isLoading={createSecurityGroupMutation.isPending}\n error={createError}\n />\n </>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups/\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n analytics: {\n name: \"network.securitygroups.list\",\n },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return <SecurityGroups project={projectId} />\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,IAAaW,KAAuE,EAClFC,WACAC,YACAC,kBACAC,aACAC,gBAAa,IACbC,WAAQ,WACT;CACC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GAER,EAAEC,eAAYC,kBAAeC,qBAAkBX,EAAiB;EACpEE;EACAU,cAAc;CAChB,CAAA,GAEMC,IAAavB,EAAEwB,OAAO,EAC1BC,SAASzB,EAAE0B,OAAM,CAAA,CAAGC,QAAQC,MAAUA,MAAU,UAAU,EACxDC,SAASC,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA,EACrC,CAAA,EACF,CAAA,GAEMC,IAAO9B,EAAQ;EACnB+B,eAAe,EACbP,SAAS,GACX;EACAQ,YAAY,EACVC,UAAUX,EACZ;EACAW,UAAU,YAAA;GACJlB,MAEJI,EAAAA,GACAL,EAASD,EAAcqB,EAAE;EAC3B;CACF,CAAA,GAEMC,IAAYlC,EAAS6B,EAAKM,QAAQC,MAAUA,EAAMC,gBAAgBD,EAAME,OAAOf,YAAY,QAAA,GAE3FgB,IAAoB3B,EAAc4B,QAAQ5B,EAAcqB;CAS9D,OACE,gBAAC/B,GAAAA;EACCyC,MAAMjC;EACNkC,gBAVgB;GAIlBjC,AAHAM,EAAAA,GACAY,EAAKa,MAAK,GACVvB,EAAAA,GACAR,EAAAA;EACF;EAMIkC,MAAK;EACLC,OAAOlB,EAAAA,EAAC;;GAA0BW,QAAAA,EAAAA,qBAAAA;EAAmB,CAAA;EACrDQ,oBAAoBjC,IAAac,EAAAA,EAAC,EAAA,IAAA,SAAY,CAAA,IAAIA,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC1DoB,sBAAqB;EACrBC,WAAWpB,EAAKqB;EAChBC,mBAAmBvB,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;EAC3BwB,sBAAsBlB,KAAapB;EACnCuC,qBAAqBvC;EACrBwC,oBAAoBxC;EAEpB,UAAA,gBAACX,GAAAA;GAAMoD,WAAU;GAAWC,KAAI;;IAC7BzC,KAAS,gBAACX,GAAAA;KAAQqD,SAAQ;KAAS1C,UAAAA;;IAEpC,gBAAC2C,KAAAA;KAAEC,WAAU;KACX,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;IAGF,gBAACtD,GAAAA;KACCsD,WAAU;KACV1B,IAAG;KACHD,WAAW4B,MAAAA;MAET/B,AADA+B,EAAEC,eAAc,GAChBhC,EAAKqB,aAAY;KACnB;KAEA,UAAA,gBAAC5C,GAAAA,EACC,UAAA,gBAACuB,EAAKiC,OAAK;MACTtB,MAAK;MACLuB,WAAWC,MACT,gBAACzD,GAAAA;OACC0D,OAAOrC,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA;OACjCK,IAAI+B,EAAMxB;OACVA,MAAMwB,EAAMxB;OACZd,OAAOsC,EAAM5B,MAAMV;OACnBwC,WAAWN,MAAMI,EAAMG,aAAaP,EAAEQ,OAAO1C,KAAK;OAClD2C,aAAY;OACZC,UAAUxD;OACVyD,cAAa;OACbC,WAAS;OACTC,eAAY;OACZC,UAAQ;;;;;;;AAS1B;;;ACnFA,SAAgBO,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,EACC,UAAA,gBAACC,KAAAA;IAAEN,WAAU;IAAWlB,UAAAA,EAAGyB;;GAG/B,gBAACjC,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;;;;;CAhCnGA,GAAAA,EAAGgB,EAAE;AAsChB;;;AC/DA,IAAa8B,MAA8B,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,EAAAA,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,MAAcC,MAAAA;EAMlBN,AAJIH,KAAyBA,EAAsBU,OAAOD,EAAGC,MAAMd,KACjEA,EAAAA,GAEFK,EAAyBQ,CAAAA,GACzBN,EAAiB,EAAA;CACnB,GAEMQ,MAAgBF,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;CAwCA,OArCAnC,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,IACK,gBAACR,GAAAA;EAAO6C,QAAO;EAAWC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAW,CAAA;MAIlDtC,IACK,gBAACT,GAAAA;EAAO6C,QAAO;EAAQC,OAAOpC,GAAOsC,WAAWD,EAAAA,EAAC,EAAA,IAAA,SAA+B,CAAA;MAIvF,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACnD,GAAAA;EAASqD,SAAS9B,IAAmB,IAAI;EAAG+B,mBAAmB/B,IAAmB,CAAC,CAAE,IAAG,CAAC,CAAE;EAC1F,UAAA,CAAA,gBAACpB,GAAAA,EAAAA,UAAAA,CACEoB,KAAoB,gBAACrB,GAAAA,CAAAA,CAAAA,GACrB;GAACiD,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,CAACI,KAAKC,MAC1D,gBAACtD,GAAAA,EAA8BsD,UAAAA,EAARA,GAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,GAI1B7C,KAAkBA,EAAe8C,SAAS,IACzC9C,EAAe4C,KAAKlB,MAAAA;GAElB,IAAMqB,IAAaC,GAAQrC,KAAoBe,EAAGuB,cAAcvB,EAAGuB,eAAetC;GAElF,OACE,gBAACb,GAAAA;IAECoD,eAAexB;IACFtB;IACb+C,QAAQ1B;IACR2B,UAAUxB;IACVyB,eAAexB;IACHkB;IACZO,kBAAkB1C;IAClB2C,YAAY;IACZC,gBAAU,CAAO;GATZ9B,GAAAA,EAAGC,EAAE;EAYhB,CAAA,IAEA,gBAACnC,GAAAA,EACC,UAAA,gBAACF,GAAAA;GAAamE,SAAS7C,IAAmB,IAAI;GAC5C,UAAA,gBAACnB,GAAAA;IACC6C,QAAO;IACPC,OAAOC,EAAAA,EAAC,EAAA,IAAA,SAAyB,CAAA;IACjCkB,MAAMlB,EAAAA,EAAC,EAAA,IAAA,SAA4K,CAAA;;;CAO5LvB,CAAAA,GAAAA,KACC,gBAAA,GAAA,EAAA,UAAA,CACE,gBAACrB,IAAAA;EACCsD,eAAejC;EACf0C,MAAMxC;EACNyC,SAAS3B;EACT4B,WAAWlC,GAAImC,MACTtD,IACKA,EAAsBmB,GAAImC,CAAAA,IAE5BC,QAAQC,QAAO;EAExB/D,WAAWQ;EACXN,OAAOO;CAET,CAAA,GAAA,gBAACb,GAAAA;EACCqD,eAAejC;EACfgD,QAAQ5C;EACRuC,SAAS1B;EACTkB,WAAWzB,MAAAA;GACT,AAAItB,KACFA,EAAsBsB,CAAAA;EAE1B;EACAuC,YAAY5D;EACZH,OAAOI;;AAMnB,GCxKM0E,IAAsD;CAC1DC,MAAM;CACNC,aAAa;CACbC,UAAU;AACZ,GAEaC,MAAqE,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,MACXC,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,MACXC,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,GChFa8B,MAAkB,EAAEC,SAASC,QAAgC;CACxE,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACRC,IAAW5B,EAAAA,GACX6B,IAAe5B,GAAU,EAAE6B,QAAQ,GAAM,CAAA,GAEzC,CAACC,GAAcC,KAAmBlC,EAA+B;EACrEmC,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,KAAqB1C,EAAyB;EACnE2C,SAAS,CACP;GACEC,aAAaP,EAAAA,EAAC,EAAA,IAAA,SAAO,CAAA;GACrBQ,YAAY;GACZC,QAAQ,CAAC,QAAQ,OAAQ;GACzBC,oBAAoB;EACtB,CACD;EACDC,iBAAiB9B,EAAoBa,CAAAA;CACvC,CAAA,GAEM,CAACkB,GAAYC,KAAiBlD,EAAS+B,EAAaoB,UAAU,EAAA,GAC9D,CAACC,GAAiBC,KAAsBrD,EAAS,EAAA,GACjD,CAACsD,GAAaC,KAAkBvD,EAAwB,IAAA,GACxD,CAACwD,GAAaC,KAAkBzD,EAAwB,IAAA,GACxD,CAAC0D,GAAaC,KAAkB3D,EAAwB,IAAA,GAExD4D,IAAQjD,EAAUkD,SAAQ;CAEhC5D,QAAU;EAURiD,AATAhB,GAAiB4B,OAAU;GACzB,GAAGA;GACHvB,QAAQR,EAAaQ,UAAU;GAC/BC,eAAeT,EAAaS,iBAAiB;EAC/C,EAAA,GACAE,GAAmBoB,OAAU;GAC3B,GAAGA;GACHd,iBAAiB9B,EAAoBa,CAAAA;EACvC,EAAA,GACAmB,EAAcnB,EAAaoB,UAAU,EAAA;CACvC,GAAG;EAACpB,EAAaQ;EAAQR,EAAaS;EAAeT,EAAaoB;EAAQpB,EAAagC;CAAO,CAAA;CAE9F,IAAMC,IAAa9C,EAAoBa,CAAAA,GACjCkC,KAAalC,EAAaQ,UAAU,QACpC2B,IAAmBnC,EAAaS,iBAAiB,OACjD2B,IAAgBpC,EAAaoB,UAAU,IAEvC,EACJiB,MAAMC,GACNC,cACAC,YACAC,aACE7D,EAAU8D,QAAQC,cAAcC,KAAKC,SACvC;EACEC,YAAYjD,KAAa;EACzBkD,UAAUb;EACVc,UAAUb;EACV,GAAG/C,GAAkB6C,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,mBAAgBnE,EAA4BW,CAAAA,GAE9CyD,KAA8B1E,EAAU8D,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,KAA8BvF,EAAU8D,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;GACjE,IAAM,EAAE4D,YAAS,GAAG9D,MAAYZ,EAAiCiD,EAAMyB,OAAO;GAC9EzF,EAAMgE,MAAMyB,GAAS9D,CAAAA;EACvB;CACF,CAAA,GAEMiE,IAA8BzF,EAAU8D,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;GACjE,IAAM,EAAE4D,YAAS,GAAG9D,MAAYV,EAAiC+C,EAAMyB,OAAO;GAC9EzF,EAAMgE,MAAMyB,GAAS9D,CAAAA;EACvB;CACF,CAAA,GAEMmE,KAA4B,OAAOC,MAAAA;EACvC9C,EAAe,IAAA;EACf,IAAI;GACF,MAAM4B,GAA4BmB,YAAY;IAAE3B,YAAYjD;IAAW,GAAG2E;GAAkB,CAAA;EAC9F,QAAQ,CAER;CACF,GAEME,MAA6BX,MAAAA;EACjCvC,EAAe,IAAA;EACf,IAAMmD,IAASzB,EAAe0B,MAAMC,MAAOA,EAAGb,OAAOD,CAAAA,CAAAA,EAAkBe,QAAQf;EAC/EI,GAA4BY,OAC1B;GAAEjC,YAAYjD;GAAWkE;EAAgB,GACzC,EACEN,iBAAW;GACT,IAAM,EAAES,YAAS,GAAG9D,MAAYb,GAA6BoF,CAAAA;GAC7DlG,EAAMuG,QAAQd,GAAS9D,CAAAA;EACzB,EACF,CAAA;CAEJ,GAEM6E,KAA4B,OAChClB,GACA1B,MAAAA;EAEAT,EAAe,IAAA;EACf,IAAM+C,IAAStC,EAAKyC,QAAQ5B,EAAe0B,MAAMC,MAAOA,EAAGb,OAAOD,CAAAA,CAAAA,EAAkBe,QAAQf;EAC5F,IAAI;GACF,MAAMM,EAA4BI,YAAY;IAAE3B,YAAYjD;IAAWkE;IAAiB,GAAG1B;GAAK,CAAA;GAChG,IAAM,EAAE6B,YAAS,GAAG9D,MAAYX,GAA6BkF,CAAAA;GAC7DlG,EAAMuG,QAAQd,GAAS9D,CAAAA;EACzB,QAAQ,CAER;CACF,GAEM8E,WAAyB;EAC7BtD,EAAe,IAAA;CACjB,GAEMuD,MAAoBC,MAAAA;EACxB,IAAMC,IAAiC;GACrCjF,SAASgF,EAAgBhF;GACzBI,QAAQ4E,EAAgB5E,QAAQ8E,SAAAA,KAAc;GAC9C7E,eAAe2E,EAAgB3E,iBAAiB;EAClD;EAEAV,AADAI,EAAgBkF,CAAAA,GAChBtF,EAAS;GACPqB,SAAUW,OAAsC;IAC9C,GAAGA;IACHvB,QAAQ6E,EAAS7E;IACjBC,eAAe4E,EAAS5E;GAC1B;GACA8E,SAAS;EACX,CAAA;CACF,GAEMC,KAAsBC,MAAAA;EAE1B1F,AADAY,EAAkB8E,CAAAA,GAClB1F,EAAS;GACPqB,SAAUW,MACR1C,GAAqBoG,EAAkBxE,mBAAmB,CAAA,GAAIwE,EAAkB7E,SAAS;IACvFQ,QAAQW,EAAKX;IACbZ,QAAQuB,EAAKvB;IACbC,eAAesB,EAAKtB;GACtB,CAAA;GACF8E,SAAS;EACX,CAAA;CACF,GAEMG,MAAsBC,MAAAA;EAC1B,IAAMC,IAAc,OAAOD,KAAS,WAAWA,IAAO;EAEtD5F,AADAoB,EAAcyE,CAAAA,GACd7F,EAAS;GACPqB,SAAUW,OAAsC;IAC9C,GAAGA;IACHX,QAAQwE,KAAeC,KAAAA;GACzB;GACAN,SAAS;EACX,CAAA;CACF;CAcA,OAZIhD,IACK,gBAAC7D,GAAAA;EAAOoH,QAAO;EAAWC,OAAOzF,EAAAA,EAAC,EAAA,IAAA,SAA2B,CAAA;MAGlEkC,KAAW,CAACU,EAAe8C,SAE3B,gBAAC1H,GAAAA;EAAM2H,WAAU;EAAOC,cAAa;EAASC,WAAU;EAASC,WAAU;EACxEjD,UAAAA,MAAa7C,EAAAA,EAAC,EAAA,IAAA,SAA+B,CAAA;MAMlD,gBAAA,GAAA,EAAA,UAAA;EACE,gBAAC3B,GAAAA;GAAcoH,OAAOzF,EAAAA,EAAC,EAAA,IAAA,SAAgB,CAAA;GAAcT;;EAErD,gBAACvB,GAAAA;GAAM4H,cAAa;GAAMC,WAAU;GAASE,KAAI;GAAIJ,WAAU;GAC7D,UAAA,gBAAC3H,GAAAA;IAAM+H,KAAI;IACT,UAAA,CAAA,gBAACxH,GAAAA;KACCuB,SAASF,EAAaE;KACtBI,QAAQN,EAAaM;KACrBC,eAAeP,EAAaO,iBAAiB;KAC7C6F,iBAAgB;KAChBC,iBAAiBC,MACfrB,GAAiB;MAAE,GAAGjF;MAAcM,QAAQgG;MAAG/F,eAAeP,EAAaO;KAAc,CAAA;KAE3FgG,wBAAwBC,MAAQvB,GAAiB;MAAE,GAAGjF;MAAcO,eAAeiG;KAAI,CAAA;IAExFrD,CAAAA,GAAAA,EAAYsD,aACX,gBAACtI,GAAAA;KAAOuI,eAAetF,EAAmB,EAAA;KAAOuF,SAAQ;KAAUZ,WAAU;KAC3E,UAAA,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;;;;EAMR,gBAAC1H,GAAAA,EACC,UAAA,gBAACD,GAAAA;GAAM8H,WAAU;GAAWC,KAAI;GAC9B,UAAA,CAAA,gBAAC/H,GAAAA;IAAM4H,cAAa;IAAUC,WAAU;IACtC,UAAA,CAAA,gBAACpH,GAAAA;KACC6B,SAASF,EAAeE;KACxB0F,iBAAgB;KAChBQ,mBAAkB;KAClBC,WAAWC,MAAAA;MACT,IAAMC,IAAc3H,GAClBoB,EAAeO,mBAAmB,CAAA,GAClC+F,GACAtG,EAAeE,OAAO;MAEpBqG,OAAiBvG,EAAeO,mBAAmB,CAAA,MACvDuE,EAAmB;OAAE,GAAG9E;OAAgBO,iBAAiBgG;MAAY,CAAA;KACvE;IAEF,CAAA,GAAA,gBAACzI,GAAAA;KACC0I,aAAa5G,EAAAA,EAAC,EAAA,IAAA,SAA0B,CAAA;KACxC6G,eAAY;KACZ5G,OAAOW;KACPkG,UAAUC,MAAAA;MACR,IAAMb,IAAIa,EAAEC,cAAc/G;MAC1BY,EAAcqF,CAAAA;KAChB;KACAe,WAAWf,MAAAA;MACTd,GAAmB,OAAOc,KAAM,WAAWA,IAAI,EAAA;KACjD;KACAgB,eAAS;MAEP9B,AADAvE,EAAc,EAAA,GACduE,GAAmB,EAAA;KACrB;;GAGHhF,CAAAA,GAAAA,EAAeO,mBAAmBP,EAAeO,gBAAgB+E,SAAS,KACzE,gBAAClH,GAAAA;IACCmC,iBAAiBP,EAAeO;IAChCwG,WAAWC,MACTlC,EAAmB;KACjB,GAAG9E;KACHO,kBAAkBP,EAAeO,mBAAmB,CAAA,EAAA,CAAI0G,QACrDC,MAAQA,EAAE9C,SAAS4C,EAAe5C,QAAQ8C,EAAErH,UAAUmH,EAAenH,KAAI;IAE9E,CAAA;IAEFiH,eAAehC,EAAmB;KAAE,GAAG9E;KAAgBO,iBAAiB,CAAA;IAAG,CAAA;;;EAMnF,gBAACjC,IAAAA;GACiBkE;GAChBX,WAAW;GACXC,SAAS;GACTC,OAAO;GACMY;GACbwE,qBAAqBvG,EAAmB,EAAA;GACxCwG,uBAAuBpD;GACvBqD,yBAAyB5D,GAA4B6D;GACxCzG;GACb0G,uBAAuBhD;GACvBiD,yBAAyB7D,EAA4B2D;GACxCrG;GACbwG,kBAAkBtI;GAClBuI,kBAAkB;GAClBC,oBAAoBnD;;EAGtB,gBAACjG,IAAAA;GACCqJ,QAAQjH;GACRkH,eAAS;IAEPjH,AADAI,EAAe,IAAA,GACfJ,EAAmB,EAAA;GACrB;GACAkH,UAAUjE;GACVhC,WAAWe,GAA4B0E;GACvCvF,OAAOhB;;;AAIf;;;ACzVA,SAASkH,IAAAA;CACP,IAAM,EAAEC,iBAAcF,EAAMG,UAAS,GAC/B,EAAEC,kBAAeJ,EAAMK,gBAAe;CAE5C,IAAI,CAACD,GACH,MAAUE,MAAM,8CAAA;CAGlB,OAAO,gBAAC,IAAA,EAAe,SAASJ,EAAAA,CAAAA;AAClC"}
@@ -0,0 +1,8 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { Outlet as t } from "@tanstack/react-router";
3
+ //#region src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=component
4
+ var n = () => /*#__PURE__*/ e(t, {});
5
+ //#endregion
6
+ export { n as component };
7
+
8
+ //# sourceMappingURL=securitygroups-CtKne8UQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securitygroups-CtKne8UQ.mjs","names":["Outlet","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\nimport { msg } from \"@lingui/core/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n crumb: { text: msg`Security Groups` },\n } satisfies RouteInfo,\n component: () => <Outlet />,\n})\n"],"mappings":";;;AAAgE,IAAAC,UAU7C,gBAAC,GAAA,CAAA,CAAA"}
@@ -4,14 +4,12 @@ var r = e("/_auth/projects/$projectId/network/securitygroups/")({
4
4
  staticData: {
5
5
  section: "network",
6
6
  service: "securitygroups",
7
- analytics: { name: "network.securitygroups.list" },
8
- sectionCrumb: { labelKey: "Network" },
9
- crumb: { labelKey: "Security Groups" }
7
+ analytics: { name: "network.securitygroups.list" }
10
8
  },
11
9
  head: () => ({ meta: [{ title: n._({ id: "4opp4r" }) }] }),
12
- component: t(() => import("./securitygroups-Bd_uV4S9.mjs"), "component")
10
+ component: t(() => import("./securitygroups-BjhgLBHm.mjs"), "component")
13
11
  });
14
12
  //#endregion
15
13
  export { r as t };
16
14
 
17
- //# sourceMappingURL=securitygroups-Byte-iSp.mjs.map
15
+ //# sourceMappingURL=securitygroups-DEJQBcxm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securitygroups-DEJQBcxm.mjs","names":["createFileRoute","t","Route","staticData","section","service","analytics","name","RouteInfo","head","meta","title","component","lazyRouteComponent","$$splitComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups/index.tsx"],"sourcesContent":["import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups/\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n analytics: {\n name: \"network.securitygroups.list\",\n },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return <SecurityGroups project={projectId} />\n}\n"],"mappings":";;AAKA,IAAaE,IAAQF,EAAgB,oDAAA,CAAA,CAAsD;CACzFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,WAAW,EACTC,MAAM,8BACR;CACF;CACAE,aAAa,EAAEC,MAAM,CAAC,EAAEC,OAAOV,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA,EAAkB,CAAC,EAAE;CACrDW,WAASC,iDAAA,WAAA;AACX,CAAA"}
@@ -125,7 +125,6 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
125
125
  create: import('@trpc/server').TRPCMutationProcedure<{
126
126
  input: {
127
127
  project_id: string;
128
- tenant_id: string;
129
128
  floating_network_id: string;
130
129
  fixed_ip_address?: string | undefined;
131
130
  floating_ip_address?: string | undefined;
@@ -1745,6 +1744,137 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
1745
1744
  meta: object;
1746
1745
  }>;
1747
1746
  }>>;
1747
+ lifecycle: import('@trpc/server').TRPCBuiltRouter<{
1748
+ ctx: import('../server/context').AuroraPortalContext;
1749
+ meta: object;
1750
+ errorShape: import('@trpc/server').TRPCDefaultErrorShape;
1751
+ transformer: false;
1752
+ }, import('@trpc/server').TRPCDecorateCreateRouterOptions<{
1753
+ get: import('@trpc/server').TRPCQueryProcedure<{
1754
+ input: {
1755
+ project_id: string;
1756
+ bucketName: string;
1757
+ };
1758
+ output: {
1759
+ rules: {
1760
+ Status: string;
1761
+ ID?: string | undefined;
1762
+ Prefix?: string | undefined;
1763
+ Filter?: {
1764
+ [x: string]: unknown;
1765
+ Prefix?: string | undefined;
1766
+ Tag?: {
1767
+ Key: string;
1768
+ Value: string;
1769
+ } | undefined;
1770
+ ObjectSizeGreaterThan?: number | undefined;
1771
+ ObjectSizeLessThan?: number | undefined;
1772
+ And?: {
1773
+ Prefix?: string | undefined;
1774
+ Tags?: {
1775
+ Key: string;
1776
+ Value: string;
1777
+ }[] | undefined;
1778
+ ObjectSizeGreaterThan?: number | undefined;
1779
+ ObjectSizeLessThan?: number | undefined;
1780
+ } | undefined;
1781
+ } | undefined;
1782
+ Expiration?: {
1783
+ [x: string]: unknown;
1784
+ Days?: number | undefined;
1785
+ Date?: string | Date | undefined;
1786
+ ExpiredObjectDeleteMarker?: boolean | undefined;
1787
+ } | undefined;
1788
+ Transitions?: {
1789
+ [x: string]: unknown;
1790
+ StorageClass: string;
1791
+ Days?: number | undefined;
1792
+ Date?: string | Date | undefined;
1793
+ }[] | undefined;
1794
+ NoncurrentVersionExpiration?: {
1795
+ [x: string]: unknown;
1796
+ NoncurrentDays?: number | undefined;
1797
+ NewerNoncurrentVersions?: number | undefined;
1798
+ } | undefined;
1799
+ NoncurrentVersionTransitions?: {
1800
+ [x: string]: unknown;
1801
+ StorageClass: string;
1802
+ NoncurrentDays?: number | undefined;
1803
+ NewerNoncurrentVersions?: number | undefined;
1804
+ }[] | undefined;
1805
+ AbortIncompleteMultipartUpload?: {
1806
+ [x: string]: unknown;
1807
+ DaysAfterInitiation?: number | undefined;
1808
+ } | undefined;
1809
+ }[] | null;
1810
+ skippedRuleCount: number;
1811
+ };
1812
+ meta: object;
1813
+ }>;
1814
+ set: import('@trpc/server').TRPCMutationProcedure<{
1815
+ input: {
1816
+ project_id: string;
1817
+ bucketName: string;
1818
+ lifecycleConfiguration: {
1819
+ Rules: {
1820
+ Status: "Enabled" | "Disabled";
1821
+ ID?: string | undefined;
1822
+ Prefix?: string | undefined;
1823
+ Filter?: {
1824
+ Prefix?: string | undefined;
1825
+ Tag?: {
1826
+ Key: string;
1827
+ Value: string;
1828
+ } | undefined;
1829
+ ObjectSizeGreaterThan?: number | undefined;
1830
+ ObjectSizeLessThan?: number | undefined;
1831
+ And?: {
1832
+ Prefix?: string | undefined;
1833
+ Tags?: {
1834
+ Key: string;
1835
+ Value: string;
1836
+ }[] | undefined;
1837
+ ObjectSizeGreaterThan?: number | undefined;
1838
+ ObjectSizeLessThan?: number | undefined;
1839
+ } | undefined;
1840
+ } | undefined;
1841
+ Expiration?: {
1842
+ Days?: number | undefined;
1843
+ Date?: string | undefined;
1844
+ ExpiredObjectDeleteMarker?: boolean | undefined;
1845
+ } | undefined;
1846
+ Transitions?: {
1847
+ StorageClass: string;
1848
+ Days?: number | undefined;
1849
+ Date?: string | undefined;
1850
+ }[] | undefined;
1851
+ NoncurrentVersionExpiration?: {
1852
+ NoncurrentDays: number;
1853
+ NewerNoncurrentVersions?: number | undefined;
1854
+ } | undefined;
1855
+ NoncurrentVersionTransitions?: {
1856
+ NoncurrentDays: number;
1857
+ StorageClass: string;
1858
+ NewerNoncurrentVersions?: number | undefined;
1859
+ }[] | undefined;
1860
+ AbortIncompleteMultipartUpload?: {
1861
+ DaysAfterInitiation: number;
1862
+ } | undefined;
1863
+ }[];
1864
+ };
1865
+ };
1866
+ output: boolean;
1867
+ meta: object;
1868
+ }>;
1869
+ delete: import('@trpc/server').TRPCMutationProcedure<{
1870
+ input: {
1871
+ project_id: string;
1872
+ bucketName: string;
1873
+ };
1874
+ output: boolean;
1875
+ meta: object;
1876
+ }>;
1877
+ }>>;
1748
1878
  }>>;
1749
1879
  };
1750
1880
  }> & import('@trpc/server').TRPCDecorateCreateRouterOptions<{
@@ -1881,6 +2011,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
1881
2011
  first?: string | undefined;
1882
2012
  next?: string | undefined;
1883
2013
  schema?: string | undefined;
2014
+ totalCount?: number | undefined;
1884
2015
  };
1885
2016
  meta: object;
1886
2017
  }>;
@@ -1964,6 +2095,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
1964
2095
  first?: string | undefined;
1965
2096
  next?: string | undefined;
1966
2097
  schema?: string | undefined;
2098
+ totalCount?: number | undefined;
1967
2099
  };
1968
2100
  meta: object;
1969
2101
  }>;
@@ -2755,7 +2887,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
2755
2887
  domain: {
2756
2888
  id?: string;
2757
2889
  name?: string;
2758
- } | undefined;
2890
+ };
2759
2891
  } | {
2760
2892
  project: {
2761
2893
  domain?: {
@@ -2764,7 +2896,7 @@ export declare const trpcReactClient: TRPCClient<import('@trpc/server').TRPCBuil
2764
2896
  };
2765
2897
  id?: string;
2766
2898
  name?: string;
2767
- } | undefined;
2899
+ };
2768
2900
  domain: {
2769
2901
  id?: string;
2770
2902
  name?: string;
@@ -0,0 +1,54 @@
1
+ import { t as e } from "./routeInfo-DP3v74Wg.mjs";
2
+ import { t } from "./DynamicBreadcrumbContext-CVcUQFou.mjs";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ import { createContext as r, useContext as i, useMemo as a, useState as o } from "react";
5
+ import { useMatches as s, useNavigate as c } from "@tanstack/react-router";
6
+ import { useLingui as l } from "@lingui/react";
7
+ //#region src/client/context/BreadcrumbExtensionContext.tsx
8
+ var u = /*#__PURE__*/ r({
9
+ breadcrumbs: [],
10
+ setBreadcrumbs: () => {}
11
+ });
12
+ function d({ children: e }) {
13
+ let [t, r] = o([]);
14
+ return /*#__PURE__*/ n(u.Provider, {
15
+ value: {
16
+ breadcrumbs: t,
17
+ setBreadcrumbs: r
18
+ },
19
+ children: e
20
+ });
21
+ }
22
+ //#endregion
23
+ //#region src/client/hooks/useBreadcrumbs.ts
24
+ function f() {
25
+ let { i18n: n, _: r } = l(), o = c(), u = s(), { crumbs: d } = i(t);
26
+ return a(() => {
27
+ let t = u.filter((t) => e(t.staticData) && t.staticData.crumb || d.has(t.routeId));
28
+ return t.map((r, i) => {
29
+ let a = d.get(r.routeId), s = e(r.staticData) ? r.staticData.crumb : void 0, c = a?.text ? p(a.text, n) : s?.text ? p(s.text, n) : void 0, l = a?.to ?? s?.to, u = a?.icon ?? s?.icon, f = i === t.length - 1;
30
+ return {
31
+ label: c,
32
+ icon: u,
33
+ onClick: f ? void 0 : () => o({
34
+ to: l ?? r.pathname,
35
+ params: r.params
36
+ }),
37
+ active: f
38
+ };
39
+ });
40
+ }, [
41
+ u,
42
+ d,
43
+ o,
44
+ n,
45
+ n.locale
46
+ ]);
47
+ }
48
+ function p(e, t) {
49
+ return typeof e == "string" ? e : t._(e);
50
+ }
51
+ //#endregion
52
+ export { u as n, d as r, f as t };
53
+
54
+ //# sourceMappingURL=useBreadcrumbs-ha3IlaxX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBreadcrumbs-ha3IlaxX.mjs","names":["createContext","useState","BreadcrumbExtensionContext","breadcrumbs","setBreadcrumbs","BreadcrumbExtensionProvider","children","Provider","value","useMatches","useNavigate","useMemo","useContext","isRouteInfo","DynamicBreadcrumbContext","useBreadcrumbs","i18n","useLingui","navigate","matches","crumbs","dynamicCrumbs","crumbMatches","filter","m","staticData","crumb","has","routeId","map","match","i","dynamic","get","staticCrumb","undefined","crumbText","text","resolveCrumbText","crumbTo","to","crumbIcon","icon","isLast","length","label","onClick","pathname","params","active","locale","_"],"sources":["../../src/client/context/BreadcrumbExtensionContext.tsx","../../src/client/hooks/useBreadcrumbs.ts"],"sourcesContent":["import { createContext, useState } from \"react\"\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\"\nimport type { BreadcrumbItem } from \"@/client/hooks/useBreadcrumbs\"\n\nexport const BreadcrumbExtensionContext = createContext<{\n breadcrumbs: BreadcrumbItem[]\n setBreadcrumbs: Dispatch<SetStateAction<BreadcrumbItem[]>>\n}>({ breadcrumbs: [], setBreadcrumbs: () => {} })\n\nexport function BreadcrumbExtensionProvider({ children }: { children: ReactNode }) {\n const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>([])\n return (\n <BreadcrumbExtensionContext.Provider value={{ breadcrumbs, setBreadcrumbs }}>\n {children}\n </BreadcrumbExtensionContext.Provider>\n )\n}\n","import { useMatches, useNavigate } from \"@tanstack/react-router\"\nimport { useMemo, useContext } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { I18n } from \"@lingui/core\"\nimport type { MessageDescriptor } from \"@lingui/core\"\nimport { isRouteInfo, type RouteInfo } from \"@/client/routes/routeInfo\"\nimport { DynamicBreadcrumbContext } from \"@/client/context/DynamicBreadcrumbContext\"\n\n/**\n * Returns the ordered breadcrumb chain for the current route.\n * Reads static crumbs from route staticData and dynamic crumbs from useSetBreadcrumb.\n * Works with any TanStack Router instance — suitable for embedded sub-apps (e.g. SCI services).\n *\n * Requirements:\n * - Must be rendered inside DynamicBreadcrumbProvider and a lingui I18nProvider\n * - To include SCI extension crumbs in OSS, use the Breadcrumbs component which merges BreadcrumbExtensionContext\n */\nexport type BreadcrumbItem = {\n label?: string\n icon?: string\n onClick?: () => void\n active?: boolean\n}\n\nexport function useBreadcrumbs(): BreadcrumbItem[] {\n const { i18n } = useLingui()\n const navigate = useNavigate()\n const matches = useMatches()\n const { crumbs: dynamicCrumbs } = useContext(DynamicBreadcrumbContext)\n\n return useMemo(() => {\n const crumbMatches = matches.filter(\n (m) => (isRouteInfo(m.staticData) && (m.staticData as RouteInfo).crumb) || dynamicCrumbs.has(m.routeId)\n )\n\n return crumbMatches.map((match, i) => {\n const dynamic = dynamicCrumbs.get(match.routeId)\n const staticCrumb = isRouteInfo(match.staticData) ? (match.staticData as RouteInfo).crumb : undefined\n const crumbText = dynamic?.text\n ? resolveCrumbText(dynamic.text, i18n)\n : staticCrumb?.text\n ? resolveCrumbText(staticCrumb.text, i18n)\n : undefined\n const crumbTo = dynamic?.to ?? staticCrumb?.to\n const crumbIcon = dynamic?.icon ?? staticCrumb?.icon\n const isLast = i === crumbMatches.length - 1\n return {\n label: crumbText,\n icon: crumbIcon,\n onClick: isLast\n ? undefined\n : () => navigate({ to: (crumbTo ?? match.pathname) as never, params: match.params as never }),\n active: isLast,\n }\n })\n }, [matches, dynamicCrumbs, navigate, i18n, i18n.locale])\n}\n\nfunction resolveCrumbText(text: string | MessageDescriptor, i18n: I18n): string {\n return typeof text === \"string\" ? text : i18n._(text)\n}\n"],"mappings":";;;;;;;AAIA,IAAaE,IAA6BF,gBAGvC;CAAEG,aAAa,CAAA;CAAIC,sBAAgB,CAAO;AAAE,CAAA;AAE/C,SAAgBC,EAA4B,EAAEC,eAAmC;CAC/E,IAAM,CAACH,GAAaC,KAAkBH,EAA2B,CAAA,CAAE;CACnE,OACE,gBAACC,EAA2BK,UAAQ;EAACC,OAAO;GAAEL;GAAaC;EAAe;EACvEE;;AAGP;;;ACQA,SAAgBS,IAAAA;CACd,IAAM,EAAEC,SAAI,GAAA,MAAKC,EAAAA,GACXC,IAAWR,EAAAA,GACXS,IAAUV,EAAAA,GACV,EAAEW,QAAQC,MAAkBT,EAAWE,CAAAA;CAE7C,OAAOH,QAAQ;EACb,IAAMW,IAAeH,EAAQI,QAC1BC,MAAM,EAAaA,EAAEC,UAAU,KAAK,EAAGA,WAAyBC,SAAUL,EAAcM,IAAIH,EAAEI,OAAO,CAAA;EAGxG,OAAON,EAAaO,KAAKC,GAAOC,MAAAA;GAC9B,IAAMC,IAAUX,EAAcY,IAAIH,EAAMF,OAAO,GACzCM,IAAcrB,EAAYiB,EAAML,UAAU,IAAI,EAAOA,WAAyBC,QAAQS,KAAAA,GACtFC,IAAYJ,GAASK,OACvBC,EAAiBN,EAAQK,MAAMrB,CAAAA,IAC/BkB,GAAaG,OACXC,EAAiBJ,EAAYG,MAAMrB,CAAAA,IACnCmB,KAAAA,GACAI,IAAUP,GAASQ,MAAMN,GAAaM,IACtCC,IAAYT,GAASU,QAAQR,GAAaQ,MAC1CC,IAASZ,MAAMT,EAAasB,SAAS;GAC3C,OAAO;IACLC,OAAOT;IACPM,MAAMD;IACNK,SAASH,IACLR,KAAAA,UACMjB,EAAS;KAAEsB,IAAKD,KAAWT,EAAMiB;KAAoBC,QAAQlB,EAAMkB;IAAgB,CAAA;IAC7FC,QAAQN;GACV;EACF,CAAA;CACF,GAAG;EAACxB;EAASE;EAAeH;EAAUF;EAAMA,EAAKkC;CAAO,CAAA;AAC1D;AAEA,SAASZ,EAAiBD,GAAkCrB,GAAU;CACpE,OAAO,OAAOqB,KAAS,WAAWA,IAAOrB,EAAKmC,EAAEd,CAAAA;AAClD"}
@@ -0,0 +1,33 @@
1
+ import { useEffect as e, useRef as t } from "react";
2
+ import { useRouteContext as n } from "@tanstack/react-router";
3
+ //#region src/client/hooks/useModalTracking.ts
4
+ var r = ({ isOpen: r, actionPrefix: i }) => {
5
+ let { onTrackEvent: a } = n({ strict: !1 }), o = t(!1), s = t(!1);
6
+ return e(() => {
7
+ r && !o.current && (a?.({
8
+ source: "modal",
9
+ action: `${i}.open`
10
+ }), o.current = !0);
11
+ }, [
12
+ r,
13
+ a,
14
+ i
15
+ ]), {
16
+ trackClose: () => {
17
+ r && !s.current && a?.({
18
+ source: "modal",
19
+ action: `${i}.close`
20
+ });
21
+ },
22
+ markSubmitted: () => {
23
+ s.current = !0;
24
+ },
25
+ resetTracking: () => {
26
+ s.current = !1, o.current = !1;
27
+ }
28
+ };
29
+ };
30
+ //#endregion
31
+ export { r as t };
32
+
33
+ //# sourceMappingURL=useModalTracking-BcOKTYRN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useModalTracking-BcOKTYRN.mjs","names":["useEffect","useRef","useRouteContext","useModalTracking","isOpen","actionPrefix","onTrackEvent","strict","hasTrackedOpen","hasSubmitted","current","source","action","trackClose","markSubmitted","resetTracking"],"sources":["../../src/client/hooks/useModalTracking.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { useRouteContext } from \"@tanstack/react-router\"\n\ninterface UseModalTrackingOptions {\n isOpen: boolean\n actionPrefix: string // e.g., \"storage.ceph.bucket.create\"\n}\n\ninterface UseModalTrackingReturn {\n trackClose: () => void\n markSubmitted: () => void\n resetTracking: () => void\n}\n\n/**\n * Custom hook to handle modal open/close analytics tracking.\n *\n * Tracks:\n * - `.open` event when modal opens (once per modal open)\n * - `.close` event when modal closes without submission (cancelled)\n *\n * @example\n * const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n * isOpen,\n * actionPrefix: \"storage.ceph.bucket.create\"\n * })\n *\n * // In handleClose:\n * trackClose()\n *\n * // In handleSubmit:\n * markSubmitted()\n *\n * // In cleanup/reset:\n * resetTracking()\n */\nexport const useModalTracking = ({ isOpen, actionPrefix }: UseModalTrackingOptions): UseModalTrackingReturn => {\n const { onTrackEvent } = useRouteContext({ strict: false })\n const hasTrackedOpen = useRef(false)\n // Use useRef instead of useState to avoid timing race with synchronous close paths\n // See: https://github.com/... - setState doesn't apply until next render, so trackClose()\n // could read stale hasSubmitted === false even after markSubmitted() was called\n const hasSubmitted = useRef(false)\n\n // Track when user opens the modal (once per modal open)\n useEffect(() => {\n if (isOpen && !hasTrackedOpen.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.open`,\n })\n hasTrackedOpen.current = true\n }\n }, [isOpen, onTrackEvent, actionPrefix])\n\n /**\n * Track close event if user didn't submit.\n * Call this at the start of your handleClose function.\n */\n const trackClose = () => {\n if (isOpen && !hasSubmitted.current) {\n onTrackEvent?.({\n source: \"modal\",\n action: `${actionPrefix}.close`,\n })\n }\n }\n\n /**\n * Mark that the user submitted the form.\n * Call this in your handleSubmit function before the mutation.\n */\n const markSubmitted = () => {\n hasSubmitted.current = true\n }\n\n /**\n * Reset tracking state.\n * Call this in handleClose after tracking close event.\n */\n const resetTracking = () => {\n hasSubmitted.current = false\n hasTrackedOpen.current = false\n }\n\n return {\n trackClose,\n markSubmitted,\n resetTracking,\n }\n}\n"],"mappings":";;;AAoCA,IAAaG,KAAoB,EAAEC,WAAQC,sBAAuC;CAChF,IAAM,EAAEC,oBAAiBJ,EAAgB,EAAEK,QAAQ,GAAM,CAAA,GACnDC,IAAiBP,EAAO,EAAA,GAIxBQ,IAAeR,EAAO,EAAA;CA2C5B,OAxCAD,QAAU;EACR,AAAII,KAAU,CAACI,EAAeE,YAC5BJ,IAAe;GACbK,QAAQ;GACRC,QAAQ,GAAGP,EAAa;EAC1B,CAAA,GACAG,EAAeE,UAAU;CAE7B,GAAG;EAACN;EAAQE;EAAcD;CAAa,CAAA,GAgChC;EACLQ,kBA3BiB;GACjB,AAAIT,KAAU,CAACK,EAAaC,WAC1BJ,IAAe;IACbK,QAAQ;IACRC,QAAQ,GAAGP,EAAa;GAC1B,CAAA;EAEJ;EAqBES,qBAfoB;GACpBL,EAAaC,UAAU;EACzB;EAcEK,qBARoB;GAEpBP,AADAC,EAAaC,UAAU,IACvBF,EAAeE,UAAU;EAC3B;CAMA;AACF"}