@backstage-community/plugin-servicenow 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +34 -0
- package/dist/api/ServiceNowBackendClient.esm.js +45 -0
- package/dist/api/ServiceNowBackendClient.esm.js.map +1 -0
- package/dist/components/Servicenow/ClosedIcon.esm.js +14 -0
- package/dist/components/Servicenow/ClosedIcon.esm.js.map +1 -0
- package/dist/components/Servicenow/CustomSvgIcon.esm.js +13 -0
- package/dist/components/Servicenow/CustomSvgIcon.esm.js.map +1 -0
- package/dist/components/Servicenow/InProgressIcon.esm.js +14 -0
- package/dist/components/Servicenow/InProgressIcon.esm.js.map +1 -0
- package/dist/components/Servicenow/IncidentsFilter.esm.js +69 -0
- package/dist/components/Servicenow/IncidentsFilter.esm.js.map +1 -0
- package/dist/components/Servicenow/IncidentsListColumns.esm.js +43 -0
- package/dist/components/Servicenow/IncidentsListColumns.esm.js.map +1 -0
- package/dist/components/Servicenow/IncidentsTableBody.esm.js +28 -0
- package/dist/components/Servicenow/IncidentsTableBody.esm.js.map +1 -0
- package/dist/components/Servicenow/IncidentsTableHeader.esm.js +44 -0
- package/dist/components/Servicenow/IncidentsTableHeader.esm.js.map +1 -0
- package/dist/components/Servicenow/IncidentsTableRow.esm.js +54 -0
- package/dist/components/Servicenow/IncidentsTableRow.esm.js.map +1 -0
- package/dist/components/Servicenow/ModerateIcon.esm.js +14 -0
- package/dist/components/Servicenow/ModerateIcon.esm.js.map +1 -0
- package/dist/components/Servicenow/ServicenowContent.esm.js +196 -0
- package/dist/components/Servicenow/ServicenowContent.esm.js.map +1 -0
- package/dist/components/Servicenow/index.esm.js +2 -0
- package/dist/components/Servicenow/index.esm.js.map +1 -0
- package/dist/components/shared-components/IncidentEnumFilter.esm.js +79 -0
- package/dist/components/shared-components/IncidentEnumFilter.esm.js.map +1 -0
- package/dist/hooks/useDebouncedValue.esm.js +13 -0
- package/dist/hooks/useDebouncedValue.esm.js.map +1 -0
- package/dist/hooks/useQueryArrayFilter.esm.js +38 -0
- package/dist/hooks/useQueryArrayFilter.esm.js.map +1 -0
- package/dist/hooks/useQueryArrayState.esm.js +44 -0
- package/dist/hooks/useQueryArrayState.esm.js.map +1 -0
- package/dist/hooks/useQueryHelpers.esm.js +24 -0
- package/dist/hooks/useQueryHelpers.esm.js.map +1 -0
- package/dist/hooks/useQueryState.esm.js +50 -0
- package/dist/hooks/useQueryState.esm.js.map +1 -0
- package/dist/hooks/useUserEmail.esm.js +22 -0
- package/dist/hooks/useUserEmail.esm.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +43 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/types.esm.js +13 -0
- package/dist/types.esm.js.map +1 -0
- package/dist/utils/incidentUtils.esm.js +58 -0
- package/dist/utils/incidentUtils.esm.js.map +1 -0
- package/dist/utils/queryParamsUtils.esm.js +37 -0
- package/dist/utils/queryParamsUtils.esm.js.map +1 -0
- package/dist/utils/stringUtils.esm.js +13 -0
- package/dist/utils/stringUtils.esm.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { useApi, identityApiRef } from '@backstage/core-plugin-api';
|
|
4
|
+
import { useEntity, CatalogFilterLayout } from '@backstage/plugin-catalog-react';
|
|
5
|
+
import { Table } from '@backstage/core-components';
|
|
6
|
+
import Box from '@mui/material/Box';
|
|
7
|
+
import TablePagination from '@mui/material/TablePagination';
|
|
8
|
+
import { IncidentsFilter } from './IncidentsFilter.esm.js';
|
|
9
|
+
import { IncidentsListColumns } from './IncidentsListColumns.esm.js';
|
|
10
|
+
import { IncidentsTableBody } from './IncidentsTableBody.esm.js';
|
|
11
|
+
import { IncidentsTableHeader } from './IncidentsTableHeader.esm.js';
|
|
12
|
+
import { IncidentTableFieldEnum } from '../../types.esm.js';
|
|
13
|
+
import { SortingOrderEnum, ServiceAnnotationFieldName } from '@backstage-community/plugin-servicenow-common';
|
|
14
|
+
import { buildIncidentQueryParams } from '../../utils/queryParamsUtils.esm.js';
|
|
15
|
+
import { useDebouncedValue } from '../../hooks/useDebouncedValue.esm.js';
|
|
16
|
+
import { useQueryState } from '../../hooks/useQueryState.esm.js';
|
|
17
|
+
import { useQueryArrayState } from '../../hooks/useQueryArrayState.esm.js';
|
|
18
|
+
import { serviceNowApiRef } from '../../api/ServiceNowBackendClient.esm.js';
|
|
19
|
+
import { useUserEmail } from '../../hooks/useUserEmail.esm.js';
|
|
20
|
+
import CircularProgress from '@mui/material/CircularProgress';
|
|
21
|
+
import TableBody from '@mui/material/TableBody';
|
|
22
|
+
import TableRow from '@mui/material/TableRow';
|
|
23
|
+
import TableCell from '@mui/material/TableCell';
|
|
24
|
+
import { useUpdateQueryParams } from '../../hooks/useQueryHelpers.esm.js';
|
|
25
|
+
|
|
26
|
+
const ServicenowContent = () => {
|
|
27
|
+
const { entity } = useEntity();
|
|
28
|
+
const serviceNowApi = useApi(serviceNowApiRef);
|
|
29
|
+
const [search, setSearch] = useQueryState("search", "");
|
|
30
|
+
const [input, setInput] = useState(search);
|
|
31
|
+
const debouncedInput = useDebouncedValue(input, 300);
|
|
32
|
+
const [order, setOrder] = useQueryState("order", SortingOrderEnum.Asc);
|
|
33
|
+
const [orderBy, setOrderBy] = useQueryState(
|
|
34
|
+
"orderBy",
|
|
35
|
+
IncidentTableFieldEnum.Number
|
|
36
|
+
);
|
|
37
|
+
const [rowsPerPage] = useQueryState("limit", 5);
|
|
38
|
+
const [offset, setOffset] = useQueryState("offset", 0);
|
|
39
|
+
const [state] = useQueryArrayState("state", []);
|
|
40
|
+
const [priority] = useQueryArrayState("priority", []);
|
|
41
|
+
const pageNumber = Math.floor(offset / rowsPerPage);
|
|
42
|
+
const [count, setCount] = useState(0);
|
|
43
|
+
const [incidentsData, setIncidentsData] = useState([]);
|
|
44
|
+
const [loading, setLoading] = useState(false);
|
|
45
|
+
const [error, setError] = useState(null);
|
|
46
|
+
const updateQueryParams = useUpdateQueryParams();
|
|
47
|
+
const entityId = entity.metadata.annotations?.[ServiceAnnotationFieldName];
|
|
48
|
+
const kind = entity.kind.toLocaleLowerCase("en-US");
|
|
49
|
+
const userEmail = useUserEmail(kind);
|
|
50
|
+
const identityApi = useApi(identityApiRef);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
identityApi.getBackstageIdentity().then((identity) => {
|
|
53
|
+
if (identity.userEntityRef) {
|
|
54
|
+
localStorage.setItem("userEntityRef", identity.userEntityRef);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}, [identityApi]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (debouncedInput !== search) {
|
|
60
|
+
setSearch(debouncedInput);
|
|
61
|
+
setOffset(0);
|
|
62
|
+
}
|
|
63
|
+
}, [debouncedInput, search, setSearch, setOffset]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
async function fetchIncidents() {
|
|
66
|
+
setLoading(true);
|
|
67
|
+
setError(null);
|
|
68
|
+
if (!userEmail && !entityId) {
|
|
69
|
+
setIncidentsData([]);
|
|
70
|
+
setLoading(false);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const queryParams = buildIncidentQueryParams({
|
|
75
|
+
limit: rowsPerPage,
|
|
76
|
+
offset,
|
|
77
|
+
order,
|
|
78
|
+
orderBy,
|
|
79
|
+
search,
|
|
80
|
+
priority: priority ?? void 0,
|
|
81
|
+
state: state ?? void 0,
|
|
82
|
+
userEmail,
|
|
83
|
+
entityId
|
|
84
|
+
});
|
|
85
|
+
const { incidents, totalCount } = await serviceNowApi.getIncidents(
|
|
86
|
+
queryParams
|
|
87
|
+
);
|
|
88
|
+
setIncidentsData(incidents);
|
|
89
|
+
setCount(totalCount);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
setError(e.message);
|
|
92
|
+
setIncidentsData([]);
|
|
93
|
+
} finally {
|
|
94
|
+
setLoading(false);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
fetchIncidents();
|
|
98
|
+
}, [
|
|
99
|
+
rowsPerPage,
|
|
100
|
+
offset,
|
|
101
|
+
order,
|
|
102
|
+
orderBy,
|
|
103
|
+
search,
|
|
104
|
+
serviceNowApi,
|
|
105
|
+
entityId,
|
|
106
|
+
priority,
|
|
107
|
+
state,
|
|
108
|
+
userEmail
|
|
109
|
+
]);
|
|
110
|
+
const handleRowsPerPageChange = (event) => {
|
|
111
|
+
const newLimit = parseInt(event.target.value, 10);
|
|
112
|
+
updateQueryParams({
|
|
113
|
+
limit: String(newLimit),
|
|
114
|
+
offset: "0"
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
const handlePageChange = (_event, page) => {
|
|
118
|
+
setOffset(page * rowsPerPage);
|
|
119
|
+
};
|
|
120
|
+
const handleRequestSort = (_event, property) => {
|
|
121
|
+
const isAsc = orderBy === property && order === SortingOrderEnum.Asc;
|
|
122
|
+
setOrder(isAsc ? SortingOrderEnum.Desc : SortingOrderEnum.Asc);
|
|
123
|
+
setOrderBy(property);
|
|
124
|
+
setOffset(0);
|
|
125
|
+
};
|
|
126
|
+
const handleSearch = (str) => {
|
|
127
|
+
setInput(str);
|
|
128
|
+
};
|
|
129
|
+
const IncidentsTableHeaderComponent = () => /* @__PURE__ */ jsx(
|
|
130
|
+
IncidentsTableHeader,
|
|
131
|
+
{
|
|
132
|
+
order,
|
|
133
|
+
orderBy,
|
|
134
|
+
onRequestSort: handleRequestSort
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
const IncidentsTableBodyComponent = () => loading ? /* @__PURE__ */ jsx(TableBody, { children: /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: IncidentsListColumns.length, align: "center", children: /* @__PURE__ */ jsx(Box, { sx: { py: 3 }, children: /* @__PURE__ */ jsx(CircularProgress, {}) }) }) }) }) : /* @__PURE__ */ jsx(IncidentsTableBody, { rows: incidentsData });
|
|
138
|
+
const TablePaginationComponent = () => {
|
|
139
|
+
return /* @__PURE__ */ jsx(
|
|
140
|
+
TablePagination,
|
|
141
|
+
{
|
|
142
|
+
rowsPerPageOptions: [5, 10, 20, 50, 100].map((n) => ({
|
|
143
|
+
value: n,
|
|
144
|
+
label: `${n} rows`
|
|
145
|
+
})),
|
|
146
|
+
component: "div",
|
|
147
|
+
sx: { mr: 1 },
|
|
148
|
+
count: count ?? 0,
|
|
149
|
+
rowsPerPage,
|
|
150
|
+
page: pageNumber,
|
|
151
|
+
onPageChange: handlePageChange,
|
|
152
|
+
onRowsPerPageChange: handleRowsPerPageChange,
|
|
153
|
+
labelRowsPerPage: null,
|
|
154
|
+
showFirstButton: true,
|
|
155
|
+
showLastButton: true
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(CatalogFilterLayout, { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(CatalogFilterLayout.Filters, { children: /* @__PURE__ */ jsx(IncidentsFilter, {}) }),
|
|
161
|
+
/* @__PURE__ */ jsx(CatalogFilterLayout.Content, { children: error ? /* @__PURE__ */ jsxs(Box, { sx: { padding: 2, color: "error.main" }, children: [
|
|
162
|
+
"Error loading incidents: ",
|
|
163
|
+
error
|
|
164
|
+
] }) : /* @__PURE__ */ jsx(
|
|
165
|
+
Table,
|
|
166
|
+
{
|
|
167
|
+
data: loading ? [] : incidentsData,
|
|
168
|
+
columns: IncidentsListColumns,
|
|
169
|
+
onSearchChange: handleSearch,
|
|
170
|
+
title: count === 0 ? "ServiceNow tickets" : `ServiceNow tickets (${count})`,
|
|
171
|
+
localization: { toolbar: { searchPlaceholder: "Search" } },
|
|
172
|
+
components: {
|
|
173
|
+
Header: IncidentsTableHeaderComponent,
|
|
174
|
+
Body: IncidentsTableBodyComponent,
|
|
175
|
+
Pagination: TablePaginationComponent
|
|
176
|
+
},
|
|
177
|
+
emptyContent: loading ? null : /* @__PURE__ */ jsx(
|
|
178
|
+
Box,
|
|
179
|
+
{
|
|
180
|
+
"data-testid": "no-incidents-found",
|
|
181
|
+
sx: {
|
|
182
|
+
padding: 2,
|
|
183
|
+
display: "flex",
|
|
184
|
+
justifyContent: "center"
|
|
185
|
+
},
|
|
186
|
+
children: "No records found"
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
isLoading: loading
|
|
190
|
+
}
|
|
191
|
+
) })
|
|
192
|
+
] }) });
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export { ServicenowContent };
|
|
196
|
+
//# sourceMappingURL=ServicenowContent.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServicenowContent.esm.js","sources":["../../../src/components/Servicenow/ServicenowContent.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { useEffect, useState, MouseEvent, ChangeEvent } from 'react';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport {\n CatalogFilterLayout,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Table } from '@backstage/core-components';\nimport Box from '@mui/material/Box';\nimport TablePagination from '@mui/material/TablePagination';\n\nimport { IncidentsFilter } from './IncidentsFilter';\nimport { IncidentsListColumns } from './IncidentsListColumns';\nimport { IncidentsTableBody } from './IncidentsTableBody';\nimport { IncidentsTableHeader } from './IncidentsTableHeader';\nimport {\n IncidentTableFieldEnum,\n type IncidentsData,\n type IncidentTableField,\n} from '../../types';\nimport {\n Order,\n SortingOrderEnum,\n ServiceAnnotationFieldName,\n} from '@backstage-community/plugin-servicenow-common';\nimport { buildIncidentQueryParams } from '../../utils/queryParamsUtils';\nimport { useDebouncedValue } from '../../hooks/useDebouncedValue';\nimport { useQueryState } from '../../hooks/useQueryState';\nimport { useQueryArrayState } from '../../hooks/useQueryArrayState';\nimport { serviceNowApiRef } from '../../api/ServiceNowBackendClient';\nimport useUserEmail from '../../hooks/useUserEmail';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport TableBody from '@mui/material/TableBody';\nimport TableRow from '@mui/material/TableRow';\nimport TableCell from '@mui/material/TableCell';\nimport { useUpdateQueryParams } from '../../hooks/useQueryHelpers';\n\nexport const ServicenowContent = () => {\n const { entity } = useEntity();\n const serviceNowApi = useApi(serviceNowApiRef);\n\n const [search, setSearch] = useQueryState<string>('search', '');\n const [input, setInput] = useState(search);\n const debouncedInput = useDebouncedValue(input, 300);\n\n const [order, setOrder] = useQueryState<Order>('order', SortingOrderEnum.Asc);\n const [orderBy, setOrderBy] = useQueryState<IncidentTableField>(\n 'orderBy',\n IncidentTableFieldEnum.Number,\n );\n\n const [rowsPerPage] = useQueryState<number>('limit', 5);\n const [offset, setOffset] = useQueryState<number>('offset', 0);\n const [state] = useQueryArrayState('state', []);\n const [priority] = useQueryArrayState('priority', []);\n\n const pageNumber = Math.floor(offset / rowsPerPage);\n\n const [count, setCount] = useState<number>(0);\n const [incidentsData, setIncidentsData] = useState<IncidentsData[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const updateQueryParams = useUpdateQueryParams();\n\n const entityId = entity.metadata.annotations?.[ServiceAnnotationFieldName];\n\n const kind = entity.kind.toLocaleLowerCase('en-US');\n const userEmail = useUserEmail(kind);\n\n const identityApi = useApi(identityApiRef);\n\n useEffect(() => {\n identityApi.getBackstageIdentity().then(identity => {\n if (identity.userEntityRef) {\n localStorage.setItem('userEntityRef', identity.userEntityRef);\n }\n });\n }, [identityApi]);\n\n useEffect(() => {\n if (debouncedInput !== search) {\n setSearch(debouncedInput);\n setOffset(0);\n }\n }, [debouncedInput, search, setSearch, setOffset]);\n\n useEffect(() => {\n async function fetchIncidents() {\n setLoading(true);\n setError(null);\n\n if (!userEmail && !entityId) {\n setIncidentsData([]);\n setLoading(false);\n return;\n }\n\n try {\n const queryParams = buildIncidentQueryParams({\n limit: rowsPerPage,\n offset,\n order,\n orderBy,\n search: search,\n priority: priority ?? undefined,\n state: state ?? undefined,\n userEmail,\n entityId,\n });\n\n const { incidents, totalCount } = await serviceNowApi.getIncidents(\n queryParams,\n );\n setIncidentsData(incidents);\n setCount(totalCount);\n } catch (e) {\n setError((e as Error).message);\n setIncidentsData([]);\n } finally {\n setLoading(false);\n }\n }\n\n fetchIncidents();\n }, [\n rowsPerPage,\n offset,\n order,\n orderBy,\n search,\n serviceNowApi,\n entityId,\n priority,\n state,\n userEmail,\n ]);\n\n const handleRowsPerPageChange = (event: ChangeEvent<HTMLInputElement>) => {\n const newLimit = parseInt(event.target.value, 10);\n updateQueryParams({\n limit: String(newLimit),\n offset: '0',\n });\n };\n\n const handlePageChange = (_event: unknown, page: number) => {\n setOffset(page * rowsPerPage);\n };\n\n const handleRequestSort = (\n _event: MouseEvent<unknown>,\n property: IncidentTableField,\n ) => {\n const isAsc = orderBy === property && order === SortingOrderEnum.Asc;\n setOrder(isAsc ? SortingOrderEnum.Desc : SortingOrderEnum.Asc);\n setOrderBy(property);\n setOffset(0);\n };\n\n const handleSearch = (str: string) => {\n setInput(str);\n };\n\n const IncidentsTableHeaderComponent = () => (\n <IncidentsTableHeader\n order={order}\n orderBy={orderBy}\n onRequestSort={handleRequestSort}\n />\n );\n\n const IncidentsTableBodyComponent = () =>\n loading ? (\n <TableBody>\n <TableRow>\n <TableCell colSpan={IncidentsListColumns.length} align=\"center\">\n <Box sx={{ py: 3 }}>\n <CircularProgress />\n </Box>\n </TableCell>\n </TableRow>\n </TableBody>\n ) : (\n <IncidentsTableBody rows={incidentsData} />\n );\n\n const TablePaginationComponent = () => {\n return (\n <TablePagination\n rowsPerPageOptions={[5, 10, 20, 50, 100].map(n => ({\n value: n,\n label: `${n} rows`,\n }))}\n component=\"div\"\n sx={{ mr: 1 }}\n count={count ?? 0}\n rowsPerPage={rowsPerPage}\n page={pageNumber}\n onPageChange={handlePageChange}\n onRowsPerPageChange={handleRowsPerPageChange}\n labelRowsPerPage={null}\n showFirstButton\n showLastButton\n />\n );\n };\n\n return (\n <Box>\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <IncidentsFilter />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n {error ? (\n <Box sx={{ padding: 2, color: 'error.main' }}>\n Error loading incidents: {error}\n </Box>\n ) : (\n <Table\n data={loading ? [] : incidentsData}\n columns={IncidentsListColumns}\n onSearchChange={handleSearch}\n title={\n count === 0\n ? 'ServiceNow tickets'\n : `ServiceNow tickets (${count})`\n }\n localization={{ toolbar: { searchPlaceholder: 'Search' } }}\n components={{\n Header: IncidentsTableHeaderComponent,\n Body: IncidentsTableBodyComponent,\n Pagination: TablePaginationComponent,\n }}\n emptyContent={\n loading ? null : (\n <Box\n data-testid=\"no-incidents-found\"\n sx={{\n padding: 2,\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n No records found\n </Box>\n )\n }\n isLoading={loading}\n />\n )}\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import Autocomplete from '@mui/material/Autocomplete';
|
|
3
|
+
import Box from '@mui/material/Box';
|
|
4
|
+
import Checkbox from '@mui/material/Checkbox';
|
|
5
|
+
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
|
6
|
+
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
|
7
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
8
|
+
import InputLabel from '@mui/material/InputLabel';
|
|
9
|
+
import TextField from '@mui/material/TextField';
|
|
10
|
+
import { PRIORITY_MAP, INCIDENT_STATE_MAP, renderStatusLabel } from '../../utils/incidentUtils.esm.js';
|
|
11
|
+
|
|
12
|
+
const IncidentEnumFilter = ({
|
|
13
|
+
label,
|
|
14
|
+
filterKey,
|
|
15
|
+
dataMap,
|
|
16
|
+
value,
|
|
17
|
+
onChange
|
|
18
|
+
}) => {
|
|
19
|
+
const items = Object.entries(dataMap).map(
|
|
20
|
+
([key, itemValue]) => ({
|
|
21
|
+
value: key,
|
|
22
|
+
label: itemValue.label
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
return /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column" }, children: [
|
|
26
|
+
/* @__PURE__ */ jsx(
|
|
27
|
+
InputLabel,
|
|
28
|
+
{
|
|
29
|
+
sx: {
|
|
30
|
+
transform: "initial",
|
|
31
|
+
fontWeight: "bold",
|
|
32
|
+
fontSize: (theme) => theme.typography.body2.fontSize,
|
|
33
|
+
fontFamily: (theme) => theme.typography.fontFamily,
|
|
34
|
+
color: (theme) => theme.palette.text.primary
|
|
35
|
+
},
|
|
36
|
+
children: label
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
Autocomplete,
|
|
41
|
+
{
|
|
42
|
+
multiple: true,
|
|
43
|
+
disableCloseOnSelect: true,
|
|
44
|
+
"aria-label": label,
|
|
45
|
+
options: items,
|
|
46
|
+
isOptionEqualToValue: (option, val) => option.value === val.value,
|
|
47
|
+
getOptionLabel: (option) => option.label,
|
|
48
|
+
onChange,
|
|
49
|
+
renderOption: (renderProps, option, { selected }) => {
|
|
50
|
+
const { key, ...optionProps } = renderProps;
|
|
51
|
+
const statusData = filterKey === "priority" ? PRIORITY_MAP[Number(option.value)] : INCIDENT_STATE_MAP[Number(option.value)];
|
|
52
|
+
return /* @__PURE__ */ jsxs("li", { ...optionProps, children: [
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
Checkbox,
|
|
55
|
+
{
|
|
56
|
+
icon: /* @__PURE__ */ jsx(CheckBoxOutlineBlankIcon, { fontSize: "small" }),
|
|
57
|
+
checkedIcon: /* @__PURE__ */ jsx(CheckBoxIcon, { fontSize: "small" }),
|
|
58
|
+
checked: selected
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
renderStatusLabel(statusData)
|
|
62
|
+
] }, key);
|
|
63
|
+
},
|
|
64
|
+
size: "small",
|
|
65
|
+
value,
|
|
66
|
+
popupIcon: /* @__PURE__ */ jsx(
|
|
67
|
+
ExpandMoreIcon,
|
|
68
|
+
{
|
|
69
|
+
"data-testid": `select-${label.toLowerCase().replace(/\s/g, "-")}`
|
|
70
|
+
}
|
|
71
|
+
),
|
|
72
|
+
renderInput: (params) => /* @__PURE__ */ jsx(TextField, { ...params, variant: "outlined" })
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
] });
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export { IncidentEnumFilter };
|
|
79
|
+
//# sourceMappingURL=IncidentEnumFilter.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IncidentEnumFilter.esm.js","sources":["../../../src/components/shared-components/IncidentEnumFilter.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 { SelectItem } from '@backstage/core-components';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';\nimport CheckBoxIcon from '@mui/icons-material/CheckBox';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport InputLabel from '@mui/material/InputLabel';\nimport TextField from '@mui/material/TextField';\nimport {\n INCIDENT_STATE_MAP,\n PRIORITY_MAP,\n renderStatusLabel,\n} from '../../utils/incidentUtils';\n\ntype SourceMap = Record<number, { label: string }>;\n\nexport interface IncidentEnumFilterProps {\n label: string;\n filterKey: string;\n dataMap: SourceMap;\n value: SelectItem[];\n onChange: (event: any, value: SelectItem[]) => void;\n}\n\nexport const IncidentEnumFilter = ({\n label,\n filterKey,\n dataMap,\n value,\n onChange,\n}: IncidentEnumFilterProps) => {\n const items: SelectItem[] = Object.entries(dataMap).map(\n ([key, itemValue]) => ({\n value: key,\n label: itemValue.label,\n }),\n );\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column' }}>\n <InputLabel\n sx={{\n transform: 'initial',\n fontWeight: 'bold',\n fontSize: theme => theme.typography.body2.fontSize,\n fontFamily: theme => theme.typography.fontFamily,\n color: theme => theme.palette.text.primary,\n }}\n >\n {label}\n </InputLabel>\n <Autocomplete\n multiple\n disableCloseOnSelect\n aria-label={label}\n options={items}\n isOptionEqualToValue={(option, val) => option.value === val.value}\n getOptionLabel={option => option.label}\n onChange={onChange}\n renderOption={(renderProps, option, { selected }) => {\n const { key, ...optionProps } = renderProps;\n const statusData =\n filterKey === 'priority'\n ? PRIORITY_MAP[Number(option.value)]\n : INCIDENT_STATE_MAP[Number(option.value)];\n\n return (\n <li key={key} {...optionProps}>\n <Checkbox\n icon={<CheckBoxOutlineBlankIcon fontSize=\"small\" />}\n checkedIcon={<CheckBoxIcon fontSize=\"small\" />}\n checked={selected}\n />\n {renderStatusLabel(statusData)}\n </li>\n );\n }}\n size=\"small\"\n value={value}\n popupIcon={\n <ExpandMoreIcon\n data-testid={`select-${label.toLowerCase().replace(/\\s/g, '-')}`}\n />\n }\n renderInput={params => <TextField {...params} variant=\"outlined\" />}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAyCO,MAAM,qBAAqB,CAAC;AAAA,EACjC,KAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAA+B,KAAA;AAC7B,EAAA,MAAM,KAAsB,GAAA,MAAA,CAAO,OAAQ,CAAA,OAAO,CAAE,CAAA,GAAA;AAAA,IAClD,CAAC,CAAC,GAAK,EAAA,SAAS,CAAO,MAAA;AAAA,MACrB,KAAO,EAAA,GAAA;AAAA,MACP,OAAO,SAAU,CAAA;AAAA,KACnB;AAAA,GACF;AAEA,EACE,uBAAA,IAAA,CAAC,OAAI,EAAI,EAAA,EAAE,SAAS,MAAQ,EAAA,aAAA,EAAe,UACzC,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,EAAI,EAAA;AAAA,UACF,SAAW,EAAA,SAAA;AAAA,UACX,UAAY,EAAA,MAAA;AAAA,UACZ,QAAU,EAAA,CAAA,KAAA,KAAS,KAAM,CAAA,UAAA,CAAW,KAAM,CAAA,QAAA;AAAA,UAC1C,UAAA,EAAY,CAAS,KAAA,KAAA,KAAA,CAAM,UAAW,CAAA,UAAA;AAAA,UACtC,KAAO,EAAA,CAAA,KAAA,KAAS,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA;AAAA,SACrC;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,oBACA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,QAAQ,EAAA,IAAA;AAAA,QACR,oBAAoB,EAAA,IAAA;AAAA,QACpB,YAAY,EAAA,KAAA;AAAA,QACZ,OAAS,EAAA,KAAA;AAAA,QACT,sBAAsB,CAAC,MAAA,EAAQ,GAAQ,KAAA,MAAA,CAAO,UAAU,GAAI,CAAA,KAAA;AAAA,QAC5D,cAAA,EAAgB,YAAU,MAAO,CAAA,KAAA;AAAA,QACjC,QAAA;AAAA,QACA,cAAc,CAAC,WAAA,EAAa,MAAQ,EAAA,EAAE,UAAe,KAAA;AACnD,UAAA,MAAM,EAAE,GAAA,EAAK,GAAG,WAAA,EAAgB,GAAA,WAAA;AAChC,UAAA,MAAM,UACJ,GAAA,SAAA,KAAc,UACV,GAAA,YAAA,CAAa,MAAO,CAAA,MAAA,CAAO,KAAK,CAAC,CACjC,GAAA,kBAAA,CAAmB,MAAO,CAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAE7C,UACE,uBAAA,IAAA,CAAC,IAAc,EAAA,EAAA,GAAG,WAChB,EAAA,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAM,kBAAA,GAAA,CAAC,wBAAyB,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA,CAAA;AAAA,gBACjD,WAAa,kBAAA,GAAA,CAAC,YAAa,EAAA,EAAA,QAAA,EAAS,OAAQ,EAAA,CAAA;AAAA,gBAC5C,OAAS,EAAA;AAAA;AAAA,aACX;AAAA,YACC,kBAAkB,UAAU;AAAA,WAAA,EAAA,EANtB,GAOT,CAAA;AAAA,SAEJ;AAAA,QACA,IAAK,EAAA,OAAA;AAAA,QACL,KAAA;AAAA,QACA,SACE,kBAAA,GAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YACC,aAAA,EAAa,UAAU,KAAM,CAAA,WAAA,GAAc,OAAQ,CAAA,KAAA,EAAO,GAAG,CAAC,CAAA;AAAA;AAAA,SAChE;AAAA,QAEF,aAAa,CAAU,MAAA,qBAAA,GAAA,CAAC,aAAW,GAAG,MAAA,EAAQ,SAAQ,UAAW,EAAA;AAAA;AAAA;AACnE,GACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
function useDebouncedValue(value, delay) {
|
|
4
|
+
const [debounced, setDebounced] = useState(value);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const timer = setTimeout(() => setDebounced(value), delay);
|
|
7
|
+
return () => clearTimeout(timer);
|
|
8
|
+
}, [value, delay]);
|
|
9
|
+
return debounced;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { useDebouncedValue };
|
|
13
|
+
//# sourceMappingURL=useDebouncedValue.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDebouncedValue.esm.js","sources":["../../src/hooks/useDebouncedValue.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { useState, useEffect } from 'react';\n\nexport function useDebouncedValue<T>(value: T, delay: number): T {\n const [debounced, setDebounced] = useState(value);\n\n useEffect(() => {\n const timer = setTimeout(() => setDebounced(value), delay);\n return () => clearTimeout(timer);\n }, [value, delay]);\n\n return debounced;\n}\n"],"names":[],"mappings":";;AAkBgB,SAAA,iBAAA,CAAqB,OAAU,KAAkB,EAAA;AAC/D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,UAAW,CAAA,MAAM,YAAa,CAAA,KAAK,GAAG,KAAK,CAAA;AACzD,IAAO,OAAA,MAAM,aAAa,KAAK,CAAA;AAAA,GAC9B,EAAA,CAAC,KAAO,EAAA,KAAK,CAAC,CAAA;AAEjB,EAAO,OAAA,SAAA;AACT;;;;"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useMemo, useCallback } from 'react';
|
|
2
|
+
import { useQueryState } from './useQueryState.esm.js';
|
|
3
|
+
import { INCIDENT_STATE_MAP, PRIORITY_MAP } from '../utils/incidentUtils.esm.js';
|
|
4
|
+
|
|
5
|
+
const useQueryArrayFilter = (filterName) => {
|
|
6
|
+
const [raw, setRaw] = useQueryState(filterName, "");
|
|
7
|
+
const [, setOffset] = useQueryState("offset", 0);
|
|
8
|
+
const map = filterName === "state" ? INCIDENT_STATE_MAP : PRIORITY_MAP;
|
|
9
|
+
const current = useMemo(() => {
|
|
10
|
+
return raw.split(",").filter((v) => v !== "").map((value) => ({
|
|
11
|
+
value,
|
|
12
|
+
label: map[Number(value)]?.label
|
|
13
|
+
})).filter((item) => item.label);
|
|
14
|
+
}, [raw, map]);
|
|
15
|
+
const set = useCallback(
|
|
16
|
+
(newValues) => {
|
|
17
|
+
const joined = newValues.join(",");
|
|
18
|
+
setRaw(joined);
|
|
19
|
+
setOffset(0);
|
|
20
|
+
},
|
|
21
|
+
[setRaw, setOffset]
|
|
22
|
+
);
|
|
23
|
+
const clear = useCallback(() => {
|
|
24
|
+
setRaw("");
|
|
25
|
+
setOffset(0);
|
|
26
|
+
}, [setRaw, setOffset]);
|
|
27
|
+
return useMemo(
|
|
28
|
+
() => ({
|
|
29
|
+
current,
|
|
30
|
+
set,
|
|
31
|
+
clear
|
|
32
|
+
}),
|
|
33
|
+
[current, set, clear]
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export { useQueryArrayFilter };
|
|
38
|
+
//# sourceMappingURL=useQueryArrayFilter.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQueryArrayFilter.esm.js","sources":["../../src/hooks/useQueryArrayFilter.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { useMemo, useCallback } from 'react';\nimport { useQueryState } from './useQueryState';\nimport { INCIDENT_STATE_MAP, PRIORITY_MAP } from '../utils/incidentUtils';\nimport { SelectItem } from '@backstage/core-components';\n\nexport const useQueryArrayFilter = (filterName: 'state' | 'priority') => {\n const [raw, setRaw] = useQueryState<string>(filterName, '');\n const [, setOffset] = useQueryState<number>('offset', 0);\n\n const map = filterName === 'state' ? INCIDENT_STATE_MAP : PRIORITY_MAP;\n\n const current: SelectItem[] = useMemo(() => {\n return raw\n .split(',')\n .filter(v => v !== '')\n .map(value => ({\n value,\n label: map[Number(value)]?.label,\n }))\n .filter(item => item.label);\n }, [raw, map]);\n\n const set = useCallback(\n (newValues: (string | number)[]) => {\n const joined = newValues.join(',');\n setRaw(joined);\n setOffset(0);\n },\n [setRaw, setOffset],\n );\n\n const clear = useCallback(() => {\n setRaw('');\n setOffset(0);\n }, [setRaw, setOffset]);\n\n return useMemo(\n () =>\n ({\n current,\n set,\n clear,\n } as const),\n [current, set, clear],\n );\n};\n"],"names":[],"mappings":";;;;AAqBa,MAAA,mBAAA,GAAsB,CAAC,UAAqC,KAAA;AACvE,EAAA,MAAM,CAAC,GAAK,EAAA,MAAM,CAAI,GAAA,aAAA,CAAsB,YAAY,EAAE,CAAA;AAC1D,EAAA,MAAM,GAAG,SAAS,CAAI,GAAA,aAAA,CAAsB,UAAU,CAAC,CAAA;AAEvD,EAAM,MAAA,GAAA,GAAM,UAAe,KAAA,OAAA,GAAU,kBAAqB,GAAA,YAAA;AAE1D,EAAM,MAAA,OAAA,GAAwB,QAAQ,MAAM;AAC1C,IAAO,OAAA,GAAA,CACJ,KAAM,CAAA,GAAG,CACT,CAAA,MAAA,CAAO,OAAK,CAAM,KAAA,EAAE,CACpB,CAAA,GAAA,CAAI,CAAU,KAAA,MAAA;AAAA,MACb,KAAA;AAAA,MACA,KAAO,EAAA,GAAA,CAAI,MAAO,CAAA,KAAK,CAAC,CAAG,EAAA;AAAA,KAC3B,CAAA,CAAA,CACD,MAAO,CAAA,CAAA,IAAA,KAAQ,KAAK,KAAK,CAAA;AAAA,GAC3B,EAAA,CAAC,GAAK,EAAA,GAAG,CAAC,CAAA;AAEb,EAAA,MAAM,GAAM,GAAA,WAAA;AAAA,IACV,CAAC,SAAmC,KAAA;AAClC,MAAM,MAAA,MAAA,GAAS,SAAU,CAAA,IAAA,CAAK,GAAG,CAAA;AACjC,MAAA,MAAA,CAAO,MAAM,CAAA;AACb,MAAA,SAAA,CAAU,CAAC,CAAA;AAAA,KACb;AAAA,IACA,CAAC,QAAQ,SAAS;AAAA,GACpB;AAEA,EAAM,MAAA,KAAA,GAAQ,YAAY,MAAM;AAC9B,IAAA,MAAA,CAAO,EAAE,CAAA;AACT,IAAA,SAAA,CAAU,CAAC,CAAA;AAAA,GACV,EAAA,CAAC,MAAQ,EAAA,SAAS,CAAC,CAAA;AAEtB,EAAO,OAAA,OAAA;AAAA,IACL,OACG;AAAA,MACC,OAAA;AAAA,MACA,GAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACF,CAAC,OAAS,EAAA,GAAA,EAAK,KAAK;AAAA,GACtB;AACF;;;;"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useCallback, useState, useEffect } from 'react';
|
|
2
|
+
import { useSearchParams } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
function useQueryArrayState(key, defaultValue = []) {
|
|
5
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
6
|
+
const getArrayFromParam = useCallback(() => {
|
|
7
|
+
const raw = searchParams.get(key);
|
|
8
|
+
return raw ? raw.split(",").filter(Boolean) : defaultValue;
|
|
9
|
+
}, [key, searchParams, defaultValue]);
|
|
10
|
+
const [state, setState] = useState(() => getArrayFromParam());
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const value = getArrayFromParam();
|
|
13
|
+
setState((prev) => {
|
|
14
|
+
const prevRaw = prev.join(",");
|
|
15
|
+
const nextRaw = value.join(",");
|
|
16
|
+
return prevRaw === nextRaw ? prev : value;
|
|
17
|
+
});
|
|
18
|
+
}, [getArrayFromParam]);
|
|
19
|
+
const setValue = useCallback(
|
|
20
|
+
(newValue) => {
|
|
21
|
+
const newRaw = newValue.join(",");
|
|
22
|
+
const currentRaw = searchParams.get(key);
|
|
23
|
+
if (currentRaw === newRaw || !currentRaw && newRaw === "") return;
|
|
24
|
+
setSearchParams(
|
|
25
|
+
(prev) => {
|
|
26
|
+
const params = new URLSearchParams(prev);
|
|
27
|
+
if (newRaw === "") {
|
|
28
|
+
params.delete(key);
|
|
29
|
+
} else {
|
|
30
|
+
params.set(key, newRaw);
|
|
31
|
+
}
|
|
32
|
+
return params;
|
|
33
|
+
},
|
|
34
|
+
{ replace: true }
|
|
35
|
+
);
|
|
36
|
+
setState(newValue);
|
|
37
|
+
},
|
|
38
|
+
[key, searchParams, setSearchParams]
|
|
39
|
+
);
|
|
40
|
+
return [state, setValue];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { useQueryArrayState };
|
|
44
|
+
//# sourceMappingURL=useQueryArrayState.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQueryArrayState.esm.js","sources":["../../src/hooks/useQueryArrayState.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { useCallback, useEffect, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\n\nexport function useQueryArrayState(\n key: string,\n defaultValue: string[] = [],\n): [string[], (value: string[]) => void] {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const getArrayFromParam = useCallback((): string[] => {\n const raw = searchParams.get(key);\n return raw ? raw.split(',').filter(Boolean) : defaultValue;\n }, [key, searchParams, defaultValue]);\n\n const [state, setState] = useState<string[]>(() => getArrayFromParam());\n\n useEffect(() => {\n const value = getArrayFromParam();\n setState(prev => {\n const prevRaw = prev.join(',');\n const nextRaw = value.join(',');\n return prevRaw === nextRaw ? prev : value;\n });\n }, [getArrayFromParam]);\n\n const setValue = useCallback(\n (newValue: string[]) => {\n const newRaw = newValue.join(',');\n const currentRaw = searchParams.get(key);\n\n if (currentRaw === newRaw || (!currentRaw && newRaw === '')) return;\n\n setSearchParams(\n prev => {\n const params = new URLSearchParams(prev);\n if (newRaw === '') {\n params.delete(key);\n } else {\n params.set(key, newRaw);\n }\n return params;\n },\n { replace: true },\n );\n\n setState(newValue);\n },\n [key, searchParams, setSearchParams],\n );\n\n return [state, setValue];\n}\n"],"names":[],"mappings":";;;AAkBO,SAAS,kBACd,CAAA,GAAA,EACA,YAAyB,GAAA,EACc,EAAA;AACvC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,eAAgB,EAAA;AAExD,EAAM,MAAA,iBAAA,GAAoB,YAAY,MAAgB;AACpD,IAAM,MAAA,GAAA,GAAM,YAAa,CAAA,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,OAAO,MAAM,GAAI,CAAA,KAAA,CAAM,GAAG,CAAE,CAAA,MAAA,CAAO,OAAO,CAAI,GAAA,YAAA;AAAA,GAC7C,EAAA,CAAC,GAAK,EAAA,YAAA,EAAc,YAAY,CAAC,CAAA;AAEpC,EAAA,MAAM,CAAC,KAAO,EAAA,QAAQ,IAAI,QAAmB,CAAA,MAAM,mBAAmB,CAAA;AAEtE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,iBAAkB,EAAA;AAChC,IAAA,QAAA,CAAS,CAAQ,IAAA,KAAA;AACf,MAAM,MAAA,OAAA,GAAU,IAAK,CAAA,IAAA,CAAK,GAAG,CAAA;AAC7B,MAAM,MAAA,OAAA,GAAU,KAAM,CAAA,IAAA,CAAK,GAAG,CAAA;AAC9B,MAAO,OAAA,OAAA,KAAY,UAAU,IAAO,GAAA,KAAA;AAAA,KACrC,CAAA;AAAA,GACH,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,QAAuB,KAAA;AACtB,MAAM,MAAA,MAAA,GAAS,QAAS,CAAA,IAAA,CAAK,GAAG,CAAA;AAChC,MAAM,MAAA,UAAA,GAAa,YAAa,CAAA,GAAA,CAAI,GAAG,CAAA;AAEvC,MAAA,IAAI,UAAe,KAAA,MAAA,IAAW,CAAC,UAAA,IAAc,WAAW,EAAK,EAAA;AAE7D,MAAA,eAAA;AAAA,QACE,CAAQ,IAAA,KAAA;AACN,UAAM,MAAA,MAAA,GAAS,IAAI,eAAA,CAAgB,IAAI,CAAA;AACvC,UAAA,IAAI,WAAW,EAAI,EAAA;AACjB,YAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,WACZ,MAAA;AACL,YAAO,MAAA,CAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA;AAExB,UAAO,OAAA,MAAA;AAAA,SACT;AAAA,QACA,EAAE,SAAS,IAAK;AAAA,OAClB;AAEA,MAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,KACnB;AAAA,IACA,CAAC,GAAK,EAAA,YAAA,EAAc,eAAe;AAAA,GACrC;AAEA,EAAO,OAAA,CAAC,OAAO,QAAQ,CAAA;AACzB;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useSearchParams } from 'react-router-dom';
|
|
2
|
+
|
|
3
|
+
function useUpdateQueryParams() {
|
|
4
|
+
const [, setSearchParams] = useSearchParams();
|
|
5
|
+
return (updates) => {
|
|
6
|
+
setSearchParams(
|
|
7
|
+
(prev) => {
|
|
8
|
+
const params = new URLSearchParams(prev);
|
|
9
|
+
for (const key in updates) {
|
|
10
|
+
if (updates[key] === "") {
|
|
11
|
+
params.delete(key);
|
|
12
|
+
} else {
|
|
13
|
+
params.set(key, updates[key]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return params;
|
|
17
|
+
},
|
|
18
|
+
{ replace: true }
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { useUpdateQueryParams };
|
|
24
|
+
//# sourceMappingURL=useQueryHelpers.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQueryHelpers.esm.js","sources":["../../src/hooks/useQueryHelpers.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { useSearchParams } from 'react-router-dom';\n\nexport function useUpdateQueryParams() {\n const [, setSearchParams] = useSearchParams();\n\n return (updates: Record<string, string>) => {\n setSearchParams(\n prev => {\n const params = new URLSearchParams(prev);\n for (const key in updates) {\n if (updates[key] === '') {\n params.delete(key);\n } else {\n params.set(key, updates[key]);\n }\n }\n return params;\n },\n { replace: true },\n );\n };\n}\n"],"names":[],"mappings":";;AAkBO,SAAS,oBAAuB,GAAA;AACrC,EAAA,MAAM,GAAG,eAAe,CAAA,GAAI,eAAgB,EAAA;AAE5C,EAAA,OAAO,CAAC,OAAoC,KAAA;AAC1C,IAAA,eAAA;AAAA,MACE,CAAQ,IAAA,KAAA;AACN,QAAM,MAAA,MAAA,GAAS,IAAI,eAAA,CAAgB,IAAI,CAAA;AACvC,QAAA,KAAA,MAAW,OAAO,OAAS,EAAA;AACzB,UAAI,IAAA,OAAA,CAAQ,GAAG,CAAA,KAAM,EAAI,EAAA;AACvB,YAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,WACZ,MAAA;AACL,YAAA,MAAA,CAAO,GAAI,CAAA,GAAA,EAAK,OAAQ,CAAA,GAAG,CAAC,CAAA;AAAA;AAC9B;AAEF,QAAO,OAAA,MAAA;AAAA,OACT;AAAA,MACA,EAAE,SAAS,IAAK;AAAA,KAClB;AAAA,GACF;AACF;;;;"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useCallback, useState, useEffect } from 'react';
|
|
2
|
+
import { useSearchParams } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
function useQueryState(key, defaultValue) {
|
|
5
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
6
|
+
const getValueFromParams = useCallback(
|
|
7
|
+
(raw) => {
|
|
8
|
+
if (typeof defaultValue === "number") {
|
|
9
|
+
return raw !== null ? Number(raw) : defaultValue;
|
|
10
|
+
}
|
|
11
|
+
if (typeof defaultValue === "boolean") {
|
|
12
|
+
return raw === "true";
|
|
13
|
+
}
|
|
14
|
+
return raw ?? defaultValue;
|
|
15
|
+
},
|
|
16
|
+
[defaultValue]
|
|
17
|
+
);
|
|
18
|
+
const [state, setState] = useState(
|
|
19
|
+
() => getValueFromParams(searchParams.get(key))
|
|
20
|
+
);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const paramValue = getValueFromParams(searchParams.get(key));
|
|
23
|
+
setState(paramValue);
|
|
24
|
+
}, [getValueFromParams, searchParams, key]);
|
|
25
|
+
const setValue = useCallback(
|
|
26
|
+
(newValue) => {
|
|
27
|
+
const currentRaw = searchParams.get(key);
|
|
28
|
+
const newRaw = String(newValue);
|
|
29
|
+
if (currentRaw === newRaw || !currentRaw && newRaw === "") return;
|
|
30
|
+
setSearchParams(
|
|
31
|
+
(prev) => {
|
|
32
|
+
const params = new URLSearchParams(prev);
|
|
33
|
+
if (newRaw === "") {
|
|
34
|
+
params.delete(key);
|
|
35
|
+
} else {
|
|
36
|
+
params.set(key, newRaw);
|
|
37
|
+
}
|
|
38
|
+
return params;
|
|
39
|
+
},
|
|
40
|
+
{ replace: true }
|
|
41
|
+
);
|
|
42
|
+
setState(newValue);
|
|
43
|
+
},
|
|
44
|
+
[key, searchParams, setSearchParams]
|
|
45
|
+
);
|
|
46
|
+
return [state, setValue];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { useQueryState };
|
|
50
|
+
//# sourceMappingURL=useQueryState.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQueryState.esm.js","sources":["../../src/hooks/useQueryState.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { useCallback, useEffect, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\n\nexport function useQueryState<T>(\n key: string,\n defaultValue: T,\n): [T, (value: T) => void] {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const getValueFromParams = useCallback(\n (raw: string | null): T => {\n if (typeof defaultValue === 'number') {\n return (raw !== null ? Number(raw) : defaultValue) as T;\n }\n if (typeof defaultValue === 'boolean') {\n return (raw === 'true') as T;\n }\n return (raw ?? defaultValue) as T;\n },\n [defaultValue],\n );\n\n const [state, setState] = useState<T>(() =>\n getValueFromParams(searchParams.get(key)),\n );\n\n useEffect(() => {\n const paramValue = getValueFromParams(searchParams.get(key));\n setState(paramValue);\n }, [getValueFromParams, searchParams, key]);\n\n const setValue = useCallback(\n (newValue: T) => {\n const currentRaw = searchParams.get(key);\n const newRaw = String(newValue);\n\n if (currentRaw === newRaw || (!currentRaw && newRaw === '')) return;\n\n setSearchParams(\n prev => {\n const params = new URLSearchParams(prev);\n\n if (newRaw === '') {\n params.delete(key);\n } else {\n params.set(key, newRaw);\n }\n\n return params;\n },\n { replace: true },\n );\n\n setState(newValue);\n },\n [key, searchParams, setSearchParams],\n );\n\n return [state, setValue];\n}\n"],"names":[],"mappings":";;;AAkBgB,SAAA,aAAA,CACd,KACA,YACyB,EAAA;AACzB,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,eAAgB,EAAA;AAExD,EAAA,MAAM,kBAAqB,GAAA,WAAA;AAAA,IACzB,CAAC,GAA0B,KAAA;AACzB,MAAI,IAAA,OAAO,iBAAiB,QAAU,EAAA;AACpC,QAAA,OAAQ,GAAQ,KAAA,IAAA,GAAO,MAAO,CAAA,GAAG,CAAI,GAAA,YAAA;AAAA;AAEvC,MAAI,IAAA,OAAO,iBAAiB,SAAW,EAAA;AACrC,QAAA,OAAQ,GAAQ,KAAA,MAAA;AAAA;AAElB,MAAA,OAAQ,GAAO,IAAA,YAAA;AAAA,KACjB;AAAA,IACA,CAAC,YAAY;AAAA,GACf;AAEA,EAAM,MAAA,CAAC,KAAO,EAAA,QAAQ,CAAI,GAAA,QAAA;AAAA,IAAY,MACpC,kBAAA,CAAmB,YAAa,CAAA,GAAA,CAAI,GAAG,CAAC;AAAA,GAC1C;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAa,GAAA,kBAAA,CAAmB,YAAa,CAAA,GAAA,CAAI,GAAG,CAAC,CAAA;AAC3D,IAAA,QAAA,CAAS,UAAU,CAAA;AAAA,GAClB,EAAA,CAAC,kBAAoB,EAAA,YAAA,EAAc,GAAG,CAAC,CAAA;AAE1C,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,QAAgB,KAAA;AACf,MAAM,MAAA,UAAA,GAAa,YAAa,CAAA,GAAA,CAAI,GAAG,CAAA;AACvC,MAAM,MAAA,MAAA,GAAS,OAAO,QAAQ,CAAA;AAE9B,MAAA,IAAI,UAAe,KAAA,MAAA,IAAW,CAAC,UAAA,IAAc,WAAW,EAAK,EAAA;AAE7D,MAAA,eAAA;AAAA,QACE,CAAQ,IAAA,KAAA;AACN,UAAM,MAAA,MAAA,GAAS,IAAI,eAAA,CAAgB,IAAI,CAAA;AAEvC,UAAA,IAAI,WAAW,EAAI,EAAA;AACjB,YAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,WACZ,MAAA;AACL,YAAO,MAAA,CAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA;AAGxB,UAAO,OAAA,MAAA;AAAA,SACT;AAAA,QACA,EAAE,SAAS,IAAK;AAAA,OAClB;AAEA,MAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,KACnB;AAAA,IACA,CAAC,GAAK,EAAA,YAAA,EAAc,eAAe;AAAA,GACrC;AAEA,EAAO,OAAA,CAAC,OAAO,QAAQ,CAAA;AACzB;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useApi, identityApiRef } from '@backstage/core-plugin-api';
|
|
2
|
+
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
|
3
|
+
import { useAsync } from 'react-use';
|
|
4
|
+
|
|
5
|
+
function useUserEmail(kind) {
|
|
6
|
+
const identityApi = useApi(identityApiRef);
|
|
7
|
+
const catalogApi = useApi(catalogApiRef);
|
|
8
|
+
const state = useAsync(async () => {
|
|
9
|
+
if (kind !== "user") return void 0;
|
|
10
|
+
const profile = await identityApi.getProfileInfo();
|
|
11
|
+
if (profile?.email) return profile.email;
|
|
12
|
+
const identity = await identityApi.getBackstageIdentity();
|
|
13
|
+
const userEntity = await catalogApi.getEntityByRef(
|
|
14
|
+
identity.userEntityRef
|
|
15
|
+
);
|
|
16
|
+
return userEntity?.spec?.profile?.email;
|
|
17
|
+
}, [identityApi, catalogApi, kind]);
|
|
18
|
+
return state.value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { useUserEmail as default, useUserEmail };
|
|
22
|
+
//# sourceMappingURL=useUserEmail.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUserEmail.esm.js","sources":["../../src/hooks/useUserEmail.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { useAsync } from 'react-use';\n\nexport function useUserEmail(kind: string): string | undefined {\n const identityApi = useApi(identityApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n const state = useAsync(async () => {\n if (kind !== 'user') return undefined;\n\n const profile = await identityApi.getProfileInfo();\n if (profile?.email) return profile.email;\n\n const identity = await identityApi.getBackstageIdentity();\n const userEntity = (await catalogApi.getEntityByRef(\n identity.userEntityRef,\n )) as UserEntity | undefined;\n return userEntity?.spec?.profile?.email;\n }, [identityApi, catalogApi, kind]);\n\n return state.value;\n}\n\nexport default useUserEmail;\n"],"names":[],"mappings":";;;;AAqBO,SAAS,aAAa,IAAkC,EAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAM,MAAA,KAAA,GAAQ,SAAS,YAAY;AACjC,IAAI,IAAA,IAAA,KAAS,QAAe,OAAA,MAAA;AAE5B,IAAM,MAAA,OAAA,GAAU,MAAM,WAAA,CAAY,cAAe,EAAA;AACjD,IAAI,IAAA,OAAA,EAAS,KAAO,EAAA,OAAO,OAAQ,CAAA,KAAA;AAEnC,IAAM,MAAA,QAAA,GAAW,MAAM,WAAA,CAAY,oBAAqB,EAAA;AACxD,IAAM,MAAA,UAAA,GAAc,MAAM,UAAW,CAAA,cAAA;AAAA,MACnC,QAAS,CAAA;AAAA,KACX;AACA,IAAO,OAAA,UAAA,EAAY,MAAM,OAAS,EAAA,KAAA;AAAA,GACjC,EAAA,CAAC,WAAa,EAAA,UAAA,EAAY,IAAI,CAAC,CAAA;AAElC,EAAA,OAAO,KAAM,CAAA,KAAA;AACf;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
3
|
+
import { Entity } from '@backstage/catalog-model';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Servicenow Plugin
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
declare const servicenowPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
10
|
+
root: _backstage_core_plugin_api.RouteRef<undefined>;
|
|
11
|
+
}, {}, {}>;
|
|
12
|
+
/**
|
|
13
|
+
* Servicenow Page
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
declare const ServicenowPage: () => react_jsx_runtime.JSX.Element;
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
* Check if the current entity is the logged-in user
|
|
20
|
+
*/
|
|
21
|
+
declare const isMyProfile: (entity: Entity) => boolean;
|
|
22
|
+
|
|
23
|
+
export { ServicenowPage, isMyProfile, servicenowPlugin };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|