@flightctl/ui-components 0.0.5 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.d.ts +3 -1
- package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.d.ts.map +1 -1
- package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.js +2 -2
- package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/DeviceTableToolbar.d.ts +2 -2
- package/dist/src/components/Device/DevicesPage/DeviceTableToolbar.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/DeviceTableToolbar.js +8 -8
- package/dist/src/components/Device/DevicesPage/DeviceTableToolbar.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/DeviceToolbarFilters.d.ts +3 -3
- package/dist/src/components/Device/DevicesPage/DeviceToolbarFilters.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/DeviceToolbarFilters.js +23 -3
- package/dist/src/components/Device/DevicesPage/DeviceToolbarFilters.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/DevicesPage.d.ts +7 -1
- package/dist/src/components/Device/DevicesPage/DevicesPage.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/DevicesPage.js +23 -23
- package/dist/src/components/Device/DevicesPage/DevicesPage.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/EnrollmentRequestList.d.ts +0 -7
- package/dist/src/components/Device/DevicesPage/EnrollmentRequestList.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/EnrollmentRequestList.js +42 -51
- package/dist/src/components/Device/DevicesPage/EnrollmentRequestList.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/useDeviceBackendFilters.d.ts +2 -0
- package/dist/src/components/Device/DevicesPage/useDeviceBackendFilters.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/useDeviceBackendFilters.js +10 -3
- package/dist/src/components/Device/DevicesPage/useDeviceBackendFilters.js.map +1 -1
- package/dist/src/components/Device/DevicesPage/useDevices.d.ts +10 -4
- package/dist/src/components/Device/DevicesPage/useDevices.d.ts.map +1 -1
- package/dist/src/components/Device/DevicesPage/useDevices.js +25 -26
- package/dist/src/components/Device/DevicesPage/useDevices.js.map +1 -1
- package/dist/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.css +10 -0
- package/dist/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.d.ts +5 -0
- package/dist/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.d.ts.map +1 -0
- package/dist/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.js +22 -0
- package/dist/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.js.map +1 -0
- package/dist/src/components/Fleet/FleetDetails/FleetDevices.d.ts.map +1 -1
- package/dist/src/components/Fleet/FleetDetails/FleetDevices.js +7 -7
- package/dist/src/components/Fleet/FleetDetails/FleetDevices.js.map +1 -1
- package/dist/src/components/Fleet/FleetsPage.d.ts.map +1 -1
- package/dist/src/components/Fleet/FleetsPage.js +17 -23
- package/dist/src/components/Fleet/FleetsPage.js.map +1 -1
- package/dist/src/components/Fleet/useFleets.d.ts +18 -0
- package/dist/src/components/Fleet/useFleets.d.ts.map +1 -0
- package/dist/src/components/Fleet/useFleets.js +61 -0
- package/dist/src/components/Fleet/useFleets.js.map +1 -0
- package/dist/src/components/OverviewPage/Cards/Status/StatusCard.d.ts.map +1 -1
- package/dist/src/components/OverviewPage/Cards/Status/StatusCard.js +4 -3
- package/dist/src/components/OverviewPage/Cards/Status/StatusCard.js.map +1 -1
- package/dist/src/components/OverviewPage/Cards/ToDo/ToDoCard.d.ts.map +1 -1
- package/dist/src/components/OverviewPage/Cards/ToDo/ToDoCard.js +5 -9
- package/dist/src/components/OverviewPage/Cards/ToDo/ToDoCard.js.map +1 -1
- package/dist/src/components/OverviewPage/Overview.js +1 -1
- package/dist/src/components/OverviewPage/Overview.js.map +1 -1
- package/dist/src/components/Repository/CreateRepository/CreateRepository.js +2 -2
- package/dist/src/components/Repository/CreateRepository/CreateRepository.js.map +1 -1
- package/dist/src/components/Repository/RepositoryDetails/DeleteRepositoryModal.js +1 -1
- package/dist/src/components/Repository/RepositoryDetails/DeleteRepositoryModal.js.map +1 -1
- package/dist/src/components/Repository/RepositoryList.d.ts.map +1 -1
- package/dist/src/components/Repository/RepositoryList.js +1 -1
- package/dist/src/components/Repository/RepositoryList.js.map +1 -1
- package/dist/src/components/ResourceSync/RepositoryResourceSyncList.d.ts.map +1 -1
- package/dist/src/components/ResourceSync/RepositoryResourceSyncList.js +2 -2
- package/dist/src/components/ResourceSync/RepositoryResourceSyncList.js.map +1 -1
- package/dist/src/components/Table/Table.d.ts +12 -2
- package/dist/src/components/Table/Table.d.ts.map +1 -1
- package/dist/src/components/Table/Table.js +3 -3
- package/dist/src/components/Table/Table.js.map +1 -1
- package/dist/src/components/charts/DonutChart.css +5 -0
- package/dist/src/components/charts/DonutChart.js +1 -1
- package/dist/src/components/charts/DonutChart.js.map +1 -1
- package/dist/src/components/common/LeaveFormConfirmation.js +1 -1
- package/dist/src/components/common/LeaveFormConfirmation.js.map +1 -1
- package/dist/src/components/modals/massModals/MassDeleteRepositoryModal/MassDeleteRepositoryModal.d.ts.map +1 -1
- package/dist/src/components/modals/massModals/MassDeleteRepositoryModal/MassDeleteRepositoryModal.js +2 -2
- package/dist/src/components/modals/massModals/MassDeleteRepositoryModal/MassDeleteRepositoryModal.js.map +1 -1
- package/dist/src/hooks/useApiTableSort.d.ts +8 -0
- package/dist/src/hooks/useApiTableSort.d.ts.map +1 -0
- package/dist/src/hooks/useApiTableSort.js +44 -0
- package/dist/src/hooks/useApiTableSort.js.map +1 -0
- package/dist/src/hooks/useAppContext.d.ts +4 -4
- package/dist/src/hooks/useAppContext.d.ts.map +1 -1
- package/dist/src/hooks/useNavigate.d.ts +3 -3
- package/dist/src/hooks/useNavigate.d.ts.map +1 -1
- package/dist/src/hooks/useNavigate.js +3 -3
- package/dist/src/hooks/useNavigate.js.map +1 -1
- package/dist/src/hooks/usePendingEnrollmentRequestsCount.d.ts +2 -0
- package/dist/src/hooks/usePendingEnrollmentRequestsCount.d.ts.map +1 -0
- package/dist/src/hooks/usePendingEnrollmentRequestsCount.js +13 -0
- package/dist/src/hooks/usePendingEnrollmentRequestsCount.js.map +1 -0
- package/dist/src/utils/query.d.ts +6 -0
- package/dist/src/utils/query.d.ts.map +1 -0
- package/dist/src/utils/query.js +32 -0
- package/dist/src/utils/query.js.map +1 -0
- package/dist/src/utils/sort/generic.d.ts +1 -4
- package/dist/src/utils/sort/generic.d.ts.map +1 -1
- package/dist/src/utils/sort/generic.js +1 -28
- package/dist/src/utils/sort/generic.js.map +1 -1
- package/dist/src/utils/status/devices.d.ts +2 -1
- package/dist/src/utils/status/devices.d.ts.map +1 -1
- package/dist/src/utils/status/devices.js +1 -0
- package/dist/src/utils/status/devices.js.map +1 -1
- package/package.json +6 -6
- package/src/components/Device/DeviceDetails/DeviceDetailsPage.tsx +2 -2
- package/src/components/Device/DevicesPage/DeviceTableToolbar.tsx +13 -13
- package/src/components/Device/DevicesPage/DeviceToolbarFilters.tsx +35 -8
- package/src/components/Device/DevicesPage/DevicesPage.tsx +41 -27
- package/src/components/Device/DevicesPage/EnrollmentRequestList.tsx +91 -116
- package/src/components/Device/DevicesPage/useDeviceBackendFilters.ts +14 -3
- package/src/components/Device/DevicesPage/useDevices.ts +43 -32
- package/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.css +10 -0
- package/src/components/EnrollmentRequest/PendingEnrollmentRequestsBadge.tsx +27 -0
- package/src/components/Fleet/FleetDetails/FleetDevices.tsx +12 -18
- package/src/components/Fleet/FleetsPage.tsx +39 -28
- package/src/components/Fleet/useFleets.ts +86 -0
- package/src/components/OverviewPage/Cards/Status/StatusCard.tsx +4 -3
- package/src/components/OverviewPage/Cards/ToDo/ToDoCard.tsx +6 -10
- package/src/components/OverviewPage/Overview.tsx +1 -1
- package/src/components/Repository/CreateRepository/CreateRepository.tsx +2 -2
- package/src/components/Repository/RepositoryDetails/DeleteRepositoryModal.tsx +1 -1
- package/src/components/Repository/RepositoryList.tsx +1 -0
- package/src/components/ResourceSync/RepositoryResourceSyncList.tsx +2 -1
- package/src/components/Table/Table.tsx +19 -5
- package/src/components/charts/DonutChart.css +5 -0
- package/src/components/charts/DonutChart.tsx +1 -1
- package/src/components/modals/massModals/MassDeleteRepositoryModal/MassDeleteRepositoryModal.tsx +4 -2
- package/src/hooks/useApiTableSort.ts +49 -0
- package/src/hooks/useNavigate.tsx +3 -3
- package/src/hooks/usePendingEnrollmentRequestsCount.ts +12 -0
- package/src/utils/query.ts +29 -0
- package/src/utils/sort/generic.ts +1 -30
- package/src/utils/status/devices.ts +1 -0
- package/dist/src/components/Device/DevicesPage/useDeviceFilters.d.ts +0 -8
- package/dist/src/components/Device/DevicesPage/useDeviceFilters.d.ts.map +0 -1
- package/dist/src/components/Device/DevicesPage/useDeviceFilters.js +0 -16
- package/dist/src/components/Device/DevicesPage/useDeviceFilters.js.map +0 -1
- package/dist/src/utils/sort/device.d.ts +0 -4
- package/dist/src/utils/sort/device.d.ts.map +0 -1
- package/dist/src/utils/sort/device.js +0 -49
- package/dist/src/utils/sort/device.js.map +0 -1
- package/dist/src/utils/sort/fleet.d.ts +0 -4
- package/dist/src/utils/sort/fleet.d.ts.map +0 -1
- package/dist/src/utils/sort/fleet.js +0 -18
- package/dist/src/utils/sort/fleet.js.map +0 -1
- package/src/components/Device/DevicesPage/useDeviceFilters.ts +0 -15
- package/src/utils/sort/device.ts +0 -60
- package/src/utils/sort/fleet.ts +0 -16
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
PageSectionVariants,
|
|
9
9
|
ToolbarItem,
|
|
10
10
|
} from '@patternfly/react-core';
|
|
11
|
-
import { Tbody } from '@patternfly/react-table';
|
|
11
|
+
import { Tbody, ThProps } from '@patternfly/react-table';
|
|
12
12
|
import { MicrochipIcon } from '@patternfly/react-icons/dist/js/icons/microchip-icon';
|
|
13
13
|
import { Trans } from 'react-i18next';
|
|
14
14
|
import { TFunction } from 'i18next';
|
|
@@ -20,16 +20,12 @@ import ListPage from '../../ListPage/ListPage';
|
|
|
20
20
|
import ListPageBody from '../../ListPage/ListPageBody';
|
|
21
21
|
import { useDeleteListAction } from '../../ListPage/ListPageActions';
|
|
22
22
|
import AddDeviceModal from '../AddDeviceModal/AddDeviceModal';
|
|
23
|
-
import
|
|
24
|
-
import { sortDeviceStatus, sortDevicesByFleet } from '../../../utils/sort/device';
|
|
25
|
-
import Table, { TableColumn } from '../../Table/Table';
|
|
23
|
+
import Table, { ApiSortTableColumn } from '../../Table/Table';
|
|
26
24
|
import DeviceTableToolbar from './DeviceTableToolbar';
|
|
27
|
-
import { useDeviceFilters } from './useDeviceFilters';
|
|
28
25
|
import DeviceTableRow from './DeviceTableRow';
|
|
29
26
|
import { FlightCtlLabel } from '../../../types/extraTypes';
|
|
30
27
|
import MassDeleteDeviceModal from '../../modals/massModals/MassDeleteDeviceModal/MassDeleteDeviceModal';
|
|
31
28
|
import ResourceListEmptyState from '../../common/ResourceListEmptyState';
|
|
32
|
-
import { useTableSort } from '../../../hooks/useTableSort';
|
|
33
29
|
import { useTableSelect } from '../../../hooks/useTableSelect';
|
|
34
30
|
import { useTranslation } from '../../../hooks/useTranslation';
|
|
35
31
|
import { Link, ROUTE } from '../../../hooks/useNavigate';
|
|
@@ -40,9 +36,10 @@ import {
|
|
|
40
36
|
getDeviceStatusHelperText,
|
|
41
37
|
getUpdateStatusHelperText,
|
|
42
38
|
} from '../../Status/utils';
|
|
39
|
+
import EnrollmentRequestList from './EnrollmentRequestList';
|
|
43
40
|
import { FilterStatusMap } from './types';
|
|
44
41
|
import { useFetchPeriodically } from '../../../hooks/useFetchPeriodically';
|
|
45
|
-
import
|
|
42
|
+
import { useApiTableSort } from '../../../hooks/useApiTableSort';
|
|
46
43
|
|
|
47
44
|
type DeviceEmptyStateProps = {
|
|
48
45
|
onAddDevice: VoidFunction;
|
|
@@ -67,38 +64,39 @@ const DeviceEmptyState: React.FC<DeviceEmptyStateProps> = ({ onAddDevice }) => {
|
|
|
67
64
|
);
|
|
68
65
|
};
|
|
69
66
|
|
|
70
|
-
const getDeviceColumns = (t: TFunction):
|
|
67
|
+
const getDeviceColumns = (t: TFunction): ApiSortTableColumn[] => [
|
|
71
68
|
{
|
|
72
69
|
name: t('Alias'),
|
|
73
|
-
|
|
70
|
+
// Sorting works on this field even though "alias" is actually a label
|
|
71
|
+
sortableField: 'metadata.alias',
|
|
74
72
|
},
|
|
75
73
|
{
|
|
76
74
|
name: t('Name'),
|
|
77
|
-
|
|
75
|
+
sortableField: 'metadata.name',
|
|
78
76
|
},
|
|
79
77
|
{
|
|
80
78
|
name: t('Fleet'),
|
|
81
|
-
|
|
79
|
+
sortableField: 'metadata.owner',
|
|
82
80
|
},
|
|
83
81
|
{
|
|
84
82
|
name: t('Application status'),
|
|
85
83
|
helperText: getApplicationStatusHelperText(t),
|
|
86
|
-
|
|
84
|
+
sortableField: 'status.applicationsSummary.status',
|
|
87
85
|
},
|
|
88
86
|
{
|
|
89
87
|
name: t('Device status'),
|
|
90
88
|
helperText: getDeviceStatusHelperText(t),
|
|
91
|
-
|
|
89
|
+
sortableField: 'status.summary.status',
|
|
92
90
|
defaultSort: true,
|
|
93
91
|
},
|
|
94
92
|
{
|
|
95
93
|
name: t('Update status'),
|
|
96
94
|
helperText: getUpdateStatusHelperText(t),
|
|
97
|
-
|
|
95
|
+
sortableField: 'status.updated.status',
|
|
98
96
|
},
|
|
99
97
|
{
|
|
100
98
|
name: t('Last seen'),
|
|
101
|
-
|
|
99
|
+
sortableField: 'status.lastSeen',
|
|
102
100
|
},
|
|
103
101
|
];
|
|
104
102
|
|
|
@@ -108,6 +106,8 @@ interface DeviceTableProps {
|
|
|
108
106
|
ownerFleets: string[];
|
|
109
107
|
activeStatuses: FilterStatusMap;
|
|
110
108
|
hasFiltersEnabled: boolean;
|
|
109
|
+
nameOrAlias: string | undefined;
|
|
110
|
+
setNameOrAlias: (text: string) => void;
|
|
111
111
|
setOwnerFleets: (ownerFleets: string[]) => void;
|
|
112
112
|
setActiveStatuses: (activeStatuses: FilterStatusMap) => void;
|
|
113
113
|
allLabels: FlightCtlLabel[];
|
|
@@ -115,11 +115,15 @@ interface DeviceTableProps {
|
|
|
115
115
|
setSelectedLabels: (labels: FlightCtlLabel[]) => void;
|
|
116
116
|
fleets: Fleet[];
|
|
117
117
|
isFilterUpdating: boolean;
|
|
118
|
+
deviceColumns: ApiSortTableColumn[];
|
|
119
|
+
getSortParams: (columnIndex: number) => ThProps['sort'];
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
export const DeviceTable = ({
|
|
121
123
|
devices,
|
|
122
124
|
refetch,
|
|
125
|
+
nameOrAlias,
|
|
126
|
+
setNameOrAlias,
|
|
123
127
|
ownerFleets,
|
|
124
128
|
setOwnerFleets,
|
|
125
129
|
activeStatuses,
|
|
@@ -130,17 +134,14 @@ export const DeviceTable = ({
|
|
|
130
134
|
hasFiltersEnabled,
|
|
131
135
|
fleets,
|
|
132
136
|
isFilterUpdating,
|
|
137
|
+
deviceColumns,
|
|
138
|
+
getSortParams,
|
|
133
139
|
}: DeviceTableProps) => {
|
|
134
140
|
const { t } = useTranslation();
|
|
135
141
|
const [addDeviceModal, setAddDeviceModal] = React.useState(false);
|
|
136
142
|
const [isMassDeleteModalOpen, setIsMassDeleteModalOpen] = React.useState(false);
|
|
137
143
|
const { remove } = useFetch();
|
|
138
144
|
|
|
139
|
-
const deviceColumns = React.useMemo(() => getDeviceColumns(t), [t]);
|
|
140
|
-
|
|
141
|
-
const { filteredData, hasFiltersEnabled: hasUIFiltersEnabled, ...rest } = useDeviceFilters(devices);
|
|
142
|
-
const { getSortParams, sortedData } = useTableSort(filteredData, deviceColumns);
|
|
143
|
-
|
|
144
145
|
const { onRowSelect, hasSelectedRows, isAllSelected, isRowSelected, setAllSelected } = useTableSelect();
|
|
145
146
|
|
|
146
147
|
const { deleteAction: deleteDeviceAction, deleteModal: deleteDeviceModal } = useDeleteListAction({
|
|
@@ -154,7 +155,8 @@ export const DeviceTable = ({
|
|
|
154
155
|
return (
|
|
155
156
|
<>
|
|
156
157
|
<DeviceTableToolbar
|
|
157
|
-
{
|
|
158
|
+
nameOrAlias={nameOrAlias}
|
|
159
|
+
setNameOrAlias={setNameOrAlias}
|
|
158
160
|
ownerFleets={ownerFleets}
|
|
159
161
|
setOwnerFleets={setOwnerFleets}
|
|
160
162
|
activeStatuses={activeStatuses}
|
|
@@ -176,15 +178,16 @@ export const DeviceTable = ({
|
|
|
176
178
|
</DeviceTableToolbar>
|
|
177
179
|
<Table
|
|
178
180
|
aria-label={t('Devices table')}
|
|
181
|
+
loading={isFilterUpdating}
|
|
179
182
|
columns={deviceColumns}
|
|
180
|
-
emptyFilters={
|
|
183
|
+
emptyFilters={!hasFiltersEnabled}
|
|
181
184
|
emptyData={devices.length === 0}
|
|
182
185
|
getSortParams={getSortParams}
|
|
183
186
|
isAllSelected={isAllSelected}
|
|
184
187
|
onSelectAll={setAllSelected}
|
|
185
188
|
>
|
|
186
189
|
<Tbody>
|
|
187
|
-
{
|
|
190
|
+
{devices.map((device, index) => (
|
|
188
191
|
<DeviceTableRow
|
|
189
192
|
key={device.metadata.name || ''}
|
|
190
193
|
device={device}
|
|
@@ -196,15 +199,13 @@ export const DeviceTable = ({
|
|
|
196
199
|
))}
|
|
197
200
|
</Tbody>
|
|
198
201
|
</Table>
|
|
199
|
-
{!hasFiltersEnabled &&
|
|
200
|
-
<DeviceEmptyState onAddDevice={() => setAddDeviceModal(true)} />
|
|
201
|
-
)}
|
|
202
|
+
{!hasFiltersEnabled && devices.length === 0 && <DeviceEmptyState onAddDevice={() => setAddDeviceModal(true)} />}
|
|
202
203
|
{deleteDeviceModal}
|
|
203
204
|
{addDeviceModal && <AddDeviceModal onClose={() => setAddDeviceModal(false)} />}
|
|
204
205
|
{isMassDeleteModalOpen && (
|
|
205
206
|
<MassDeleteDeviceModal
|
|
206
207
|
onClose={() => setIsMassDeleteModalOpen(false)}
|
|
207
|
-
resources={
|
|
208
|
+
resources={devices.filter(isRowSelected)}
|
|
208
209
|
onDeleteSuccess={() => {
|
|
209
210
|
setIsMassDeleteModalOpen(false);
|
|
210
211
|
refetch();
|
|
@@ -217,7 +218,11 @@ export const DeviceTable = ({
|
|
|
217
218
|
|
|
218
219
|
const DevicesPage = () => {
|
|
219
220
|
const { t } = useTranslation();
|
|
221
|
+
const deviceColumns = React.useMemo(() => getDeviceColumns(t), [t]);
|
|
222
|
+
|
|
220
223
|
const {
|
|
224
|
+
nameOrAlias,
|
|
225
|
+
setNameOrAlias,
|
|
221
226
|
ownerFleets,
|
|
222
227
|
activeStatuses,
|
|
223
228
|
hasFiltersEnabled,
|
|
@@ -226,10 +231,15 @@ const DevicesPage = () => {
|
|
|
226
231
|
selectedLabels,
|
|
227
232
|
setSelectedLabels,
|
|
228
233
|
} = useDeviceBackendFilters();
|
|
234
|
+
const { getSortParams, sortField, direction } = useApiTableSort(deviceColumns);
|
|
235
|
+
|
|
229
236
|
const [data, loading, error, updating, refetch, allLabels] = useDevices({
|
|
237
|
+
nameOrAlias,
|
|
230
238
|
ownerFleets,
|
|
231
239
|
activeStatuses,
|
|
232
240
|
labels: selectedLabels,
|
|
241
|
+
sortField,
|
|
242
|
+
direction,
|
|
233
243
|
});
|
|
234
244
|
|
|
235
245
|
const [fleetsList, flLoading, flError] = useFetchPeriodically<FleetList>({
|
|
@@ -246,6 +256,8 @@ const DevicesPage = () => {
|
|
|
246
256
|
devices={data}
|
|
247
257
|
allLabels={allLabels}
|
|
248
258
|
refetch={refetch}
|
|
259
|
+
nameOrAlias={nameOrAlias}
|
|
260
|
+
setNameOrAlias={setNameOrAlias}
|
|
249
261
|
hasFiltersEnabled={hasFiltersEnabled || updating}
|
|
250
262
|
ownerFleets={ownerFleets}
|
|
251
263
|
activeStatuses={activeStatuses}
|
|
@@ -255,6 +267,8 @@ const DevicesPage = () => {
|
|
|
255
267
|
setSelectedLabels={setSelectedLabels}
|
|
256
268
|
fleets={fleetsList?.items || []}
|
|
257
269
|
isFilterUpdating={updating}
|
|
270
|
+
deviceColumns={deviceColumns}
|
|
271
|
+
getSortParams={getSortParams}
|
|
258
272
|
/>
|
|
259
273
|
</ListPageBody>
|
|
260
274
|
</ListPage>
|
|
@@ -5,7 +5,7 @@ import { SelectList, SelectOption, Spinner, ToolbarItem } from '@patternfly/reac
|
|
|
5
5
|
|
|
6
6
|
import { EnrollmentRequest, EnrollmentRequestList as EnrollmentRequestListType } from '@flightctl/types';
|
|
7
7
|
|
|
8
|
-
import Table, {
|
|
8
|
+
import Table, { ApiSortTableColumn } from '../../Table/Table';
|
|
9
9
|
import TableActions from '../../Table/TableActions';
|
|
10
10
|
import ListPage from '../../ListPage/ListPage';
|
|
11
11
|
import ListPageBody from '../../ListPage/ListPageBody';
|
|
@@ -14,9 +14,8 @@ import { useFetch } from '../../../hooks/useFetch';
|
|
|
14
14
|
import { useTranslation } from '../../../hooks/useTranslation';
|
|
15
15
|
import { useFetchPeriodically } from '../../../hooks/useFetchPeriodically';
|
|
16
16
|
import { useTableSelect } from '../../../hooks/useTableSelect';
|
|
17
|
-
import {
|
|
17
|
+
import { useApiTableSort } from '../../../hooks/useApiTableSort';
|
|
18
18
|
import { useTableTextSearch } from '../../../hooks/useTableTextSearch';
|
|
19
|
-
import { sortByCreationDate, sortByName } from '../../../utils/sort/generic';
|
|
20
19
|
|
|
21
20
|
import ApproveDeviceModal from '../../modals/ApproveDeviceModal/ApproveDeviceModal';
|
|
22
21
|
import MassDeleteDeviceModal from '../../modals/massModals/MassDeleteDeviceModal/MassDeleteDeviceModal';
|
|
@@ -24,41 +23,41 @@ import MassApproveDeviceModal from '../../modals/massModals/MassApproveDeviceMod
|
|
|
24
23
|
import EnrollmentRequestTableRow from '../../EnrollmentRequest/EnrollmentRequestTableRow';
|
|
25
24
|
import EnrollmentRequestTableToolbar from './EnrollmentRequestTableToolbar';
|
|
26
25
|
|
|
27
|
-
const getEnrollmentColumns = (t: TFunction):
|
|
26
|
+
const getEnrollmentColumns = (t: TFunction): ApiSortTableColumn[] => [
|
|
28
27
|
{
|
|
29
28
|
name: t('Name'),
|
|
30
|
-
|
|
29
|
+
sortableField: 'metadata.name',
|
|
30
|
+
defaultSort: true,
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
name: t('Created'),
|
|
34
|
-
|
|
34
|
+
sortableField: 'metadata.creationTimestamp',
|
|
35
35
|
},
|
|
36
36
|
];
|
|
37
37
|
|
|
38
|
-
interface EnrollmentRequestTableProps {
|
|
39
|
-
pendingEnrollments: Array<EnrollmentRequest>;
|
|
40
|
-
approveRefetch: VoidFunction;
|
|
41
|
-
deleteRefetch: VoidFunction;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
38
|
const getSearchText = (er: EnrollmentRequest) => [er.metadata.name];
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
pendingEnrollments,
|
|
48
|
-
approveRefetch,
|
|
49
|
-
deleteRefetch,
|
|
50
|
-
}: EnrollmentRequestTableProps) => {
|
|
40
|
+
const EnrollmentRequestList = ({ refetchDevices }: { refetchDevices: VoidFunction }) => {
|
|
51
41
|
const { t } = useTranslation();
|
|
52
42
|
const { remove } = useFetch();
|
|
43
|
+
const enrollmentColumns = React.useMemo(() => getEnrollmentColumns(t), [t]);
|
|
44
|
+
const { getSortParams, sortField, direction } = useApiTableSort(enrollmentColumns);
|
|
45
|
+
|
|
46
|
+
const [erList, isLoading, error, refetch] = useFetchPeriodically<EnrollmentRequestListType>({
|
|
47
|
+
endpoint: `enrollmentrequests?fieldSelector=!status.approval.approved${sortField ? `&sortBy=${sortField}&sortOrder=${direction}` : ''}`,
|
|
48
|
+
});
|
|
49
|
+
const pendingEnrollments = erList?.items || [];
|
|
50
|
+
|
|
51
|
+
const refetchWithDevices = () => {
|
|
52
|
+
refetch();
|
|
53
|
+
refetchDevices();
|
|
54
|
+
};
|
|
53
55
|
|
|
54
56
|
const [approvingErId, setApprovingErId] = React.useState<string>();
|
|
55
57
|
const [isMassDeleteModalOpen, setIsMassDeleteModalOpen] = React.useState(false);
|
|
56
58
|
const [isMassApproveModalOpen, setIsMassApproveModalOpen] = React.useState(false);
|
|
57
59
|
|
|
58
|
-
const enrollmentColumns = React.useMemo(() => getEnrollmentColumns(t), [t]);
|
|
59
|
-
|
|
60
60
|
const { search, setSearch, filteredData } = useTableTextSearch(pendingEnrollments, getSearchText);
|
|
61
|
-
const { getSortParams, sortedData } = useTableSort(filteredData, enrollmentColumns);
|
|
62
61
|
|
|
63
62
|
const { onRowSelect, hasSelectedRows, isAllSelected, isRowSelected, setAllSelected } = useTableSelect();
|
|
64
63
|
|
|
@@ -66,115 +65,91 @@ export const EnrollmentRequestTable = ({
|
|
|
66
65
|
resourceType: 'EnrollmentRequest',
|
|
67
66
|
onDelete: async (enrollmentId: string) => {
|
|
68
67
|
await remove(`enrollmentrequests/${enrollmentId}`);
|
|
69
|
-
|
|
68
|
+
refetch();
|
|
70
69
|
},
|
|
71
70
|
});
|
|
72
71
|
|
|
73
|
-
const currentEnrollmentRequest = pendingEnrollments.find((er) => er.metadata.name === approvingErId);
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<>
|
|
77
|
-
<EnrollmentRequestTableToolbar search={search} setSearch={setSearch} enrollments={pendingEnrollments}>
|
|
78
|
-
<ToolbarItem>
|
|
79
|
-
<TableActions isDisabled={!hasSelectedRows}>
|
|
80
|
-
<SelectList>
|
|
81
|
-
<SelectOption onClick={() => setIsMassApproveModalOpen(true)}>{t('Approve')}</SelectOption>
|
|
82
|
-
<SelectOption onClick={() => setIsMassDeleteModalOpen(true)}>{t('Delete')}</SelectOption>
|
|
83
|
-
</SelectList>
|
|
84
|
-
</TableActions>
|
|
85
|
-
</ToolbarItem>
|
|
86
|
-
</EnrollmentRequestTableToolbar>
|
|
87
|
-
<Table
|
|
88
|
-
aria-label={t('Table for devices pending approval')}
|
|
89
|
-
columns={enrollmentColumns}
|
|
90
|
-
emptyFilters={filteredData.length === 0}
|
|
91
|
-
emptyData={false}
|
|
92
|
-
getSortParams={getSortParams}
|
|
93
|
-
isAllSelected={isAllSelected}
|
|
94
|
-
onSelectAll={setAllSelected}
|
|
95
|
-
>
|
|
96
|
-
<Tbody>
|
|
97
|
-
{sortedData.map((er, index) => (
|
|
98
|
-
<EnrollmentRequestTableRow
|
|
99
|
-
key={er.metadata.name || ''}
|
|
100
|
-
er={er}
|
|
101
|
-
deleteAction={deleteAction}
|
|
102
|
-
onRowSelect={onRowSelect}
|
|
103
|
-
isRowSelected={isRowSelected}
|
|
104
|
-
rowIndex={index}
|
|
105
|
-
onApprove={() => {
|
|
106
|
-
setApprovingErId(er.metadata.name as string);
|
|
107
|
-
}}
|
|
108
|
-
/>
|
|
109
|
-
))}
|
|
110
|
-
</Tbody>
|
|
111
|
-
</Table>
|
|
112
|
-
|
|
113
|
-
{deleteModal}
|
|
114
|
-
{currentEnrollmentRequest && (
|
|
115
|
-
<ApproveDeviceModal
|
|
116
|
-
enrollmentRequest={currentEnrollmentRequest}
|
|
117
|
-
onClose={(updateList) => {
|
|
118
|
-
setApprovingErId(undefined);
|
|
119
|
-
updateList && approveRefetch();
|
|
120
|
-
}}
|
|
121
|
-
/>
|
|
122
|
-
)}
|
|
123
|
-
{isMassDeleteModalOpen && (
|
|
124
|
-
<MassDeleteDeviceModal
|
|
125
|
-
onClose={() => setIsMassDeleteModalOpen(false)}
|
|
126
|
-
resources={filteredData.filter(isRowSelected)}
|
|
127
|
-
onDeleteSuccess={() => {
|
|
128
|
-
setIsMassDeleteModalOpen(false);
|
|
129
|
-
deleteRefetch();
|
|
130
|
-
}}
|
|
131
|
-
/>
|
|
132
|
-
)}
|
|
133
|
-
{isMassApproveModalOpen && (
|
|
134
|
-
<MassApproveDeviceModal
|
|
135
|
-
onClose={() => setIsMassApproveModalOpen(false)}
|
|
136
|
-
pendingEnrollments={filteredData.filter(isRowSelected)}
|
|
137
|
-
onApproveSuccess={() => {
|
|
138
|
-
setAllSelected(false);
|
|
139
|
-
setIsMassApproveModalOpen(false);
|
|
140
|
-
approveRefetch();
|
|
141
|
-
}}
|
|
142
|
-
/>
|
|
143
|
-
)}
|
|
144
|
-
</>
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const EnrollmentRequestList = ({ refetchDevices }: { refetchDevices: VoidFunction }) => {
|
|
149
|
-
const { t } = useTranslation();
|
|
150
|
-
const [erList, isLoading, error, refetch] = useFetchPeriodically<EnrollmentRequestListType>({
|
|
151
|
-
endpoint: 'enrollmentrequests',
|
|
152
|
-
});
|
|
153
|
-
|
|
154
72
|
if (isLoading) {
|
|
155
73
|
return <Spinner size="md" />;
|
|
156
74
|
}
|
|
157
75
|
|
|
158
|
-
// The content only appears if there are pending enrollment requests
|
|
159
|
-
// TODO move the filter as part of the query once it's available via the API
|
|
160
|
-
const pendingEnrollments = (erList?.items || []).filter((er) => er.status?.approval?.approved !== true);
|
|
161
|
-
|
|
162
76
|
if (pendingEnrollments.length === 0) {
|
|
163
77
|
return null;
|
|
164
78
|
}
|
|
165
79
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
refetchDevices();
|
|
169
|
-
};
|
|
80
|
+
const currentEnrollmentRequest = pendingEnrollments.find((er) => er.metadata.name === approvingErId);
|
|
81
|
+
|
|
170
82
|
return (
|
|
171
83
|
<ListPage title={t('Devices pending approval')} headingLevel="h2">
|
|
172
|
-
<ListPageBody error={error} loading={
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
84
|
+
<ListPageBody error={error} loading={isLoading}>
|
|
85
|
+
<EnrollmentRequestTableToolbar search={search} setSearch={setSearch} enrollments={pendingEnrollments}>
|
|
86
|
+
<ToolbarItem>
|
|
87
|
+
<TableActions isDisabled={!hasSelectedRows}>
|
|
88
|
+
<SelectList>
|
|
89
|
+
<SelectOption onClick={() => setIsMassApproveModalOpen(true)}>{t('Approve')}</SelectOption>
|
|
90
|
+
<SelectOption onClick={() => setIsMassDeleteModalOpen(true)}>{t('Delete')}</SelectOption>
|
|
91
|
+
</SelectList>
|
|
92
|
+
</TableActions>
|
|
93
|
+
</ToolbarItem>
|
|
94
|
+
</EnrollmentRequestTableToolbar>
|
|
95
|
+
<Table
|
|
96
|
+
aria-label={t('Table for devices pending approval')}
|
|
97
|
+
loading={isLoading}
|
|
98
|
+
columns={enrollmentColumns}
|
|
99
|
+
emptyFilters={filteredData.length === 0}
|
|
100
|
+
emptyData={false}
|
|
101
|
+
getSortParams={getSortParams}
|
|
102
|
+
isAllSelected={isAllSelected}
|
|
103
|
+
onSelectAll={setAllSelected}
|
|
104
|
+
>
|
|
105
|
+
<Tbody>
|
|
106
|
+
{pendingEnrollments.map((er, index) => (
|
|
107
|
+
<EnrollmentRequestTableRow
|
|
108
|
+
key={er.metadata.name || ''}
|
|
109
|
+
er={er}
|
|
110
|
+
deleteAction={deleteAction}
|
|
111
|
+
onRowSelect={onRowSelect}
|
|
112
|
+
isRowSelected={isRowSelected}
|
|
113
|
+
rowIndex={index}
|
|
114
|
+
onApprove={() => {
|
|
115
|
+
setApprovingErId(er.metadata.name as string);
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
118
|
+
))}
|
|
119
|
+
</Tbody>
|
|
120
|
+
</Table>
|
|
121
|
+
|
|
122
|
+
{deleteModal}
|
|
123
|
+
{currentEnrollmentRequest && (
|
|
124
|
+
<ApproveDeviceModal
|
|
125
|
+
enrollmentRequest={currentEnrollmentRequest}
|
|
126
|
+
onClose={(updateList) => {
|
|
127
|
+
setApprovingErId(undefined);
|
|
128
|
+
updateList && refetchWithDevices();
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
132
|
+
{isMassDeleteModalOpen && (
|
|
133
|
+
<MassDeleteDeviceModal
|
|
134
|
+
onClose={() => setIsMassDeleteModalOpen(false)}
|
|
135
|
+
resources={filteredData.filter(isRowSelected)}
|
|
136
|
+
onDeleteSuccess={() => {
|
|
137
|
+
setIsMassDeleteModalOpen(false);
|
|
138
|
+
refetch();
|
|
139
|
+
}}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
{isMassApproveModalOpen && (
|
|
143
|
+
<MassApproveDeviceModal
|
|
144
|
+
onClose={() => setIsMassApproveModalOpen(false)}
|
|
145
|
+
pendingEnrollments={filteredData.filter(isRowSelected)}
|
|
146
|
+
onApproveSuccess={() => {
|
|
147
|
+
setAllSelected(false);
|
|
148
|
+
setIsMassApproveModalOpen(false);
|
|
149
|
+
refetchWithDevices();
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
178
153
|
</ListPageBody>
|
|
179
154
|
</ListPage>
|
|
180
155
|
);
|
|
@@ -3,7 +3,6 @@ import { ApplicationsSummaryStatusType, DeviceSummaryStatusType, DeviceUpdatedSt
|
|
|
3
3
|
|
|
4
4
|
import { FilterSearchParams } from '../../../utils/status/devices';
|
|
5
5
|
import { useAppContext } from '../../../hooks/useAppContext';
|
|
6
|
-
import { EnrollmentRequestStatus } from '../../../utils/status/enrollmentRequest';
|
|
7
6
|
import { FilterStatusMap } from './types';
|
|
8
7
|
import { FlightCtlLabel } from '../../../types/extraTypes';
|
|
9
8
|
import { labelToString } from '../../../utils/labels';
|
|
@@ -11,7 +10,6 @@ import { labelToString } from '../../../utils/labels';
|
|
|
11
10
|
const validAppStatuses = Object.values(ApplicationsSummaryStatusType) as string[];
|
|
12
11
|
const validUpdatedStatuses = Object.values(DeviceUpdatedStatusType) as string[];
|
|
13
12
|
const validDeviceStatuses = Object.values(DeviceSummaryStatusType) as string[];
|
|
14
|
-
validDeviceStatuses.push(EnrollmentRequestStatus.Pending);
|
|
15
13
|
|
|
16
14
|
const getNewParams = (currentParams: URLSearchParams, newValues: { [key: string]: string[] }) => {
|
|
17
15
|
let newParams = [...currentParams.entries()];
|
|
@@ -30,6 +28,7 @@ export const useDeviceBackendFilters = () => {
|
|
|
30
28
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
31
29
|
const paramsRef = React.useRef(searchParams);
|
|
32
30
|
const ownerFleets = searchParams.getAll(FilterSearchParams.Fleet) || undefined;
|
|
31
|
+
const nameOrAlias = searchParams.get(FilterSearchParams.NameOrAlias) || undefined;
|
|
33
32
|
|
|
34
33
|
const updateSearchParams = React.useCallback(
|
|
35
34
|
(params: [string, string][]) => {
|
|
@@ -104,10 +103,22 @@ export const useDeviceBackendFilters = () => {
|
|
|
104
103
|
[updateSearchParams],
|
|
105
104
|
);
|
|
106
105
|
|
|
106
|
+
const setNameOrAlias = React.useCallback(
|
|
107
|
+
(nameOrAlias: string) => {
|
|
108
|
+
updateSearchParams(getNewParams(paramsRef.current, { [FilterSearchParams.NameOrAlias]: [nameOrAlias] }));
|
|
109
|
+
},
|
|
110
|
+
[updateSearchParams],
|
|
111
|
+
);
|
|
112
|
+
|
|
107
113
|
const hasFiltersEnabled =
|
|
108
|
-
!!
|
|
114
|
+
!!nameOrAlias ||
|
|
115
|
+
!!selectedLabels.length ||
|
|
116
|
+
!!ownerFleets.length ||
|
|
117
|
+
Object.values(activeStatuses).some((s) => !!s.length);
|
|
109
118
|
|
|
110
119
|
return {
|
|
120
|
+
nameOrAlias,
|
|
121
|
+
setNameOrAlias,
|
|
111
122
|
activeStatuses,
|
|
112
123
|
setActiveStatuses,
|
|
113
124
|
ownerFleets,
|
|
@@ -1,53 +1,65 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import { useDebounce } from 'use-debounce';
|
|
3
3
|
|
|
4
|
-
import { Device, DeviceList, DevicesSummary } from '@flightctl/types';
|
|
4
|
+
import { Device, DeviceList, DevicesSummary, SortOrder } from '@flightctl/types';
|
|
5
5
|
import { FilterSearchParams } from '../../../utils/status/devices';
|
|
6
|
+
import * as queryUtils from '../../../utils/query';
|
|
7
|
+
import { fromAPILabel } from '../../../utils/labels';
|
|
6
8
|
import { useFetchPeriodically } from '../../../hooks/useFetchPeriodically';
|
|
7
9
|
import { FlightCtlLabel } from '../../../types/extraTypes';
|
|
8
10
|
import { FilterStatusMap } from './types';
|
|
9
11
|
|
|
10
|
-
import { fromAPILabel } from '../../../utils/labels';
|
|
11
|
-
|
|
12
|
-
const setLabelParams = (params: URLSearchParams, labels?: FlightCtlLabel[]) => {
|
|
13
|
-
if (labels?.length) {
|
|
14
|
-
const labelSelector = labels.reduce((acc, curr) => {
|
|
15
|
-
if (!acc) {
|
|
16
|
-
acc = `${curr.key}=${curr.value || ''}`;
|
|
17
|
-
} else {
|
|
18
|
-
acc += `,${curr.key}=${curr.value || ''}`;
|
|
19
|
-
}
|
|
20
|
-
return acc;
|
|
21
|
-
}, '');
|
|
22
|
-
params.append('labelSelector', labelSelector);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
12
|
type DevicesEndpointArgs = {
|
|
13
|
+
nameOrAlias?: string;
|
|
27
14
|
ownerFleets?: string[];
|
|
28
15
|
activeStatuses?: FilterStatusMap;
|
|
29
16
|
labels?: FlightCtlLabel[];
|
|
17
|
+
sortField?: string;
|
|
18
|
+
direction?: string;
|
|
30
19
|
summaryOnly?: boolean;
|
|
31
20
|
};
|
|
32
21
|
|
|
33
|
-
const getDevicesEndpoint = ({
|
|
22
|
+
const getDevicesEndpoint = ({
|
|
23
|
+
nameOrAlias,
|
|
24
|
+
ownerFleets,
|
|
25
|
+
activeStatuses,
|
|
26
|
+
labels,
|
|
27
|
+
sortField,
|
|
28
|
+
direction,
|
|
29
|
+
summaryOnly,
|
|
30
|
+
}: DevicesEndpointArgs) => {
|
|
34
31
|
const filterByAppStatus = activeStatuses?.[FilterSearchParams.AppStatus];
|
|
35
32
|
const filterByDevStatus = activeStatuses?.[FilterSearchParams.DeviceStatus];
|
|
36
33
|
const filterByUpdateStatus = activeStatuses?.[FilterSearchParams.UpdatedStatus];
|
|
37
34
|
|
|
38
|
-
const
|
|
35
|
+
const fieldSelectors: string[] = [];
|
|
36
|
+
queryUtils.addQueryConditions(fieldSelectors, 'status.applicationsSummary.status', filterByAppStatus);
|
|
37
|
+
queryUtils.addQueryConditions(fieldSelectors, 'status.summary.status', filterByDevStatus);
|
|
38
|
+
queryUtils.addQueryConditions(fieldSelectors, 'status.updated.status', filterByUpdateStatus);
|
|
39
|
+
|
|
40
|
+
if (nameOrAlias) {
|
|
41
|
+
queryUtils.addTextContainsCondition(fieldSelectors, 'metadata.nameoralias', nameOrAlias);
|
|
42
|
+
}
|
|
39
43
|
if (ownerFleets?.length) {
|
|
40
|
-
|
|
44
|
+
queryUtils.addQueryConditions(
|
|
45
|
+
fieldSelectors,
|
|
46
|
+
'metadata.owner',
|
|
47
|
+
ownerFleets.map((fleet) => `Fleet/${fleet}`),
|
|
48
|
+
);
|
|
41
49
|
}
|
|
42
|
-
filterByAppStatus?.forEach((appSt) => params.append('statusFilter', `applications.summary.status=${appSt}`));
|
|
43
|
-
filterByDevStatus?.forEach((devSt) => params.append('statusFilter', `summary.status=${devSt}`));
|
|
44
|
-
filterByUpdateStatus?.forEach((updSt) => params.append('statusFilter', `updated.status=${updSt}`));
|
|
45
|
-
|
|
46
|
-
setLabelParams(params, labels);
|
|
47
50
|
|
|
51
|
+
const params = new URLSearchParams();
|
|
52
|
+
if (fieldSelectors.length > 0) {
|
|
53
|
+
params.set('fieldSelector', fieldSelectors.join(','));
|
|
54
|
+
}
|
|
55
|
+
queryUtils.setLabelParams(params, labels);
|
|
48
56
|
if (summaryOnly) {
|
|
49
57
|
params.set('summaryOnly', 'true');
|
|
50
58
|
}
|
|
59
|
+
if (sortField) {
|
|
60
|
+
params.set('sortBy', sortField);
|
|
61
|
+
params.set('sortOrder', direction || SortOrder.ASC);
|
|
62
|
+
}
|
|
51
63
|
return params.size ? `devices?${params.toString()}` : 'devices';
|
|
52
64
|
};
|
|
53
65
|
|
|
@@ -72,19 +84,18 @@ export const useDevicesSummary = ({
|
|
|
72
84
|
return [deviceList?.summary, listLoading];
|
|
73
85
|
};
|
|
74
86
|
|
|
75
|
-
export const useDevices = ({
|
|
76
|
-
|
|
77
|
-
activeStatuses,
|
|
78
|
-
labels,
|
|
79
|
-
}: {
|
|
87
|
+
export const useDevices = (args: {
|
|
88
|
+
nameOrAlias?: string;
|
|
80
89
|
ownerFleets?: string[];
|
|
81
90
|
activeStatuses?: FilterStatusMap;
|
|
82
91
|
labels?: FlightCtlLabel[];
|
|
92
|
+
sortField?: string;
|
|
93
|
+
direction?: string;
|
|
83
94
|
}): [Device[], boolean, unknown, boolean, VoidFunction, FlightCtlLabel[]] => {
|
|
84
95
|
const [deviceLabelList] = useFetchPeriodically<DeviceList>({
|
|
85
96
|
endpoint: 'devices',
|
|
86
97
|
});
|
|
87
|
-
const [devicesEndpoint, devicesDebouncing] = useDevicesEndpoint(
|
|
98
|
+
const [devicesEndpoint, devicesDebouncing] = useDevicesEndpoint(args);
|
|
88
99
|
const [devicesList, devicesLoading, devicesError, devicesRefetch, updating] = useFetchPeriodically<DeviceList>({
|
|
89
100
|
endpoint: devicesEndpoint,
|
|
90
101
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
/* The default color is too light */
|
|
3
|
+
.fctl-pendingdevices-badge {
|
|
4
|
+
--pf-v5-c-badge--m-unread--BackgroundColor: var(--pf-v5-global--active-color--100)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* For the dark theme, we need to put it back to the correct value */
|
|
8
|
+
.pf-v5-theme-dark .fctl-pendingdevices-badge {
|
|
9
|
+
--pf-v5-c-badge--m-unread--BackgroundColor: var(--pf-v5-global--active-color--300)
|
|
10
|
+
}
|