@backstage/plugin-catalog-react 1.14.3-next.2 → 1.15.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/CHANGELOG.md +30 -0
- package/dist/components/EntityAutocompletePicker/EntityAutocompletePicker.esm.js +0 -1
- package/dist/components/EntityAutocompletePicker/EntityAutocompletePicker.esm.js.map +1 -1
- package/dist/components/EntityKindPicker/EntityKindPicker.esm.js +8 -7
- package/dist/components/EntityKindPicker/EntityKindPicker.esm.js.map +1 -1
- package/dist/components/EntityKindPicker/kindFilterUtils.esm.js +13 -17
- package/dist/components/EntityKindPicker/kindFilterUtils.esm.js.map +1 -1
- package/dist/components/EntityTypePicker/EntityTypePicker.esm.js +3 -0
- package/dist/components/EntityTypePicker/EntityTypePicker.esm.js.map +1 -1
- package/dist/components/UserListPicker/useAllEntitiesCount.esm.js +1 -1
- package/dist/components/UserListPicker/useAllEntitiesCount.esm.js.map +1 -1
- package/dist/components/UserListPicker/useOwnedEntitiesCount.esm.js.map +1 -1
- package/dist/components/UserListPicker/useStarredEntitiesCount.esm.js.map +1 -1
- package/dist/filters.esm.js +2 -1
- package/dist/filters.esm.js.map +1 -1
- package/dist/hooks/useEntityListProvider.esm.js +0 -1
- package/dist/hooks/useEntityListProvider.esm.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/package.json +20 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-react
|
|
2
2
|
|
|
3
|
+
## 1.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1ffb9f3: Update `EntityKindFilter` to include a `label` field with the properly capitalized Kind facet string
|
|
8
|
+
- ceaf602: Sort EntityTypePicker by default
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- d97a2cd: Fixed an issue causing the `EntityOwnerPicker` to reset scrolling when more elements are loaded.
|
|
13
|
+
- c36bd35: Internal refactor to break potential circular imports
|
|
14
|
+
- f18c67d: Fix catalog filtering to allow searching entities by display name
|
|
15
|
+
- 95092a6: Fixed an issue where `<CatalogFilterLayout.Filters />` would re-render its children on page load for smaller screens, potentially leading to unnecessary additional backend requests.
|
|
16
|
+
- 4a43398: Fixed an issue where the `EntityOwnerPicker` component failed to load when the `mode` prop was set to `owners-only`. In this mode, the `EntityOwnerPicker` does not load details about the owners, such as `displayName` or `title`. To display these details, use `mode=all` instead.
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @backstage/catalog-client@1.9.0
|
|
19
|
+
- @backstage/core-compat-api@0.3.4
|
|
20
|
+
- @backstage/frontend-plugin-api@0.9.3
|
|
21
|
+
- @backstage/core-components@0.16.2
|
|
22
|
+
- @backstage/errors@1.2.6
|
|
23
|
+
- @backstage/catalog-model@1.7.2
|
|
24
|
+
- @backstage/core-plugin-api@1.10.2
|
|
25
|
+
- @backstage/frontend-test-utils@0.2.4
|
|
26
|
+
- @backstage/integration-react@1.2.2
|
|
27
|
+
- @backstage/types@1.2.0
|
|
28
|
+
- @backstage/version-bridge@1.0.10
|
|
29
|
+
- @backstage/plugin-catalog-common@1.1.2
|
|
30
|
+
- @backstage/plugin-permission-common@0.8.3
|
|
31
|
+
- @backstage/plugin-permission-react@0.4.29
|
|
32
|
+
|
|
3
33
|
## 1.14.3-next.2
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -11,7 +11,6 @@ import { EntityAutocompletePickerOption } from './EntityAutocompletePickerOption
|
|
|
11
11
|
import { EntityAutocompletePickerInput } from './EntityAutocompletePickerInput.esm.js';
|
|
12
12
|
import { useEntityList } from '../../hooks/useEntityListProvider.esm.js';
|
|
13
13
|
import { reduceBackendCatalogFilters } from '../../utils/filters.esm.js';
|
|
14
|
-
import '@backstage/catalog-model';
|
|
15
14
|
|
|
16
15
|
const useStyles = makeStyles(
|
|
17
16
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityAutocompletePicker.esm.js","sources":["../../../src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport { TextFieldProps } from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport React, { useEffect, useMemo, useState, ReactNode } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityAutocompletePickerOption } from './EntityAutocompletePickerOption';\nimport { EntityAutocompletePickerInput } from './EntityAutocompletePickerInput';\nimport {\n DefaultEntityFilters,\n useEntityList,\n} from '../../hooks/useEntityListProvider';\nimport { EntityFilter } from '../../types';\nimport { reduceBackendCatalogFilters } from '../../utils';\n\n/** @public */\nexport type AllowedEntityFilters<T extends DefaultEntityFilters> = {\n [K in keyof T]-?: NonNullable<T[K]> extends EntityFilter & {\n values: string[];\n }\n ? K\n : never;\n}[keyof T];\n\n/** @public */\nexport type EntityAutocompletePickerProps<\n T extends DefaultEntityFilters = DefaultEntityFilters,\n Name extends AllowedEntityFilters<T> = AllowedEntityFilters<T>,\n> = {\n label: string;\n name: Name;\n path: string;\n showCounts?: boolean;\n Filter: { new (values: string[]): NonNullable<T[Name]> };\n InputProps?: TextFieldProps;\n initialSelectedOptions?: string[];\n filtersForAvailableValues?: Array<keyof T>;\n};\n\n/** @public */\nexport type CatalogReactEntityAutocompletePickerClassKey = 'root' | 'label';\n\nconst useStyles = makeStyles(\n {\n root: {},\n label: {\n textTransform: 'none',\n fontWeight: 'bold',\n },\n },\n { name: 'CatalogReactEntityAutocompletePicker' },\n);\n\n/** @public */\nexport function EntityAutocompletePicker<\n T extends DefaultEntityFilters = DefaultEntityFilters,\n Name extends AllowedEntityFilters<T> = AllowedEntityFilters<T>,\n>(props: EntityAutocompletePickerProps<T, Name>) {\n const {\n label,\n name,\n path,\n showCounts,\n Filter,\n InputProps,\n initialSelectedOptions = [],\n filtersForAvailableValues = ['kind'],\n } = props;\n\n const classes = useStyles();\n\n const {\n updateFilters,\n filters,\n queryParameters: { [name]: queryParameter },\n } = useEntityList<T>();\n\n const catalogApi = useApi(catalogApiRef);\n const availableValuesFilters = filtersForAvailableValues.map(\n f => filters[f] as EntityFilter | undefined,\n );\n const { value: availableValues } = useAsync(async () => {\n const facet = path;\n const { facets } = await catalogApi.getEntityFacets({\n facets: [facet],\n filter: reduceBackendCatalogFilters(\n availableValuesFilters.filter(Boolean) as EntityFilter[],\n ),\n });\n\n return Object.fromEntries(\n facets[facet].map(({ value, count }) => [value, count]),\n );\n }, [...availableValuesFilters]);\n\n const queryParameters = useMemo(\n () => [queryParameter].flat().filter(Boolean) as string[],\n [queryParameter],\n );\n\n const [selectedOptions, setSelectedOptions] = useState(\n queryParameters.length\n ? queryParameters\n : (filters[name] as unknown as { values: string[] })?.values ??\n initialSelectedOptions,\n );\n\n // Set selected options on query parameter updates; this happens at initial page load and from\n // external updates to the page location\n useEffect(() => {\n if (queryParameters.length) {\n setSelectedOptions(queryParameters);\n }\n }, [queryParameters]);\n\n const availableOptions = Object.keys(availableValues ?? {});\n const shouldAddFilter = selectedOptions.length && availableOptions.length;\n\n useEffect(() => {\n updateFilters({\n [name]: shouldAddFilter ? new Filter(selectedOptions) : undefined,\n } as Partial<T>);\n }, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);\n\n const filter = filters[name];\n if (\n (filter && typeof filter === 'object' && !('values' in filter)) ||\n !availableOptions.length\n ) {\n return null;\n }\n\n return (\n <Box className={classes.root} pb={1} pt={1}>\n <Typography className={classes.label} variant=\"button\" component=\"label\">\n {label}\n <Autocomplete<string, true>\n PopperComponent={popperProps => (\n <div {...popperProps}>{popperProps.children as ReactNode}</div>\n )}\n multiple\n disableCloseOnSelect\n options={availableOptions}\n value={selectedOptions}\n onChange={(_event: object, options: string[]) =>\n setSelectedOptions(options)\n }\n renderOption={(option, { selected }) => (\n <EntityAutocompletePickerOption\n selected={selected}\n value={option}\n availableOptions={availableValues}\n showCounts={!!showCounts}\n />\n )}\n size=\"small\"\n popupIcon={\n <ExpandMoreIcon data-testid={`${String(name)}-picker-expand`} />\n }\n renderInput={params => (\n <EntityAutocompletePickerInput {...params} {...InputProps} />\n )}\n />\n </Typography>\n </Box>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntityAutocompletePicker.esm.js","sources":["../../../src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport { TextFieldProps } from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport React, { useEffect, useMemo, useState, ReactNode } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityAutocompletePickerOption } from './EntityAutocompletePickerOption';\nimport { EntityAutocompletePickerInput } from './EntityAutocompletePickerInput';\nimport {\n DefaultEntityFilters,\n useEntityList,\n} from '../../hooks/useEntityListProvider';\nimport { EntityFilter } from '../../types';\nimport { reduceBackendCatalogFilters } from '../../utils/filters';\n\n/** @public */\nexport type AllowedEntityFilters<T extends DefaultEntityFilters> = {\n [K in keyof T]-?: NonNullable<T[K]> extends EntityFilter & {\n values: string[];\n }\n ? K\n : never;\n}[keyof T];\n\n/** @public */\nexport type EntityAutocompletePickerProps<\n T extends DefaultEntityFilters = DefaultEntityFilters,\n Name extends AllowedEntityFilters<T> = AllowedEntityFilters<T>,\n> = {\n label: string;\n name: Name;\n path: string;\n showCounts?: boolean;\n Filter: { new (values: string[]): NonNullable<T[Name]> };\n InputProps?: TextFieldProps;\n initialSelectedOptions?: string[];\n filtersForAvailableValues?: Array<keyof T>;\n};\n\n/** @public */\nexport type CatalogReactEntityAutocompletePickerClassKey = 'root' | 'label';\n\nconst useStyles = makeStyles(\n {\n root: {},\n label: {\n textTransform: 'none',\n fontWeight: 'bold',\n },\n },\n { name: 'CatalogReactEntityAutocompletePicker' },\n);\n\n/** @public */\nexport function EntityAutocompletePicker<\n T extends DefaultEntityFilters = DefaultEntityFilters,\n Name extends AllowedEntityFilters<T> = AllowedEntityFilters<T>,\n>(props: EntityAutocompletePickerProps<T, Name>) {\n const {\n label,\n name,\n path,\n showCounts,\n Filter,\n InputProps,\n initialSelectedOptions = [],\n filtersForAvailableValues = ['kind'],\n } = props;\n\n const classes = useStyles();\n\n const {\n updateFilters,\n filters,\n queryParameters: { [name]: queryParameter },\n } = useEntityList<T>();\n\n const catalogApi = useApi(catalogApiRef);\n const availableValuesFilters = filtersForAvailableValues.map(\n f => filters[f] as EntityFilter | undefined,\n );\n const { value: availableValues } = useAsync(async () => {\n const facet = path;\n const { facets } = await catalogApi.getEntityFacets({\n facets: [facet],\n filter: reduceBackendCatalogFilters(\n availableValuesFilters.filter(Boolean) as EntityFilter[],\n ),\n });\n\n return Object.fromEntries(\n facets[facet].map(({ value, count }) => [value, count]),\n );\n }, [...availableValuesFilters]);\n\n const queryParameters = useMemo(\n () => [queryParameter].flat().filter(Boolean) as string[],\n [queryParameter],\n );\n\n const [selectedOptions, setSelectedOptions] = useState(\n queryParameters.length\n ? queryParameters\n : (filters[name] as unknown as { values: string[] })?.values ??\n initialSelectedOptions,\n );\n\n // Set selected options on query parameter updates; this happens at initial page load and from\n // external updates to the page location\n useEffect(() => {\n if (queryParameters.length) {\n setSelectedOptions(queryParameters);\n }\n }, [queryParameters]);\n\n const availableOptions = Object.keys(availableValues ?? {});\n const shouldAddFilter = selectedOptions.length && availableOptions.length;\n\n useEffect(() => {\n updateFilters({\n [name]: shouldAddFilter ? new Filter(selectedOptions) : undefined,\n } as Partial<T>);\n }, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);\n\n const filter = filters[name];\n if (\n (filter && typeof filter === 'object' && !('values' in filter)) ||\n !availableOptions.length\n ) {\n return null;\n }\n\n return (\n <Box className={classes.root} pb={1} pt={1}>\n <Typography className={classes.label} variant=\"button\" component=\"label\">\n {label}\n <Autocomplete<string, true>\n PopperComponent={popperProps => (\n <div {...popperProps}>{popperProps.children as ReactNode}</div>\n )}\n multiple\n disableCloseOnSelect\n options={availableOptions}\n value={selectedOptions}\n onChange={(_event: object, options: string[]) =>\n setSelectedOptions(options)\n }\n renderOption={(option, { selected }) => (\n <EntityAutocompletePickerOption\n selected={selected}\n value={option}\n availableOptions={availableValues}\n showCounts={!!showCounts}\n />\n )}\n size=\"small\"\n popupIcon={\n <ExpandMoreIcon data-testid={`${String(name)}-picker-expand`} />\n }\n renderInput={params => (\n <EntityAutocompletePickerInput {...params} {...InputProps} />\n )}\n />\n </Typography>\n </Box>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -42,16 +42,17 @@ function useEntityKindFilter(opts) {
|
|
|
42
42
|
setSelectedKind(filters.kind?.value);
|
|
43
43
|
}
|
|
44
44
|
}, [filters.kind]);
|
|
45
|
+
const { allKinds, loading, error } = useAllKinds();
|
|
46
|
+
const selectedKindLabel = allKinds.get(selectedKind) || selectedKind;
|
|
45
47
|
useEffect(() => {
|
|
46
48
|
updateFilters({
|
|
47
|
-
kind: selectedKind ? new EntityKindFilter(selectedKind) : void 0
|
|
49
|
+
kind: selectedKind ? new EntityKindFilter(selectedKind, selectedKindLabel) : void 0
|
|
48
50
|
});
|
|
49
|
-
}, [selectedKind, updateFilters]);
|
|
50
|
-
const { allKinds, loading, error } = useAllKinds();
|
|
51
|
+
}, [selectedKind, selectedKindLabel, updateFilters]);
|
|
51
52
|
return {
|
|
52
53
|
loading,
|
|
53
54
|
error,
|
|
54
|
-
allKinds
|
|
55
|
+
allKinds,
|
|
55
56
|
selectedKind,
|
|
56
57
|
setSelectedKind
|
|
57
58
|
};
|
|
@@ -73,9 +74,9 @@ const EntityKindPicker = (props) => {
|
|
|
73
74
|
}, [error, alertApi, t]);
|
|
74
75
|
if (error) return null;
|
|
75
76
|
const options = filterKinds(allKinds, allowedKinds, selectedKind);
|
|
76
|
-
const items =
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const items = [...options.entries()].map(([key, value]) => ({
|
|
78
|
+
label: value,
|
|
79
|
+
value: key
|
|
79
80
|
}));
|
|
80
81
|
return hidden ? null : /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(
|
|
81
82
|
Select,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityKindPicker.esm.js","sources":["../../../src/components/EntityKindPicker/EntityKindPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Select } from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport Box from '@material-ui/core/Box';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { EntityKindFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { filterKinds, useAllKinds } from './kindFilterUtils';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nfunction useEntityKindFilter(opts: { initialFilter: string }): {\n loading: boolean;\n error?: Error;\n allKinds: string
|
|
1
|
+
{"version":3,"file":"EntityKindPicker.esm.js","sources":["../../../src/components/EntityKindPicker/EntityKindPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Select } from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport Box from '@material-ui/core/Box';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { EntityKindFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { filterKinds, useAllKinds } from './kindFilterUtils';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nfunction useEntityKindFilter(opts: { initialFilter: string }): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n selectedKind: string;\n setSelectedKind: (kind: string) => void;\n} {\n const {\n filters,\n queryParameters: { kind: kindParameter },\n updateFilters,\n } = useEntityList();\n\n const queryParamKind = useMemo(\n () => [kindParameter].flat()[0],\n [kindParameter],\n );\n\n const [selectedKind, setSelectedKind] = useState(\n queryParamKind ?? filters.kind?.value ?? opts.initialFilter,\n );\n\n // Set selected kinds on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamKind) {\n setSelectedKind(queryParamKind);\n }\n }, [queryParamKind]);\n\n // Set selected kind from filters; this happens when the kind filter is\n // updated from another component\n useEffect(() => {\n if (filters.kind?.value) {\n setSelectedKind(filters.kind?.value);\n }\n }, [filters.kind]);\n\n const { allKinds, loading, error } = useAllKinds();\n const selectedKindLabel = allKinds.get(selectedKind) || selectedKind;\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind\n ? new EntityKindFilter(selectedKind, selectedKindLabel)\n : undefined,\n });\n }, [selectedKind, selectedKindLabel, updateFilters]);\n\n return {\n loading,\n error,\n allKinds,\n selectedKind,\n setSelectedKind,\n };\n}\n\n/**\n * Props for {@link EntityKindPicker}.\n *\n * @public\n */\nexport interface EntityKindPickerProps {\n /**\n * Entity kinds to show in the dropdown; by default all kinds are fetched from the catalog and\n * displayed.\n */\n allowedKinds?: string[];\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityKindPicker = (props: EntityKindPickerProps) => {\n const { allowedKinds, hidden, initialFilter = 'component' } = props;\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n const alertApi = useApi(alertApiRef);\n\n const { error, allKinds, selectedKind, setSelectedKind } =\n useEntityKindFilter({\n initialFilter: initialFilter,\n });\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityKindPicker.errorMessage'),\n severity: 'error',\n });\n }\n }, [error, alertApi, t]);\n\n if (error) return null;\n\n const options = filterKinds(allKinds, allowedKinds, selectedKind);\n\n const items = [...options.entries()].map(([key, value]) => ({\n label: value,\n value: key,\n }));\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityKindPicker.title')}\n items={items}\n selected={selectedKind.toLocaleLowerCase('en-US')}\n onChange={value => setSelectedKind(String(value))}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0BA,SAAS,oBAAoB,IAM3B,EAAA;AACA,EAAM,MAAA;AAAA,IACJ,OAAA;AAAA,IACA,eAAA,EAAiB,EAAE,IAAA,EAAM,aAAc,EAAA;AAAA,IACvC;AAAA,MACE,aAAc,EAAA;AAElB,EAAA,MAAM,cAAiB,GAAA,OAAA;AAAA,IACrB,MAAM,CAAC,aAAa,CAAE,CAAA,IAAA,GAAO,CAAC,CAAA;AAAA,IAC9B,CAAC,aAAa;AAAA,GAChB;AAEA,EAAM,MAAA,CAAC,YAAc,EAAA,eAAe,CAAI,GAAA,QAAA;AAAA,IACtC,cAAkB,IAAA,OAAA,CAAQ,IAAM,EAAA,KAAA,IAAS,IAAK,CAAA;AAAA,GAChD;AAIA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAA,eAAA,CAAgB,cAAc,CAAA;AAAA;AAChC,GACF,EAAG,CAAC,cAAc,CAAC,CAAA;AAInB,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,OAAA,CAAQ,MAAM,KAAO,EAAA;AACvB,MAAgB,eAAA,CAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA;AACrC,GACC,EAAA,CAAC,OAAQ,CAAA,IAAI,CAAC,CAAA;AAEjB,EAAA,MAAM,EAAE,QAAA,EAAU,OAAS,EAAA,KAAA,KAAU,WAAY,EAAA;AACjD,EAAA,MAAM,iBAAoB,GAAA,QAAA,CAAS,GAAI,CAAA,YAAY,CAAK,IAAA,YAAA;AAExD,EAAA,SAAA,CAAU,MAAM;AACd,IAAc,aAAA,CAAA;AAAA,MACZ,MAAM,YACF,GAAA,IAAI,gBAAiB,CAAA,YAAA,EAAc,iBAAiB,CACpD,GAAA,KAAA;AAAA,KACL,CAAA;AAAA,GACA,EAAA,CAAC,YAAc,EAAA,iBAAA,EAAmB,aAAa,CAAC,CAAA;AAEnD,EAAO,OAAA;AAAA,IACL,OAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;AAkBa,MAAA,gBAAA,GAAmB,CAAC,KAAiC,KAAA;AAChE,EAAA,MAAM,EAAE,YAAA,EAAc,MAAQ,EAAA,aAAA,GAAgB,aAAgB,GAAA,KAAA;AAC9D,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AAEnC,EAAA,MAAM,EAAE,KAAO,EAAA,QAAA,EAAU,YAAc,EAAA,eAAA,KACrC,mBAAoB,CAAA;AAAA,IAClB;AAAA,GACD,CAAA;AAEH,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,OAAA,EAAS,EAAE,+BAA+B,CAAA;AAAA,QAC1C,QAAU,EAAA;AAAA,OACX,CAAA;AAAA;AACH,GACC,EAAA,CAAC,KAAO,EAAA,QAAA,EAAU,CAAC,CAAC,CAAA;AAEvB,EAAA,IAAI,OAAc,OAAA,IAAA;AAElB,EAAA,MAAM,OAAU,GAAA,WAAA,CAAY,QAAU,EAAA,YAAA,EAAc,YAAY,CAAA;AAEhE,EAAA,MAAM,KAAQ,GAAA,CAAC,GAAG,OAAA,CAAQ,OAAQ,EAAC,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,GAAK,EAAA,KAAK,CAAO,MAAA;AAAA,IAC1D,KAAO,EAAA,KAAA;AAAA,IACP,KAAO,EAAA;AAAA,GACP,CAAA,CAAA;AAEF,EAAA,OAAO,SAAS,IACd,mBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAG,IAAI,CACd,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,KAAA;AAAA,MACA,QAAA,EAAU,YAAa,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,MAChD,QAAU,EAAA,CAAA,KAAA,KAAS,eAAgB,CAAA,MAAA,CAAO,KAAK,CAAC;AAAA;AAAA,GAEpD,CAAA;AAEJ;;;;"}
|
|
@@ -9,29 +9,25 @@ function useAllKinds() {
|
|
|
9
9
|
loading,
|
|
10
10
|
value: allKinds
|
|
11
11
|
} = useAsync(async () => {
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const { facets } = await catalogApi.getEntityFacets({ facets: ["kind"] });
|
|
13
|
+
const kindFacets = (facets.kind ?? []).map((f) => f.value);
|
|
14
|
+
return new Map(
|
|
15
|
+
kindFacets.map((kind) => [kind.toLocaleLowerCase("en-US"), kind])
|
|
16
|
+
);
|
|
14
17
|
}, [catalogApi]);
|
|
15
|
-
return { loading, error, allKinds: allKinds ??
|
|
18
|
+
return { loading, error, allKinds: allKinds ?? /* @__PURE__ */ new Map() };
|
|
16
19
|
}
|
|
17
20
|
function filterKinds(allKinds, allowedKinds, forcedKinds) {
|
|
18
|
-
let availableKinds = allKinds;
|
|
21
|
+
let availableKinds = Array.from(allKinds.keys());
|
|
19
22
|
if (allowedKinds) {
|
|
20
|
-
availableKinds =
|
|
21
|
-
(k) => allowedKinds.some(
|
|
22
|
-
(a) => a.toLocaleLowerCase("en-US") === k.toLocaleLowerCase("en-US")
|
|
23
|
-
)
|
|
24
|
-
);
|
|
23
|
+
availableKinds = allowedKinds.map((k) => k.toLocaleLowerCase("en-US")).filter((k) => allKinds.has(k));
|
|
25
24
|
}
|
|
26
|
-
|
|
27
|
-
(
|
|
28
|
-
)
|
|
29
|
-
|
|
25
|
+
const kindsMap = new Map(
|
|
26
|
+
availableKinds.map((kind) => [kind, allKinds.get(kind) || kind])
|
|
27
|
+
);
|
|
28
|
+
if (forcedKinds && !kindsMap.has(forcedKinds)) {
|
|
29
|
+
kindsMap.set(forcedKinds.toLocaleLowerCase("en-US"), forcedKinds);
|
|
30
30
|
}
|
|
31
|
-
const kindsMap = availableKinds.sort().reduce((acc, kind) => {
|
|
32
|
-
acc[kind.toLocaleLowerCase("en-US")] = kind;
|
|
33
|
-
return acc;
|
|
34
|
-
}, {});
|
|
35
31
|
return kindsMap;
|
|
36
32
|
}
|
|
37
33
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kindFilterUtils.esm.js","sources":["../../../src/components/EntityKindPicker/kindFilterUtils.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\n\n/**\n * Fetch and return all
|
|
1
|
+
{"version":3,"file":"kindFilterUtils.esm.js","sources":["../../../src/components/EntityKindPicker/kindFilterUtils.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\n\n/**\n * Fetch and return all available kinds.\n */\nexport function useAllKinds(): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n} {\n const catalogApi = useApi(catalogApiRef);\n\n const {\n error,\n loading,\n value: allKinds,\n } = useAsync(async () => {\n const { facets } = await catalogApi.getEntityFacets({ facets: ['kind'] });\n const kindFacets = (facets.kind ?? []).map(f => f.value);\n return new Map(\n kindFacets.map(kind => [kind.toLocaleLowerCase('en-US'), kind]),\n );\n }, [catalogApi]);\n\n return { loading, error, allKinds: allKinds ?? new Map() };\n}\n\n/**\n * Filter and capitalize accessible kinds.\n */\nexport function filterKinds(\n allKinds: Map<string, string>,\n allowedKinds?: string[],\n forcedKinds?: string,\n): Map<string, string> {\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n let availableKinds = Array.from(allKinds.keys());\n if (allowedKinds) {\n availableKinds = allowedKinds\n .map(k => k.toLocaleLowerCase('en-US'))\n .filter(k => allKinds.has(k));\n }\n\n const kindsMap = new Map(\n availableKinds.map(kind => [kind, allKinds.get(kind) || kind]),\n );\n\n if (forcedKinds && !kindsMap.has(forcedKinds)) {\n // this is the only time we set a label for a kind which is not properly capitalized\n kindsMap.set(forcedKinds.toLocaleLowerCase('en-US'), forcedKinds);\n }\n\n return kindsMap;\n}\n"],"names":[],"mappings":";;;;AAuBO,SAAS,WAId,GAAA;AACA,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAM,MAAA;AAAA,IACJ,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAO,EAAA;AAAA,GACT,GAAI,SAAS,YAAY;AACvB,IAAM,MAAA,EAAE,MAAO,EAAA,GAAI,MAAM,UAAA,CAAW,eAAgB,CAAA,EAAE,MAAQ,EAAA,CAAC,MAAM,CAAA,EAAG,CAAA;AACxE,IAAM,MAAA,UAAA,GAAA,CAAc,OAAO,IAAQ,IAAA,IAAI,GAAI,CAAA,CAAA,CAAA,KAAK,EAAE,KAAK,CAAA;AACvD,IAAA,OAAO,IAAI,GAAA;AAAA,MACT,UAAA,CAAW,IAAI,CAAQ,IAAA,KAAA,CAAC,KAAK,iBAAkB,CAAA,OAAO,CAAG,EAAA,IAAI,CAAC;AAAA,KAChE;AAAA,GACF,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,OAAO,EAAE,OAAS,EAAA,KAAA,EAAO,UAAU,QAAY,oBAAA,IAAI,KAAM,EAAA;AAC3D;AAKgB,SAAA,WAAA,CACd,QACA,EAAA,YAAA,EACA,WACqB,EAAA;AAMrB,EAAA,IAAI,cAAiB,GAAA,KAAA,CAAM,IAAK,CAAA,QAAA,CAAS,MAAM,CAAA;AAC/C,EAAA,IAAI,YAAc,EAAA;AAChB,IAAA,cAAA,GAAiB,YACd,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,iBAAkB,CAAA,OAAO,CAAC,CAAA,CACrC,MAAO,CAAA,CAAA,CAAA,KAAK,QAAS,CAAA,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA;AAGhC,EAAA,MAAM,WAAW,IAAI,GAAA;AAAA,IACnB,cAAA,CAAe,GAAI,CAAA,CAAA,IAAA,KAAQ,CAAC,IAAA,EAAM,SAAS,GAAI,CAAA,IAAI,CAAK,IAAA,IAAI,CAAC;AAAA,GAC/D;AAEA,EAAA,IAAI,WAAe,IAAA,CAAC,QAAS,CAAA,GAAA,CAAI,WAAW,CAAG,EAAA;AAE7C,IAAA,QAAA,CAAS,GAAI,CAAA,WAAA,CAAY,iBAAkB,CAAA,OAAO,GAAG,WAAW,CAAA;AAAA;AAGlE,EAAO,OAAA,QAAA;AACT;;;;"}
|
|
@@ -23,6 +23,9 @@ const EntityTypePicker = (props) => {
|
|
|
23
23
|
}
|
|
24
24
|
}, [error, alertApi, initialFilter, setSelectedTypes, t]);
|
|
25
25
|
if (availableTypes.length === 0 || error) return null;
|
|
26
|
+
availableTypes.sort(
|
|
27
|
+
(a, b) => a.toLocaleLowerCase("en-US").localeCompare(b.toLocaleLowerCase("en-US"))
|
|
28
|
+
);
|
|
26
29
|
const items = [
|
|
27
30
|
{ value: "all", label: t("entityTypePicker.optionAllTitle") },
|
|
28
31
|
...availableTypes.map((type) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityTypePicker.esm.js","sources":["../../../src/components/EntityTypePicker/EntityTypePicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';\n\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Select } from '@backstage/core-components';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Props for {@link EntityTypePicker}.\n *\n * @public\n */\nexport interface EntityTypePickerProps {\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityTypePicker = (props: EntityTypePickerProps) => {\n const { hidden, initialFilter } = props;\n const alertApi = useApi(alertApiRef);\n const { error, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityTypePicker.errorMessage'),\n severity: 'error',\n });\n }\n if (initialFilter) {\n setSelectedTypes([initialFilter]);\n }\n }, [error, alertApi, initialFilter, setSelectedTypes, t]);\n\n if (availableTypes.length === 0 || error) return null;\n\n const items = [\n { value: 'all', label: t('entityTypePicker.optionAllTitle') },\n ...availableTypes.map((type: string) => ({\n value: type,\n label: type,\n })),\n ];\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityTypePicker.title')}\n items={items}\n selected={(items.length > 1 ? selectedTypes[0] : undefined) ?? 'all'}\n onChange={value =>\n setSelectedTypes(value === 'all' ? [] : [String(value)])\n }\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAoCa,MAAA,gBAAA,GAAmB,CAAC,KAAiC,KAAA;AAChE,EAAM,MAAA,EAAE,MAAQ,EAAA,aAAA,EAAkB,GAAA,KAAA;AAClC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,EAAE,KAAO,EAAA,cAAA,EAAgB,aAAe,EAAA,gBAAA,KAC5C,mBAAoB,EAAA;AACtB,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,OAAA,EAAS,EAAE,+BAA+B,CAAA;AAAA,QAC1C,QAAU,EAAA;AAAA,OACX,CAAA;AAAA;AAEH,IAAA,IAAI,aAAe,EAAA;AACjB,MAAiB,gBAAA,CAAA,CAAC,aAAa,CAAC,CAAA;AAAA;AAClC,KACC,CAAC,KAAA,EAAO,UAAU,aAAe,EAAA,gBAAA,EAAkB,CAAC,CAAC,CAAA;AAExD,EAAA,IAAI,cAAe,CAAA,MAAA,KAAW,CAAK,IAAA,KAAA,EAAc,OAAA,IAAA;AAEjD,EAAA,MAAM,KAAQ,GAAA;AAAA,IACZ,EAAE,KAAO,EAAA,KAAA,EAAO,KAAO,EAAA,CAAA,CAAE,iCAAiC,CAAE,EAAA;AAAA,IAC5D,GAAG,cAAA,CAAe,GAAI,CAAA,CAAC,IAAkB,MAAA;AAAA,MACvC,KAAO,EAAA,IAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACP,CAAA;AAAA,GACJ;AAEA,EAAA,OAAO,SAAS,IACd,mBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAG,IAAI,CACd,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,KAAA;AAAA,MACA,WAAW,KAAM,CAAA,MAAA,GAAS,IAAI,aAAc,CAAA,CAAC,IAAI,KAAc,CAAA,KAAA,KAAA;AAAA,MAC/D,QAAA,EAAU,CACR,KAAA,KAAA,gBAAA,CAAiB,KAAU,KAAA,KAAA,GAAQ,EAAC,GAAI,CAAC,MAAA,CAAO,KAAK,CAAC,CAAC;AAAA;AAAA,GAG7D,CAAA;AAEJ;;;;"}
|
|
1
|
+
{"version":3,"file":"EntityTypePicker.esm.js","sources":["../../../src/components/EntityTypePicker/EntityTypePicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';\n\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Select } from '@backstage/core-components';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Props for {@link EntityTypePicker}.\n *\n * @public\n */\nexport interface EntityTypePickerProps {\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityTypePicker = (props: EntityTypePickerProps) => {\n const { hidden, initialFilter } = props;\n const alertApi = useApi(alertApiRef);\n const { error, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityTypePicker.errorMessage'),\n severity: 'error',\n });\n }\n if (initialFilter) {\n setSelectedTypes([initialFilter]);\n }\n }, [error, alertApi, initialFilter, setSelectedTypes, t]);\n\n if (availableTypes.length === 0 || error) return null;\n\n availableTypes.sort((a, b) =>\n a.toLocaleLowerCase('en-US').localeCompare(b.toLocaleLowerCase('en-US')),\n );\n\n const items = [\n { value: 'all', label: t('entityTypePicker.optionAllTitle') },\n ...availableTypes.map((type: string) => ({\n value: type,\n label: type,\n })),\n ];\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityTypePicker.title')}\n items={items}\n selected={(items.length > 1 ? selectedTypes[0] : undefined) ?? 'all'}\n onChange={value =>\n setSelectedTypes(value === 'all' ? [] : [String(value)])\n }\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAoCa,MAAA,gBAAA,GAAmB,CAAC,KAAiC,KAAA;AAChE,EAAM,MAAA,EAAE,MAAQ,EAAA,aAAA,EAAkB,GAAA,KAAA;AAClC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,EAAE,KAAO,EAAA,cAAA,EAAgB,aAAe,EAAA,gBAAA,KAC5C,mBAAoB,EAAA;AACtB,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,OAAA,EAAS,EAAE,+BAA+B,CAAA;AAAA,QAC1C,QAAU,EAAA;AAAA,OACX,CAAA;AAAA;AAEH,IAAA,IAAI,aAAe,EAAA;AACjB,MAAiB,gBAAA,CAAA,CAAC,aAAa,CAAC,CAAA;AAAA;AAClC,KACC,CAAC,KAAA,EAAO,UAAU,aAAe,EAAA,gBAAA,EAAkB,CAAC,CAAC,CAAA;AAExD,EAAA,IAAI,cAAe,CAAA,MAAA,KAAW,CAAK,IAAA,KAAA,EAAc,OAAA,IAAA;AAEjD,EAAe,cAAA,CAAA,IAAA;AAAA,IAAK,CAAC,CAAG,EAAA,CAAA,KACtB,CAAE,CAAA,iBAAA,CAAkB,OAAO,CAAA,CAAE,aAAc,CAAA,CAAA,CAAE,iBAAkB,CAAA,OAAO,CAAC;AAAA,GACzE;AAEA,EAAA,MAAM,KAAQ,GAAA;AAAA,IACZ,EAAE,KAAO,EAAA,KAAA,EAAO,KAAO,EAAA,CAAA,CAAE,iCAAiC,CAAE,EAAA;AAAA,IAC5D,GAAG,cAAA,CAAe,GAAI,CAAA,CAAC,IAAkB,MAAA;AAAA,MACvC,KAAO,EAAA,IAAA;AAAA,MACP,KAAO,EAAA;AAAA,KACP,CAAA;AAAA,GACJ;AAEA,EAAA,OAAO,SAAS,IACd,mBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,EAAI,EAAA,CAAA,EAAG,IAAI,CACd,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,KAAA;AAAA,MACA,WAAW,KAAM,CAAA,MAAA,GAAS,IAAI,aAAc,CAAA,CAAC,IAAI,KAAc,CAAA,KAAA,KAAA;AAAA,MAC/D,QAAA,EAAU,CACR,KAAA,KAAA,gBAAA,CAAiB,KAAU,KAAA,KAAA,GAAQ,EAAC,GAAI,CAAC,MAAA,CAAO,KAAK,CAAC,CAAC;AAAA;AAAA,GAG7D,CAAA;AAEJ;;;;"}
|
|
@@ -8,12 +8,12 @@ import { useEntityList } from '../../hooks/useEntityListProvider.esm.js';
|
|
|
8
8
|
import 'lodash/isEqual';
|
|
9
9
|
import 'lodash/sortBy';
|
|
10
10
|
import '@backstage/catalog-model';
|
|
11
|
-
import { reduceCatalogFilters } from '../../utils/filters.esm.js';
|
|
12
11
|
import 'react-use/esm/useObservable';
|
|
13
12
|
import '../../apis/EntityPresentationApi/EntityPresentationApi.esm.js';
|
|
14
13
|
import 'lodash/get';
|
|
15
14
|
import '../../apis/StarredEntitiesApi/StarredEntitiesApi.esm.js';
|
|
16
15
|
import 'zen-observable';
|
|
16
|
+
import { reduceCatalogFilters } from '../../utils/filters.esm.js';
|
|
17
17
|
|
|
18
18
|
function useAllEntitiesCount() {
|
|
19
19
|
const catalogApi = useApi(catalogApiRef);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAllEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useAllEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { QueryEntitiesInitialRequest } from '@backstage/catalog-client';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { compact, isEqual } from 'lodash';\nimport { useMemo, useRef } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { useEntityList } from '../../hooks';\nimport { reduceCatalogFilters } from '../../utils';\n\nexport function useAllEntitiesCount() {\n const catalogApi = useApi(catalogApiRef);\n const { filters } = useEntityList();\n\n const prevRequest = useRef<QueryEntitiesInitialRequest>();\n const request = useMemo(() => {\n const { user, ...allFilters } = filters;\n const compacted = compact(Object.values(allFilters));\n const catalogFilters = reduceCatalogFilters(compacted);\n const newRequest: QueryEntitiesInitialRequest = {\n ...catalogFilters,\n limit: 0,\n };\n\n if (Object.keys(catalogFilters.filter).length === 0) {\n prevRequest.current = undefined;\n return prevRequest.current;\n }\n\n if (isEqual(newRequest, prevRequest.current)) {\n return prevRequest.current;\n }\n prevRequest.current = newRequest;\n return newRequest;\n }, [filters]);\n\n const { value: count, loading } = useAsync(async () => {\n if (request === undefined) {\n return 0;\n }\n const { totalItems } = await catalogApi.queryEntities(request);\n\n return totalItems;\n }, [request]);\n\n return { count, loading };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAwBO,SAAS,mBAAsB,GAAA;AACpC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,EAAA;AAElC,EAAA,MAAM,cAAc,MAAoC,EAAA;AACxD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM;AAC5B,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,UAAA,EAAe,GAAA,OAAA;AAChC,IAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAO,CAAA,MAAA,CAAO,UAAU,CAAC,CAAA;AACnD,IAAM,MAAA,cAAA,GAAiB,qBAAqB,SAAS,CAAA;AACrD,IAAA,MAAM,UAA0C,GAAA;AAAA,MAC9C,GAAG,cAAA;AAAA,MACH,KAAO,EAAA;AAAA,KACT;AAEA,IAAA,IAAI,OAAO,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA,CAAE,WAAW,CAAG,EAAA;AACnD,MAAA,WAAA,CAAY,OAAU,GAAA,KAAA,CAAA;AACtB,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAGrB,IAAA,IAAI,OAAQ,CAAA,UAAA,EAAY,WAAY,CAAA,OAAO,CAAG,EAAA;AAC5C,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAErB,IAAA,WAAA,CAAY,OAAU,GAAA,UAAA;AACtB,IAAO,OAAA,UAAA;AAAA,GACT,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAO,OAAQ,EAAA,GAAI,SAAS,YAAY;AACrD,IAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,MAAO,OAAA,CAAA;AAAA;AAET,IAAA,MAAM,EAAE,UAAW,EAAA,GAAI,MAAM,UAAA,CAAW,cAAc,OAAO,CAAA;AAE7D,IAAO,OAAA,UAAA;AAAA,GACT,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAO,OAAA,EAAE,OAAO,OAAQ,EAAA;AAC1B;;;;"}
|
|
1
|
+
{"version":3,"file":"useAllEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useAllEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { QueryEntitiesInitialRequest } from '@backstage/catalog-client';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { compact, isEqual } from 'lodash';\nimport { useMemo, useRef } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { useEntityList } from '../../hooks';\nimport { reduceCatalogFilters } from '../../utils/filters';\n\nexport function useAllEntitiesCount() {\n const catalogApi = useApi(catalogApiRef);\n const { filters } = useEntityList();\n\n const prevRequest = useRef<QueryEntitiesInitialRequest>();\n const request = useMemo(() => {\n const { user, ...allFilters } = filters;\n const compacted = compact(Object.values(allFilters));\n const catalogFilters = reduceCatalogFilters(compacted);\n const newRequest: QueryEntitiesInitialRequest = {\n ...catalogFilters,\n limit: 0,\n };\n\n if (Object.keys(catalogFilters.filter).length === 0) {\n prevRequest.current = undefined;\n return prevRequest.current;\n }\n\n if (isEqual(newRequest, prevRequest.current)) {\n return prevRequest.current;\n }\n prevRequest.current = newRequest;\n return newRequest;\n }, [filters]);\n\n const { value: count, loading } = useAsync(async () => {\n if (request === undefined) {\n return 0;\n }\n const { totalItems } = await catalogApi.queryEntities(request);\n\n return totalItems;\n }, [request]);\n\n return { count, loading };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAwBO,SAAS,mBAAsB,GAAA;AACpC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,EAAA;AAElC,EAAA,MAAM,cAAc,MAAoC,EAAA;AACxD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM;AAC5B,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,UAAA,EAAe,GAAA,OAAA;AAChC,IAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAO,CAAA,MAAA,CAAO,UAAU,CAAC,CAAA;AACnD,IAAM,MAAA,cAAA,GAAiB,qBAAqB,SAAS,CAAA;AACrD,IAAA,MAAM,UAA0C,GAAA;AAAA,MAC9C,GAAG,cAAA;AAAA,MACH,KAAO,EAAA;AAAA,KACT;AAEA,IAAA,IAAI,OAAO,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA,CAAE,WAAW,CAAG,EAAA;AACnD,MAAA,WAAA,CAAY,OAAU,GAAA,KAAA,CAAA;AACtB,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAGrB,IAAA,IAAI,OAAQ,CAAA,UAAA,EAAY,WAAY,CAAA,OAAO,CAAG,EAAA;AAC5C,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAErB,IAAA,WAAA,CAAY,OAAU,GAAA,UAAA;AACtB,IAAO,OAAA,UAAA;AAAA,GACT,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAO,OAAQ,EAAA,GAAI,SAAS,YAAY;AACrD,IAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,MAAO,OAAA,CAAA;AAAA;AAET,IAAA,MAAM,EAAE,UAAW,EAAA,GAAI,MAAM,UAAA,CAAW,cAAc,OAAO,CAAA;AAE7D,IAAO,OAAA,UAAA;AAAA,GACT,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAO,OAAA,EAAE,OAAO,OAAQ,EAAA;AAC1B;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOwnedEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useOwnedEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport { compact, intersection } from 'lodash';\nimport { useMemo } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityOwnerFilter, EntityUserFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { CatalogFilters, reduceCatalogFilters } from '../../utils';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDeepCompareEffect from 'react-use/esm/useDeepCompareEffect';\n\nexport function useOwnedEntitiesCount() {\n const identityApi = useApi(identityApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n const { filters } = useEntityList();\n\n const { value: ownershipEntityRefs, loading: loadingEntityRefs } = useAsync(\n async () => (await identityApi.getBackstageIdentity()).ownershipEntityRefs,\n // load only on mount\n [],\n );\n\n const { user, owners, ...allFilters } = filters;\n const catalogFilters = reduceCatalogFilters(\n compact(Object.values(allFilters)),\n );\n\n const [{ value: count, loading: loadingEntityOwnership }, fetchEntities] =\n useAsyncFn(\n async (req: {\n ownershipEntityRefs: string[];\n owners: EntityOwnerFilter | undefined;\n filter: CatalogFilters;\n }) => {\n const ownedClaims = getOwnedCountClaims(\n req.owners,\n req.ownershipEntityRefs,\n );\n if (ownedClaims === undefined) {\n // this implicitly means that there aren't claims in common with\n // the logged in users, so avoid invoking the queryEntities endpoint\n // which will implicitly returns 0\n return 0;\n }\n\n const { ['metadata.name']: metadata, ...filter } = req.filter.filter;\n\n const { totalItems } = await catalogApi.queryEntities({\n ...req.filter,\n filter: {\n ...filter,\n 'relations.ownedBy': ownedClaims,\n },\n limit: 0,\n });\n return totalItems;\n },\n [],\n { loading: true },\n );\n\n useDeepCompareEffect(() => {\n // context contains no filter, wait\n if (Object.keys(catalogFilters.filter).length === 0) {\n return;\n }\n // ownershipEntityRefs is loading, wait\n if (ownershipEntityRefs === undefined) {\n return;\n }\n fetchEntities({\n ownershipEntityRefs,\n owners,\n filter: catalogFilters,\n });\n }, [ownershipEntityRefs, owners, catalogFilters]);\n\n const loading = loadingEntityRefs || loadingEntityOwnership;\n\n return {\n count,\n loading,\n filter: useMemo(\n () => EntityUserFilter.owned(ownershipEntityRefs ?? []),\n [ownershipEntityRefs],\n ),\n ownershipEntityRefs,\n };\n}\n\nfunction getOwnedCountClaims(\n owners: EntityOwnerFilter | undefined,\n ownershipEntityRefs: string[] | undefined,\n) {\n if (ownershipEntityRefs === undefined) {\n return undefined;\n }\n const ownersRefs = owners?.values ?? [];\n if (ownersRefs.length) {\n const commonOwnedBy = intersection(ownersRefs, ownershipEntityRefs);\n if (commonOwnedBy.length === 0) {\n return undefined;\n }\n return commonOwnedBy;\n }\n return ownershipEntityRefs;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useOwnedEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useOwnedEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport { compact, intersection } from 'lodash';\nimport { useMemo } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityOwnerFilter, EntityUserFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { CatalogFilters, reduceCatalogFilters } from '../../utils/filters';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDeepCompareEffect from 'react-use/esm/useDeepCompareEffect';\n\nexport function useOwnedEntitiesCount() {\n const identityApi = useApi(identityApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n const { filters } = useEntityList();\n\n const { value: ownershipEntityRefs, loading: loadingEntityRefs } = useAsync(\n async () => (await identityApi.getBackstageIdentity()).ownershipEntityRefs,\n // load only on mount\n [],\n );\n\n const { user, owners, ...allFilters } = filters;\n const catalogFilters = reduceCatalogFilters(\n compact(Object.values(allFilters)),\n );\n\n const [{ value: count, loading: loadingEntityOwnership }, fetchEntities] =\n useAsyncFn(\n async (req: {\n ownershipEntityRefs: string[];\n owners: EntityOwnerFilter | undefined;\n filter: CatalogFilters;\n }) => {\n const ownedClaims = getOwnedCountClaims(\n req.owners,\n req.ownershipEntityRefs,\n );\n if (ownedClaims === undefined) {\n // this implicitly means that there aren't claims in common with\n // the logged in users, so avoid invoking the queryEntities endpoint\n // which will implicitly returns 0\n return 0;\n }\n\n const { ['metadata.name']: metadata, ...filter } = req.filter.filter;\n\n const { totalItems } = await catalogApi.queryEntities({\n ...req.filter,\n filter: {\n ...filter,\n 'relations.ownedBy': ownedClaims,\n },\n limit: 0,\n });\n return totalItems;\n },\n [],\n { loading: true },\n );\n\n useDeepCompareEffect(() => {\n // context contains no filter, wait\n if (Object.keys(catalogFilters.filter).length === 0) {\n return;\n }\n // ownershipEntityRefs is loading, wait\n if (ownershipEntityRefs === undefined) {\n return;\n }\n fetchEntities({\n ownershipEntityRefs,\n owners,\n filter: catalogFilters,\n });\n }, [ownershipEntityRefs, owners, catalogFilters]);\n\n const loading = loadingEntityRefs || loadingEntityOwnership;\n\n return {\n count,\n loading,\n filter: useMemo(\n () => EntityUserFilter.owned(ownershipEntityRefs ?? []),\n [ownershipEntityRefs],\n ),\n ownershipEntityRefs,\n };\n}\n\nfunction getOwnedCountClaims(\n owners: EntityOwnerFilter | undefined,\n ownershipEntityRefs: string[] | undefined,\n) {\n if (ownershipEntityRefs === undefined) {\n return undefined;\n }\n const ownersRefs = owners?.values ?? [];\n if (ownersRefs.length) {\n const commonOwnedBy = intersection(ownersRefs, ownershipEntityRefs);\n if (commonOwnedBy.length === 0) {\n return undefined;\n }\n return commonOwnedBy;\n }\n return ownershipEntityRefs;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BO,SAAS,qBAAwB,GAAA;AACtC,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,EAAA;AAElC,EAAA,MAAM,EAAE,KAAA,EAAO,mBAAqB,EAAA,OAAA,EAAS,mBAAsB,GAAA,QAAA;AAAA,IACjE,YAAa,CAAA,MAAM,WAAY,CAAA,oBAAA,EAAwB,EAAA,mBAAA;AAAA;AAAA,IAEvD;AAAC,GACH;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,MAAQ,EAAA,GAAG,YAAe,GAAA,OAAA;AACxC,EAAA,MAAM,cAAiB,GAAA,oBAAA;AAAA,IACrB,OAAQ,CAAA,MAAA,CAAO,MAAO,CAAA,UAAU,CAAC;AAAA,GACnC;AAEA,EAAM,MAAA,CAAC,EAAE,KAAO,EAAA,KAAA,EAAO,SAAS,sBAAuB,EAAA,EAAG,aAAa,CACrE,GAAA,UAAA;AAAA,IACE,OAAO,GAID,KAAA;AACJ,MAAA,MAAM,WAAc,GAAA,mBAAA;AAAA,QAClB,GAAI,CAAA,MAAA;AAAA,QACJ,GAAI,CAAA;AAAA,OACN;AACA,MAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAI7B,QAAO,OAAA,CAAA;AAAA;AAGT,MAAM,MAAA,EAAE,CAAC,eAAe,GAAG,UAAU,GAAG,MAAA,EAAW,GAAA,GAAA,CAAI,MAAO,CAAA,MAAA;AAE9D,MAAA,MAAM,EAAE,UAAA,EAAe,GAAA,MAAM,WAAW,aAAc,CAAA;AAAA,QACpD,GAAG,GAAI,CAAA,MAAA;AAAA,QACP,MAAQ,EAAA;AAAA,UACN,GAAG,MAAA;AAAA,UACH,mBAAqB,EAAA;AAAA,SACvB;AAAA,QACA,KAAO,EAAA;AAAA,OACR,CAAA;AACD,MAAO,OAAA,UAAA;AAAA,KACT;AAAA,IACA,EAAC;AAAA,IACD,EAAE,SAAS,IAAK;AAAA,GAClB;AAEF,EAAA,oBAAA,CAAqB,MAAM;AAEzB,IAAA,IAAI,OAAO,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA,CAAE,WAAW,CAAG,EAAA;AACnD,MAAA;AAAA;AAGF,IAAA,IAAI,wBAAwB,KAAW,CAAA,EAAA;AACrC,MAAA;AAAA;AAEF,IAAc,aAAA,CAAA;AAAA,MACZ,mBAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAQ,EAAA;AAAA,KACT,CAAA;AAAA,GACA,EAAA,CAAC,mBAAqB,EAAA,MAAA,EAAQ,cAAc,CAAC,CAAA;AAEhD,EAAA,MAAM,UAAU,iBAAqB,IAAA,sBAAA;AAErC,EAAO,OAAA;AAAA,IACL,KAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAQ,EAAA,OAAA;AAAA,MACN,MAAM,gBAAA,CAAiB,KAAM,CAAA,mBAAA,IAAuB,EAAE,CAAA;AAAA,MACtD,CAAC,mBAAmB;AAAA,KACtB;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,mBAAA,CACP,QACA,mBACA,EAAA;AACA,EAAA,IAAI,wBAAwB,KAAW,CAAA,EAAA;AACrC,IAAO,OAAA,KAAA,CAAA;AAAA;AAET,EAAM,MAAA,UAAA,GAAa,MAAQ,EAAA,MAAA,IAAU,EAAC;AACtC,EAAA,IAAI,WAAW,MAAQ,EAAA;AACrB,IAAM,MAAA,aAAA,GAAgB,YAAa,CAAA,UAAA,EAAY,mBAAmB,CAAA;AAClE,IAAI,IAAA,aAAA,CAAc,WAAW,CAAG,EAAA;AAC9B,MAAO,OAAA,KAAA,CAAA;AAAA;AAET,IAAO,OAAA,aAAA;AAAA;AAET,EAAO,OAAA,mBAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStarredEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useStarredEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { QueryEntitiesInitialRequest } from '@backstage/catalog-client';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { compact, isEqual } from 'lodash';\nimport { useMemo, useRef } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityUserFilter } from '../../filters';\nimport { useEntityList, useStarredEntities } from '../../hooks';\nimport { reduceCatalogFilters } from '../../utils';\n\nexport function useStarredEntitiesCount() {\n const catalogApi = useApi(catalogApiRef);\n const { filters } = useEntityList();\n const { starredEntities } = useStarredEntities();\n\n const prevRequest = useRef<QueryEntitiesInitialRequest>();\n const request = useMemo(() => {\n const { user, ...allFilters } = filters;\n const compacted = compact(Object.values(allFilters));\n const catalogFilters = reduceCatalogFilters(compacted);\n\n const facet = 'metadata.name';\n\n const newRequest: QueryEntitiesInitialRequest = {\n ...catalogFilters,\n filter: {\n ...catalogFilters.filter,\n /**\n * here we are filtering entities by `name`. Given this filter,\n * the response might contain more entities than expected, in case multiple entities\n * of different kind or namespace share the same name. Those extra entities are filtered out\n * client side by `EntityUserFilter`, so they won't be visible to the user.\n */\n [facet]: Array.from(starredEntities).map(e => parseEntityRef(e).name),\n },\n /**\n * limit is set to a high value as we are not expecting many starred entities\n */\n limit: 1000,\n };\n if (isEqual(newRequest, prevRequest.current)) {\n return prevRequest.current;\n }\n prevRequest.current = newRequest;\n\n return newRequest;\n }, [filters, starredEntities]);\n\n const { value: count, loading } = useAsync(async () => {\n if (!starredEntities.size) {\n return 0;\n }\n\n /**\n * given a list of starred entity refs and some filters coming from CatalogPage,\n * it reduces the list of starred entities, to a list of entities that matches the\n * provided filters. It won't be possible to getEntitiesByRefs\n * as the method doesn't accept any filter.\n */\n const response = await catalogApi.queryEntities(request);\n\n return response.items\n .map(e =>\n stringifyEntityRef({\n kind: e.kind,\n namespace: e.metadata.namespace,\n name: e.metadata.name,\n }),\n )\n .filter(e => starredEntities.has(e)).length;\n }, [request, starredEntities]);\n\n const filter = useMemo(\n () => EntityUserFilter.starred(Array.from(starredEntities)),\n [starredEntities],\n );\n\n return { count, loading, filter };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AA2BO,SAAS,uBAA0B,GAAA;AACxC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,EAAA;AAClC,EAAM,MAAA,EAAE,eAAgB,EAAA,GAAI,kBAAmB,EAAA;AAE/C,EAAA,MAAM,cAAc,MAAoC,EAAA;AACxD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM;AAC5B,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,UAAA,EAAe,GAAA,OAAA;AAChC,IAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAO,CAAA,MAAA,CAAO,UAAU,CAAC,CAAA;AACnD,IAAM,MAAA,cAAA,GAAiB,qBAAqB,SAAS,CAAA;AAErD,IAAA,MAAM,KAAQ,GAAA,eAAA;AAEd,IAAA,MAAM,UAA0C,GAAA;AAAA,MAC9C,GAAG,cAAA;AAAA,MACH,MAAQ,EAAA;AAAA,QACN,GAAG,cAAe,CAAA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOlB,CAAC,KAAK,GAAG,KAAA,CAAM,IAAK,CAAA,eAAe,CAAE,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,cAAA,CAAe,CAAC,CAAA,CAAE,IAAI;AAAA,OACtE;AAAA;AAAA;AAAA;AAAA,MAIA,KAAO,EAAA;AAAA,KACT;AACA,IAAA,IAAI,OAAQ,CAAA,UAAA,EAAY,WAAY,CAAA,OAAO,CAAG,EAAA;AAC5C,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAErB,IAAA,WAAA,CAAY,OAAU,GAAA,UAAA;AAEtB,IAAO,OAAA,UAAA;AAAA,GACN,EAAA,CAAC,OAAS,EAAA,eAAe,CAAC,CAAA;AAE7B,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAO,OAAQ,EAAA,GAAI,SAAS,YAAY;AACrD,IAAI,IAAA,CAAC,gBAAgB,IAAM,EAAA;AACzB,MAAO,OAAA,CAAA;AAAA;AAST,IAAA,MAAM,QAAW,GAAA,MAAM,UAAW,CAAA,aAAA,CAAc,OAAO,CAAA;AAEvD,IAAA,OAAO,SAAS,KACb,CAAA,GAAA;AAAA,MAAI,OACH,kBAAmB,CAAA;AAAA,QACjB,MAAM,CAAE,CAAA,IAAA;AAAA,QACR,SAAA,EAAW,EAAE,QAAS,CAAA,SAAA;AAAA,QACtB,IAAA,EAAM,EAAE,QAAS,CAAA;AAAA,OAClB;AAAA,MAEF,MAAO,CAAA,CAAA,CAAA,KAAK,gBAAgB,GAAI,CAAA,CAAC,CAAC,CAAE,CAAA,MAAA;AAAA,GACtC,EAAA,CAAC,OAAS,EAAA,eAAe,CAAC,CAAA;AAE7B,EAAA,MAAM,MAAS,GAAA,OAAA;AAAA,IACb,MAAM,gBAAiB,CAAA,OAAA,CAAQ,KAAM,CAAA,IAAA,CAAK,eAAe,CAAC,CAAA;AAAA,IAC1D,CAAC,eAAe;AAAA,GAClB;AAEA,EAAO,OAAA,EAAE,KAAO,EAAA,OAAA,EAAS,MAAO,EAAA;AAClC;;;;"}
|
|
1
|
+
{"version":3,"file":"useStarredEntitiesCount.esm.js","sources":["../../../src/components/UserListPicker/useStarredEntitiesCount.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { QueryEntitiesInitialRequest } from '@backstage/catalog-client';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { compact, isEqual } from 'lodash';\nimport { useMemo, useRef } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\nimport { EntityUserFilter } from '../../filters';\nimport { useEntityList, useStarredEntities } from '../../hooks';\nimport { reduceCatalogFilters } from '../../utils/filters';\n\nexport function useStarredEntitiesCount() {\n const catalogApi = useApi(catalogApiRef);\n const { filters } = useEntityList();\n const { starredEntities } = useStarredEntities();\n\n const prevRequest = useRef<QueryEntitiesInitialRequest>();\n const request = useMemo(() => {\n const { user, ...allFilters } = filters;\n const compacted = compact(Object.values(allFilters));\n const catalogFilters = reduceCatalogFilters(compacted);\n\n const facet = 'metadata.name';\n\n const newRequest: QueryEntitiesInitialRequest = {\n ...catalogFilters,\n filter: {\n ...catalogFilters.filter,\n /**\n * here we are filtering entities by `name`. Given this filter,\n * the response might contain more entities than expected, in case multiple entities\n * of different kind or namespace share the same name. Those extra entities are filtered out\n * client side by `EntityUserFilter`, so they won't be visible to the user.\n */\n [facet]: Array.from(starredEntities).map(e => parseEntityRef(e).name),\n },\n /**\n * limit is set to a high value as we are not expecting many starred entities\n */\n limit: 1000,\n };\n if (isEqual(newRequest, prevRequest.current)) {\n return prevRequest.current;\n }\n prevRequest.current = newRequest;\n\n return newRequest;\n }, [filters, starredEntities]);\n\n const { value: count, loading } = useAsync(async () => {\n if (!starredEntities.size) {\n return 0;\n }\n\n /**\n * given a list of starred entity refs and some filters coming from CatalogPage,\n * it reduces the list of starred entities, to a list of entities that matches the\n * provided filters. It won't be possible to getEntitiesByRefs\n * as the method doesn't accept any filter.\n */\n const response = await catalogApi.queryEntities(request);\n\n return response.items\n .map(e =>\n stringifyEntityRef({\n kind: e.kind,\n namespace: e.metadata.namespace,\n name: e.metadata.name,\n }),\n )\n .filter(e => starredEntities.has(e)).length;\n }, [request, starredEntities]);\n\n const filter = useMemo(\n () => EntityUserFilter.starred(Array.from(starredEntities)),\n [starredEntities],\n );\n\n return { count, loading, filter };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AA2BO,SAAS,uBAA0B,GAAA;AACxC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,EAAA;AAClC,EAAM,MAAA,EAAE,eAAgB,EAAA,GAAI,kBAAmB,EAAA;AAE/C,EAAA,MAAM,cAAc,MAAoC,EAAA;AACxD,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM;AAC5B,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,UAAA,EAAe,GAAA,OAAA;AAChC,IAAA,MAAM,SAAY,GAAA,OAAA,CAAQ,MAAO,CAAA,MAAA,CAAO,UAAU,CAAC,CAAA;AACnD,IAAM,MAAA,cAAA,GAAiB,qBAAqB,SAAS,CAAA;AAErD,IAAA,MAAM,KAAQ,GAAA,eAAA;AAEd,IAAA,MAAM,UAA0C,GAAA;AAAA,MAC9C,GAAG,cAAA;AAAA,MACH,MAAQ,EAAA;AAAA,QACN,GAAG,cAAe,CAAA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOlB,CAAC,KAAK,GAAG,KAAA,CAAM,IAAK,CAAA,eAAe,CAAE,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,cAAA,CAAe,CAAC,CAAA,CAAE,IAAI;AAAA,OACtE;AAAA;AAAA;AAAA;AAAA,MAIA,KAAO,EAAA;AAAA,KACT;AACA,IAAA,IAAI,OAAQ,CAAA,UAAA,EAAY,WAAY,CAAA,OAAO,CAAG,EAAA;AAC5C,MAAA,OAAO,WAAY,CAAA,OAAA;AAAA;AAErB,IAAA,WAAA,CAAY,OAAU,GAAA,UAAA;AAEtB,IAAO,OAAA,UAAA;AAAA,GACN,EAAA,CAAC,OAAS,EAAA,eAAe,CAAC,CAAA;AAE7B,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAO,OAAQ,EAAA,GAAI,SAAS,YAAY;AACrD,IAAI,IAAA,CAAC,gBAAgB,IAAM,EAAA;AACzB,MAAO,OAAA,CAAA;AAAA;AAST,IAAA,MAAM,QAAW,GAAA,MAAM,UAAW,CAAA,aAAA,CAAc,OAAO,CAAA;AAEvD,IAAA,OAAO,SAAS,KACb,CAAA,GAAA;AAAA,MAAI,OACH,kBAAmB,CAAA;AAAA,QACjB,MAAM,CAAE,CAAA,IAAA;AAAA,QACR,SAAA,EAAW,EAAE,QAAS,CAAA,SAAA;AAAA,QACtB,IAAA,EAAM,EAAE,QAAS,CAAA;AAAA,OAClB;AAAA,MAEF,MAAO,CAAA,CAAA,CAAA,KAAK,gBAAgB,GAAI,CAAA,CAAC,CAAC,CAAE,CAAA,MAAA;AAAA,GACtC,EAAA,CAAC,OAAS,EAAA,eAAe,CAAC,CAAA;AAE7B,EAAA,MAAM,MAAS,GAAA,OAAA;AAAA,IACb,MAAM,gBAAiB,CAAA,OAAA,CAAQ,KAAM,CAAA,IAAA,CAAK,eAAe,CAAC,CAAA;AAAA,IAC1D,CAAC,eAAe;AAAA,GAClB;AAEA,EAAO,OAAA,EAAE,KAAO,EAAA,OAAA,EAAS,MAAO,EAAA;AAClC;;;;"}
|
package/dist/filters.esm.js
CHANGED
|
@@ -2,8 +2,9 @@ import { stringifyEntityRef, parseEntityRef, RELATION_OWNED_BY } from '@backstag
|
|
|
2
2
|
import { getEntityRelations } from './utils/getEntityRelations.esm.js';
|
|
3
3
|
|
|
4
4
|
class EntityKindFilter {
|
|
5
|
-
constructor(value) {
|
|
5
|
+
constructor(value, label) {
|
|
6
6
|
this.value = value;
|
|
7
|
+
this.label = label;
|
|
7
8
|
}
|
|
8
9
|
getCatalogFilters() {
|
|
9
10
|
return { kind: this.value };
|
package/dist/filters.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filters.esm.js","sources":["../src/filters.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AlphaEntity } from '@backstage/catalog-model/alpha';\nimport { EntityFilter, UserListFilterKind } from './types';\nimport { getEntityRelations } from './utils';\n\n/**\n * Filter entities based on Kind.\n * @public\n */\nexport class EntityKindFilter implements EntityFilter {\n constructor(readonly value: string) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { kind: this.value };\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on type\n * @public\n */\nexport class EntityTypeFilter implements EntityFilter {\n constructor(readonly value: string | string[]) {}\n\n // Simplify `string | string[]` for consumers, always returns an array\n getTypes(): string[] {\n return Array.isArray(this.value) ? this.value : [this.value];\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.type': this.getTypes() };\n }\n\n toQueryValue(): string[] {\n return this.getTypes();\n }\n}\n\n/**\n * Filters entities based on tag.\n * @public\n */\nexport class EntityTagFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n filterEntity(entity: Entity): boolean {\n return this.values.every(v => (entity.metadata.tags ?? []).includes(v));\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.tags': this.values };\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities where the text matches spec, title or tags.\n * @public\n */\nexport class EntityTextFilter implements EntityFilter {\n constructor(readonly value: string) {}\n\n filterEntity(entity: Entity): boolean {\n const words = this.toUpperArray(this.value.split(/\\s/));\n const exactMatch = this.toUpperArray([entity.metadata.tags]);\n const partialMatch = this.toUpperArray([\n entity.metadata.name,\n entity.metadata.title,\n (entity.spec?.profile as { displayName?: string })?.displayName,\n ]);\n\n for (const word of words) {\n if (\n exactMatch.every(m => m !== word) &&\n partialMatch.every(m => !m.includes(word))\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n getFullTextFilters() {\n return {\n term: this.value,\n // Update this to be more dynamic based on table columns.\n fields: ['metadata.name', 'metadata.title', 'spec.profile.displayName'],\n };\n }\n\n toQueryValue() {\n return this.value;\n }\n\n private toUpperArray(\n value: Array<string | string[] | undefined>,\n ): Array<string> {\n return value\n .flat()\n .filter((m): m is string => Boolean(m))\n .map(m => m.toLocaleUpperCase('en-US'));\n }\n}\n\n/**\n * Filter matching entities that are owned by group.\n * @public\n *\n * CAUTION: This class may contain both full and partial entity refs.\n */\nexport class EntityOwnerFilter implements EntityFilter {\n readonly values: string[];\n constructor(values: string[]) {\n this.values = values.reduce((fullRefs, ref) => {\n // Attempt to remove bad entity references here.\n try {\n fullRefs.push(\n stringifyEntityRef(parseEntityRef(ref, { defaultKind: 'Group' })),\n );\n return fullRefs;\n } catch (err) {\n return fullRefs;\n }\n }, [] as string[]);\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'relations.ownedBy': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v =>\n getEntityRelations(entity, RELATION_OWNED_BY).some(\n o => stringifyEntityRef(o) === v,\n ),\n );\n }\n\n /**\n * Get the URL query parameter value. May be a mix of full and humanized entity refs.\n * @returns list of entity refs.\n */\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities on lifecycle.\n * @public\n */\nexport class EntityLifecycleFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.lifecycle': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.spec?.lifecycle === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities to those within the given namespace(s).\n * @public\n */\nexport class EntityNamespaceFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.namespace': this.values };\n }\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.metadata.namespace === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * @public\n */\nexport class EntityUserFilter implements EntityFilter {\n private constructor(\n readonly value: UserListFilterKind,\n readonly refs?: string[],\n ) {}\n\n static owned(ownershipEntityRefs: string[]) {\n return new EntityUserFilter('owned', ownershipEntityRefs);\n }\n\n static all() {\n return new EntityUserFilter('all');\n }\n\n static starred(starredEntityRefs: string[]) {\n return new EntityUserFilter('starred', starredEntityRefs);\n }\n\n getCatalogFilters(): Record<string, string[]> {\n if (this.value === 'owned') {\n return { 'relations.ownedBy': this.refs ?? [] };\n }\n if (this.value === 'starred') {\n return {\n 'metadata.name': this.refs?.map(e => parseEntityRef(e).name) ?? [],\n };\n }\n return {};\n }\n\n filterEntity(entity: Entity) {\n if (this.value === 'starred') {\n return this.refs?.includes(stringifyEntityRef(entity)) ?? true;\n }\n // used only for retro-compatibility with non paginated data.\n // This is supposed to return always true for paginated\n // owned entities, since the filters are applied server side.\n if (this.value === 'owned') {\n const relations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n this.refs?.some(v =>\n relations.some(o => stringifyEntityRef(o) === v),\n ) ?? false\n );\n }\n return true;\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on whatever the user has starred or owns them.\n * @deprecated use EntityUserFilter\n * @public\n */\nexport class UserListFilter implements EntityFilter {\n constructor(\n readonly value: UserListFilterKind,\n readonly isOwnedEntity: (entity: Entity) => boolean,\n readonly isStarredEntity: (entity: Entity) => boolean,\n ) {}\n\n filterEntity(entity: Entity): boolean {\n switch (this.value) {\n case 'owned':\n return this.isOwnedEntity(entity);\n case 'starred':\n return this.isStarredEntity(entity);\n default:\n return true;\n }\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based if it is an orphan or not.\n * @public\n */\nexport class EntityOrphanFilter implements EntityFilter {\n constructor(readonly value: boolean) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n if (this.value) {\n return { 'metadata.annotations.backstage.io/orphan': String(this.value) };\n }\n return {};\n }\n\n filterEntity(entity: Entity): boolean {\n const orphan = entity.metadata.annotations?.['backstage.io/orphan'];\n return orphan !== undefined && this.value.toString() === orphan;\n }\n}\n\n/**\n * Filters entities based on if it has errors or not.\n * @public\n */\nexport class EntityErrorFilter implements EntityFilter {\n constructor(readonly value: boolean) {}\n\n filterEntity(entity: Entity): boolean {\n const error =\n ((entity as AlphaEntity)?.status?.items?.length as number) > 0;\n return error !== undefined && this.value === error;\n }\n}\n"],"names":[],"mappings":";;;AA8BO,MAAM,gBAAyC,CAAA;AAAA,EACpD,YAAqB,KAAe,EAAA;AAAf,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAAgB,EAErC,iBAAuD,GAAA;AACrD,IAAO,OAAA,EAAE,IAAM,EAAA,IAAA,CAAK,KAAM,EAAA;AAAA;AAC5B,EAEA,YAAuB,GAAA;AACrB,IAAA,OAAO,IAAK,CAAA,KAAA;AAAA;AAEhB;AAMO,MAAM,gBAAyC,CAAA;AAAA,EACpD,YAAqB,KAA0B,EAAA;AAA1B,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAA2B;AAAA,EAGhD,QAAqB,GAAA;AACnB,IAAO,OAAA,KAAA,CAAM,QAAQ,IAAK,CAAA,KAAK,IAAI,IAAK,CAAA,KAAA,GAAQ,CAAC,IAAA,CAAK,KAAK,CAAA;AAAA;AAC7D,EAEA,iBAAuD,GAAA;AACrD,IAAA,OAAO,EAAE,WAAA,EAAa,IAAK,CAAA,QAAA,EAAW,EAAA;AAAA;AACxC,EAEA,YAAyB,GAAA;AACvB,IAAA,OAAO,KAAK,QAAS,EAAA;AAAA;AAEzB;AAMO,MAAM,eAAwC,CAAA;AAAA,EACnD,YAAqB,MAAkB,EAAA;AAAlB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAAmB,EAExC,aAAa,MAAyB,EAAA;AACpC,IAAO,OAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,CAAM,CAAA,KAAA,CAAA,MAAA,CAAO,QAAS,CAAA,IAAA,IAAQ,EAAC,EAAG,QAAS,CAAA,CAAC,CAAC,CAAA;AAAA;AACxE,EAEA,iBAAuD,GAAA;AACrD,IAAO,OAAA,EAAE,eAAiB,EAAA,IAAA,CAAK,MAAO,EAAA;AAAA;AACxC,EAEA,YAAyB,GAAA;AACvB,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB;AAMO,MAAM,gBAAyC,CAAA;AAAA,EACpD,YAAqB,KAAe,EAAA;AAAf,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAAgB,EAErC,aAAa,MAAyB,EAAA;AACpC,IAAA,MAAM,QAAQ,IAAK,CAAA,YAAA,CAAa,KAAK,KAAM,CAAA,KAAA,CAAM,IAAI,CAAC,CAAA;AACtD,IAAA,MAAM,aAAa,IAAK,CAAA,YAAA,CAAa,CAAC,MAAO,CAAA,QAAA,CAAS,IAAI,CAAC,CAAA;AAC3D,IAAM,MAAA,YAAA,GAAe,KAAK,YAAa,CAAA;AAAA,MACrC,OAAO,QAAS,CAAA,IAAA;AAAA,MAChB,OAAO,QAAS,CAAA,KAAA;AAAA,MACf,MAAA,CAAO,MAAM,OAAsC,EAAA;AAAA,KACrD,CAAA;AAED,IAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,MAAA,IACE,UAAW,CAAA,KAAA,CAAM,CAAK,CAAA,KAAA,CAAA,KAAM,IAAI,CAChC,IAAA,YAAA,CAAa,KAAM,CAAA,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,QAAS,CAAA,IAAI,CAAC,CACzC,EAAA;AACA,QAAO,OAAA,KAAA;AAAA;AACT;AAGF,IAAO,OAAA,IAAA;AAAA;AACT,EAEA,kBAAqB,GAAA;AACnB,IAAO,OAAA;AAAA,MACL,MAAM,IAAK,CAAA,KAAA;AAAA;AAAA,MAEX,MAAQ,EAAA,CAAC,eAAiB,EAAA,gBAAA,EAAkB,0BAA0B;AAAA,KACxE;AAAA;AACF,EAEA,YAAe,GAAA;AACb,IAAA,OAAO,IAAK,CAAA,KAAA;AAAA;AACd,EAEQ,aACN,KACe,EAAA;AACf,IAAA,OAAO,KACJ,CAAA,IAAA,EACA,CAAA,MAAA,CAAO,CAAC,CAAmB,KAAA,OAAA,CAAQ,CAAC,CAAC,EACrC,GAAI,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,iBAAA,CAAkB,OAAO,CAAC,CAAA;AAAA;AAE5C;AAQO,MAAM,iBAA0C,CAAA;AAAA,EAC5C,MAAA;AAAA,EACT,YAAY,MAAkB,EAAA;AAC5B,IAAA,IAAA,CAAK,MAAS,GAAA,MAAA,CAAO,MAAO,CAAA,CAAC,UAAU,GAAQ,KAAA;AAE7C,MAAI,IAAA;AACF,QAAS,QAAA,CAAA,IAAA;AAAA,UACP,mBAAmB,cAAe,CAAA,GAAA,EAAK,EAAE,WAAa,EAAA,OAAA,EAAS,CAAC;AAAA,SAClE;AACA,QAAO,OAAA,QAAA;AAAA,eACA,GAAK,EAAA;AACZ,QAAO,OAAA,QAAA;AAAA;AACT,KACF,EAAG,EAAc,CAAA;AAAA;AACnB,EAEA,iBAAuD,GAAA;AACrD,IAAO,OAAA,EAAE,mBAAqB,EAAA,IAAA,CAAK,MAAO,EAAA;AAAA;AAC5C,EAEA,aAAa,MAAyB,EAAA;AACpC,IAAA,OAAO,KAAK,MAAO,CAAA,IAAA;AAAA,MAAK,CACtB,CAAA,KAAA,kBAAA,CAAmB,MAAQ,EAAA,iBAAiB,CAAE,CAAA,IAAA;AAAA,QAC5C,CAAA,CAAA,KAAK,kBAAmB,CAAA,CAAC,CAAM,KAAA;AAAA;AACjC,KACF;AAAA;AACF;AAAA;AAAA;AAAA;AAAA,EAMA,YAAyB,GAAA;AACvB,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB;AAMO,MAAM,qBAA8C,CAAA;AAAA,EACzD,YAAqB,MAAkB,EAAA;AAAlB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAAmB,EAExC,iBAAuD,GAAA;AACrD,IAAO,OAAA,EAAE,gBAAkB,EAAA,IAAA,CAAK,MAAO,EAAA;AAAA;AACzC,EAEA,aAAa,MAAyB,EAAA;AACpC,IAAA,OAAO,KAAK,MAAO,CAAA,IAAA,CAAK,OAAK,MAAO,CAAA,IAAA,EAAM,cAAc,CAAC,CAAA;AAAA;AAC3D,EAEA,YAAyB,GAAA;AACvB,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB;AAMO,MAAM,qBAA8C,CAAA;AAAA,EACzD,YAAqB,MAAkB,EAAA;AAAlB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAAmB,EAExC,iBAAuD,GAAA;AACrD,IAAO,OAAA,EAAE,oBAAsB,EAAA,IAAA,CAAK,MAAO,EAAA;AAAA;AAC7C,EACA,aAAa,MAAyB,EAAA;AACpC,IAAA,OAAO,KAAK,MAAO,CAAA,IAAA,CAAK,OAAK,MAAO,CAAA,QAAA,CAAS,cAAc,CAAC,CAAA;AAAA;AAC9D,EAEA,YAAyB,GAAA;AACvB,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB;AAKO,MAAM,gBAAyC,CAAA;AAAA,EAC5C,WAAA,CACG,OACA,IACT,EAAA;AAFS,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA;AACR,EAEH,OAAO,MAAM,mBAA+B,EAAA;AAC1C,IAAO,OAAA,IAAI,gBAAiB,CAAA,OAAA,EAAS,mBAAmB,CAAA;AAAA;AAC1D,EAEA,OAAO,GAAM,GAAA;AACX,IAAO,OAAA,IAAI,iBAAiB,KAAK,CAAA;AAAA;AACnC,EAEA,OAAO,QAAQ,iBAA6B,EAAA;AAC1C,IAAO,OAAA,IAAI,gBAAiB,CAAA,SAAA,EAAW,iBAAiB,CAAA;AAAA;AAC1D,EAEA,iBAA8C,GAAA;AAC5C,IAAI,IAAA,IAAA,CAAK,UAAU,OAAS,EAAA;AAC1B,MAAA,OAAO,EAAE,mBAAA,EAAqB,IAAK,CAAA,IAAA,IAAQ,EAAG,EAAA;AAAA;AAEhD,IAAI,IAAA,IAAA,CAAK,UAAU,SAAW,EAAA;AAC5B,MAAO,OAAA;AAAA,QACL,eAAA,EAAiB,IAAK,CAAA,IAAA,EAAM,GAAI,CAAA,CAAA,CAAA,KAAK,eAAe,CAAC,CAAA,CAAE,IAAI,CAAA,IAAK;AAAC,OACnE;AAAA;AAEF,IAAA,OAAO,EAAC;AAAA;AACV,EAEA,aAAa,MAAgB,EAAA;AAC3B,IAAI,IAAA,IAAA,CAAK,UAAU,SAAW,EAAA;AAC5B,MAAA,OAAO,KAAK,IAAM,EAAA,QAAA,CAAS,kBAAmB,CAAA,MAAM,CAAC,CAAK,IAAA,IAAA;AAAA;AAK5D,IAAI,IAAA,IAAA,CAAK,UAAU,OAAS,EAAA;AAC1B,MAAM,MAAA,SAAA,GAAY,kBAAmB,CAAA,MAAA,EAAQ,iBAAiB,CAAA;AAE9D,MAAA,OACE,KAAK,IAAM,EAAA,IAAA;AAAA,QAAK,OACd,SAAU,CAAA,IAAA,CAAK,OAAK,kBAAmB,CAAA,CAAC,MAAM,CAAC;AAAA,OAC5C,IAAA,KAAA;AAAA;AAGT,IAAO,OAAA,IAAA;AAAA;AACT,EAEA,YAAuB,GAAA;AACrB,IAAA,OAAO,IAAK,CAAA,KAAA;AAAA;AAEhB;AAOO,MAAM,cAAuC,CAAA;AAAA,EAClD,WAAA,CACW,KACA,EAAA,aAAA,EACA,eACT,EAAA;AAHS,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAAA;AACR,EAEH,aAAa,MAAyB,EAAA;AACpC,IAAA,QAAQ,KAAK,KAAO;AAAA,MAClB,KAAK,OAAA;AACH,QAAO,OAAA,IAAA,CAAK,cAAc,MAAM,CAAA;AAAA,MAClC,KAAK,SAAA;AACH,QAAO,OAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,MACpC;AACE,QAAO,OAAA,IAAA;AAAA;AACX;AACF,EAEA,YAAuB,GAAA;AACrB,IAAA,OAAO,IAAK,CAAA,KAAA;AAAA;AAEhB;AAMO,MAAM,kBAA2C,CAAA;AAAA,EACtD,YAAqB,KAAgB,EAAA;AAAhB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAAiB,EAEtC,iBAAuD,GAAA;AACrD,IAAA,IAAI,KAAK,KAAO,EAAA;AACd,MAAA,OAAO,EAAE,0CAAA,EAA4C,MAAO,CAAA,IAAA,CAAK,KAAK,CAAE,EAAA;AAAA;AAE1E,IAAA,OAAO,EAAC;AAAA;AACV,EAEA,aAAa,MAAyB,EAAA;AACpC,IAAA,MAAM,MAAS,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,qBAAqB,CAAA;AAClE,IAAA,OAAO,MAAW,KAAA,KAAA,CAAA,IAAa,IAAK,CAAA,KAAA,CAAM,UAAe,KAAA,MAAA;AAAA;AAE7D;AAMO,MAAM,iBAA0C,CAAA;AAAA,EACrD,YAAqB,KAAgB,EAAA;AAAhB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA;AAAiB,EAEtC,aAAa,MAAyB,EAAA;AACpC,IAAA,MAAM,KACF,GAAA,MAAA,EAAwB,MAAQ,EAAA,KAAA,EAAO,MAAoB,GAAA,CAAA;AAC/D,IAAO,OAAA,KAAA,KAAU,KAAa,CAAA,IAAA,IAAA,CAAK,KAAU,KAAA,KAAA;AAAA;AAEjD;;;;"}
|
|
1
|
+
{"version":3,"file":"filters.esm.js","sources":["../src/filters.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AlphaEntity } from '@backstage/catalog-model/alpha';\nimport { EntityFilter, UserListFilterKind } from './types';\nimport { getEntityRelations } from './utils/getEntityRelations';\n\n/**\n * Filter entities based on Kind.\n * @public\n */\nexport class EntityKindFilter implements EntityFilter {\n constructor(readonly value: string, readonly label: string) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { kind: this.value };\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on type\n * @public\n */\nexport class EntityTypeFilter implements EntityFilter {\n constructor(readonly value: string | string[]) {}\n\n // Simplify `string | string[]` for consumers, always returns an array\n getTypes(): string[] {\n return Array.isArray(this.value) ? this.value : [this.value];\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.type': this.getTypes() };\n }\n\n toQueryValue(): string[] {\n return this.getTypes();\n }\n}\n\n/**\n * Filters entities based on tag.\n * @public\n */\nexport class EntityTagFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n filterEntity(entity: Entity): boolean {\n return this.values.every(v => (entity.metadata.tags ?? []).includes(v));\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.tags': this.values };\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities where the text matches spec, title or tags.\n * @public\n */\nexport class EntityTextFilter implements EntityFilter {\n constructor(readonly value: string) {}\n\n filterEntity(entity: Entity): boolean {\n const words = this.toUpperArray(this.value.split(/\\s/));\n const exactMatch = this.toUpperArray([entity.metadata.tags]);\n const partialMatch = this.toUpperArray([\n entity.metadata.name,\n entity.metadata.title,\n (entity.spec?.profile as { displayName?: string })?.displayName,\n ]);\n\n for (const word of words) {\n if (\n exactMatch.every(m => m !== word) &&\n partialMatch.every(m => !m.includes(word))\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n getFullTextFilters() {\n return {\n term: this.value,\n // Update this to be more dynamic based on table columns.\n fields: ['metadata.name', 'metadata.title', 'spec.profile.displayName'],\n };\n }\n\n toQueryValue() {\n return this.value;\n }\n\n private toUpperArray(\n value: Array<string | string[] | undefined>,\n ): Array<string> {\n return value\n .flat()\n .filter((m): m is string => Boolean(m))\n .map(m => m.toLocaleUpperCase('en-US'));\n }\n}\n\n/**\n * Filter matching entities that are owned by group.\n * @public\n *\n * CAUTION: This class may contain both full and partial entity refs.\n */\nexport class EntityOwnerFilter implements EntityFilter {\n readonly values: string[];\n constructor(values: string[]) {\n this.values = values.reduce((fullRefs, ref) => {\n // Attempt to remove bad entity references here.\n try {\n fullRefs.push(\n stringifyEntityRef(parseEntityRef(ref, { defaultKind: 'Group' })),\n );\n return fullRefs;\n } catch (err) {\n return fullRefs;\n }\n }, [] as string[]);\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'relations.ownedBy': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v =>\n getEntityRelations(entity, RELATION_OWNED_BY).some(\n o => stringifyEntityRef(o) === v,\n ),\n );\n }\n\n /**\n * Get the URL query parameter value. May be a mix of full and humanized entity refs.\n * @returns list of entity refs.\n */\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities on lifecycle.\n * @public\n */\nexport class EntityLifecycleFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.lifecycle': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.spec?.lifecycle === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities to those within the given namespace(s).\n * @public\n */\nexport class EntityNamespaceFilter implements EntityFilter {\n constructor(readonly values: string[]) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.namespace': this.values };\n }\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.metadata.namespace === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * @public\n */\nexport class EntityUserFilter implements EntityFilter {\n private constructor(\n readonly value: UserListFilterKind,\n readonly refs?: string[],\n ) {}\n\n static owned(ownershipEntityRefs: string[]) {\n return new EntityUserFilter('owned', ownershipEntityRefs);\n }\n\n static all() {\n return new EntityUserFilter('all');\n }\n\n static starred(starredEntityRefs: string[]) {\n return new EntityUserFilter('starred', starredEntityRefs);\n }\n\n getCatalogFilters(): Record<string, string[]> {\n if (this.value === 'owned') {\n return { 'relations.ownedBy': this.refs ?? [] };\n }\n if (this.value === 'starred') {\n return {\n 'metadata.name': this.refs?.map(e => parseEntityRef(e).name) ?? [],\n };\n }\n return {};\n }\n\n filterEntity(entity: Entity) {\n if (this.value === 'starred') {\n return this.refs?.includes(stringifyEntityRef(entity)) ?? true;\n }\n // used only for retro-compatibility with non paginated data.\n // This is supposed to return always true for paginated\n // owned entities, since the filters are applied server side.\n if (this.value === 'owned') {\n const relations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n this.refs?.some(v =>\n relations.some(o => stringifyEntityRef(o) === v),\n ) ?? false\n );\n }\n return true;\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on whatever the user has starred or owns them.\n * @deprecated use EntityUserFilter\n * @public\n */\nexport class UserListFilter implements EntityFilter {\n constructor(\n readonly value: UserListFilterKind,\n readonly isOwnedEntity: (entity: Entity) => boolean,\n readonly isStarredEntity: (entity: Entity) => boolean,\n ) {}\n\n filterEntity(entity: Entity): boolean {\n switch (this.value) {\n case 'owned':\n return this.isOwnedEntity(entity);\n case 'starred':\n return this.isStarredEntity(entity);\n default:\n return true;\n }\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based if it is an orphan or not.\n * @public\n */\nexport class EntityOrphanFilter implements EntityFilter {\n constructor(readonly value: boolean) {}\n\n getCatalogFilters(): Record<string, string | string[]> {\n if (this.value) {\n return { 'metadata.annotations.backstage.io/orphan': String(this.value) };\n }\n return {};\n }\n\n filterEntity(entity: Entity): boolean {\n const orphan = entity.metadata.annotations?.['backstage.io/orphan'];\n return orphan !== undefined && this.value.toString() === orphan;\n }\n}\n\n/**\n * Filters entities based on if it has errors or not.\n * @public\n */\nexport class EntityErrorFilter implements EntityFilter {\n constructor(readonly value: boolean) {}\n\n filterEntity(entity: Entity): boolean {\n const error =\n ((entity as AlphaEntity)?.status?.items?.length as number) > 0;\n return error !== undefined && this.value === error;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ import useDebounce from 'react-use/esm/useDebounce';
|
|
|
7
7
|
import useMountedState from 'react-use/esm/useMountedState';
|
|
8
8
|
import { catalogApiRef } from '../api.esm.js';
|
|
9
9
|
import { reduceCatalogFilters, reduceBackendCatalogFilters, reduceEntityFilters } from '../utils/filters.esm.js';
|
|
10
|
-
import '@backstage/catalog-model';
|
|
11
10
|
import { useApi } from '@backstage/core-plugin-api';
|
|
12
11
|
|
|
13
12
|
const EntityListContext = createContext(void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEntityListProvider.esm.js","sources":["../../src/hooks/useEntityListProvider.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { compact, isEqual } from 'lodash';\nimport qs from 'qs';\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport { useLocation } from 'react-router-dom';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport useMountedState from 'react-use/esm/useMountedState';\nimport { catalogApiRef } from '../api';\nimport {\n EntityErrorFilter,\n EntityKindFilter,\n EntityLifecycleFilter,\n EntityNamespaceFilter,\n EntityOrphanFilter,\n EntityOwnerFilter,\n EntityTagFilter,\n EntityTextFilter,\n EntityTypeFilter,\n EntityUserFilter,\n UserListFilter,\n} from '../filters';\nimport { EntityFilter, EntityListPagination } from '../types';\nimport {\n reduceBackendCatalogFilters,\n reduceCatalogFilters,\n reduceEntityFilters,\n} from '../utils';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { QueryEntitiesResponse } from '@backstage/catalog-client';\n\n/** @public */\nexport type DefaultEntityFilters = {\n kind?: EntityKindFilter;\n type?: EntityTypeFilter;\n user?: UserListFilter | EntityUserFilter;\n owners?: EntityOwnerFilter;\n lifecycles?: EntityLifecycleFilter;\n tags?: EntityTagFilter;\n text?: EntityTextFilter;\n orphan?: EntityOrphanFilter;\n error?: EntityErrorFilter;\n namespace?: EntityNamespaceFilter;\n};\n\n/** @public */\nexport type PaginationMode = 'cursor' | 'offset' | 'none';\n\n/** @public */\nexport type EntityListContextProps<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n> = {\n /**\n * The currently registered filters, adhering to the shape of DefaultEntityFilters or an extension\n * of that default (to add custom filter types).\n */\n filters: EntityFilters;\n\n /**\n * The resolved list of catalog entities, after all filters are applied.\n */\n entities: Entity[];\n\n /**\n * The resolved list of catalog entities, after _only catalog-backend_ filters are applied.\n */\n backendEntities: Entity[];\n\n /**\n * Update one or more of the registered filters. Optional filters can be set to `undefined` to\n * reset the filter.\n */\n updateFilters: (\n filters:\n | Partial<EntityFilters>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => void;\n\n /**\n * Filter values from query parameters.\n */\n queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;\n\n loading: boolean;\n error?: Error;\n\n pageInfo?: {\n next?: () => void;\n prev?: () => void;\n };\n totalItems?: number;\n limit: number;\n offset?: number;\n setLimit: (limit: number) => void;\n setOffset?: (offset: number) => void;\n paginationMode: PaginationMode;\n};\n\n/**\n * Creates new context for entity listing and filtering.\n * @public\n */\nexport const EntityListContext = createContext<\n EntityListContextProps<any> | undefined\n>(undefined);\n\ntype OutputState<EntityFilters extends DefaultEntityFilters> = {\n appliedFilters: EntityFilters;\n appliedCursor?: string;\n entities: Entity[];\n backendEntities: Entity[];\n pageInfo?: QueryEntitiesResponse['pageInfo'];\n totalItems?: number;\n offset?: number;\n limit?: number;\n};\n\n/**\n * @public\n */\nexport type EntityListProviderProps = PropsWithChildren<{\n pagination?: EntityListPagination;\n}>;\n\n/**\n * Provides entities and filters for a catalog listing.\n * @public\n */\nexport const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(\n props: EntityListProviderProps,\n) => {\n const isMounted = useMountedState();\n const catalogApi = useApi(catalogApiRef);\n const [requestedFilters, setRequestedFilters] = useState<EntityFilters>(\n {} as EntityFilters,\n );\n\n // We use react-router's useLocation hook so updates from external sources trigger an update to\n // the queryParameters in outputState. Updates from this hook use replaceState below and won't\n // trigger a useLocation change; this would instead come from an external source, such as a manual\n // update of the URL or two catalog sidebar links with different catalog filters.\n const location = useLocation();\n\n const getPaginationMode = (): PaginationMode => {\n if (props.pagination === true) {\n return 'cursor';\n }\n return typeof props.pagination === 'object'\n ? props.pagination.mode ?? 'cursor'\n : 'none';\n };\n\n const paginationMode: PaginationMode = getPaginationMode();\n const paginationLimit =\n typeof props.pagination === 'object' ? props.pagination.limit ?? 20 : 20;\n\n const {\n queryParameters,\n cursor: initialCursor,\n offset: initialOffset,\n limit: initialLimit,\n } = useMemo(() => {\n const parsed = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n });\n\n let limit = paginationLimit;\n if (typeof parsed.limit === 'string') {\n const queryLimit = Number.parseInt(parsed.limit, 10);\n if (!isNaN(queryLimit)) {\n limit = queryLimit;\n }\n }\n\n const offset =\n typeof parsed.offset === 'string' && paginationMode === 'offset'\n ? Number.parseInt(parsed.offset, 10)\n : undefined;\n\n return {\n queryParameters: (parsed.filters ?? {}) as Record<\n string,\n string | string[]\n >,\n cursor:\n typeof parsed.cursor === 'string' && paginationMode === 'cursor'\n ? parsed.cursor\n : undefined,\n offset:\n paginationMode === 'offset' && offset && !isNaN(offset)\n ? offset\n : undefined,\n limit,\n };\n }, [paginationMode, location.search, paginationLimit]);\n\n const [cursor, setCursor] = useState(initialCursor);\n const [offset, setOffset] = useState<number | undefined>(initialOffset);\n const [limit, setLimit] = useState(initialLimit);\n\n const [outputState, setOutputState] = useState<OutputState<EntityFilters>>(\n () => {\n return {\n appliedFilters: {} as EntityFilters,\n entities: [],\n backendEntities: [],\n pageInfo: paginationMode === 'cursor' ? {} : undefined,\n offset,\n limit,\n };\n },\n );\n\n // The main async filter worker. Note that while it has a lot of dependencies\n // in terms of its implementation, the triggering only happens (debounced)\n // based on the requested filters changing.\n const [{ loading, error }, refresh] = useAsyncFn(\n async () => {\n const compacted = compact(Object.values(requestedFilters));\n\n const queryParams = Object.keys(requestedFilters).reduce(\n (params, key) => {\n const filter = requestedFilters[key as keyof EntityFilters] as\n | EntityFilter\n | undefined;\n if (filter?.toQueryValue) {\n params[key] = filter.toQueryValue();\n }\n return params;\n },\n {} as Record<string, string | string[]>,\n );\n\n if (paginationMode !== 'none') {\n if (cursor) {\n if (cursor !== outputState.appliedCursor) {\n const entityFilter = reduceEntityFilters(compacted);\n const response = await catalogApi.queryEntities({\n cursor,\n limit,\n });\n setOutputState({\n appliedFilters: requestedFilters,\n appliedCursor: cursor,\n backendEntities: response.items,\n entities: response.items.filter(entityFilter),\n pageInfo: response.pageInfo,\n totalItems: response.totalItems,\n });\n }\n } else {\n const entityFilter = reduceEntityFilters(compacted);\n const backendFilter = reduceCatalogFilters(compacted);\n const previousBackendFilter = reduceCatalogFilters(\n compact(Object.values(outputState.appliedFilters)),\n );\n\n if (\n paginationMode === 'offset' ||\n !isEqual(previousBackendFilter, backendFilter)\n ) {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit,\n offset,\n orderFields: [{ field: 'metadata.name', order: 'asc' }],\n });\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: response.items,\n entities: response.items.filter(entityFilter),\n pageInfo: response.pageInfo,\n totalItems: response.totalItems,\n limit,\n offset,\n });\n }\n }\n } else {\n const entityFilter = reduceEntityFilters(compacted);\n const backendFilter = reduceBackendCatalogFilters(compacted);\n const previousBackendFilter = reduceBackendCatalogFilters(\n compact(Object.values(outputState.appliedFilters)),\n );\n\n // TODO(mtlewis): currently entities will never be requested unless\n // there's at least one filter, we should allow an initial request\n // to happen with no filters.\n if (!isEqual(previousBackendFilter, backendFilter)) {\n // TODO(timbonicus): should limit fields here, but would need filter\n // fields + table columns\n const response = await catalogApi.getEntities({\n filter: backendFilter,\n });\n const entities = response.items.filter(entityFilter);\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: response.items,\n entities,\n totalItems: entities.length,\n });\n } else {\n const entities = outputState.backendEntities.filter(entityFilter);\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: outputState.backendEntities,\n entities,\n totalItems: entities.length,\n });\n }\n }\n\n if (isMounted()) {\n const oldParams = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n });\n const newParams = qs.stringify(\n { ...oldParams, filters: queryParams, cursor, offset, limit },\n { addQueryPrefix: true, arrayFormat: 'repeat' },\n );\n const newUrl = `${window.location.pathname}${newParams}`;\n // We use direct history manipulation since useSearchParams and\n // useNavigate in react-router-dom cause unnecessary extra rerenders.\n // Also make sure to replace the state rather than pushing, since we\n // don't want there to be back/forward slots for every single filter\n // change.\n window.history?.replaceState(null, document.title, newUrl);\n }\n },\n [\n catalogApi,\n queryParameters,\n requestedFilters,\n outputState,\n cursor,\n paginationMode,\n limit,\n offset,\n ],\n { loading: true },\n );\n\n // Slight debounce on the refresh, since (especially on page load) several\n // filters will be calling this in rapid succession.\n useDebounce(refresh, 10, [requestedFilters, cursor, limit, offset]);\n\n const updateFilters = useCallback(\n (\n update:\n | Partial<EntityFilter>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => {\n // changing filters will affect pagination, so we need to reset\n // the cursor and start from the first page.\n // TODO(vinzscam): this is currently causing issues at page reload\n // where the state is not kept. Unfortunately we need to rethink\n // the way filters work in order to fix this.\n setCursor(undefined);\n setRequestedFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [],\n );\n\n const pageInfo = useMemo(() => {\n if (paginationMode !== 'cursor') {\n return undefined;\n }\n\n const prevCursor = outputState.pageInfo?.prevCursor;\n const nextCursor = outputState.pageInfo?.nextCursor;\n return {\n prev: prevCursor ? () => setCursor(prevCursor) : undefined,\n next: nextCursor ? () => setCursor(nextCursor) : undefined,\n };\n }, [paginationMode, outputState.pageInfo]);\n\n const value = useMemo(\n () => ({\n filters: outputState.appliedFilters,\n entities: outputState.entities,\n backendEntities: outputState.backendEntities,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n totalItems: outputState.totalItems,\n limit,\n offset,\n setLimit,\n setOffset,\n paginationMode,\n }),\n [\n outputState,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n limit,\n offset,\n paginationMode,\n setLimit,\n setOffset,\n ],\n );\n\n return (\n <EntityListContext.Provider value={value}>\n {props.children}\n </EntityListContext.Provider>\n );\n};\n\n/**\n * Hook for interacting with the entity list context provided by the {@link EntityListProvider}.\n * @public\n */\nexport function useEntityList<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n>(): EntityListContextProps<EntityFilters> {\n const context = useContext(EntityListContext);\n if (!context)\n throw new Error('useEntityList must be used within EntityListProvider');\n return context;\n}\n"],"names":["limit","offset"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useEntityListProvider.esm.js","sources":["../../src/hooks/useEntityListProvider.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { compact, isEqual } from 'lodash';\nimport qs from 'qs';\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport { useLocation } from 'react-router-dom';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport useMountedState from 'react-use/esm/useMountedState';\nimport { catalogApiRef } from '../api';\nimport {\n EntityErrorFilter,\n EntityKindFilter,\n EntityLifecycleFilter,\n EntityNamespaceFilter,\n EntityOrphanFilter,\n EntityOwnerFilter,\n EntityTagFilter,\n EntityTextFilter,\n EntityTypeFilter,\n EntityUserFilter,\n UserListFilter,\n} from '../filters';\nimport { EntityFilter, EntityListPagination } from '../types';\nimport {\n reduceBackendCatalogFilters,\n reduceCatalogFilters,\n reduceEntityFilters,\n} from '../utils/filters';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { QueryEntitiesResponse } from '@backstage/catalog-client';\n\n/** @public */\nexport type DefaultEntityFilters = {\n kind?: EntityKindFilter;\n type?: EntityTypeFilter;\n user?: UserListFilter | EntityUserFilter;\n owners?: EntityOwnerFilter;\n lifecycles?: EntityLifecycleFilter;\n tags?: EntityTagFilter;\n text?: EntityTextFilter;\n orphan?: EntityOrphanFilter;\n error?: EntityErrorFilter;\n namespace?: EntityNamespaceFilter;\n};\n\n/** @public */\nexport type PaginationMode = 'cursor' | 'offset' | 'none';\n\n/** @public */\nexport type EntityListContextProps<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n> = {\n /**\n * The currently registered filters, adhering to the shape of DefaultEntityFilters or an extension\n * of that default (to add custom filter types).\n */\n filters: EntityFilters;\n\n /**\n * The resolved list of catalog entities, after all filters are applied.\n */\n entities: Entity[];\n\n /**\n * The resolved list of catalog entities, after _only catalog-backend_ filters are applied.\n */\n backendEntities: Entity[];\n\n /**\n * Update one or more of the registered filters. Optional filters can be set to `undefined` to\n * reset the filter.\n */\n updateFilters: (\n filters:\n | Partial<EntityFilters>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => void;\n\n /**\n * Filter values from query parameters.\n */\n queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;\n\n loading: boolean;\n error?: Error;\n\n pageInfo?: {\n next?: () => void;\n prev?: () => void;\n };\n totalItems?: number;\n limit: number;\n offset?: number;\n setLimit: (limit: number) => void;\n setOffset?: (offset: number) => void;\n paginationMode: PaginationMode;\n};\n\n/**\n * Creates new context for entity listing and filtering.\n * @public\n */\nexport const EntityListContext = createContext<\n EntityListContextProps<any> | undefined\n>(undefined);\n\ntype OutputState<EntityFilters extends DefaultEntityFilters> = {\n appliedFilters: EntityFilters;\n appliedCursor?: string;\n entities: Entity[];\n backendEntities: Entity[];\n pageInfo?: QueryEntitiesResponse['pageInfo'];\n totalItems?: number;\n offset?: number;\n limit?: number;\n};\n\n/**\n * @public\n */\nexport type EntityListProviderProps = PropsWithChildren<{\n pagination?: EntityListPagination;\n}>;\n\n/**\n * Provides entities and filters for a catalog listing.\n * @public\n */\nexport const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(\n props: EntityListProviderProps,\n) => {\n const isMounted = useMountedState();\n const catalogApi = useApi(catalogApiRef);\n const [requestedFilters, setRequestedFilters] = useState<EntityFilters>(\n {} as EntityFilters,\n );\n\n // We use react-router's useLocation hook so updates from external sources trigger an update to\n // the queryParameters in outputState. Updates from this hook use replaceState below and won't\n // trigger a useLocation change; this would instead come from an external source, such as a manual\n // update of the URL or two catalog sidebar links with different catalog filters.\n const location = useLocation();\n\n const getPaginationMode = (): PaginationMode => {\n if (props.pagination === true) {\n return 'cursor';\n }\n return typeof props.pagination === 'object'\n ? props.pagination.mode ?? 'cursor'\n : 'none';\n };\n\n const paginationMode: PaginationMode = getPaginationMode();\n const paginationLimit =\n typeof props.pagination === 'object' ? props.pagination.limit ?? 20 : 20;\n\n const {\n queryParameters,\n cursor: initialCursor,\n offset: initialOffset,\n limit: initialLimit,\n } = useMemo(() => {\n const parsed = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n });\n\n let limit = paginationLimit;\n if (typeof parsed.limit === 'string') {\n const queryLimit = Number.parseInt(parsed.limit, 10);\n if (!isNaN(queryLimit)) {\n limit = queryLimit;\n }\n }\n\n const offset =\n typeof parsed.offset === 'string' && paginationMode === 'offset'\n ? Number.parseInt(parsed.offset, 10)\n : undefined;\n\n return {\n queryParameters: (parsed.filters ?? {}) as Record<\n string,\n string | string[]\n >,\n cursor:\n typeof parsed.cursor === 'string' && paginationMode === 'cursor'\n ? parsed.cursor\n : undefined,\n offset:\n paginationMode === 'offset' && offset && !isNaN(offset)\n ? offset\n : undefined,\n limit,\n };\n }, [paginationMode, location.search, paginationLimit]);\n\n const [cursor, setCursor] = useState(initialCursor);\n const [offset, setOffset] = useState<number | undefined>(initialOffset);\n const [limit, setLimit] = useState(initialLimit);\n\n const [outputState, setOutputState] = useState<OutputState<EntityFilters>>(\n () => {\n return {\n appliedFilters: {} as EntityFilters,\n entities: [],\n backendEntities: [],\n pageInfo: paginationMode === 'cursor' ? {} : undefined,\n offset,\n limit,\n };\n },\n );\n\n // The main async filter worker. Note that while it has a lot of dependencies\n // in terms of its implementation, the triggering only happens (debounced)\n // based on the requested filters changing.\n const [{ loading, error }, refresh] = useAsyncFn(\n async () => {\n const compacted = compact(Object.values(requestedFilters));\n\n const queryParams = Object.keys(requestedFilters).reduce(\n (params, key) => {\n const filter = requestedFilters[key as keyof EntityFilters] as\n | EntityFilter\n | undefined;\n if (filter?.toQueryValue) {\n params[key] = filter.toQueryValue();\n }\n return params;\n },\n {} as Record<string, string | string[]>,\n );\n\n if (paginationMode !== 'none') {\n if (cursor) {\n if (cursor !== outputState.appliedCursor) {\n const entityFilter = reduceEntityFilters(compacted);\n const response = await catalogApi.queryEntities({\n cursor,\n limit,\n });\n setOutputState({\n appliedFilters: requestedFilters,\n appliedCursor: cursor,\n backendEntities: response.items,\n entities: response.items.filter(entityFilter),\n pageInfo: response.pageInfo,\n totalItems: response.totalItems,\n });\n }\n } else {\n const entityFilter = reduceEntityFilters(compacted);\n const backendFilter = reduceCatalogFilters(compacted);\n const previousBackendFilter = reduceCatalogFilters(\n compact(Object.values(outputState.appliedFilters)),\n );\n\n if (\n paginationMode === 'offset' ||\n !isEqual(previousBackendFilter, backendFilter)\n ) {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit,\n offset,\n orderFields: [{ field: 'metadata.name', order: 'asc' }],\n });\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: response.items,\n entities: response.items.filter(entityFilter),\n pageInfo: response.pageInfo,\n totalItems: response.totalItems,\n limit,\n offset,\n });\n }\n }\n } else {\n const entityFilter = reduceEntityFilters(compacted);\n const backendFilter = reduceBackendCatalogFilters(compacted);\n const previousBackendFilter = reduceBackendCatalogFilters(\n compact(Object.values(outputState.appliedFilters)),\n );\n\n // TODO(mtlewis): currently entities will never be requested unless\n // there's at least one filter, we should allow an initial request\n // to happen with no filters.\n if (!isEqual(previousBackendFilter, backendFilter)) {\n // TODO(timbonicus): should limit fields here, but would need filter\n // fields + table columns\n const response = await catalogApi.getEntities({\n filter: backendFilter,\n });\n const entities = response.items.filter(entityFilter);\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: response.items,\n entities,\n totalItems: entities.length,\n });\n } else {\n const entities = outputState.backendEntities.filter(entityFilter);\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: outputState.backendEntities,\n entities,\n totalItems: entities.length,\n });\n }\n }\n\n if (isMounted()) {\n const oldParams = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n });\n const newParams = qs.stringify(\n { ...oldParams, filters: queryParams, cursor, offset, limit },\n { addQueryPrefix: true, arrayFormat: 'repeat' },\n );\n const newUrl = `${window.location.pathname}${newParams}`;\n // We use direct history manipulation since useSearchParams and\n // useNavigate in react-router-dom cause unnecessary extra rerenders.\n // Also make sure to replace the state rather than pushing, since we\n // don't want there to be back/forward slots for every single filter\n // change.\n window.history?.replaceState(null, document.title, newUrl);\n }\n },\n [\n catalogApi,\n queryParameters,\n requestedFilters,\n outputState,\n cursor,\n paginationMode,\n limit,\n offset,\n ],\n { loading: true },\n );\n\n // Slight debounce on the refresh, since (especially on page load) several\n // filters will be calling this in rapid succession.\n useDebounce(refresh, 10, [requestedFilters, cursor, limit, offset]);\n\n const updateFilters = useCallback(\n (\n update:\n | Partial<EntityFilter>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => {\n // changing filters will affect pagination, so we need to reset\n // the cursor and start from the first page.\n // TODO(vinzscam): this is currently causing issues at page reload\n // where the state is not kept. Unfortunately we need to rethink\n // the way filters work in order to fix this.\n setCursor(undefined);\n setRequestedFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [],\n );\n\n const pageInfo = useMemo(() => {\n if (paginationMode !== 'cursor') {\n return undefined;\n }\n\n const prevCursor = outputState.pageInfo?.prevCursor;\n const nextCursor = outputState.pageInfo?.nextCursor;\n return {\n prev: prevCursor ? () => setCursor(prevCursor) : undefined,\n next: nextCursor ? () => setCursor(nextCursor) : undefined,\n };\n }, [paginationMode, outputState.pageInfo]);\n\n const value = useMemo(\n () => ({\n filters: outputState.appliedFilters,\n entities: outputState.entities,\n backendEntities: outputState.backendEntities,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n totalItems: outputState.totalItems,\n limit,\n offset,\n setLimit,\n setOffset,\n paginationMode,\n }),\n [\n outputState,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n limit,\n offset,\n paginationMode,\n setLimit,\n setOffset,\n ],\n );\n\n return (\n <EntityListContext.Provider value={value}>\n {props.children}\n </EntityListContext.Provider>\n );\n};\n\n/**\n * Hook for interacting with the entity list context provided by the {@link EntityListProvider}.\n * @public\n */\nexport function useEntityList<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n>(): EntityListContextProps<EntityFilters> {\n const context = useContext(EntityListContext);\n if (!context)\n throw new Error('useEntityList must be used within EntityListProvider');\n return context;\n}\n"],"names":["limit","offset"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -556,7 +556,8 @@ declare const EntityNamespacePicker: (props: EntityNamespacePickerProps) => Reac
|
|
|
556
556
|
*/
|
|
557
557
|
declare class EntityKindFilter implements EntityFilter {
|
|
558
558
|
readonly value: string;
|
|
559
|
-
|
|
559
|
+
readonly label: string;
|
|
560
|
+
constructor(value: string, label: string);
|
|
560
561
|
getCatalogFilters(): Record<string, string | string[]>;
|
|
561
562
|
toQueryValue(): string;
|
|
562
563
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "A frontend library that helps other Backstage plugins interact with the catalog",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "web-library",
|
|
@@ -73,20 +73,20 @@
|
|
|
73
73
|
"test": "backstage-cli package test"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@backstage/catalog-client": "1.9.0
|
|
77
|
-
"@backstage/catalog-model": "1.7.2
|
|
78
|
-
"@backstage/core-compat-api": "0.3.4
|
|
79
|
-
"@backstage/core-components": "0.16.2
|
|
80
|
-
"@backstage/core-plugin-api": "1.10.2
|
|
81
|
-
"@backstage/errors": "1.2.6
|
|
82
|
-
"@backstage/frontend-plugin-api": "0.9.3
|
|
83
|
-
"@backstage/frontend-test-utils": "0.2.4
|
|
84
|
-
"@backstage/integration-react": "1.2.2
|
|
85
|
-
"@backstage/plugin-catalog-common": "1.1.2
|
|
86
|
-
"@backstage/plugin-permission-common": "0.8.3
|
|
87
|
-
"@backstage/plugin-permission-react": "0.4.29
|
|
88
|
-
"@backstage/types": "1.2.0",
|
|
89
|
-
"@backstage/version-bridge": "1.0.10",
|
|
76
|
+
"@backstage/catalog-client": "^1.9.0",
|
|
77
|
+
"@backstage/catalog-model": "^1.7.2",
|
|
78
|
+
"@backstage/core-compat-api": "^0.3.4",
|
|
79
|
+
"@backstage/core-components": "^0.16.2",
|
|
80
|
+
"@backstage/core-plugin-api": "^1.10.2",
|
|
81
|
+
"@backstage/errors": "^1.2.6",
|
|
82
|
+
"@backstage/frontend-plugin-api": "^0.9.3",
|
|
83
|
+
"@backstage/frontend-test-utils": "^0.2.4",
|
|
84
|
+
"@backstage/integration-react": "^1.2.2",
|
|
85
|
+
"@backstage/plugin-catalog-common": "^1.1.2",
|
|
86
|
+
"@backstage/plugin-permission-common": "^0.8.3",
|
|
87
|
+
"@backstage/plugin-permission-react": "^0.4.29",
|
|
88
|
+
"@backstage/types": "^1.2.0",
|
|
89
|
+
"@backstage/version-bridge": "^1.0.10",
|
|
90
90
|
"@material-ui/core": "^4.12.2",
|
|
91
91
|
"@material-ui/icons": "^4.9.1",
|
|
92
92
|
"@material-ui/lab": "4.0.0-alpha.61",
|
|
@@ -100,11 +100,11 @@
|
|
|
100
100
|
"zen-observable": "^0.10.0"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
|
-
"@backstage/cli": "0.29.
|
|
104
|
-
"@backstage/core-app-api": "1.15.3
|
|
105
|
-
"@backstage/plugin-catalog-common": "1.1.2
|
|
106
|
-
"@backstage/plugin-scaffolder-common": "1.5.8
|
|
107
|
-
"@backstage/test-utils": "1.7.3
|
|
103
|
+
"@backstage/cli": "^0.29.4",
|
|
104
|
+
"@backstage/core-app-api": "^1.15.3",
|
|
105
|
+
"@backstage/plugin-catalog-common": "^1.1.2",
|
|
106
|
+
"@backstage/plugin-scaffolder-common": "^1.5.8",
|
|
107
|
+
"@backstage/test-utils": "^1.7.3",
|
|
108
108
|
"@testing-library/dom": "^10.0.0",
|
|
109
109
|
"@testing-library/jest-dom": "^6.0.0",
|
|
110
110
|
"@testing-library/react": "^16.0.0",
|