@cobaltcore-dev/aurora 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/DeleteFlavorModal-C2MqUgGR.mjs +801 -0
- package/dist/client/DeleteFlavorModal-C2MqUgGR.mjs.map +1 -0
- package/dist/client/{FiltersInput-CKI6zWnm.mjs → FiltersInput-Becwxo_J.mjs} +36 -33
- package/dist/client/FiltersInput-Becwxo_J.mjs.map +1 -0
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs → FloatingIpActionModals-Cq10WljB.mjs} +2 -2
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs.map → FloatingIpActionModals-Cq10WljB.mjs.map} +1 -1
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs +1135 -0
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs.map +1 -0
- package/dist/client/RouteIdLevelDefaultError-CSseJ1yG.mjs +26 -0
- package/dist/client/RouteIdLevelDefaultError-CSseJ1yG.mjs.map +1 -0
- package/dist/client/{_flavorId-Dg7MS0Af.mjs → _flavorId-CaA4-Pnf.mjs} +4 -3
- package/dist/client/_flavorId-CaA4-Pnf.mjs.map +1 -0
- package/dist/client/_flavorId-DYv_StX22.mjs +276 -0
- package/dist/client/_flavorId-DYv_StX22.mjs.map +1 -0
- package/dist/client/_flavorId-YV3jCS5g.mjs +22 -0
- package/dist/client/_flavorId-YV3jCS5g.mjs.map +1 -0
- package/dist/client/{_floatingIpId-C9xfRWot.mjs → _floatingIpId-BeYElanB.mjs} +2 -2
- package/dist/client/{_floatingIpId-C9xfRWot.mjs.map → _floatingIpId-BeYElanB.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs → _floatingIpId-Dpsc7GU4.mjs} +5 -5
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs.map → _floatingIpId-Dpsc7GU4.mjs.map} +1 -1
- package/dist/client/_imageId-mfKp3JHn.mjs +558 -0
- package/dist/client/_imageId-mfKp3JHn.mjs.map +1 -0
- package/dist/client/_imageId-mpXUMCh_.mjs +22 -0
- package/dist/client/_imageId-mpXUMCh_.mjs.map +1 -0
- package/dist/client/{_imageId-8JIbFmGB.mjs → _imageId-pBSS0YcC.mjs} +4 -3
- package/dist/client/_imageId-pBSS0YcC.mjs.map +1 -0
- package/dist/client/{_projectId-B3wmSala.mjs → _projectId-AjgJX6Gl.mjs} +2 -2
- package/dist/client/_projectId-AjgJX6Gl.mjs.map +1 -0
- package/dist/client/{_projectId-DPzv0CCp.mjs → _projectId-BnTBxKfp.mjs} +4 -4
- package/dist/client/_projectId-BnTBxKfp.mjs.map +1 -0
- package/dist/client/{_projectId-DfeVJy0G.mjs → _projectId-CVrdJ52s.mjs} +2 -2
- package/dist/client/_projectId-CVrdJ52s.mjs.map +1 -0
- package/dist/client/_projectId-DgciZslU.mjs +92 -0
- package/dist/client/_projectId-DgciZslU.mjs.map +1 -0
- package/dist/client/{_securityGroupId-C6eHmrx_.mjs → _securityGroupId-AO3wnH8g.mjs} +2 -2
- package/dist/client/_securityGroupId-AO3wnH8g.mjs.map +1 -0
- package/dist/client/{_securityGroupId-DmplhDgt.mjs → _securityGroupId-Bq0ZyG6z.mjs} +750 -741
- package/dist/client/_securityGroupId-Bq0ZyG6z.mjs.map +1 -0
- package/dist/client/_storageType-c-DAu8qr.mjs +858 -0
- package/dist/client/_storageType-c-DAu8qr.mjs.map +1 -0
- package/dist/client/components/{Error → Errors}/RouteError.d.ts +5 -0
- package/dist/client/components/Errors/RouteIdLevelDefaultError.d.ts +17 -0
- package/dist/client/components/Errors/ServiceLevelDefaultError.d.ts +9 -0
- package/dist/client/components/ListToolbar/SelectedFilters.d.ts +7 -2
- package/dist/client/components/ListToolbar/types.d.ts +6 -0
- package/dist/client/components/ListToolbar/valueLabels.d.ts +11 -0
- package/dist/client/flavors-Bgq3KZmx.mjs +659 -0
- package/dist/client/flavors-Bgq3KZmx.mjs.map +1 -0
- package/dist/client/{flavors-B1SDOPDu.mjs → flavors-ZudiAiTU.mjs} +2 -2
- package/dist/client/{flavors-B1SDOPDu.mjs.map → flavors-ZudiAiTU.mjs.map} +1 -1
- package/dist/client/{floatingips-DrCvtXtT.mjs → floatingips-B1oLH8z6.mjs} +6 -6
- package/dist/client/{floatingips-DrCvtXtT.mjs.map → floatingips-B1oLH8z6.mjs.map} +1 -1
- package/dist/client/floatingips-BeQEkVH8.mjs +14 -0
- package/dist/client/floatingips-BeQEkVH8.mjs.map +1 -0
- package/dist/client/floatingips-BtLg3yEQ.mjs +22 -0
- package/dist/client/floatingips-BtLg3yEQ.mjs.map +1 -0
- package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -1
- package/dist/client/{images-BGQv9kKT.mjs → images-CnTW3bpy.mjs} +810 -770
- package/dist/client/images-CnTW3bpy.mjs.map +1 -0
- package/dist/client/{images-CPmMa4SQ.mjs → images-DZHDYDQu.mjs} +2 -2
- package/dist/client/{images-CPmMa4SQ.mjs.map → images-DZHDYDQu.mjs.map} +1 -1
- package/dist/client/index.js +412 -409
- package/dist/client/index.js.map +1 -1
- package/dist/client/{objects-DVccbrL1.mjs → objects-25xsh4Ia.mjs} +2 -2
- package/dist/client/objects-25xsh4Ia.mjs.map +1 -0
- package/dist/client/objects-KXY6dgwq.mjs +82 -0
- package/dist/client/objects-KXY6dgwq.mjs.map +1 -0
- package/dist/client/objects-QryuClU3.mjs +82 -0
- package/dist/client/objects-QryuClU3.mjs.map +1 -0
- package/dist/client/{objects-BR3eeSNH.mjs → objects-jYQBFzwg.mjs} +4668 -4699
- package/dist/client/objects-jYQBFzwg.mjs.map +1 -0
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/securitygroups--0PS2wbM.mjs +580 -0
- package/dist/client/securitygroups--0PS2wbM.mjs.map +1 -0
- package/dist/client/{securitygroups-DEJQBcxm.mjs → securitygroups-BRndk7wh.mjs} +2 -2
- package/dist/client/{securitygroups-DEJQBcxm.mjs.map → securitygroups-BRndk7wh.mjs.map} +1 -1
- package/dist/client/securitygroups-CdN4yAAw.mjs +14 -0
- package/dist/client/securitygroups-CdN4yAAw.mjs.map +1 -0
- package/dist/client/securitygroups-Cs2Op-tu.mjs +22 -0
- package/dist/client/securitygroups-Cs2Op-tu.mjs.map +1 -0
- package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -1
- package/dist/client/trpcClient.d.ts +6 -1
- package/dist/client/useModalTracking-BYd37pXm.mjs +37 -0
- package/dist/client/useModalTracking-BYd37pXm.mjs.map +1 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs +294 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs.map +1 -0
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +96 -30
- package/package.json +4 -4
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +0 -773
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +0 -1
- package/dist/client/FiltersInput-CKI6zWnm.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +0 -1152
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +0 -1
- package/dist/client/_flavorId-Dg7MS0Af.mjs.map +0 -1
- package/dist/client/_flavorId-kHl-b8rI.mjs +0 -232
- package/dist/client/_flavorId-kHl-b8rI.mjs.map +0 -1
- package/dist/client/_imageId-8JIbFmGB.mjs.map +0 -1
- package/dist/client/_imageId-BBAlRioC.mjs +0 -574
- package/dist/client/_imageId-BBAlRioC.mjs.map +0 -1
- package/dist/client/_projectId-7Nl1MQTJ.mjs +0 -99
- package/dist/client/_projectId-7Nl1MQTJ.mjs.map +0 -1
- package/dist/client/_projectId-B3wmSala.mjs.map +0 -1
- package/dist/client/_projectId-DPzv0CCp.mjs.map +0 -1
- package/dist/client/_projectId-DfeVJy0G.mjs.map +0 -1
- package/dist/client/_securityGroupId-C6eHmrx_.mjs.map +0 -1
- package/dist/client/_securityGroupId-DmplhDgt.mjs.map +0 -1
- package/dist/client/_storageType-C5gS9eut.mjs +0 -845
- package/dist/client/_storageType-C5gS9eut.mjs.map +0 -1
- package/dist/client/flavors-D8_PzQUB.mjs +0 -628
- package/dist/client/flavors-D8_PzQUB.mjs.map +0 -1
- package/dist/client/images-BGQv9kKT.mjs.map +0 -1
- package/dist/client/objects-AERkhfiM.mjs +0 -66
- package/dist/client/objects-AERkhfiM.mjs.map +0 -1
- package/dist/client/objects-BR3eeSNH.mjs.map +0 -1
- package/dist/client/objects-DVccbrL1.mjs.map +0 -1
- package/dist/client/securitygroups-BjhgLBHm.mjs +0 -620
- package/dist/client/securitygroups-BjhgLBHm.mjs.map +0 -1
- package/dist/client/useModalTracking-BcOKTYRN.mjs +0 -33
- package/dist/client/useModalTracking-BcOKTYRN.mjs.map +0 -1
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs +0 -227
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_storageType-c-DAu8qr.mjs","names":["useState","trpcReact","Modal","TextInput","Stack","Message","useProjectId","useModalTracking","CreateContainerModal","isOpen","onClose","onSuccess","onPartialSuccess","maxContainerNameLength","existingContainers","useLingui","projectId","containerName","setContainerName","nameError","setNameError","submitError","setSubmitError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","createContainerMutation","storage","swift","createContainer","useMutation","data","listContainers","invalidate","name","trim","optionsApplied","optionsError","t","handleClose","onError","error","code","message","reset","validateName","trimmed","length","includes","some","c","handleNameChange","e","value","target","handleSubmit","mutate","project_id","container","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","isPending","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","dismissible","onDismiss","role","aria-live","data-testid","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","autoFocus","placeholder","useEffect","useState","useNavigate","useParams","Button","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","Status","formatBytesBinary","formatSwiftDate","useVirtualizedTableBody","CreateContainerModal","EmptyContainerModal","DeleteContainerModal","EditContainerMetadataModal","ManageContainerAccessModal","ContainerTableView","containers","createModalOpen","setCreateModalOpen","maxContainerNameLength","existingContainers","onCreateSuccess","onCreatePartialSuccess","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","onPropertiesSuccess","onPropertiesError","onAclSuccess","onAclError","selectedContainers","setSelectedContainers","hasAnyBulkAction","projectId","provider","storageType","from","useLingui","navigate","scrollbarWidth","setScrollbarWidth","emptyModalContainer","setEmptyModalContainer","deleteModalContainer","setDeleteModalContainer","propertiesModalContainer","setPropertiesModalContainer","accessControlModalContainer","setAccessControlModalContainer","ref","tableBodyRef","elementRef","parentRef","height","bodyHeight","virtualItems","totalSize","measureElement","count","length","current","width","offsetWidth","clientWidth","handleSelectContainer","containerName","includes","filter","name","columnCount","gridColumnTemplate","div","className","style","paddingRight","columns","data-testid","marginRight","colSpan","status","title","t","body","position","map","virtualRow","container","index","isSelected","handleRowNavigate","to","params","data-index","top","left","transform","start","display","gridTemplateColumns","alignItems","tabIndex","onClick","onKeyDown","e","key","preventDefault","stopPropagation","checked","onChange","span","toLocaleString","last_modified","bytes","as","icon","aria-label","label","isOpen","onClose","onSuccess","onPartialSuccess","onError","Tooltip","TooltipTrigger","TooltipContent","Icon","formatBytesBinary","LimitItem","label","value","undefined","span","className","icon","size","CapabilityItem","Section","title","children","ContainerLimitsTooltip","serviceInfo","accountInfo","open","useLingui","swift","capabilityMap","account_quotas","t","container_quotas","bulk_delete","bulk_upload","slo","container_sync","tempurl","symlink","versioned_writes","capabilities","Object","entries","filter","key","map","triggerEvent","placement","objectCount","toLocaleString","bytesUsed","quotaBytes","max_file_size","max_container_name_length","max_object_name_length","container_listing_limit","account_listing_limit","max_header_size","max_meta_count","max_meta_name_length","max_meta_value_length","max_meta_overall_size","max_deletes_per_request","max_containers_per_extraction","max_manifest_segments","length","cap","z","useForm","useStore","useState","trpcReact","Modal","Status","Stack","Form","FormSection","TextInput","useProjectId","useModalTracking","MAX_VISIBLE","CONFIRM_WORD","EmptyContainersModal","isOpen","containers","onClose","onComplete","i18n","useLingui","projectId","progress","setProgress","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","transform","val","trim","refine","value","message","t","form","defaultValues","validators","onSubmit","emptyContainerMutation","isPending","emptiedCount","totalDeleted","errors","total","length","i","current","container","deleted","mutateAsync","project_id","name","err","Error","String","push","utils","storage","swift","listContainers","invalidate","handleClose","canEmpty","store","state","isSubmitting","values","useUtils","emptyContainer","useMutation","reset","totalCount","visibleContainers","slice","hiddenCount","progressCurrent","progressTotal","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","cancelButtonLabel","onConfirm","handleSubmit","disableConfirmButton","disableCancelButton","disableCloseButton","size","status","className","div","p","strong","direction","gap","map","count","span","_","plural","id","e","preventDefault","Field","children","field","label","placeholder","onChange","handleChange","target","disabled","autoFocus","required","useState","useEffect","useRef","startTransition","SortInput","trpcReact","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Status","Stack","toast","formatBytesBinary","parseSwiftDate","ContainerTableView","getContainerCreatedToast","getContainerCreatedWithWarningToast","getContainerEmptiedToast","getContainerEmptyErrorToast","getContainerDeletedToast","getContainerDeleteErrorToast","getContainerUpdatedToast","getContainerUpdateErrorToast","getContainerAclUpdatedToast","getContainerAclUpdateErrorToast","getContainersEmptyCompleteToast","ContainerLimitsTooltip","EmptyContainersModal","useNavigate","Route","useProjectId","SwiftContainers","i18n","useLingui","projectId","navigate","from","fullPath","sortBy","sortDirection","search","searchParam","useSearch","hasAnyBulkAction","createModalOpen","setCreateModalOpen","emptyAllModalOpen","setEmptyAllModalOpen","selectedContainers","setSelectedContainers","localSearchTerm","setLocalSearchTerm","debounceTimer","undefined","clearTimeout","current","handleCreateSuccess","containerName","message","options","success","handleCreatePartialSuccess","reason","warning","handleEmptySuccess","deletedCount","handleEmptyError","errorMessage","error","handleDeleteSuccess","handleDeleteError","handlePropertiesSuccess","handlePropertiesError","handleAclSuccess","handleAclError","handleEmptyAllComplete","emptiedCount","totalDeleted","errors","length","failedContainerNames","Set","map","e","split","prev","filter","name","has","severity","sortSettings","label","t","value","data","containers","isLoading","storage","swift","listContainers","useQuery","project_id","format","accountInfo","getAccountMetadata","serviceInfo","getServiceInfo","sortContainers","sort","a","b","comparison","localeCompare","count","bytes","last_modified","at","getTime","bt","filteredContainers","container","toLowerCase","includes","sortedContainers","handleSearchChange","term","handleSortChange","newSortSettings","resolvedSortBy","toString","resolvedDirection","status","title","body","bytesUsed","quotaBytes","remainingBytes","selectedContainerSummaries","c","hasSelection","selectedCount","totalCount","filteredCount","isFiltered","displayedNames","allSelected","every","n","someSelected","some","handleToggleSelectAll","div","className","direction","distribution","alignment","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","variant","onClick","placeholder","data-testid","onInput","currentTarget","window","setTimeout","onSearch","onClear","checked","indeterminate","onChange","as","disabled","size","icon","_","plural","span","maxContainerNameLength","max_container_name_length","existingContainers","onCreateSuccess","onCreatePartialSuccess","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","onPropertiesSuccess","onPropertiesError","onAclSuccess","onAclError","isOpen","onClose","onComplete","useParams","ErrorBoundary","SwiftContainers","CephBuckets","Trans","useLingui","ContentHeader","StorageDashboard","project","provider","from","select","params","projectId","storageType","t","pageTitle","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/CreateContainerModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerLimitsTooltip.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/EmptyContainersModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx?tsr-split=component"],"sourcesContent":["import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\n\ninterface CreateContainerModalProps {\n isOpen: boolean\n onClose: () => void\n onSuccess?: (containerName: string) => void\n onPartialSuccess?: (containerName: string, reason: string) => void\n maxContainerNameLength?: number\n existingContainers?: ContainerSummary[]\n}\n\nexport const CreateContainerModal = ({\n isOpen,\n onClose,\n onSuccess,\n onPartialSuccess,\n maxContainerNameLength = 256,\n existingContainers = [],\n}: CreateContainerModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [containerName, setContainerName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [submitError, setSubmitError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.container.create\",\n })\n\n const utils = trpcReact.useUtils()\n\n const createContainerMutation = trpcReact.storage.swift.createContainer.useMutation({\n onSuccess: (data) => {\n utils.storage.swift.listContainers.invalidate()\n const name = containerName.trim()\n if (data.optionsApplied) {\n onSuccess?.(name)\n } else {\n onPartialSuccess?.(name, data.optionsError ?? t`The container's settings could not be applied.`)\n }\n handleClose()\n },\n onError: (error) => {\n if (error.data?.code === \"CONFLICT\") {\n setNameError(t`A container with this name already exists`)\n setSubmitError(null)\n } else {\n setSubmitError(error.message || t`The container could not be created. Try again or choose a different name.`)\n }\n\n resetTracking()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setContainerName(\"\")\n setNameError(null)\n setSubmitError(null)\n resetTracking()\n createContainerMutation.reset()\n onClose()\n }\n\n const validateName = (name: string): boolean => {\n const trimmed = name.trim()\n\n if (!trimmed) {\n setNameError(t`Container name is required`)\n return false\n }\n if (trimmed.length > maxContainerNameLength) {\n setNameError(t`Container name must be ${maxContainerNameLength} characters or fewer`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNameError(t`Container name cannot contain slashes`)\n return false\n }\n\n if (existingContainers.some((c) => c.name === trimmed)) {\n setNameError(t`A container with this name already exists`)\n return false\n }\n\n setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setContainerName(value)\n setSubmitError(null)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(containerName)) return\n setSubmitError(null)\n markSubmitted()\n createContainerMutation.mutate({\n project_id: projectId,\n container: containerName.trim(),\n })\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") {\n handleSubmit()\n }\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Create Container`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={createContainerMutation.isPending ? t`Creating...` : t`Create`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={createContainerMutation.isPending || !containerName.trim()}\n disableCancelButton={createContainerMutation.isPending}\n disableCloseButton={createContainerMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {submitError && (\n <Message\n variant=\"error\"\n dismissible\n onDismiss={() => setSubmitError(null)}\n role=\"alert\"\n aria-live=\"assertive\"\n data-testid=\"create-container-error\"\n >\n {submitError}\n </Message>\n )}\n <p className=\"text-theme-default\">\n <Trans>\n Inside a project, objects are stored in containers. Containers are where you define access permissions and\n quotas.\n </Trans>\n </p>\n <TextInput\n label={t`Container name`}\n required\n value={containerName}\n onChange={handleNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={createContainerMutation.isPending}\n autoFocus\n placeholder={t`Enter container name`}\n />\n </Stack>\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport {\n Button,\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { formatSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { useVirtualizedTableBody } from \"@/client/hooks/useVirtualizedTableBody\"\nimport { CreateContainerModal } from \"./CreateContainerModal\"\nimport { EmptyContainerModal } from \"./EmptyContainerModal\"\nimport { DeleteContainerModal } from \"./DeleteContainerModal\"\nimport { EditContainerMetadataModal } from \"./EditContainerMetadataModal\"\nimport { ManageContainerAccessModal } from \"./ManageContainerAccessModal\"\n\ninterface ContainerTableViewProps {\n containers: ContainerSummary[]\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n maxContainerNameLength?: number\n existingContainers?: ContainerSummary[]\n onCreateSuccess: (containerName: string) => void\n onCreatePartialSuccess: (containerName: string, reason: string) => void\n onEmptySuccess: (containerName: string, deletedCount: number) => void\n onEmptyError: (containerName: string, errorMessage: string) => void\n onDeleteSuccess: (containerName: string) => void\n onDeleteError: (containerName: string, errorMessage: string) => void\n onPropertiesSuccess: (containerName: string) => void\n onPropertiesError: (containerName: string, errorMessage: string) => void\n onAclSuccess: (containerName: string) => void\n onAclError: (containerName: string, errorMessage: string) => void\n selectedContainers: string[]\n setSelectedContainers: (containers: string[]) => void\n // When false, the row-selection column (header checkbox + per-row checkboxes)\n // is dropped entirely and the grid renders one fewer column. Defaults to true\n // so existing callers that don't pass it keep the selectable layout.\n hasAnyBulkAction?: boolean\n}\n\nexport const ContainerTableView = ({\n containers,\n createModalOpen,\n setCreateModalOpen,\n maxContainerNameLength,\n existingContainers = [],\n onCreateSuccess,\n onCreatePartialSuccess,\n onEmptySuccess,\n onEmptyError,\n onDeleteSuccess,\n onDeleteError,\n onPropertiesSuccess,\n onPropertiesError,\n onAclSuccess,\n onAclError,\n selectedContainers,\n setSelectedContainers,\n hasAnyBulkAction = true,\n}: ContainerTableViewProps) => {\n const { projectId, provider, storageType } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n })\n\n const { t } = useLingui()\n const navigate = useNavigate()\n\n const [scrollbarWidth, setScrollbarWidth] = useState(0)\n const [emptyModalContainer, setEmptyModalContainer] = useState<ContainerSummary | null>(null)\n const [deleteModalContainer, setDeleteModalContainer] = useState<ContainerSummary | null>(null)\n const [propertiesModalContainer, setPropertiesModalContainer] = useState<ContainerSummary | null>(null)\n const [accessControlModalContainer, setAccessControlModalContainer] = useState<ContainerSummary | null>(null)\n\n // Height measured from the space actually left below the table, plus a\n // virtualizer that stays silent until that height is known.\n const {\n ref: tableBodyRef,\n elementRef: parentRef,\n height: bodyHeight,\n virtualItems,\n totalSize,\n measureElement,\n } = useVirtualizedTableBody({ count: containers.length })\n\n // Calculate scrollbar width\n useEffect(() => {\n if (parentRef.current) {\n const width = parentRef.current.offsetWidth - parentRef.current.clientWidth\n setScrollbarWidth(width)\n }\n }, [containers.length, bodyHeight])\n\n const handleSelectContainer = (containerName: string) => {\n if (selectedContainers.includes(containerName)) {\n setSelectedContainers(selectedContainers.filter((name) => name !== containerName))\n } else {\n setSelectedContainers([...selectedContainers, containerName])\n }\n }\n\n // Column count and template depend on whether the selection column is shown.\n // With selection: checkbox, name, count, last modified, size, actions menu (6).\n // Without selection: the leading 40px checkbox column is dropped (5).\n const columnCount = hasAnyBulkAction ? 6 : 5\n const gridColumnTemplate = hasAnyBulkAction\n ? \"40px minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n : \"minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n className=\"containers\"\n data-testid=\"containers-table-header\"\n >\n <DataGridRow>\n {hasAnyBulkAction && <DataGridHeadCell />}\n <DataGridHeadCell>\n <Trans>Container Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Object Count</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Total Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell style={{ marginRight: `-${scrollbarWidth}px` }} />\n </DataGridRow>\n\n {(!containers || containers.length === 0) && (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status\n status=\"empty\"\n title={t`No containers found`}\n body={t`There are no containers available with the current search criteria. Try adjusting your search term.`}\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n\n {/* Virtualized Table Body — sized to the space actually left below the\n table, so banners above it shrink the table instead of growing the\n page. */}\n <div\n ref={tableBodyRef}\n className=\"overflow-auto\"\n style={{ height: `${bodyHeight ?? 0}px` }}\n data-testid=\"containers-table-body\"\n >\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n style={{\n height: `${totalSize}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n const container = containers[virtualRow.index]\n const isSelected = selectedContainers.includes(container.name)\n\n const handleRowNavigate = () =>\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider, storageType, containerName: container.name },\n })\n\n return (\n <DataGridRow\n key={container.name}\n data-index={virtualRow.index}\n ref={measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"grid\",\n gridTemplateColumns: gridColumnTemplate,\n alignItems: \"stretch\",\n }}\n data-testid={`container-row-${container.name}`}\n tabIndex={0}\n onClick={handleRowNavigate}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n handleRowNavigate()\n }\n }}\n >\n {hasAnyBulkAction && (\n <DataGridCell\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.stopPropagation()\n }\n }}\n >\n <Checkbox\n checked={isSelected}\n onChange={() => handleSelectContainer(container.name)}\n data-testid={`select-container-${container.name}`}\n />\n </DataGridCell>\n )}\n <DataGridCell className=\"min-w-0 overflow-hidden\">\n <span className=\"block truncate\" title={container.name}>\n {container.name}\n </span>\n </DataGridCell>\n <DataGridCell>{container.count.toLocaleString()}</DataGridCell>\n <DataGridCell>{formatSwiftDate(container.last_modified) ?? t`N/A`}</DataGridCell>\n <DataGridCell>{formatBytesBinary(container.bytes)}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button\n icon=\"moreVert\"\n title={t`Container actions`}\n aria-label={t`Container actions`}\n className=\"!bg-transparent\"\n />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() => setAccessControlModalContainer(container)}\n data-testid={`access-control-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Preview and Edit metadata`}\n onClick={() => setPropertiesModalContainer(container)}\n data-testid={`properties-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Empty Container`}\n onClick={() => setEmptyModalContainer(container)}\n data-testid={`empty-action-${container.name}`}\n />\n <PopupMenuItem\n label={t`Delete Container`}\n onClick={() => setDeleteModalContainer(container)}\n data-testid={`delete-action-${container.name}`}\n />\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </div>\n </div>\n\n <CreateContainerModal\n isOpen={createModalOpen}\n onClose={() => setCreateModalOpen(false)}\n onSuccess={onCreateSuccess}\n onPartialSuccess={onCreatePartialSuccess}\n maxContainerNameLength={maxContainerNameLength}\n existingContainers={existingContainers}\n />\n\n <EmptyContainerModal\n isOpen={emptyModalContainer !== null}\n container={emptyModalContainer}\n onClose={() => setEmptyModalContainer(null)}\n onSuccess={onEmptySuccess}\n onError={onEmptyError}\n />\n\n <DeleteContainerModal\n isOpen={deleteModalContainer !== null}\n container={deleteModalContainer}\n onClose={() => setDeleteModalContainer(null)}\n onSuccess={onDeleteSuccess}\n onError={onDeleteError}\n />\n\n <EditContainerMetadataModal\n isOpen={propertiesModalContainer !== null}\n container={propertiesModalContainer}\n onClose={() => setPropertiesModalContainer(null)}\n onSuccess={onPropertiesSuccess}\n onError={onPropertiesError}\n />\n\n <ManageContainerAccessModal\n isOpen={accessControlModalContainer !== null}\n container={accessControlModalContainer}\n onClose={() => setAccessControlModalContainer(null)}\n onSuccess={onAclSuccess}\n onError={onAclError}\n />\n </>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Tooltip, TooltipTrigger, TooltipContent, Icon } from \"@cloudoperators/juno-ui-components\"\nimport { ServiceInfo, AccountInfo } from \"@/server/Storage/types/swift\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface ContainerLimitsTooltipProps {\n serviceInfo?: ServiceInfo\n accountInfo?: AccountInfo\n open?: boolean\n}\n\ninterface LimitItemProps {\n label: string\n value?: string | number\n}\n\nconst LimitItem = ({ label, value }: LimitItemProps) => {\n if (value === undefined || value === null) return null\n return (\n <span className=\"flex items-start gap-1.5\">\n <Icon icon=\"check\" size=\"16px\" className=\"text-theme-success mt-0.5 shrink-0\" />\n <span>\n <span className=\"font-medium\">{label}:</span> {value}\n </span>\n </span>\n )\n}\n\nconst CapabilityItem = ({ label }: { label: string }) => (\n <span className=\"flex items-start gap-1.5\">\n <Icon icon=\"check\" size=\"16px\" className=\"text-theme-success mt-0.5 shrink-0\" />\n <span>{label}</span>\n </span>\n)\n\nconst Section = ({ title, children }: { title: React.ReactNode; children: React.ReactNode }) => (\n <span className=\"flex flex-col gap-1.5\">\n <span className=\"text-theme-default block font-semibold\">{title}</span>\n {children}\n </span>\n)\n\nexport const ContainerLimitsTooltip = ({ serviceInfo, accountInfo, open }: ContainerLimitsTooltipProps) => {\n const { t } = useLingui()\n\n const swift = serviceInfo?.swift\n\n const capabilityMap = {\n account_quotas: t`Account quotas`,\n container_quotas: t`Container quotas`,\n bulk_delete: t`Efficient bulk deletion`,\n bulk_upload: t`Bulk upload of archive files`,\n slo: t`Static large object support`,\n container_sync: t`Container syncing`,\n tempurl: t`Temporary URLs`,\n symlink: t`Symlinks`,\n versioned_writes: t`Versioned writes`,\n } as const\n\n const capabilities = Object.entries(capabilityMap)\n .filter(([key]) => swift?.[key as keyof typeof swift])\n .map(([, label]) => label)\n\n return (\n <Tooltip triggerEvent=\"hover\" placement=\"bottom-end\" open={open}>\n <TooltipTrigger className=\"max-h-5\">\n <span>\n <Icon icon=\"info\" size=\"20px\" className=\"text-theme-light hover:text-theme-default cursor-pointer\" />\n </span>\n </TooltipTrigger>\n <TooltipContent className=\"z-10 w-72 text-sm\">\n <span className=\"flex flex-col gap-3 p-1\">\n {/* Account stats */}\n {accountInfo && (\n <Section title={<Trans>Account</Trans>}>\n <LimitItem label={t`Objects`} value={accountInfo.objectCount.toLocaleString()} />\n <LimitItem label={t`Used`} value={formatBytesBinary(accountInfo.bytesUsed)} />\n {accountInfo.quotaBytes !== undefined && (\n <LimitItem label={t`Quota`} value={formatBytesBinary(accountInfo.quotaBytes)} />\n )}\n </Section>\n )}\n\n {/* Limits */}\n {swift && (\n <Section title={<Trans>Limits</Trans>}>\n <LimitItem\n label={t`Max file size`}\n value={swift.max_file_size !== undefined ? formatBytesBinary(swift.max_file_size) : undefined}\n />\n <LimitItem label={t`Max container name length`} value={swift.max_container_name_length} />\n <LimitItem label={t`Max object name length`} value={swift.max_object_name_length} />\n <LimitItem label={t`Container listing limit`} value={swift.container_listing_limit?.toLocaleString()} />\n <LimitItem label={t`Account listing limit`} value={swift.account_listing_limit?.toLocaleString()} />\n <LimitItem label={t`Max header size`} value={swift.max_header_size} />\n <LimitItem label={t`Max meta count`} value={swift.max_meta_count} />\n <LimitItem label={t`Max meta name length`} value={swift.max_meta_name_length} />\n <LimitItem label={t`Max meta value length`} value={swift.max_meta_value_length} />\n <LimitItem label={t`Max meta overall size`} value={swift.max_meta_overall_size} />\n {swift.bulk_delete && (\n <LimitItem\n label={t`Max deletes per request`}\n value={swift.bulk_delete.max_deletes_per_request.toLocaleString()}\n />\n )}\n {swift.bulk_upload && (\n <LimitItem\n label={t`Max containers per extraction`}\n value={swift.bulk_upload.max_containers_per_extraction.toLocaleString()}\n />\n )}\n {swift.slo && (\n <LimitItem label={t`Max SLO segments`} value={swift.slo.max_manifest_segments.toLocaleString()} />\n )}\n </Section>\n )}\n\n {/* Capabilities */}\n {capabilities.length > 0 && (\n <Section title={<Trans>Capabilities</Trans>}>\n {capabilities.map((cap) => (\n <CapabilityItem key={cap} label={cap} />\n ))}\n </Section>\n )}\n </span>\n </TooltipContent>\n </Tooltip>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useState } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Status, Stack, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\n// Max number of container names shown in the list before truncating\nconst MAX_VISIBLE = 20\n\n// The literal word the user must type to confirm this destructive action.\n// The gating logic (isConfirmed) compares against this constant, NOT the\n// translated label — so a mistranslated label can never weaken or break the\n// confirmation gate. The English label below should name the same word for clarity.\nconst CONFIRM_WORD = \"empty\"\n\ninterface EmptyContainersResult {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n}\n\ninterface EmptyContainersModalProps {\n isOpen: boolean\n containers: ContainerSummary[]\n onClose: () => void\n onComplete?: (result: EmptyContainersResult) => void\n}\n\nexport const EmptyContainersModal = ({ isOpen, containers, onClose, onComplete }: EmptyContainersModalProps) => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n\n const [progress, setProgress] = useState<{ current: number; total: number } | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.containers.empty\",\n })\n\n const formSchema = z.object({\n confirm: z\n .string()\n .transform((val) => val.trim())\n .refine((value) => value === CONFIRM_WORD, {\n message: t`Type \"${CONFIRM_WORD}\" to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (emptyContainerMutation.isPending || progress !== null) return\n\n markSubmitted()\n let emptiedCount = 0\n let totalDeleted = 0\n const errors: string[] = []\n const total = containers.length\n\n for (let i = 0; i < containers.length; i++) {\n setProgress({ current: i + 1, total })\n const container = containers[i]\n\n try {\n const deleted = await emptyContainerMutation.mutateAsync({ project_id: projectId, container: container.name })\n totalDeleted += deleted\n emptiedCount++\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n errors.push(`${container.name}: ${message}`)\n }\n }\n\n if (emptiedCount > 0) {\n await utils.storage.swift.listContainers.invalidate()\n }\n\n onComplete?.({ emptiedCount, totalDeleted, errors })\n\n handleClose()\n },\n })\n\n const canEmpty = useStore(form.store, (state) => state.isSubmitting || state.values.confirm.trim() !== CONFIRM_WORD)\n\n const utils = trpcReact.useUtils()\n\n const emptyContainerMutation = trpcReact.storage.swift.emptyContainer.useMutation()\n\n const handleClose = () => {\n trackClose()\n emptyContainerMutation.reset()\n setProgress(null)\n form.reset()\n resetTracking()\n onClose()\n }\n\n if (!isOpen || containers.length === 0) return null\n\n const totalCount = containers.length\n const visibleContainers = containers.slice(0, MAX_VISIBLE)\n const hiddenCount = totalCount - visibleContainers.length\n const isPending = emptyContainerMutation.isPending || progress !== null\n const progressCurrent = progress?.current\n const progressTotal = progress?.total\n\n return (\n <Modal\n title={<Plural value={totalCount} one=\"Empty Container\" other=\"Empty # Containers\" />}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isPending ? t`Emptying...` : t`Empty`}\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || canEmpty}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Status\n status=\"progress\"\n title={\n progress ? t`Emptying Container ${progressCurrent} of ${progressTotal}, Please Wait...` : t`Emptying...`\n }\n className=\"mt-0\"\n />\n ) : (\n <div>\n <p>\n <Trans>All objects in the selected containers will be permanently deleted. This cannot be undone.</Trans>\n </p>\n <p>\n <Trans>\n For <strong>dynamic</strong> and <strong>static large objects</strong> only the manifests are deleted —\n the related segments are not deleted.\n </Trans>\n </p>\n <div className=\"my-6\">\n <p className=\"text-sm font-semibold\">\n <Trans>Containers to be emptied:</Trans>\n </p>\n <div className=\"bg-theme-background-lvl-2 mt-2 max-h-48 overflow-y-auto rounded p-3\">\n <Stack direction=\"vertical\" gap=\"1\">\n {visibleContainers.map((container) => {\n const count = container.count\n return (\n <div key={container.name} className=\"text-theme-default overflow-x-hidden text-sm wrap-anywhere\">\n {container.name}\n {count != null && (\n <span className=\"text-theme-light ml-2\">\n ({i18n._(plural(count, { one: \"# object\", other: \"# objects\" }))})\n </span>\n )}\n </div>\n )\n })}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"empty-containers-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n children={(field) => (\n <TextInput\n label={t`Type \"empty\" to confirm`}\n placeholder={CONFIRM_WORD}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n disabled={isPending}\n autoFocus\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </div>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Button,\n Checkbox,\n DataGridToolbar,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n SearchInput,\n Status,\n Stack,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { parseSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { ContainerTableView } from \"./ContainerTableView\"\nimport {\n getContainerCreatedToast,\n getContainerCreatedWithWarningToast,\n getContainerEmptiedToast,\n getContainerEmptyErrorToast,\n getContainerDeletedToast,\n getContainerDeleteErrorToast,\n getContainerUpdatedToast,\n getContainerUpdateErrorToast,\n getContainerAclUpdatedToast,\n getContainerAclUpdateErrorToast,\n getContainersEmptyCompleteToast,\n} from \"./ContainerToastNotifications\"\nimport { ContainerLimitsTooltip } from \"./ContainerLimitsTooltip\"\nimport { EmptyContainersModal } from \"./EmptyContainersModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"../../../$provider/$storageType/\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\nexport const SwiftContainers = () => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n // Sort and search state are persisted in the URL so they survive navigation,\n // browser back/forward, and deep links.\n const { sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n\n // Whether the list exposes any bulk action — drives the selection column in\n // ContainerTableView and the Zone 3 bulk-action controls. Hardcoded to true\n // for now; the only bulk action today is the destructive Empty.\n //\n // TODO(perms): wire this to the real Swift container permission source\n // (e.g. a usePermissions hook or a tRPC permissions query) instead of\n // hardcoding it.\n const hasAnyBulkAction = true\n\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [emptyAllModalOpen, setEmptyAllModalOpen] = useState(false)\n const [selectedContainers, setSelectedContainers] = useState<string[]>([])\n\n // Local mirror of the committed search term so typing stays responsive while\n // the URL commit is debounced (see Zone 2 SearchInput below).\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParam)\n const debounceTimer = useRef<number | undefined>(undefined)\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n // Keep the input in sync when the committed search term changes from outside\n // the input — browser back/forward, deep links, or programmatic navigation —\n // so the field never drifts from the URL-backed filter state. When the change\n // originated from our own debounced commit, searchParam already equals\n // localSearchTerm, so this is a no-op and won't disturb the caret.\n useEffect(() => {\n setLocalSearchTerm(searchParam)\n }, [searchParam])\n\n const handleCreateSuccess = (containerName: string) => {\n const { message, ...options } = getContainerCreatedToast(containerName)\n toast.success(message, options)\n }\n\n const handleCreatePartialSuccess = (containerName: string, reason: string) => {\n const { message, ...options } = getContainerCreatedWithWarningToast(containerName, reason)\n toast.warning(message, options)\n }\n\n const handleEmptySuccess = (containerName: string, deletedCount: number) => {\n const { message, ...options } = getContainerEmptiedToast(containerName, deletedCount)\n toast.success(message, options)\n }\n\n const handleEmptyError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerEmptyErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleDeleteSuccess = (containerName: string) => {\n const { message, ...options } = getContainerDeletedToast(containerName)\n toast.success(message, options)\n }\n\n const handleDeleteError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerDeleteErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handlePropertiesSuccess = (containerName: string) => {\n const { message, ...options } = getContainerUpdatedToast(containerName)\n toast.success(message, options)\n }\n\n const handlePropertiesError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerUpdateErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleAclSuccess = (containerName: string) => {\n const { message, ...options } = getContainerAclUpdatedToast(containerName)\n toast.success(message, options)\n }\n\n const handleAclError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerAclUpdateErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleEmptyAllComplete = ({\n emptiedCount,\n totalDeleted,\n errors,\n }: {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n }) => {\n if (errors.length === 0) {\n setSelectedContainers([])\n } else {\n // Extract the container name from each error string formatted as \"<containerName>: <message>\".\n // Using exact name extraction avoids the false-positive substring match that\n // errorMessage.includes(containerName) would produce (e.g. \"foo\" matched inside \"foobar\" error).\n const failedContainerNames = new Set(errors.map((e) => e.split(\": \")[0]))\n setSelectedContainers((prev) => prev.filter((name) => failedContainerNames.has(name)))\n }\n\n const { message, severity, ...options } = getContainersEmptyCompleteToast(emptiedCount, totalDeleted, errors)\n toast[severity](message, options)\n }\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Container Name`, value: \"name\" },\n { label: t`Object Count`, value: \"count\" },\n { label: t`Total Size`, value: \"bytes\" },\n { label: t`Last Modified`, value: \"last_modified\" },\n ],\n sortBy: sortBy ?? \"name\",\n sortDirection: sortDirection ?? \"asc\",\n }\n\n // Fetch containers from tRPC\n const {\n data: containers,\n isLoading,\n error,\n } = trpcReact.storage.swift.listContainers.useQuery({\n project_id: projectId,\n format: \"json\",\n })\n\n // Fetch account metadata for quota information\n const { data: accountInfo } = trpcReact.storage.swift.getAccountMetadata.useQuery({\n project_id: projectId,\n })\n\n // Fetch Swift service info\n const { data: serviceInfo } = trpcReact.storage.swift.getServiceInfo.useQuery()\n\n // Sort containers based on sort settings\n const sortContainers = (containers: ContainerSummary[]): ContainerSummary[] => {\n return [...containers].sort((a, b) => {\n let comparison: number\n\n switch (sortBy ?? \"name\") {\n case \"name\":\n comparison = a.name.localeCompare(b.name)\n break\n case \"count\":\n comparison = a.count - b.count\n break\n case \"bytes\":\n comparison = a.bytes - b.bytes\n break\n case \"last_modified\": {\n // Both missing → equal (keeps the comparator transitive); exactly one\n // missing → push it to the end.\n if (!a.last_modified && !b.last_modified) return 0\n if (!a.last_modified || !b.last_modified) {\n return a.last_modified ? -1 : 1\n }\n // #1236: Swift listing timestamps are UTC without a \"Z\" — parse them as\n // UTC so the ordering is correct (matters near DST boundaries). If a\n // (non-empty) value can't be parsed, treat the pair as equal so the\n // order is left untouched (matches the old NaN behaviour).\n const at = parseSwiftDate(a.last_modified)?.getTime()\n const bt = parseSwiftDate(b.last_modified)?.getTime()\n comparison = at == null || bt == null ? 0 : at - bt\n break\n }\n default:\n comparison = a.name.localeCompare(b.name)\n }\n\n return (sortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n }\n\n // Filter containers based on search term\n const filteredContainers = (containers || []).filter((container) =>\n container.name.toLowerCase().includes(searchParam.toLowerCase())\n )\n\n // Apply sorting to filtered containers\n const sortedContainers = sortContainers(filteredContainers)\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({ ...prev, search: value || undefined }),\n })\n })\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const resolvedSortBy = (newSortSettings.sortBy?.toString() || \"name\") as\n \"name\" | \"count\" | \"bytes\" | \"last_modified\"\n const resolvedDirection = (newSortSettings.sortDirection || \"asc\") as \"asc\" | \"desc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n sortBy: resolvedSortBy,\n sortDirection: resolvedDirection,\n }),\n })\n })\n }\n\n // Handle loading state\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Containers...`} />\n }\n\n // Handle error state\n if (error) {\n return <Status status=\"error\" title={t`Error Loading Containers`} body={error.message} />\n }\n\n // Calculate quota information\n const bytesUsed = accountInfo?.bytesUsed || 0\n const quotaBytes = accountInfo?.quotaBytes || 0\n const remainingBytes = quotaBytes > 0 ? quotaBytes - bytesUsed : 0\n\n // Resolve selected ContainerSummary objects from the full unfiltered list so\n // the modal always operates on what was actually selected — not the filtered\n // subset currently visible in the table.\n const selectedContainerSummaries = (containers || []).filter((c) => selectedContainers.includes(c.name))\n const hasSelection = selectedContainerSummaries.length > 0\n const selectedCount = selectedContainerSummaries.length\n\n const totalCount = (containers || []).length\n const filteredCount = filteredContainers.length\n const isFiltered = filteredCount !== totalCount\n\n // Select-all operates on the currently displayed (filtered + sorted) rows.\n const displayedNames = sortedContainers.map((c) => c.name)\n const allSelected = displayedNames.length > 0 && displayedNames.every((n) => selectedContainers.includes(n))\n const someSelected = displayedNames.some((n) => selectedContainers.includes(n))\n\n const handleToggleSelectAll = () => {\n if (allSelected) {\n setSelectedContainers((prev) => prev.filter((n) => !displayedNames.includes(n)))\n } else {\n setSelectedContainers((prev) => [...new Set([...prev, ...displayedNames])])\n }\n }\n\n return (\n <div className=\"relative\">\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and the create action (plain Stack, no background) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\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 </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setCreateModalOpen(true)}>\n <Trans>Create Container</Trans>\n </Button>\n </Stack>\n\n {/* Zone 2 — search (+ filter pills). DataGridToolbar provides the background.\n Swift containers expose no filterable dimensions yet, so there is no\n FiltersInput / SelectedFilters here. When filter dimensions are added,\n add FiltersInput alongside the search (switch the inner Stack to\n distribution=\"between\") and render SelectedFilters below, using\n applyFilterSelection from urlHelpers for merge logic. */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search containers...`}\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(() => handleSearchChange(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — bulk actions (gated) plus the container/quota info.\n Unlike the Images reference (where Zone 3 carries only bulk actions and is\n omitted entirely without permissions), this bar also hosts the Swift-specific\n count + remaining-quota + limits info, which must always be visible. So the\n bar always renders; only the bulk controls are gated. Bulk controls\n sit on the left; the count + quota are pushed right via ml-auto so they\n stay right-aligned regardless of whether the bulk block renders. */}\n <DataGridToolbar>\n <Stack distribution=\"start\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {hasAnyBulkAction ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected && !allSelected}\n onChange={handleToggleSelectAll}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={!hasSelection} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {hasSelection && (\n <PopupMenuOptions>\n <PopupMenuItem\n disabled={!hasSelection}\n label={i18n._(\n plural(selectedCount, {\n one: \"Empty Container\",\n other: \"Empty # Containers\",\n })\n )}\n onClick={() => setEmptyAllModalOpen(true)}\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n\n <div className=\"text-theme-light ml-auto flex items-center gap-1\" data-testid=\"containers-info-block\">\n {isFiltered ? (\n <Plural\n value={filteredCount}\n one={`${filteredCount} of ${totalCount} container`}\n other={`${filteredCount} of ${totalCount} containers`}\n />\n ) : (\n <Plural value={totalCount} one={`${totalCount} container`} other={`${totalCount} containers`} />\n )}\n {quotaBytes > 0 && (\n <>\n <span>,</span>\n <span>\n <Trans>Remaining Quota:</Trans>{\" \"}\n <span className=\"text-theme-default font-semibold\">{formatBytesBinary(remainingBytes)}</span>\n </span>\n </>\n )}\n <ContainerLimitsTooltip serviceInfo={serviceInfo} accountInfo={accountInfo} />\n </div>\n </Stack>\n </DataGridToolbar>\n </Stack>\n\n <ContainerTableView\n containers={sortedContainers}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n maxContainerNameLength={serviceInfo?.swift?.max_container_name_length}\n existingContainers={containers}\n onCreateSuccess={handleCreateSuccess}\n onCreatePartialSuccess={handleCreatePartialSuccess}\n onEmptySuccess={handleEmptySuccess}\n onEmptyError={handleEmptyError}\n onDeleteSuccess={handleDeleteSuccess}\n onDeleteError={handleDeleteError}\n onPropertiesSuccess={handlePropertiesSuccess}\n onPropertiesError={handlePropertiesError}\n onAclSuccess={handleAclSuccess}\n onAclError={handleAclError}\n selectedContainers={selectedContainers}\n setSelectedContainers={setSelectedContainers}\n hasAnyBulkAction={hasAnyBulkAction}\n />\n\n <EmptyContainersModal\n isOpen={emptyAllModalOpen}\n containers={selectedContainerSummaries}\n onClose={() => setEmptyAllModalOpen(false)}\n onComplete={handleEmptyAllComplete}\n />\n </div>\n )\n}\n","import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { SwiftContainers } from \"../../-components/Swift/Containers\"\nimport { CephBuckets } from \"../../-components/Ceph/Buckets\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\n/**\n * Validates that the requested storage provider is available for the given project,\n * and redirects to an appropriate fallback route when it is not.\n *\n * Redirect rules (in priority order):\n * 1. No `object-store` service at all → redirect to the project overview.\n * 2. Unknown provider (neither \"swift\" nor \"ceph\") → redirect to the first\n * available provider, or to the project overview if none exist.\n * 3. Requested provider unavailable → redirect to the other provider,\n * or to the project overview if no alternative exists.\n *\n * Ceph has a temporary fallback flag (`cephFallbackEnabled`) that treats it as\n * available even when absent from the OpenStack service catalog.\n *\n * @throws {redirect} - Always throws a TanStack Router redirect; never returns normally\n * when the requested provider/project combination is unavailable.\n */\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n }\n) => {\n const { provider, projectId } = params\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if no storage services available\n if (!serviceIndex[\"object-store\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n // Check provider availability\n const hasSwift = Boolean(serviceIndex[\"object-store\"][\"swift\"])\n const hasCeph = Boolean(serviceIndex[\"object-store\"][\"ceph\"])\n\n // TEMPORARY: Allow Ceph access even if not in catalog (relies on env config)\n // TODO: Properly register Ceph in OpenStack service catalog\n const cephFallbackEnabled = true // Set to false once Ceph is in catalog\n\n // Effective availability includes fallback flag for Ceph\n const hasEffectiveCeph = hasCeph || cephFallbackEnabled\n const fallbackProvider = hasSwift ? \"swift\" : hasEffectiveCeph ? \"ceph\" : null\n const fallbackStorageType = hasSwift ? \"containers\" : hasEffectiveCeph ? \"buckets\" : null\n\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider || !fallbackStorageType) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: fallbackProvider, storageType: fallbackStorageType },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"ceph\", storageType: \"buckets\" },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"swift\", storageType: \"containers\" },\n })\n }\n}\n\n// Search params schema\n// - sortBy: active sort column — persisted for deep links and back navigation\n// - sortDirection: \"asc\" | \"desc\" — persisted alongside sortBy\n// - search: active filter string — persisted so deep links preserve the current search\nconst containersSearchSchema = z.object({\n sortBy: z.enum([\"name\", \"count\", \"bytes\", \"last_modified\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: z.string().optional(),\n})\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType/\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n analytics: {\n name: \"storage.objectstore.list\",\n },\n } satisfies RouteInfo,\n validateSearch: containersSearchSchema,\n head: ({ match }) => ({\n meta: [\n {\n title:\n match.params.provider === \"swift\"\n ? \"Object Storage (Swift)\"\n : match.params.provider === \"ceph\"\n ? \"Object Storage (Ceph)\"\n : \"Storage Overview\",\n },\n ],\n }),\n component: () => {\n return <StorageDashboard />\n },\n notFoundComponent: () => {\n return <p>Storage service not found</p>\n },\n loader: async ({ context }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n\n return {\n client: trpcClient,\n availableServices,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n checkServiceAvailability(availableServices!, params)\n },\n})\n\nfunction StorageDashboard() {\n const { project, provider } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n select: (params) => {\n return { project: params.projectId, provider: params.provider, storageType: params.storageType }\n },\n })\n\n const { t } = useLingui()\n\n let pageTitle: string\n switch (provider) {\n case \"swift\":\n pageTitle = t`Object Storage (Swift)`\n break\n case \"ceph\":\n pageTitle = t`Object Storage (Ceph)`\n break\n default:\n pageTitle = t`Storage Overview`\n }\n\n return (\n <div>\n <ContentHeader title={pageTitle} projectId={project} />\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider]}\n fallback={\n <div className=\"p-4 text-center\">\n <Trans>Error loading component</Trans>\n </div>\n }\n >\n {(() => {\n switch (provider) {\n case \"swift\":\n return <SwiftContainers />\n case \"ceph\":\n return <CephBuckets />\n default:\n return <div>Storage Overview Page</div> // replace when available\n }\n })()}\n </ErrorBoundary>\n ) : (\n <div className=\"p-4 text-center\">\n <Trans>No project selected</Trans>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -5,5 +5,10 @@ interface RouteErrorProps {
|
|
|
5
5
|
/** Explicitly pass a safe error message to display. Use this when you want to show specific error details. */
|
|
6
6
|
safeErrorMessage?: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Renders errors that occur outside the application layout, such as an expired
|
|
10
|
+
* cookie or token. In these cases, the normal page content is unavailable and
|
|
11
|
+
* only the header may remain visible.
|
|
12
|
+
*/
|
|
8
13
|
export declare function RouteError({ error, title, helpText, safeErrorMessage }: RouteErrorProps): import("react").JSX.Element;
|
|
9
14
|
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface RouteIdLevelDefaultErrorProps {
|
|
3
|
+
errorTitle?: string;
|
|
4
|
+
errorDescription?: string;
|
|
5
|
+
action?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Renders the default error state for resource detail pages at the route-ID
|
|
9
|
+
* level, while keeping the surrounding application layout visible.
|
|
10
|
+
*
|
|
11
|
+
* This is similar to the service-level not-found component, but remains
|
|
12
|
+
* separate to make route error handling easier to trace. Callers can provide
|
|
13
|
+
* resource-specific titles, descriptions, and actions; otherwise, the default
|
|
14
|
+
* action navigates back to the current project.
|
|
15
|
+
*/
|
|
16
|
+
export declare const RouteIdLevelDefaultError: ({ errorTitle, errorDescription, action }: RouteIdLevelDefaultErrorProps) => import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders the default not-found state inside the application layout.
|
|
3
|
+
*
|
|
4
|
+
* This component is used as the router's `defaultNotFoundComponent` for routes
|
|
5
|
+
* that do not exist, such as a mistyped path (`network/floatingips` entered as
|
|
6
|
+
* `netrowk/floatingips`). Unlike a route-level error, it does not break the
|
|
7
|
+
* layout and keeps the header and navigation visible.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ServiceLevelDefaultError: () => import("react").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SelectedFilter } from './types';
|
|
1
|
+
import { Filter, SelectedFilter } from './types';
|
|
2
2
|
export type SelectedFiltersProps = {
|
|
3
3
|
/**
|
|
4
4
|
* Array of currently active filters to be displayed as closeable pills.
|
|
@@ -12,6 +12,11 @@ export type SelectedFiltersProps = {
|
|
|
12
12
|
* Callback function invoked when the "Clear all" button is clicked.
|
|
13
13
|
*/
|
|
14
14
|
onClear: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* Optional filter definitions used to resolve human-readable labels for pills;
|
|
17
|
+
* when omitted, raw name/value are shown.
|
|
18
|
+
*/
|
|
19
|
+
filters?: Filter[];
|
|
15
20
|
};
|
|
16
21
|
/**
|
|
17
22
|
* SelectedFilters Component
|
|
@@ -21,4 +26,4 @@ export type SelectedFiltersProps = {
|
|
|
21
26
|
*
|
|
22
27
|
* The pills are arranged in a flexible, wrapping layout that adapts to available space.
|
|
23
28
|
*/
|
|
24
|
-
export declare const SelectedFilters: ({ selectedFilters, onDelete, onClear }: SelectedFiltersProps) => import("react").JSX.Element;
|
|
29
|
+
export declare const SelectedFilters: ({ selectedFilters, onDelete, onClear, filters }: SelectedFiltersProps) => import("react").JSX.Element;
|
|
@@ -53,6 +53,12 @@ export type Filter = {
|
|
|
53
53
|
* visibility=public
|
|
54
54
|
*/
|
|
55
55
|
supportsMultiValue?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Optional human-readable labels for raw filter values, keyed by value.
|
|
58
|
+
* Use when the wire/URL value differs from what the table shows (e.g. `shared: "true"` → "Yes").
|
|
59
|
+
* Values without an entry fall back to the raw value.
|
|
60
|
+
*/
|
|
61
|
+
valueLabels?: Record<string, string>;
|
|
56
62
|
};
|
|
57
63
|
/**
|
|
58
64
|
* Complete filter configuration including available filters and current selections
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Filter } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the human-readable label a filter defines for one of its raw values,
|
|
4
|
+
* falling back to the raw value when no label is defined for it.
|
|
5
|
+
*
|
|
6
|
+
* Uses `Object.hasOwn` instead of a plain lookup because filter values can originate
|
|
7
|
+
* from the URL: a plain `valueLabels[value]` would resolve `__proto__` (or `constructor`,
|
|
8
|
+
* `toString`, …) to an inherited `Object.prototype` member, which is not nullish and so
|
|
9
|
+
* would slip past a `??` fallback and reach the render as a non-string.
|
|
10
|
+
*/
|
|
11
|
+
export declare const resolveValueLabel: (filter: Filter | undefined, value: string) => string;
|