@cobaltcore-dev/aurora 2.1.1 → 2.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 (173) hide show
  1. package/README.md +31 -25
  2. package/dist/client/AuroraApp.d.ts +9 -2
  3. package/dist/client/context/AppConfigContext.d.ts +44 -0
  4. package/dist/client/index.d.ts +2 -0
  5. package/dist/client/index.js +41221 -845
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/client/trpcClient.d.ts +314 -0
  8. package/dist/client/utils/appConfigGating.d.ts +21 -0
  9. package/dist/server/index.d.ts +694 -3
  10. package/dist/server/index.js +1748 -722
  11. package/package.json +3 -3
  12. package/dist/client/AuthProvider-CVSAwW9f.mjs +0 -83
  13. package/dist/client/AuthProvider-CVSAwW9f.mjs.map +0 -1
  14. package/dist/client/ContentHeader-fKKZVu-o.mjs +0 -116
  15. package/dist/client/ContentHeader-fKKZVu-o.mjs.map +0 -1
  16. package/dist/client/DeleteFlavorModal-C4nAi7gY.mjs +0 -724
  17. package/dist/client/DeleteFlavorModal-C4nAi7gY.mjs.map +0 -1
  18. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs +0 -26
  19. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs.map +0 -1
  20. package/dist/client/FiltersInput-Becwxo_J.mjs +0 -85
  21. package/dist/client/FiltersInput-Becwxo_J.mjs.map +0 -1
  22. package/dist/client/FloatingIpActionModals-Cq10WljB.mjs +0 -466
  23. package/dist/client/FloatingIpActionModals-Cq10WljB.mjs.map +0 -1
  24. package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs +0 -26
  25. package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs.map +0 -1
  26. package/dist/client/Slot-CWb612-_.mjs +0 -28
  27. package/dist/client/Slot-CWb612-_.mjs.map +0 -1
  28. package/dist/client/SortInput-4g7nSTHW.mjs +0 -34
  29. package/dist/client/SortInput-4g7nSTHW.mjs.map +0 -1
  30. package/dist/client/StorageNotFound-B-zVinVD.mjs +0 -30
  31. package/dist/client/StorageNotFound-B-zVinVD.mjs.map +0 -1
  32. package/dist/client/TwoColumnDescriptionList-DKS42RKa.mjs +0 -28
  33. package/dist/client/TwoColumnDescriptionList-DKS42RKa.mjs.map +0 -1
  34. package/dist/client/_-CAsCx-Ay.mjs +0 -6
  35. package/dist/client/_-CAsCx-Ay.mjs.map +0 -1
  36. package/dist/client/_auth-SrDjHL6j.mjs +0 -12
  37. package/dist/client/_auth-SrDjHL6j.mjs.map +0 -1
  38. package/dist/client/_flavorId-BPvssEzn.mjs +0 -277
  39. package/dist/client/_flavorId-BPvssEzn.mjs.map +0 -1
  40. package/dist/client/_flavorId-CFUBcU-l.mjs +0 -27
  41. package/dist/client/_flavorId-CFUBcU-l.mjs.map +0 -1
  42. package/dist/client/_flavorId-CZcIp0Ih.mjs +0 -22
  43. package/dist/client/_flavorId-CZcIp0Ih.mjs.map +0 -1
  44. package/dist/client/_floatingIpId-B8r64AL9.mjs +0 -196
  45. package/dist/client/_floatingIpId-B8r64AL9.mjs.map +0 -1
  46. package/dist/client/_floatingIpId-lEobpOER.mjs +0 -26
  47. package/dist/client/_floatingIpId-lEobpOER.mjs.map +0 -1
  48. package/dist/client/_imageId-BAezmV0Y.mjs +0 -526
  49. package/dist/client/_imageId-BAezmV0Y.mjs.map +0 -1
  50. package/dist/client/_imageId-D-jqz3e3.mjs +0 -40
  51. package/dist/client/_imageId-D-jqz3e3.mjs.map +0 -1
  52. package/dist/client/_imageId-gMdrdnVt.mjs +0 -22
  53. package/dist/client/_imageId-gMdrdnVt.mjs.map +0 -1
  54. package/dist/client/_projectId-BYccdAtX.mjs +0 -77
  55. package/dist/client/_projectId-BYccdAtX.mjs.map +0 -1
  56. package/dist/client/_projectId-CBjZC1tv.mjs +0 -283
  57. package/dist/client/_projectId-CBjZC1tv.mjs.map +0 -1
  58. package/dist/client/_projectId-CLEa1zgw.mjs +0 -30
  59. package/dist/client/_projectId-CLEa1zgw.mjs.map +0 -1
  60. package/dist/client/_projectId-D3VOH5lN.mjs +0 -94
  61. package/dist/client/_projectId-D3VOH5lN.mjs.map +0 -1
  62. package/dist/client/_securityGroupId-BwgZnoiR.mjs +0 -29
  63. package/dist/client/_securityGroupId-BwgZnoiR.mjs.map +0 -1
  64. package/dist/client/_securityGroupId-Cz2NUHdB.mjs +0 -1819
  65. package/dist/client/_securityGroupId-Cz2NUHdB.mjs.map +0 -1
  66. package/dist/client/_serviceType-DS8DxsrP.mjs +0 -20
  67. package/dist/client/_serviceType-DS8DxsrP.mjs.map +0 -1
  68. package/dist/client/_serviceType-M8d9rOT6.mjs +0 -6
  69. package/dist/client/_serviceType-M8d9rOT6.mjs.map +0 -1
  70. package/dist/client/_storageType-BNpP1A2N.mjs +0 -13
  71. package/dist/client/_storageType-BNpP1A2N.mjs.map +0 -1
  72. package/dist/client/_storageType-BxSGKhAI.mjs +0 -15
  73. package/dist/client/_storageType-BxSGKhAI.mjs.map +0 -1
  74. package/dist/client/_storageType-DZYCmiLt.mjs +0 -30
  75. package/dist/client/_storageType-DZYCmiLt.mjs.map +0 -1
  76. package/dist/client/_storageType-UqAMP-8d.mjs +0 -859
  77. package/dist/client/_storageType-UqAMP-8d.mjs.map +0 -1
  78. package/dist/client/_storageType-u51_7OwJ.mjs +0 -7
  79. package/dist/client/_storageType-u51_7OwJ.mjs.map +0 -1
  80. package/dist/client/about-BmQTyLWc.mjs +0 -92
  81. package/dist/client/about-BmQTyLWc.mjs.map +0 -1
  82. package/dist/client/assets/__mocks__/svgMock.d.ts +0 -3
  83. package/dist/client/aurora-CIml-f2f.mjs +0 -19
  84. package/dist/client/aurora-CIml-f2f.mjs.map +0 -1
  85. package/dist/client/build-WuxXRAqf.mjs +0 -14530
  86. package/dist/client/build-WuxXRAqf.mjs.map +0 -1
  87. package/dist/client/cn-DM4Cy3jv.mjs +0 -10
  88. package/dist/client/cn-DM4Cy3jv.mjs.map +0 -1
  89. package/dist/client/flavors-CJVSNz6R.mjs +0 -15
  90. package/dist/client/flavors-CJVSNz6R.mjs.map +0 -1
  91. package/dist/client/flavors-CflJDIEH.mjs +0 -667
  92. package/dist/client/flavors-CflJDIEH.mjs.map +0 -1
  93. package/dist/client/flavors-DWMZ6TuJ.mjs +0 -8
  94. package/dist/client/flavors-DWMZ6TuJ.mjs.map +0 -1
  95. package/dist/client/floatingips-Cz9k80cc.mjs +0 -8
  96. package/dist/client/floatingips-Cz9k80cc.mjs.map +0 -1
  97. package/dist/client/floatingips-DXnRlLvV.mjs +0 -551
  98. package/dist/client/floatingips-DXnRlLvV.mjs.map +0 -1
  99. package/dist/client/floatingips-HRbuLxiN.mjs +0 -22
  100. package/dist/client/floatingips-HRbuLxiN.mjs.map +0 -1
  101. package/dist/client/floatingips-nN1kQmsu.mjs +0 -14
  102. package/dist/client/floatingips-nN1kQmsu.mjs.map +0 -1
  103. package/dist/client/formatBytes-CZv_XyCY.mjs +0 -38
  104. package/dist/client/formatBytes-CZv_XyCY.mjs.map +0 -1
  105. package/dist/client/helpers-1PpYf-fC.mjs +0 -6
  106. package/dist/client/helpers-1PpYf-fC.mjs.map +0 -1
  107. package/dist/client/hooks-D0yKIumu.mjs +0 -22
  108. package/dist/client/hooks-D0yKIumu.mjs.map +0 -1
  109. package/dist/client/imageHelpers-DBhL2ebL.mjs +0 -1272
  110. package/dist/client/imageHelpers-DBhL2ebL.mjs.map +0 -1
  111. package/dist/client/images-BsylWUiH.mjs +0 -2011
  112. package/dist/client/images-BsylWUiH.mjs.map +0 -1
  113. package/dist/client/images-NBf2bV43.mjs +0 -8
  114. package/dist/client/images-NBf2bV43.mjs.map +0 -1
  115. package/dist/client/images-zQq1nSVv.mjs +0 -15
  116. package/dist/client/images-zQq1nSVv.mjs.map +0 -1
  117. package/dist/client/md-kvaGCNAK.mjs +0 -336
  118. package/dist/client/md-kvaGCNAK.mjs.map +0 -1
  119. package/dist/client/network-DuZm76BZ.mjs +0 -8
  120. package/dist/client/network-DuZm76BZ.mjs.map +0 -1
  121. package/dist/client/objects-BudUAfWY.mjs +0 -12909
  122. package/dist/client/objects-BudUAfWY.mjs.map +0 -1
  123. package/dist/client/objects-Dc7sKUr8.mjs +0 -67
  124. package/dist/client/objects-Dc7sKUr8.mjs.map +0 -1
  125. package/dist/client/objects-Dw7oeTq2.mjs +0 -80
  126. package/dist/client/objects-Dw7oeTq2.mjs.map +0 -1
  127. package/dist/client/objects-_g7nGIn5.mjs +0 -25
  128. package/dist/client/objects-_g7nGIn5.mjs.map +0 -1
  129. package/dist/client/objects-eBxvY6_n.mjs +0 -78
  130. package/dist/client/objects-eBxvY6_n.mjs.map +0 -1
  131. package/dist/client/projects-yiK0HGSA.mjs +0 -7
  132. package/dist/client/projects-yiK0HGSA.mjs.map +0 -1
  133. package/dist/client/routeInfo-DP3v74Wg.mjs +0 -19
  134. package/dist/client/routeInfo-DP3v74Wg.mjs.map +0 -1
  135. package/dist/client/routes-CJj7SR_K.mjs +0 -10
  136. package/dist/client/routes-CJj7SR_K.mjs.map +0 -1
  137. package/dist/client/routes-xofA3ksU.mjs +0 -110
  138. package/dist/client/routes-xofA3ksU.mjs.map +0 -1
  139. package/dist/client/securitygroups-CSmsBzUb.mjs +0 -581
  140. package/dist/client/securitygroups-CSmsBzUb.mjs.map +0 -1
  141. package/dist/client/securitygroups-CtKne8UQ.mjs +0 -8
  142. package/dist/client/securitygroups-CtKne8UQ.mjs.map +0 -1
  143. package/dist/client/securitygroups-T7kaNFEp.mjs +0 -15
  144. package/dist/client/securitygroups-T7kaNFEp.mjs.map +0 -1
  145. package/dist/client/securitygroups-WLB1_IM6.mjs +0 -22
  146. package/dist/client/securitygroups-WLB1_IM6.mjs.map +0 -1
  147. package/dist/client/securitygroups-o0IXZM6S.mjs +0 -14
  148. package/dist/client/securitygroups-o0IXZM6S.mjs.map +0 -1
  149. package/dist/client/serviceCatalog-B3lKWC9V.mjs +0 -6
  150. package/dist/client/serviceCatalog-B3lKWC9V.mjs.map +0 -1
  151. package/dist/client/services-D1PbooD1.mjs +0 -6
  152. package/dist/client/services-D1PbooD1.mjs.map +0 -1
  153. package/dist/client/services-DEMVtFyn.mjs +0 -9
  154. package/dist/client/services-DEMVtFyn.mjs.map +0 -1
  155. package/dist/client/storageProviders-CJ5rOh13.mjs +0 -15
  156. package/dist/client/storageProviders-CJ5rOh13.mjs.map +0 -1
  157. package/dist/client/trpcClient-D7gpR7YG.mjs +0 -71
  158. package/dist/client/trpcClient-D7gpR7YG.mjs.map +0 -1
  159. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs +0 -54
  160. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs.map +0 -1
  161. package/dist/client/useErrorTranslation-Dc0eE8Zt.mjs +0 -83
  162. package/dist/client/useErrorTranslation-Dc0eE8Zt.mjs.map +0 -1
  163. package/dist/client/useModal-DCs1OJh7.mjs +0 -12
  164. package/dist/client/useModal-DCs1OJh7.mjs.map +0 -1
  165. package/dist/client/useModalTracking-BYd37pXm.mjs +0 -37
  166. package/dist/client/useModalTracking-BYd37pXm.mjs.map +0 -1
  167. package/dist/client/useProjectId-DBc5lpoU.mjs +0 -11
  168. package/dist/client/useProjectId-DBc5lpoU.mjs.map +0 -1
  169. package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs +0 -294
  170. package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs.map +0 -1
  171. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs +0 -19
  172. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs.map +0 -1
  173. package/dist/client/utils/trpcErrors.d.ts +0 -13
@@ -1 +0,0 @@
1
- {"version":3,"file":"securitygroups-CSmsBzUb.mjs","names":["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","name","description","shared","p","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","columnCount","columns","minContentColumns","t","map","label","colSpan","status","title","message","length","isReadOnly","Boolean","project_id","securityGroup","onEdit","onDelete","onViewDetails","showSelectColumn","isSelected","onSelect","body","open","onClose","onUpdate","data","Promise","resolve","isOpen","isDeleting","React","useState","Modal","Form","FormRow","FormSection","TextInput","Checkbox","Button","ButtonRow","Spinner","ModalFooter","Textarea","Message","Status","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","status","id","label","onChange","required","errortext","placeholder","rows","helptext","BOOLEAN_VALUES","BOOLEAN_PARAM","true","false","isBooleanValue","value","includes","BOOLEAN_FILTER_NAMES","isBooleanFilterName","name","buildSecurityGroupFilters","labels","displayName","shared","filterName","values","valueLabels","yes","no","supportsMultiValue","stateful","buildSecurityGroupFilterParams","selectedFilters","params","selected","filter","f","inactive","at","isKnownSecurityGroupFilter","isKnownSecurityGroupFilter","parseFiltersFromUrl","searchParams","filters","shared","push","name","value","stateful","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","useRef","useNavigate","useSearch","Button","Stack","DataGridToolbar","SearchInput","Message","toast","ContentHeader","trpcReact","SortInput","SelectedFilters","FiltersInput","SecurityGroupListContainer","CreateSecurityGroupModal","useSecurityGroupPermissions","parseFiltersFromUrl","buildUrlSearchParams","applyFilterSelection","buildSecurityGroupFilterParams","buildSecurityGroupFilters","getSecurityGroupDeletedToast","getSecurityGroupDeleteErrorToast","getSecurityGroupUpdatedToast","getSecurityGroupUpdateErrorToast","SEARCH_DEBOUNCE_MS","SecurityGroups","project","projectId","useLingui","navigate","searchParams","strict","sortSettings","setSortSettings","options","label","t","value","sortBy","sortDirection","filterSettings","setFilterSettings","filters","shared","stateful","yes","no","selectedFilters","localSearchTerm","setLocalSearchTerm","search","debounceTimer","undefined","createModalOpen","setCreateModalOpen","deleteError","setDeleteError","createError","setCreateError","updateError","setUpdateError","utils","useUtils","clearTimeout","current","prev","urlFilters","urlSortBy","urlSortDirection","urlSearchTerm","data","securityGroupsData","isLoading","isError","error","network","securityGroup","list","useQuery","project_id","sort_key","sort_dir","searchTerm","refetchOnWindowFocus","placeholderData","securityGroups","listError","code","message","permissions","createSecurityGroupMutation","create","useMutation","onSuccess","createdSecurityGroup","invalidate","getById","to","params","securityGroupId","id","onError","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","title","length","variant","className","direction","distribution","alignment","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","comboboxClassName","onChange","selected","newSelected","placeholder","data-testid","onInput","e","currentTarget","window","setTimeout","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/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/filterConfig.ts","../../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 {\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>{sg.name}</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 ?? true} />\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"items-end pr-0\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem label={t`Show Details`} onClick={() => handleShowDetails()} />\n {permissions.canUpdate && !isReadOnly && <PopupMenuItem label={t`Edit Group`} onClick={() => onEdit(sg)} />}\n {permissions.canDelete && !isReadOnly && (\n <PopupMenuItem label={t`Delete Group`} onClick={() => onDelete(sg)} />\n )}\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 const columnCount = hasAnyBulkAction ? 6 : 5\n\n return (\n <>\n <DataGrid columns={columnCount} 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 {isLoading ? (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status status=\"progress\" title={t`Loading...`} />\n </DataGridCell>\n </DataGridRow>\n ) : isError ? (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status status=\"error\" title={error?.message ?? t`Failed to Load Security Groups`} />\n </DataGridCell>\n </DataGridRow>\n ) : 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={columnCount}>\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 Status,\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 && <Status status=\"progress\" title={t`Creating Security Group...`} className=\"mt-0\" />}\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 type { ListSecurityGroupsInput } from \"@/server/Network/types/securityGroup\"\nimport type { Filter, SelectedFilter } from \"@/client/components/ListToolbar/types\"\n\n/** Filter params this list may send to network.securityGroup.list. Names AND types come from the tRPC input schema. */\nexport type SecurityGroupFilterParams = Partial<Pick<ListSecurityGroupsInput, \"shared\" | \"stateful\">>\nexport type SecurityGroupFilterName = keyof SecurityGroupFilterParams\n\nconst BOOLEAN_VALUES = [\"true\", \"false\"] as const\ntype BooleanValue = (typeof BOOLEAN_VALUES)[number]\n\n// Maps the raw string value carried in the URL/pill to the typed value sent to the tRPC procedure.\n// If a server-side field ever changes type (e.g. to a string enum), this mapping fails to compile,\n// surfacing the mismatch at build time instead of at runtime.\nconst BOOLEAN_PARAM: Record<BooleanValue, boolean> = {\n true: true,\n false: false,\n}\n\nconst isBooleanValue = (value: string): value is BooleanValue => (BOOLEAN_VALUES as readonly string[]).includes(value)\n\nconst BOOLEAN_FILTER_NAMES = [\"shared\", \"stateful\"] as const satisfies readonly SecurityGroupFilterName[]\ntype BooleanFilterName = (typeof BOOLEAN_FILTER_NAMES)[number]\n\nconst isBooleanFilterName = (name: string): name is BooleanFilterName =>\n (BOOLEAN_FILTER_NAMES as readonly string[]).includes(name)\n\n/**\n * Builds the Filter definitions for the Security Groups list toolbar.\n * Labels are passed in (rather than resolved via `t` here) so this module stays plain\n * data/logic and can be unit-tested without an I18nProvider.\n */\nexport const buildSecurityGroupFilters = (labels: {\n shared: string\n stateful: string\n yes: string\n no: string\n}): Filter[] => [\n {\n displayName: labels.shared,\n filterName: \"shared\" satisfies SecurityGroupFilterName,\n values: [...BOOLEAN_VALUES],\n valueLabels: { true: labels.yes, false: labels.no },\n supportsMultiValue: false,\n },\n {\n displayName: labels.stateful,\n filterName: \"stateful\" satisfies SecurityGroupFilterName,\n values: [...BOOLEAN_VALUES],\n valueLabels: { true: labels.yes, false: labels.no },\n supportsMultiValue: false,\n },\n]\n\n/**\n * Builds the typed filter params sent to `network.securityGroup.list` from the currently\n * selected filters. Unlike the generic `Record<string, string>` builder, the return type here\n * is checked by the compiler against the tRPC input schema when spread into the query input.\n */\nexport const buildSecurityGroupFilterParams = (selectedFilters: SelectedFilter[]): SecurityGroupFilterParams => {\n const params: SecurityGroupFilterParams = {}\n\n for (const name of BOOLEAN_FILTER_NAMES) {\n // Single-value filters: the toolbar replaces an earlier selection, but the URL may still\n // carry more than one entry, in which case the last one wins.\n const selected = selectedFilters.filter((f) => !f.inactive && f.name === name).at(-1)\n\n if (selected && isBooleanValue(selected.value)) {\n params[name] = BOOLEAN_PARAM[selected.value]\n }\n }\n\n return params\n}\n\n/** Whether a raw URL value is a known, valid value for the given Security Groups filter name. */\nexport const isKnownSecurityGroupFilter = (name: string, value: string): boolean =>\n isBooleanFilterName(name) && isBooleanValue(value)\n","import { SelectedFilter, Filter } from \"@/client/components/ListToolbar/types\"\nimport { isKnownSecurityGroupFilter } from \"./filterConfig\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n stateful?: 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 && isKnownSecurityGroupFilter(\"shared\", searchParams.shared)) {\n filters.push({ name: \"shared\", value: searchParams.shared })\n }\n\n // Stateful filter\n if (searchParams.stateful && isKnownSecurityGroupFilter(\"stateful\", searchParams.stateful)) {\n filters.push({ name: \"stateful\", value: searchParams.stateful })\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, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\nimport { Button, Stack, DataGridToolbar, SearchInput, Message, toast } 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, buildUrlSearchParams, applyFilterSelection } from \"../urlHelpers\"\nimport { buildSecurityGroupFilterParams, buildSecurityGroupFilters } from \"../filterConfig\"\nimport {\n getSecurityGroupDeletedToast,\n getSecurityGroupDeleteErrorToast,\n getSecurityGroupUpdatedToast,\n getSecurityGroupUpdateErrorToast,\n} from \"./SecurityGroupToastNotifications\"\n\nconst SEARCH_DEBOUNCE_MS = 500\n\ntype SecurityGroupSortKey = \"name\" | \"project_id\"\n\ntype SecurityGroupsSearchParams = {\n shared?: string\n stateful?: 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: [{ label: t`Name`, value: \"name\" }],\n sortBy: searchParams.sortBy || \"name\",\n sortDirection: searchParams.sortDirection || \"asc\",\n })\n\n const [filterSettings, setFilterSettings] = useState<FilterSettings>({\n filters: buildSecurityGroupFilters({ shared: t`Shared`, stateful: t`Stateful`, yes: t`Yes`, no: t`No` }),\n selectedFilters: parseFiltersFromUrl(searchParams),\n })\n\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParams.search || \"\")\n const debounceTimer = useRef<number | undefined>(undefined)\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(() => () => clearTimeout(debounceTimer.current), [])\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 // Only sync the input from the URL when there's no debounced search \"in flight\" — otherwise\n // this effect would clobber characters the user typed while the debounce timer was pending.\n if (debounceTimer.current === undefined) {\n setLocalSearchTerm(searchParams.search || \"\")\n }\n }, [searchParams.sortBy, searchParams.sortDirection, searchParams.search, searchParams.shared, searchParams.stateful])\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 ...buildSecurityGroupFilterParams(urlFilters),\n ...(urlSearchTerm ? { searchTerm: urlSearchTerm } : {}),\n },\n {\n refetchOnWindowFocus: false,\n placeholderData: (prev) => prev,\n }\n )\n\n const securityGroups = securityGroupsData || []\n const listError = isError\n ? error?.data?.code === \"FORBIDDEN\"\n ? t`You do not have permission to view security groups`\n : error.message || t`Failed to Load Security Groups`\n : 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) => {\n navigate({\n search: ((prev: SecurityGroupsSearchParams) => ({\n ...prev,\n search: term || undefined,\n })) as unknown as true,\n replace: true,\n })\n }\n\n return (\n <>\n <ContentHeader title={t`Security Groups`} projectId={projectId} />\n\n {/* Non-blocking error banner for refetch failures with cached data */}\n {isError && securityGroups.length > 0 && (\n <Message variant=\"error\" className=\"mb-4\">\n {listError}\n </Message>\n )}\n\n <Stack direction=\"vertical\" className=\"juno-pattern-datagrid-outer\">\n <Stack direction=\"vertical\" className=\"juno-pattern-datagrid-header\">\n {/* Zone 1: sort + primary action */}\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 {/* Zone 2: filters, search, active filter pills */}\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 // The wrapper is inline-block/w-auto and the input reserves pr-16 for its icons, so at\n // the browser's default input width this placeholder gets cut off mid-ellipsis.\n className=\"w-60 sm:w-68\"\n placeholder={t`Search security groups...`}\n data-testid=\"searchbar\"\n value={localSearchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setLocalSearchTerm(v)\n clearTimeout(debounceTimer.current)\n debounceTimer.current = window.setTimeout(() => {\n debounceTimer.current = undefined\n handleSearchChange(v)\n }, SEARCH_DEBOUNCE_MS)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n debounceTimer.current = undefined\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n debounceTimer.current = undefined\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n {filterSettings.selectedFilters && filterSettings.selectedFilters.length > 0 && (\n <SelectedFilters\n selectedFilters={filterSettings.selectedFilters}\n filters={filterSettings.filters}\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 </Stack>\n\n {/* Renders <DataGrid> as a direct child; its Edit/Delete modals portal and add no in-flow DOM */}\n <SecurityGroupListContainer\n securityGroups={securityGroups}\n isLoading={isLoading}\n isError={isError && securityGroups.length === 0}\n error={listError ? { message: listError } : 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 </Stack>\n\n <CreateSecurityGroupModal\n isOpen={createModalOpen}\n onClose={() => {\n setCreateError(null)\n setCreateModalOpen(false)\n }}\n onCreate={handleCreateSecurityGroup}\n isLoading={createSecurityGroupMutation.isPending}\n error={createError}\n />\n </>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { SecurityGroups } from \"./-components/SecurityGroupsList\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/network/securitygroups/\")({\n staticData: {\n section: \"network\",\n service: \"securitygroups\",\n analytics: {\n name: \"network.securitygroups.list\",\n },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Security Groups` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return <SecurityGroups project={projectId} />\n}\n"],"mappings":"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"}
@@ -1,8 +0,0 @@
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
@@ -1 +0,0 @@
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, useNavigate } from \"@tanstack/react-router\"\nimport { RouteIdLevelDefaultError } from \"@/client/components/Errors/RouteIdLevelDefaultError\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { msg } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nconst SecurityGroupsErrorComponent = () => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const { projectId } = Route.useParams()\n\n return (\n <RouteIdLevelDefaultError\n action={\n <Button\n variant=\"primary\"\n onClick={() => navigate({ to: \"/projects/$projectId/network/securitygroups\", params: { projectId } })}\n >\n {t`Back to Security Groups`}\n </Button>\n }\n />\n )\n}\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 // Render errors from the security groups subtree inside the project layout\n // (side navigation, header, breadcrumbs) instead of the full-screen route error.\n errorComponent: SecurityGroupsErrorComponent,\n})\n"],"mappings":";;;AAA6E,IAAAC,UAgC1D,gBAAC,GAAA,CAAA,CAAA"}
@@ -1,15 +0,0 @@
1
- import { createFileRoute as e, lazyRouteComponent as t } from "@tanstack/react-router";
2
- import { i18n as n } from "@lingui/core";
3
- var r = e("/_auth/projects/$projectId/network/securitygroups/")({
4
- staticData: {
5
- section: "network",
6
- service: "securitygroups",
7
- analytics: { name: "network.securitygroups.list" }
8
- },
9
- head: () => ({ meta: [{ title: n._({ id: "4opp4r" }) }] }),
10
- component: t(() => import("./securitygroups-CSmsBzUb.mjs"), "component")
11
- });
12
- //#endregion
13
- export { r as t };
14
-
15
- //# sourceMappingURL=securitygroups-T7kaNFEp.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"securitygroups-T7kaNFEp.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"}
@@ -1,22 +0,0 @@
1
- import { i as e } from "./build-WuxXRAqf.mjs";
2
- import { t } from "./securitygroups-o0IXZM6S.mjs";
3
- import { t as n } from "./RouteIdLevelDefaultError-DPF_x2tG.mjs";
4
- import { jsx as r } from "react/jsx-runtime";
5
- import { useNavigate as i } from "@tanstack/react-router";
6
- import { useLingui as a } from "@lingui/react";
7
- //#region src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=errorComponent
8
- var o = () => {
9
- let { i18n: o, _: s } = a(), c = i(), { projectId: l } = t.useParams();
10
- return /*#__PURE__*/ r(n, { action: /*#__PURE__*/ r(e, {
11
- variant: "primary",
12
- onClick: () => c({
13
- to: "/projects/$projectId/network/securitygroups",
14
- params: { projectId: l }
15
- }),
16
- children: o._({ id: "U9q4M7" })
17
- }) });
18
- };
19
- //#endregion
20
- export { o as errorComponent };
21
-
22
- //# sourceMappingURL=securitygroups-WLB1_IM6.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"securitygroups-WLB1_IM6.mjs","names":["useNavigate","RouteIdLevelDefaultError","Button","useLingui","SecurityGroupsErrorComponent","t","navigate","projectId","Route","useParams","to","params","errorComponent"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx?tsr-split=errorComponent"],"sourcesContent":["import { createFileRoute, Outlet, useNavigate } from \"@tanstack/react-router\"\nimport { RouteIdLevelDefaultError } from \"@/client/components/Errors/RouteIdLevelDefaultError\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { msg } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nconst SecurityGroupsErrorComponent = () => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const { projectId } = Route.useParams()\n\n return (\n <RouteIdLevelDefaultError\n action={\n <Button\n variant=\"primary\"\n onClick={() => navigate({ to: \"/projects/$projectId/network/securitygroups\", params: { projectId } })}\n >\n {t`Back to Security Groups`}\n </Button>\n }\n />\n )\n}\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 // Render errors from the security groups subtree inside the project layout\n // (side navigation, header, breadcrumbs) instead of the full-screen route error.\n errorComponent: SecurityGroupsErrorComponent,\n})\n"],"mappings":";;;;;;;AAOA,IAAMI,UAA+BA;CACnC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQD,EAAAA,GACRG,IAAWN,EAAAA,GACX,EAAEO,iBAAcC,EAAMC,UAAS;CAErC,OACE,gBAAC,GAAA,EACC,QACE,gBAAC,GAAA;EACC,SAAQ;EACR,eAAeH,EAAS;GAAEI,IAAI;GAA+CC,QAAQ,EAAEJ,aAAU;EAAE,CAAA;EAElGF,UAAAA,EAAAA,EAAC,EAAA,IAAA,SAAA,CAAA;;AAKZ"}
@@ -1,14 +0,0 @@
1
- import { createFileRoute as e, lazyRouteComponent as t } from "@tanstack/react-router";
2
- var n = e("/_auth/projects/$projectId/network/securitygroups")({
3
- staticData: {
4
- section: "network",
5
- service: "securitygroups",
6
- crumb: { text: { id: "4opp4r" } }
7
- },
8
- component: t(() => import("./securitygroups-CtKne8UQ.mjs"), "component"),
9
- errorComponent: t(() => import("./securitygroups-WLB1_IM6.mjs"), "errorComponent")
10
- });
11
- //#endregion
12
- export { n as t };
13
-
14
- //# sourceMappingURL=securitygroups-o0IXZM6S.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"securitygroups-o0IXZM6S.mjs","names":["createFileRoute","msg","Route","staticData","section","service","crumb","text","RouteInfo","component","lazyRouteComponent","$$splitComponentImporter","errorComponent","$$splitErrorComponentImporter"],"sources":["../../src/client/routes/_auth/projects/$projectId/network/securitygroups.tsx"],"sourcesContent":["import { createFileRoute, Outlet, useNavigate } from \"@tanstack/react-router\"\nimport { RouteIdLevelDefaultError } from \"@/client/components/Errors/RouteIdLevelDefaultError\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { msg } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nconst SecurityGroupsErrorComponent = () => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const { projectId } = Route.useParams()\n\n return (\n <RouteIdLevelDefaultError\n action={\n <Button\n variant=\"primary\"\n onClick={() => navigate({ to: \"/projects/$projectId/network/securitygroups\", params: { projectId } })}\n >\n {t`Back to Security Groups`}\n </Button>\n }\n />\n )\n}\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 // Render errors from the security groups subtree inside the project layout\n // (side navigation, header, breadcrumbs) instead of the full-screen route error.\n errorComponent: SecurityGroupsErrorComponent,\n})\n"],"mappings":";AA0BA,IAAaE,IAAQF,EAAgB,mDAAA,CAAA,CAAqD;CACxFG,YAAY;EACVC,SAAS;EACTC,SAAS;EACTC,OAAO,EAAEC,MAAMN,EAAAA,IAAAA,SAAG,EAAkB;CACtC;CACAQ,WAASC,iDAAA,WAAA;CAGTE,gBAAcF,iDAAA,gBAAA;AAChB,CAAA"}
@@ -1,6 +0,0 @@
1
- //#region src/client/utils/serviceCatalog.ts
2
- var e = (e, t) => Object.values(e).some((e) => e[t]);
3
- //#endregion
4
- export { e as t };
5
-
6
- //# sourceMappingURL=serviceCatalog-B3lKWC9V.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serviceCatalog-B3lKWC9V.mjs","names":["hasServiceByName","serviceIndex","name","Object","values","some","byName"],"sources":["../../src/client/utils/serviceCatalog.ts"],"sourcesContent":["/**\n * Mirrors the backend's service resolution, which matches by NAME and ignores the\n * catalog type entirely (cephProcedure.ts:23 → ctx.openstack.service(\"ceph\");\n * swiftRouter.ts → service(\"swift\"); signal-openstack session.ts:95 takes only a name).\n * The old type-scoped lookups disagreed with it: Ceph lives in the catalog as\n * { type: \"object-store-ceph\", name: \"ceph\" }, so serviceIndex[\"object-store\"][\"ceph\"]\n * never matched, and a temporary Ceph availability fallback had to paper over it.\n */\nexport const hasServiceByName = (serviceIndex: Record<string, Record<string, boolean>>, name: string): boolean =>\n Object.values(serviceIndex).some((byName) => byName[name])\n"],"mappings":";AAQA,IAAaA,KAAoBC,GAAuDC,MACtFC,OAAOC,OAAOH,CAAAA,CAAAA,CAAcI,MAAMC,MAAWA,EAAOJ,EAAK"}
@@ -1,6 +0,0 @@
1
- import { createFileRoute as e, lazyRouteComponent as t } from "@tanstack/react-router";
2
- var n = e("/_auth/projects/$projectId/services")({ component: t(() => import("./services-DEMVtFyn.mjs"), "component") });
3
- //#endregion
4
- export { n as t };
5
-
6
- //# sourceMappingURL=services-D1PbooD1.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"services-D1PbooD1.mjs","names":["createFileRoute","Route","component","lazyRouteComponent","$$splitComponentImporter","servicesRoute"],"sources":["../../src/client/routes/_auth/projects/$projectId/services.tsx"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services\")({\n component: () => <Outlet />,\n})\n\nexport { Route as servicesRoute }\n"],"mappings":";AAEA,IAAaC,IAAQD,EAAgB,qCAAA,CAAA,CAAuC,EAC1EE,WAASC,2CAAA,WAAA,EACX,CAAA"}
@@ -1,9 +0,0 @@
1
- import { t as e } from "./services-D1PbooD1.mjs";
2
- import { jsx as t } from "react/jsx-runtime";
3
- import { Outlet as n } from "@tanstack/react-router";
4
- //#region src/client/routes/_auth/projects/$projectId/services.tsx?tsr-split=component
5
- var r = () => /*#__PURE__*/ t(n, {});
6
- //#endregion
7
- export { r as component, e as servicesRoute };
8
-
9
- //# sourceMappingURL=services-DEMVtFyn.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"services-DEMVtFyn.mjs","names":["Outlet","Route","servicesRoute","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/services.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet } from \"@tanstack/react-router\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/services\")({\n component: () => <Outlet />,\n})\n\nexport { Route as servicesRoute }\n"],"mappings":";;;;AAMiC,IAAAG,UAHd,gBAAC,GAAA,CAAA,CAAA"}
@@ -1,15 +0,0 @@
1
- //#region src/client/utils/storageProviders.ts
2
- var e = {
3
- SWIFT: "swift",
4
- CEPH: "ceph"
5
- }, t = {
6
- CONTAINERS: "containers",
7
- BUCKETS: "buckets"
8
- }, n = {
9
- [e.SWIFT]: t.CONTAINERS,
10
- [e.CEPH]: t.BUCKETS
11
- }, r = (e) => typeof e == "string" && Object.hasOwn(n, e), i = (e, t) => r(e) ? e : t, a = (e) => n[e];
12
- //#endregion
13
- export { a, r as i, n, i as r, e as t };
14
-
15
- //# sourceMappingURL=storageProviders-CJ5rOh13.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storageProviders-CJ5rOh13.mjs","names":["STORAGE_PROVIDER","SWIFT","CEPH","STORAGE_TYPE","CONTAINERS","BUCKETS","STORAGE_TYPE_BY_PROVIDER","isStorageProvider","value","Object","hasOwn","asStorageProvider","fallback","storageTypeFor","provider"],"sources":["../../src/client/utils/storageProviders.ts"],"sourcesContent":["/**\n * Single source of truth for the storage provider ↔ storage-type noun mapping\n * (`swift` → `containers`, `ceph` → `buckets`). Every route/component that needs\n * to build or validate a `/storage/$provider/$storageType` URL should go through\n * this module instead of re-hardcoding the pairing.\n */\n\n/**\n * The object-storage providers. The same spelling serves as the `$provider` URL\n * segment and as the OpenStack catalog service *name* the backend resolves by\n * (see `serviceCatalog.ts`), so one constant covers both uses.\n */\nexport const STORAGE_PROVIDER = {\n SWIFT: \"swift\",\n CEPH: \"ceph\",\n} as const\n\n/**\n * The `$storageType` URL segment noun each provider uses.\n *\n * Deliberately NOT the same vocabulary as the nav / `enabledServices` service keys\n * (`\"containers\"` / `\"ceph-containers\"`), which only happen to share the word\n * \"containers\" — Ceph's nav key is `\"ceph-containers\"`, never `\"buckets\"`. Don't\n * substitute one for the other.\n */\nexport const STORAGE_TYPE = {\n CONTAINERS: \"containers\",\n BUCKETS: \"buckets\",\n} as const\n\nexport const STORAGE_TYPE_BY_PROVIDER = {\n [STORAGE_PROVIDER.SWIFT]: STORAGE_TYPE.CONTAINERS,\n [STORAGE_PROVIDER.CEPH]: STORAGE_TYPE.BUCKETS,\n} as const\n\nexport type StorageProvider = keyof typeof STORAGE_TYPE_BY_PROVIDER\nexport type StorageType = (typeof STORAGE_TYPE_BY_PROVIDER)[StorageProvider]\n\n/**\n * Narrows an unknown value (typically a raw `$provider` URL segment) to a known\n * `StorageProvider`. Uses `Object.hasOwn` rather than `in` — `\"__proto__\" in obj`\n * evaluates to `true` for any object, which would let `/storage/__proto__/...`\n * pass validation.\n */\nexport const isStorageProvider = (value: unknown): value is StorageProvider =>\n typeof value === \"string\" && Object.hasOwn(STORAGE_TYPE_BY_PROVIDER, value)\n\n/** Returns `value` narrowed to a `StorageProvider`, or `fallback` if it isn't one. */\nexport const asStorageProvider = (value: unknown, fallback: StorageProvider): StorageProvider =>\n isStorageProvider(value) ? value : fallback\n\n/** The canonical storage-type noun for a given provider. */\nexport const storageTypeFor = (provider: StorageProvider): StorageType => STORAGE_TYPE_BY_PROVIDER[provider]\n"],"mappings":";AAYA,IAAaA,IAAmB;CAC9BC,OAAO;CACPC,MAAM;AACR,GAUaC,IAAe;CAC1BC,YAAY;CACZC,SAAS;AACX,GAEaC,IAA2B;EACrCN,EAAiBC,QAAQE,EAAaC;EACtCJ,EAAiBE,OAAOC,EAAaE;AACxC,GAWaE,KAAqBC,MAChC,OAAOA,KAAU,YAAYC,OAAOC,OAAOJ,GAA0BE,CAAAA,GAG1DG,KAAqBH,GAAgBI,MAChDL,EAAkBC,CAAAA,IAASA,IAAQI,GAGxBC,KAAkBC,MAA2CR,EAAyBQ"}
@@ -1,71 +0,0 @@
1
- import { createTRPCReact as e } from "@trpc/react-query";
2
- import { createTRPCClient as t, httpBatchLink as n, httpBatchStreamLink as r, httpLink as i, httpSubscriptionLink as a, isNonJsonSerializable as o, splitLink as s } from "@trpc/client";
3
- //#region src/client/trpcClient.ts
4
- var c = { bffEndpoint: "/polaris-bff" };
5
- function l(e) {
6
- c.bffEndpoint = e;
7
- }
8
- function u() {
9
- return c.bffEndpoint;
10
- }
11
- var d = "/csrf-token", f = () => {
12
- let e = /^https?:\/\//i.test(c.bffEndpoint) ? new URL(c.bffEndpoint).origin : globalThis.location.origin;
13
- return new URL(d, e).href;
14
- }, p = {
15
- token: null,
16
- pending: null,
17
- async getHeaders() {
18
- if (this.token) return { "x-csrf-token": this.token };
19
- this.pending ||= fetch(f()).then((e) => e.json()).then(({ csrfToken: e }) => (this.token = e, this.pending = null, e)).catch((e) => (this.pending = null, console.error("Failed to fetch CSRF token:", e), null));
20
- let e = await this.pending;
21
- return e ? { "x-csrf-token": e } : {};
22
- },
23
- invalidate() {
24
- this.token = null;
25
- }
26
- }, m = () => p.token, h = /* @__PURE__ */ new Set(["storage.swift.downloadObject", "storage.ceph.objects.downloadObject"]), g = () => [s({
27
- condition: (e) => e.type === "subscription",
28
- true: a({
29
- url: c.bffEndpoint,
30
- eventSourceOptions: async () => ({ headers: await p.getHeaders() })
31
- }),
32
- false: s({
33
- condition: (e) => o(e.input),
34
- true: i({
35
- url: c.bffEndpoint,
36
- async headers({ op: e }) {
37
- let t = await p.getHeaders(), n = e.context?.headers ?? {};
38
- return {
39
- ...t,
40
- ...n
41
- };
42
- }
43
- }),
44
- false: s({
45
- condition: (e) => h.has(e.path),
46
- true: r({
47
- url: c.bffEndpoint,
48
- async headers() {
49
- return p.getHeaders();
50
- }
51
- }),
52
- false: n({
53
- url: c.bffEndpoint,
54
- async headers() {
55
- return p.getHeaders();
56
- }
57
- })
58
- })
59
- })
60
- })], _ = e(), v = {
61
- react: null,
62
- vanilla: null
63
- }, y = new Proxy({}, { get(e, t) {
64
- return v.react ||= _.createClient({ links: g() }), v.react[t];
65
- } }), b = new Proxy({}, { get(e, n) {
66
- return v.vanilla ||= t({ links: g() }), v.vanilla[n];
67
- } });
68
- //#endregion
69
- export { _ as a, b as i, m as n, y as o, l as r, u as t };
70
-
71
- //# sourceMappingURL=trpcClient-D7gpR7YG.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trpcClient-D7gpR7YG.mjs","names":["createTRPCReact","createTRPCClient","httpBatchLink","httpBatchStreamLink","httpLink","splitLink","isNonJsonSerializable","httpSubscriptionLink","config","bffEndpoint","setBffEndpoint","endpoint","getBffEndpoint","CSRF_TOKEN_PATH","csrfTokenUrl","base","test","URL","origin","globalThis","location","href","csrfCache","token","pending","getHeaders","fetch","then","res","json","csrfToken","catch","error","console","invalidate","getCsrfToken","setCsrfToken","STREAMING_PROCEDURES","Set","getLinks","condition","op","type","true","url","eventSourceOptions","headers","false","input","csrf","extra","context","has","path","trpcReact","clients","react","vanilla","trpcReactClient","Proxy","get","_target","prop","createClient","links","trpcClient"],"sources":["../../src/client/trpcClient.ts"],"sourcesContent":["import { createTRPCReact } from \"@trpc/react-query\"\nimport type { CreateTRPCReact } from \"@trpc/react-query\"\nimport { createTRPCClient, type TRPCClient } from \"@trpc/client\"\nimport {\n httpBatchLink,\n httpBatchStreamLink,\n httpLink,\n splitLink,\n isNonJsonSerializable,\n httpSubscriptionLink,\n} from \"@trpc/client\"\nimport type { AuroraRouter } from \"../server/routers\"\n\n/** Type alias for the React tRPC client */\nexport type TrpcReact = ReturnType<typeof createTRPCReact<AuroraRouter>>\n\n/** Type alias for the vanilla tRPC client */\nexport type TrpcClient = ReturnType<typeof createTRPCClient<AuroraRouter>>\n\n/** Generic type for creating a typed React tRPC client with a custom router */\nexport type CreateTypedTrpcReact<TRouter extends AuroraRouter> = CreateTRPCReact<TRouter, unknown>\n\n/** Generic type for creating a typed vanilla tRPC client with a custom router */\nexport type CreateTypedTrpcClient<TRouter extends AuroraRouter> = TRPCClient<TRouter>\n\n// BFF endpoint - set once by App before any tRPC calls are made\nconst config = {\n bffEndpoint: \"/polaris-bff\",\n}\n\nexport function setBffEndpoint(endpoint: string) {\n config.bffEndpoint = endpoint\n}\n\n/**\n * Read the endpoint App configured. Needed by code that has to hand the value to\n * a separate JS context — a Web Worker gets its own instance of this module and\n * never sees App's setBffEndpoint() call, so it would otherwise fall back to the\n * default and break any non-default deployment. Read-only: does not affect link\n * routing.\n */\nexport function getBffEndpoint() {\n return config.bffEndpoint\n}\n\n// The CSRF token route is mounted at the server root by AuroraFastifyCsrfProtection,\n// not under the BFF prefix.\nconst CSRF_TOKEN_PATH = \"/csrf-token\"\n\n// Origin to resolve CSRF_TOKEN_PATH against.\n//\n// A bare fetch(\"/csrf-token\") is fine on the main thread but throws inside the\n// object-download worker: it is inlined (?worker&inline) and therefore runs from\n// a blob: URL, whose location has an opaque path — a root-relative URL has\n// nothing to resolve against (\"Failed to parse URL\"). getHeaders()'s catch\n// swallowed that throw and returned {}, so the request went out with no\n// x-csrf-token and the BFF answered \"Invalid csrf token\".\n//\n// The worker is handed an already-absolute bffEndpoint (see objectDownloadStore),\n// so its origin is a base that holds in either context. A relative endpoint means\n// we're on the main thread, where location is a real document URL.\nconst csrfTokenUrl = () => {\n const base = /^https?:\\/\\//i.test(config.bffEndpoint)\n ? new URL(config.bffEndpoint).origin\n : globalThis.location.origin\n return new URL(CSRF_TOKEN_PATH, base).href\n}\n\n// CSRF token cache with request deduplication\nconst csrfCache = {\n token: null as string | null,\n pending: null as Promise<string | null> | null,\n\n async getHeaders() {\n if (this.token) {\n return { \"x-csrf-token\": this.token }\n }\n\n // Dedupe concurrent fetches - only one request in flight at a time\n if (!this.pending) {\n this.pending = fetch(csrfTokenUrl())\n .then((res) => res.json())\n .then(({ csrfToken }) => {\n this.token = csrfToken\n this.pending = null\n return csrfToken as string\n })\n .catch((error) => {\n this.pending = null\n console.error(\"Failed to fetch CSRF token:\", error)\n return null\n })\n }\n\n const token = await this.pending\n return token ? { \"x-csrf-token\": token } : {}\n },\n\n invalidate() {\n this.token = null\n },\n}\n\n/**\n * Read the cached CSRF token so it can be handed to a separate JS context.\n * Synchronous by design — callers that hand it to a worker are on a sync path.\n * Null means nothing has needed a token yet, in which case the other context\n * fetches one itself. Read-only.\n */\nexport const getCsrfToken = () => csrfCache.token\n\n/**\n * Seed the CSRF token from another JS context. Mirrors setBffEndpoint(): a Web\n * Worker gets its own instance of this module, so its cache starts empty and it\n * would otherwise spend a round-trip fetching a token the main thread already has.\n * A null token is ignored — the cache then resolves one on first use.\n */\nexport const setCsrfToken = (token: string | null) => {\n if (token) csrfCache.token = token\n}\n\n// Procedures that return async iterables (chunked streaming responses).\n// These are routed through httpBatchStreamLink instead of httpBatchLink.\n// Add any new streaming procedure paths here.\nconst STREAMING_PROCEDURES = new Set<string>([\"storage.swift.downloadObject\", \"storage.ceph.objects.downloadObject\"])\n\nconst getLinks = () => [\n splitLink({\n // First check: is it a subscription?\n condition: (op) => op.type === \"subscription\",\n // Use HTTP subscription link for subscriptions (long-polling)\n true: httpSubscriptionLink({\n url: config.bffEndpoint,\n // Callback to populate headers\n eventSourceOptions: async () => {\n return { headers: await csrfCache.getHeaders() }\n },\n }),\n // For non-subscriptions, check for non-JSON data or streaming procedures\n false: splitLink({\n // Non-JSON serializable input (FormData, Blob, ArrayBuffer, etc.) → plain httpLink.\n condition: (op) => isNonJsonSerializable(op.input),\n true: httpLink({\n url: config.bffEndpoint,\n async headers({ op }) {\n const csrf = await csrfCache.getHeaders()\n // Per-request headers can be injected via tRPC operation context.\n // op.context is set by the caller and forwarded through the link chain.\n const extra = (op.context as { headers?: Record<string, string> } | undefined)?.headers ?? {}\n return { ...csrf, ...extra }\n },\n }),\n // For JSON procedures, decide between streaming and regular batching\n false: splitLink({\n // Procedures returning async iterables must use httpBatchStreamLink.\n // httpBatchLink buffers the full response before resolving, which\n // breaks streaming. httpBatchStreamLink preserves batching while\n // supporting chunked/streamed responses.\n // Note: httpBatchStreamLink is intentionally NOT used globally because\n // it is incompatible with the @fastify/csrf-protection cookie rotation\n // used in this app — CSRF tokens can expire mid-stream on long-lived\n // connections. Scope it only to procedures that actually need streaming.\n condition: (op) => STREAMING_PROCEDURES.has(op.path),\n true: httpBatchStreamLink({\n url: config.bffEndpoint,\n async headers() {\n return csrfCache.getHeaders()\n },\n }),\n // Regular JSON mutations/queries — standard batching\n false: httpBatchLink({\n url: config.bffEndpoint,\n async headers() {\n return csrfCache.getHeaders()\n },\n }),\n }),\n }),\n }),\n]\n\n// React Query client (for hooks like useQuery/useMutation/useSubscription)\nexport const trpcReact: TrpcReact = createTRPCReact<AuroraRouter>()\n\n// Lazy-initialized clients - created on first access after setBffEndpoint() has been called by App\nconst clients = {\n react: null as ReturnType<typeof trpcReact.createClient> | null,\n vanilla: null as TrpcClient | null,\n}\n\nexport const trpcReactClient = new Proxy({} as ReturnType<typeof trpcReact.createClient>, {\n get(_target, prop) {\n if (!clients.react) {\n clients.react = trpcReact.createClient({ links: getLinks() })\n }\n return (clients.react as Record<string | symbol, unknown>)[prop]\n },\n})\n\nexport const trpcClient: TrpcClient = new Proxy({} as TrpcClient, {\n get(_target, prop) {\n if (!clients.vanilla) {\n clients.vanilla = createTRPCClient<AuroraRouter>({ links: getLinks() })\n }\n return (clients.vanilla as Record<string | symbol, unknown>)[prop]\n },\n})\n"],"mappings":";;;AA0BA,IAAMQ,IAAS,EACbC,aAAa,eACf;AAEA,SAAgBC,EAAeC,GAAgB;CAC7CH,EAAOC,cAAcE;AACvB;AASA,SAAgBC,IAAAA;CACd,OAAOJ,EAAOC;AAChB;AAIA,IAAMI,IAAkB,eAclBC,UAAe;CACnB,IAAMC,IAAO,gBAAgBC,KAAKR,EAAOC,WAAW,IAChD,IAAIQ,IAAIT,EAAOC,WAAW,CAAA,CAAES,SAC5BC,WAAWC,SAASF;CACxB,OAAO,IAAID,IAAIJ,GAAiBE,CAAAA,CAAAA,CAAMM;AACxC,GAGMC,IAAY;CAChBC,OAAO;CACPC,SAAS;CAET,MAAMC,aAAAA;EACJ,IAAI,KAAKF,OACP,OAAO,EAAE,gBAAgB,KAAKA,MAAM;EAItC,AACE,KAAKC,YAAUE,MAAMZ,EAAAA,CAAAA,CAAAA,CAClBa,MAAMC,MAAQA,EAAIC,KAAI,CAAA,CAAA,CACtBF,MAAM,EAAEG,oBACP,KAAKP,QAAQO,GACb,KAAKN,UAAU,MACRM,EACT,CAAA,CACCC,OAAOC,OACN,KAAKR,UAAU,MACfS,QAAQD,MAAM,+BAA+BA,CAAAA,GACtC,KACT;EAGJ,IAAMT,IAAQ,MAAM,KAAKC;EACzB,OAAOD,IAAQ,EAAE,gBAAgBA,EAAM,IAAI,CAAC;CAC9C;CAEAW,aAAAA;EACE,KAAKX,QAAQ;CACf;AACF,GAQaY,UAAqBb,EAAUC,OAetCc,oBAAuB,IAAIC,IAAY,CAAC,gCAAgC,qCAAsC,CAAA,GAE9GC,UAAiB,CACrBlC,EAAU;CAERmC,YAAYC,MAAOA,EAAGC,SAAS;CAE/BC,MAAMpC,EAAqB;EACzBqC,KAAKpC,EAAOC;EAEZoC,oBAAoB,aACX,EAAEC,SAAS,MAAMxB,EAAUG,WAAU,EAAG;CAEnD,CAAA;CAEAsB,OAAO1C,EAAU;EAEfmC,YAAYC,MAAOnC,EAAsBmC,EAAGO,KAAK;EACjDL,MAAMvC,EAAS;GACbwC,KAAKpC,EAAOC;GACZ,MAAMqC,QAAQ,EAAEL,SAAI;IAClB,IAAMQ,IAAO,MAAM3B,EAAUG,WAAU,GAGjCyB,IAAQ,EAAIC,SAA8DL,WAAW,CAAC;IAC5F,OAAO;KAAE,GAAGG;KAAM,GAAGC;IAAM;GAC7B;EACF,CAAA;EAEAH,OAAO1C,EAAU;GASfmC,YAAYC,MAAOJ,EAAqBe,IAAIX,EAAGY,IAAI;GACnDV,MAAMxC,EAAoB;IACxByC,KAAKpC,EAAOC;IACZ,MAAMqC,UAAAA;KACJ,OAAOxB,EAAUG,WAAU;IAC7B;GACF,CAAA;GAEAsB,OAAO7C,EAAc;IACnB0C,KAAKpC,EAAOC;IACZ,MAAMqC,UAAAA;KACJ,OAAOxB,EAAUG,WAAU;IAC7B;GACF,CAAA;EACF,CAAA;CACF,CAAA;AACF,CAAA,CACD,GAGY6B,IAAuBtD,EAAAA,GAG9BuD,IAAU;CACdC,OAAO;CACPC,SAAS;AACX,GAEaC,IAAkB,IAAIC,MAAM,CAAC,GAAgD,EACxFC,IAAIC,GAASC,GAAI;CAIf,OAHA,AACEP,EAAQC,UAAQF,EAAUS,aAAa,EAAEC,OAAOzB,EAAAA,EAAW,CAAA,GAEtD,EAASiB,MAA2CM;AAC7D,EACF,CAAA,GAEaG,IAAyB,IAAIN,MAAM,CAAC,GAAiB,EAChEC,IAAIC,GAASC,GAAI;CAIf,OAHA,AACEP,EAAQE,YAAUxD,EAA+B,EAAE+D,OAAOzB,EAAAA,EAAW,CAAA,GAEhE,EAASkB,QAA6CK;AAC/D,EACF,CAAA"}
@@ -1,54 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,83 +0,0 @@
1
- import { useLingui as e } from "@lingui/react";
2
- //#region src/client/utils/useErrorTranslation.ts
3
- var t = () => {
4
- let { i18n: t, _: n } = e();
5
- return {
6
- translateError: (e) => {
7
- switch (e) {
8
- case "FLAVORS_UNAUTHORIZED": return t._({ id: "1iUuTT" });
9
- case "FLAVORS_FORBIDDEN": return t._({ id: "mSLePW" });
10
- case "FLAVORS_NOT_FOUND": return t._({ id: "EQnVgi" });
11
- case "FLAVORS_SERVER_ERROR": return t._({ id: "Hivb/4" });
12
- case "FLAVORS_FETCH_FAILED": return t._({ id: "EztMB8" });
13
- case "FLAVORS_PARSE_ERROR": return t._({ id: "t1fq6V" });
14
- case "GET_FLAVOR_DETAILS_UNAUTHORIZED": return t._({ id: "zCD96i" });
15
- case "GET_FLAVOR_DETAILS_FORBIDDEN": return t._({ id: "/9Squ9" });
16
- case "GET_FLAVOR_DETAILS_NOT_FOUND": return t._({ id: "HxTYrE" });
17
- case "GET_FLAVOR_DETAILS_SERVER_ERROR": return t._({ id: "KJC+M7" });
18
- case "GET_FLAVOR_DETAILS_INVALID_ID": return t._({ id: "YUU0QW" });
19
- case "GET_FLAVOR_DETAILS_PARSE_ERROR": return t._({ id: "ZUmOzn" });
20
- case "GET_FLAVOR_DETAILS_FAILED": return t._({ id: "RCr0yv" });
21
- case "CREATE_FLAVOR_INVALID_DATA": return t._({ id: "0kCt7e" });
22
- case "CREATE_FLAVOR_UNAUTHORIZED": return t._({ id: "oDkgME" });
23
- case "CREATE_FLAVOR_FORBIDDEN": return t._({ id: "cPKL6O" });
24
- case "CREATE_FLAVOR_CONFLICT": return t._({ id: "OlmKCg" });
25
- case "CREATE_FLAVOR_SERVER_ERROR": return t._({ id: "qaAo9Y" });
26
- case "CREATE_FLAVOR_FAILED": return t._({ id: "QuJSSl" });
27
- case "DELETE_FLAVOR_UNAUTHORIZED": return t._({ id: "2gH+i8" });
28
- case "DELETE_FLAVOR_FORBIDDEN": return t._({ id: "EPMHs9" });
29
- case "DELETE_FLAVOR_NOT_FOUND": return t._({ id: "rIi6x4" });
30
- case "DELETE_FLAVOR_SERVER_ERROR": return t._({ id: "tASa/P" });
31
- case "DELETE_FLAVOR_FAILED": return t._({ id: "h3P8z+" });
32
- case "DELETE_FLAVOR_INVALID_ID": return t._({ id: "YUU0QW" });
33
- case "CREATE_EXTRA_SPECS_UNAUTHORIZED": return t._({ id: "RTQFAw" });
34
- case "CREATE_EXTRA_SPECS_FORBIDDEN": return t._({ id: "kGmM/p" });
35
- case "CREATE_EXTRA_SPECS_NOT_FOUND": return t._({ id: "HxTYrE" });
36
- case "CREATE_EXTRA_SPECS_CONFLICT": return t._({ id: "6oolxV" });
37
- case "CREATE_EXTRA_SPECS_INVALID_DATA": return t._({ id: "JoECY1" });
38
- case "CREATE_EXTRA_SPECS_SERVER_ERROR": return t._({ id: "jMc/mo" });
39
- case "CREATE_EXTRA_SPECS_PARSE_ERROR": return t._({ id: "07WXfc" });
40
- case "CREATE_EXTRA_SPECS_FAILED": return t._({ id: "7BpykL" });
41
- case "GET_EXTRA_SPECS_UNAUTHORIZED": return t._({ id: "3nWqQW" });
42
- case "GET_EXTRA_SPECS_FORBIDDEN": return t._({ id: "wcUecy" });
43
- case "GET_EXTRA_SPECS_NOT_FOUND": return t._({ id: "M470oJ" });
44
- case "GET_EXTRA_SPECS_SERVER_ERROR": return t._({ id: "tIrNgH" });
45
- case "GET_EXTRA_SPECS_PARSE_ERROR": return t._({ id: "07WXfc" });
46
- case "GET_EXTRA_SPECS_FAILED": return t._({ id: "lhIa6x" });
47
- case "DELETE_EXTRA_SPEC_UNAUTHORIZED": return t._({ id: "dVdc7N" });
48
- case "DELETE_EXTRA_SPEC_FORBIDDEN": return t._({ id: "YrAy/S" });
49
- case "DELETE_EXTRA_SPEC_NOT_FOUND": return t._({ id: "vBUQNE" });
50
- case "DELETE_EXTRA_SPEC_SERVER_ERROR": return t._({ id: "0kc0zi" });
51
- case "DELETE_EXTRA_SPEC_INVALID_KEY": return t._({ id: "ylfbpz" });
52
- case "DELETE_EXTRA_SPEC_FAILED": return t._({ id: "TfdeUd" });
53
- case "GET_FLAVOR_ACCESS_UNAUTHORIZED": return t._({ id: "Mt6sRo" });
54
- case "GET_FLAVOR_ACCESS_FORBIDDEN": return t._({ id: "MbKJNP" });
55
- case "GET_FLAVOR_ACCESS_NOT_FOUND": return t._({ id: "HxTYrE" });
56
- case "GET_FLAVOR_ACCESS_SERVER_ERROR": return t._({ id: "YsOJlj" });
57
- case "GET_FLAVOR_ACCESS_FAILED": return t._({ id: "bISG26" });
58
- case "ADD_TENANT_ACCESS_FAILED": return t._({ id: "rIe0oV" });
59
- case "ADD_TENANT_ACCESS_INVALID_DATA": return t._({ id: "gztCjq" });
60
- case "ADD_TENANT_ACCESS_UNAUTHORIZED": return t._({ id: "+Lt5cp" });
61
- case "ADD_TENANT_ACCESS_FORBIDDEN": return t._({ id: "8s0tOH" });
62
- case "ADD_TENANT_ACCESS_NOT_FOUND": return t._({ id: "1rPB1p" });
63
- case "ADD_TENANT_ACCESS_CONFLICT": return t._({ id: "NRMm0E" });
64
- case "ADD_TENANT_ACCESS_SERVER_ERROR": return t._({ id: "KoQP4F" });
65
- case "REMOVE_TENANT_ACCESS_FAILED": return t._({ id: "ZhVSpK" });
66
- case "REMOVE_TENANT_ACCESS_INVALID_DATA": return t._({ id: "gztCjq" });
67
- case "REMOVE_TENANT_ACCESS_UNAUTHORIZED": return t._({ id: "78+riR" });
68
- case "REMOVE_TENANT_ACCESS_FORBIDDEN": return t._({ id: "qs+BrU" });
69
- case "REMOVE_TENANT_ACCESS_NOT_FOUND": return t._({ id: "Do5/uH" });
70
- case "REMOVE_TENANT_ACCESS_CONFLICT": return t._({ id: "+nQTmZ" });
71
- case "REMOVE_TENANT_ACCESS_SERVER_ERROR": return t._({ id: "0BSSYj" });
72
- case "COMPUTE_SERVICE_UNAVAILABLE": return t._({ id: "gGdfWx" });
73
- case "COMPUTE_SERVICE_CONNECTION_FAILED": return t._({ id: "Qg4EG6" });
74
- default: return t._({ id: "byKna+" });
75
- }
76
- },
77
- isRetryableError: (e) => ["FLAVORS_SERVER_ERROR", "FLAVORS_FETCH_FAILED"].includes(e)
78
- };
79
- };
80
- //#endregion
81
- export { t };
82
-
83
- //# sourceMappingURL=useErrorTranslation-Dc0eE8Zt.mjs.map