@trackunit/filters-asset-filter-definitions 2.24.10 → 2.24.11

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/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
3
3
  import { gql } from '@apollo/client';
4
- import { DefaultCheckboxFilter, FilterEvents, FilterHeader, HierarchicalCheckboxFilter, DefaultMinMaxFilter, DefaultRadioFilter, DefaultDateRangeFilter } from '@trackunit/filters-filter-bar';
4
+ import { DefaultCheckboxFilter, FilterEvents, FilterHeader, useFilterSearch, HierarchicalCheckboxFilter, DefaultMinMaxFilter, DefaultRadioFilter, DefaultDateRangeFilter } from '@trackunit/filters-filter-bar';
5
5
  import { useActiveAssetFilters, useAssetQueryFilters } from '@trackunit/filters-graphql-hook';
6
6
  import { useQuery, useConnectionPageMerger, usePaginationQuery } from '@trackunit/react-graphql-hooks';
7
7
  import { useMemo, useState, useCallback, useEffect } from 'react';
@@ -15,6 +15,7 @@ import { useLocalStorage, useDebounce, IconButton, Icon, Text, Button, usePrevio
15
15
  import { titleCase, lowerCase } from 'string-ts';
16
16
  import { objectValues, stringNaturalCompare, getCountryName, stringCompare, hourIntervals, exhaustiveCheck, enumFromValue } from '@trackunit/shared-utils';
17
17
  import { useMachineTypeTranslations } from '@trackunit/translations-machine-type';
18
+ import { parse } from 'graphql';
18
19
  import { CriticalityIndicator } from '@trackunit/criticality-indicator';
19
20
  import { useDeviceTypeTranslations } from '@trackunit/translations-device';
20
21
  import { twMerge } from 'tailwind-merge';
@@ -267,7 +268,7 @@ const GET_ACCESS_MANAGEMENT_MODE_DESIRED_SUMMARY = gql `
267
268
  }
268
269
  }
269
270
  `;
270
- const FETCH_LIMIT$5 = 1000;
271
+ const FETCH_LIMIT = 1000;
271
272
  /**
272
273
  * Maps an access-management-mode value to its static translation key.
273
274
  *
@@ -304,7 +305,7 @@ const AccessManagementModeFilterView = ({ filterDefinition, filterState, filterB
304
305
  const { data, loading } = useQuery(GET_ACCESS_MANAGEMENT_MODE_DESIRED_SUMMARY, {
305
306
  fetchPolicy: "cache-first",
306
307
  variables: {
307
- limit: FETCH_LIMIT$5,
308
+ limit: FETCH_LIMIT,
308
309
  filters: {
309
310
  ...activeFilters,
310
311
  accessManagementDesiredModes: null, // Omit the filters own values so list shows options correctly
@@ -5159,29 +5160,6 @@ const asSummaryConnectionNode = (node) => {
5159
5160
  * for a facet. `DefaultCheckboxFilter` pins the option carrying this key to the bottom of the list.
5160
5161
  */
5161
5162
  const UNDEFINED_SUMMARY_KEY = "UNDEFINED";
5162
- /**
5163
- * Flattens connection edges into plain summary entries, appending the bucket of assets without
5164
- * a value when one is reported.
5165
- *
5166
- * @param edges the edges of a key/count summary connection
5167
- * @param missing the number of assets without a value, counted by a separate query
5168
- * @param loading whether either query behind the facet is still fetching, which suppresses the
5169
- * entries until the first page arrives. The two queries resolve independently, and
5170
- * `FilterResults` only renders its loading state for an empty list, so without this a facet
5171
- * would briefly show whichever of the two landed first as its only content — the undefined
5172
- * bucket alone, or a set of values that the undefined bucket is about to be appended to.
5173
- * @returns {Array<{ key: string; count: number }>} the summary entries to render as filter options
5174
- */
5175
- const toSummaryEntries = (edges, missing, loading = false) => {
5176
- if (loading && edges.length === 0) {
5177
- return [];
5178
- }
5179
- const entries = edges.map(edge => asSummaryConnectionNode(edge.node));
5180
- if (typeof missing === "number" && missing > 0) {
5181
- entries.push({ key: UNDEFINED_SUMMARY_KEY, count: missing });
5182
- }
5183
- return entries;
5184
- };
5185
5163
  /**
5186
5164
  * Reads a group summary node.
5187
5165
  *
@@ -5203,6 +5181,11 @@ const asOwnerAccountConnectionNode = (node) => {
5203
5181
  return parsed.success ? parsed.data : { count: 0, ownerAccount: null };
5204
5182
  };
5205
5183
 
5184
+ /**
5185
+ * Stands in for the count document of a facet that has none, since the query hook has to run
5186
+ * unconditionally. It is always skipped, so it is never sent.
5187
+ */
5188
+ const NO_MISSING_COUNT_DOCUMENT = parse("query FacetWithoutMissingCount { __typename }");
5206
5189
  /**
5207
5190
  * Counts the assets that have no value for a facet.
5208
5191
  *
@@ -5210,16 +5193,16 @@ const asOwnerAccountConnectionNode = (node) => {
5210
5193
  * the facet search term and outside paging, so it is identical on every page and would only be
5211
5194
  * re-fetched for nothing if it rode along with the paginated query.
5212
5195
  *
5213
- * @param document the generated `…SummaryMissing` query
5196
+ * @param document the generated `…SummaryMissing` query, or undefined for a facet without a missing row
5214
5197
  * @param connectionField name of the connection field on `assetSummary`
5215
5198
  * @param filters the filters scoping the summary, the same ones the paginated query uses
5216
5199
  * @param options optional skip flag and Apollo context
5217
5200
  * @returns {object} the count of assets without a value, plus loading state
5218
5201
  */
5219
5202
  const useFacetMissingCount = (document, connectionField, filters, options = {}) => {
5220
- const { data, loading } = useQuery(document, {
5203
+ const { data, loading } = useQuery(document ?? NO_MISSING_COUNT_DOCUMENT, {
5221
5204
  variables: { filters: filters ?? null },
5222
- skip: options.skip,
5205
+ skip: options.skip || document === undefined,
5223
5206
  context: options.context,
5224
5207
  });
5225
5208
  const missing = useMemo(() => extractAssetSummaryConnection(data, connectionField)?.missing, [data, connectionField]);
@@ -5271,29 +5254,62 @@ const useFleetSummaryConnection = (document, connectionField, queryVariables, op
5271
5254
  }), [connectionData, edges, loading, pagination]);
5272
5255
  };
5273
5256
 
5257
+ /**
5258
+ * Everything `DefaultCheckboxFilter` needs for a facet backed by a paginated `assetSummary` connection:
5259
+ * the shared search box, the paged options with the optional missing row, and the loading state.
5260
+ *
5261
+ * `loading` is only true while there is nothing to show yet, so refreshing a list on screen does not
5262
+ * flash the loading state.
5263
+ *
5264
+ * @param filterState the filter state handed to the filter view
5265
+ * @param config the facet's data source and how its nodes become options
5266
+ * @returns {object} props to spread into `DefaultCheckboxFilter`
5267
+ */
5268
+ const useFacetConnectionOptions = (filterState, config) => {
5269
+ const activeFilters = useActiveAssetFilters(filterState.values);
5270
+ const { debouncedSearch, customSearch } = useFilterSearch();
5271
+ const filters = config.scope(activeFilters);
5272
+ const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(config.document, config.connectionField, { search: debouncedSearch, filters }, { context: config.context });
5273
+ const { missing, loading: loadingMissing } = useFacetMissingCount(config.missing?.document, config.connectionField, filters, { context: config.context });
5274
+ const loading = loadingValues || loadingMissing;
5275
+ // Reading a node validates it, so it is memoized on the pages alone: callers usually pass the
5276
+ // config inline, which reruns the cheap option mapping below on every render.
5277
+ const read = config.node?.read;
5278
+ const customNodes = useMemo(() => (read ? edges.map(edge => read(edge.node)) : []), [edges, read]);
5279
+ const summaryEntries = useMemo(() => (read ? [] : edges.map(edge => asSummaryConnectionNode(edge.node))), [edges, read]);
5280
+ const options = useMemo(() => {
5281
+ // The two queries resolve independently, so until the first page is in, show nothing rather
5282
+ // than whichever of the values or the missing row happened to land first.
5283
+ if (loading && edges.length === 0) {
5284
+ return [];
5285
+ }
5286
+ const missingRow = config.missing && typeof missing === "number" && missing > 0
5287
+ ? { key: UNDEFINED_SUMMARY_KEY, count: missing }
5288
+ : undefined;
5289
+ const facetOptions = config.node === undefined
5290
+ ? (missingRow ? [...summaryEntries, missingRow] : summaryEntries).map(config.toOption)
5291
+ : [
5292
+ ...customNodes.map(config.node.toOption),
5293
+ ...(config.missing && missingRow ? [{ ...missingRow, label: config.missing.label }] : []),
5294
+ ];
5295
+ return config.showCount === false ? facetOptions.map(option => ({ ...option, count: undefined })) : facetOptions;
5296
+ }, [config, customNodes, summaryEntries, missing, loading, edges.length]);
5297
+ return useMemo(() => ({ customSearch, loading: loading && options.length === 0, options, pagination }), [customSearch, loading, options, pagination]);
5298
+ };
5299
+
5274
5300
  /**
5275
5301
  * React component for rendering the brand filter.
5276
5302
  */
5277
5303
  const BrandFilterView = (props) => {
5278
5304
  const { getMachineTypeTranslation } = useMachineTypeTranslations();
5279
- const activeFilters = useActiveAssetFilters(props.filterState.values);
5280
- const [searchText, setSearchText] = useState("");
5281
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
5282
- const filters = { ...activeFilters, brands: null };
5283
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetBrandsSummaryConnectionDocument, "brandsConnection", {
5284
- search: debouncedSearch,
5285
- filters,
5305
+ const facet = useFacetConnectionOptions(props.filterState, {
5306
+ document: GetFleetBrandsSummaryConnectionDocument,
5307
+ connectionField: "brandsConnection",
5308
+ scope: filters => ({ ...filters, brands: null }),
5309
+ missing: { document: GetFleetBrandsSummaryMissingDocument },
5310
+ toOption: entry => ({ ...entry, label: getMachineTypeTranslation(entry.key) }),
5286
5311
  });
5287
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetBrandsSummaryMissingDocument, "brandsConnection", filters);
5288
- const loading = loadingValues || loadingMissing;
5289
- const options = useMemo(() => {
5290
- return toSummaryEntries(edges, missing, loading).map(entry => ({
5291
- key: entry.key,
5292
- count: entry.count,
5293
- label: getMachineTypeTranslation(entry.key),
5294
- }));
5295
- }, [edges, missing, loading, getMachineTypeTranslation]);
5296
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
5312
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
5297
5313
  };
5298
5314
  /**
5299
5315
  * Brand filter definition
@@ -5321,35 +5337,25 @@ const useBrandFilter = () => {
5321
5337
  */
5322
5338
  const Can1ProfileFilter = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
5323
5339
  const [t] = useTranslation();
5324
- const activeFilters = useActiveAssetFilters(filterState.values);
5325
- const [searchText, setSearchText] = useState("");
5326
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
5327
- const filters = { ...activeFilters, can1Profile: null };
5328
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetCan1ProfileSummaryConnectionDocument, "can1ProfileSummaryConnection", {
5329
- search: debouncedSearch,
5330
- filters,
5331
- });
5332
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetCan1ProfileSummaryMissingDocument, "can1ProfileSummaryConnection", filters);
5333
- const loading = loadingValues || loadingMissing;
5334
5340
  const { data: profileNamesData } = useQuery(TelematicsDeviceCan1ProfileNamesDocument, {
5335
5341
  context: { headers: { "TU-PREVIEW": "TELEMATICS_DEVICE_PREVIEW" } },
5336
5342
  fetchPolicy: "cache-first",
5337
5343
  });
5338
5344
  const profileNameByKey = useMemo(() => new Map(profileNamesData?.telematicsDeviceSummary?.can1Profiles?.summary?.map(profile => [profile.key, profile.name]) ??
5339
5345
  []), [profileNamesData?.telematicsDeviceSummary?.can1Profiles?.summary]);
5340
- const options = useMemo(() => {
5341
- return toSummaryEntries(edges, missing, loading).map(entry => {
5342
- if (entry.key === UNDEFINED_SUMMARY_KEY) {
5343
- return { key: entry.key, count: entry.count, label: t(`machine.types.Unknown`) };
5344
- }
5345
- return {
5346
- key: entry.key,
5347
- count: entry.count,
5348
- label: profileNameByKey.get(entry.key) ?? entry.key,
5349
- };
5350
- });
5351
- }, [edges, missing, loading, profileNameByKey, t]);
5352
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
5346
+ const facet = useFacetConnectionOptions(filterState, {
5347
+ document: GetFleetCan1ProfileSummaryConnectionDocument,
5348
+ connectionField: "can1ProfileSummaryConnection",
5349
+ scope: filters => ({ ...filters, can1Profile: null }),
5350
+ missing: { document: GetFleetCan1ProfileSummaryMissingDocument },
5351
+ toOption: entry => ({
5352
+ ...entry,
5353
+ label: entry.key === UNDEFINED_SUMMARY_KEY
5354
+ ? t(`machine.types.Unknown`)
5355
+ : (profileNameByKey.get(entry.key) ?? entry.key),
5356
+ }),
5357
+ });
5358
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
5353
5359
  };
5354
5360
 
5355
5361
  /**
@@ -5375,35 +5381,25 @@ const useCan1ProfileFilter = () => {
5375
5381
  */
5376
5382
  const Can2ProfileFilter = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
5377
5383
  const [t] = useTranslation();
5378
- const activeFilters = useActiveAssetFilters(filterState.values);
5379
- const [searchText, setSearchText] = useState("");
5380
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
5381
- const filters = { ...activeFilters, can2Profile: null };
5382
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetCan2ProfileSummaryConnectionDocument, "can2ProfileSummaryConnection", {
5383
- search: debouncedSearch,
5384
- filters,
5385
- });
5386
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetCan2ProfileSummaryMissingDocument, "can2ProfileSummaryConnection", filters);
5387
- const loading = loadingValues || loadingMissing;
5388
5384
  const { data: profileNamesData } = useQuery(TelematicsDeviceCan2ProfileNamesDocument, {
5389
5385
  context: { headers: { "TU-PREVIEW": "TELEMATICS_DEVICE_PREVIEW" } },
5390
5386
  fetchPolicy: "cache-first",
5391
5387
  });
5392
5388
  const profileNameByKey = useMemo(() => new Map(profileNamesData?.telematicsDeviceSummary?.can2Profiles?.summary?.map(profile => [profile.key, profile.name]) ??
5393
5389
  []), [profileNamesData?.telematicsDeviceSummary?.can2Profiles?.summary]);
5394
- const options = useMemo(() => {
5395
- return toSummaryEntries(edges, missing, loading).map(entry => {
5396
- if (entry.key === UNDEFINED_SUMMARY_KEY) {
5397
- return { key: entry.key, count: entry.count, label: t(`machine.types.Unknown`) };
5398
- }
5399
- return {
5400
- key: entry.key,
5401
- count: entry.count,
5402
- label: profileNameByKey.get(entry.key) ?? entry.key,
5403
- };
5404
- });
5405
- }, [edges, missing, loading, profileNameByKey, t]);
5406
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
5390
+ const facet = useFacetConnectionOptions(filterState, {
5391
+ document: GetFleetCan2ProfileSummaryConnectionDocument,
5392
+ connectionField: "can2ProfileSummaryConnection",
5393
+ scope: filters => ({ ...filters, can2Profile: null }),
5394
+ missing: { document: GetFleetCan2ProfileSummaryMissingDocument },
5395
+ toOption: entry => ({
5396
+ ...entry,
5397
+ label: entry.key === UNDEFINED_SUMMARY_KEY
5398
+ ? t(`machine.types.Unknown`)
5399
+ : (profileNameByKey.get(entry.key) ?? entry.key),
5400
+ }),
5401
+ });
5402
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
5407
5403
  };
5408
5404
 
5409
5405
  /**
@@ -5701,22 +5697,50 @@ const useCriticalityFilter = () => {
5701
5697
  return result;
5702
5698
  };
5703
5699
 
5704
- const FETCH_LIMIT$4 = 1000;
5700
+ /** How many rows a limited facet fetches. A full page means there may be more, so the user is asked to search. */
5701
+ const FACET_FETCH_LIMIT = 1000;
5702
+ /**
5703
+ * Supplies a `DefaultCheckboxFilter` whose options come from one summary query capped at
5704
+ * {@link FACET_FETCH_LIMIT} rows. The search text is sent as typed once debounced.
5705
+ *
5706
+ * @param filterState the filter view's state, used to resolve the active asset filters
5707
+ * @param config which query to run and how to turn its rows into options
5708
+ * @returns {object} props to spread onto `DefaultCheckboxFilter`; `loading` is only true while there are no options yet
5709
+ */
5710
+ const useFacetLimitedOptions = (filterState, config) => {
5711
+ const activeFilters = useActiveAssetFilters(filterState.values);
5712
+ const { debouncedSearch, customSearch } = useFilterSearch();
5713
+ const { data, loading } = useQuery(config.document, {
5714
+ fetchPolicy: "cache-first",
5715
+ variables: { limit: FACET_FETCH_LIMIT, search: debouncedSearch, filters: config.scope(activeFilters) },
5716
+ });
5717
+ const options = useMemo(() => {
5718
+ const items = data ? (config.read(data) ?? []) : [];
5719
+ const facetOptions = items.map(item => config.toOption(item));
5720
+ return config.showCount === false ? facetOptions.map(option => ({ ...option, count: undefined })) : facetOptions;
5721
+ }, [config, data]);
5722
+ return useMemo(() => ({
5723
+ customSearch,
5724
+ loading: loading && options.length === 0,
5725
+ options,
5726
+ showRequestMoreUseSearch: options.length === FACET_FETCH_LIMIT,
5727
+ }), [customSearch, loading, options]);
5728
+ };
5729
+
5705
5730
  /**
5706
5731
  * Custom hook to fetch customer summary data based on active filters and search text.
5707
5732
  *
5708
5733
  * @param filterValues - The current values from the filter bar.
5709
5734
  * @param customerId - The ID of the customer that owns the customers shown in the filter bar.
5710
- * @returns {object} An object containing the fetched data, loading state, and a function to set search text.
5735
+ * @returns {object} The fetched data, `loading` (only true while there are no customers yet) and the `customSearch` for the filter.
5711
5736
  */
5712
5737
  const useCustomerData = (filterValues, customerId) => {
5713
5738
  const activeFilters = useActiveAssetFilters(filterValues);
5714
- const [searchText, setSearchText] = useState("");
5715
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
5739
+ const { debouncedSearch, customSearch } = useFilterSearch();
5716
5740
  const { data, loading } = useQuery(GetCustomerIdSummaryDocument, {
5717
5741
  fetchPolicy: "cache-first",
5718
5742
  variables: {
5719
- limit: FETCH_LIMIT$4,
5743
+ limit: FACET_FETCH_LIMIT,
5720
5744
  search: debouncedSearch,
5721
5745
  filters: {
5722
5746
  ...activeFilters,
@@ -5724,7 +5748,8 @@ const useCustomerData = (filterValues, customerId) => {
5724
5748
  },
5725
5749
  },
5726
5750
  });
5727
- return useMemo(() => ({ data, loading, searchText, setSearchText }), [data, loading, searchText, setSearchText]);
5751
+ const hasCustomers = (data?.assetSummary?.customers?.summary.length ?? 0) > 0;
5752
+ return useMemo(() => ({ data, loading: loading && !hasCustomers, customSearch }), [data, loading, hasCustomers, customSearch]);
5728
5753
  };
5729
5754
 
5730
5755
  /**
@@ -5834,13 +5859,10 @@ const useCustomerHierarchy = (customerSummary) => {
5834
5859
  * @returns {ReactElement} A customer ID filter component for rendering in the UI.
5835
5860
  */
5836
5861
  const CustomerIdsFilterView = ({ customerId, hasCount = true, ...props }) => {
5837
- const { data, loading, searchText, setSearchText } = useCustomerData(props.filterState.values, customerId);
5862
+ const { data, loading, customSearch } = useCustomerData(props.filterState.values, customerId);
5838
5863
  const hierarchicalOptions = useCustomerHierarchy(data?.assetSummary?.customers?.summary);
5839
5864
  const valueNameArrayFilterDefinition = props.filterDefinition;
5840
- return (jsx(HierarchicalCheckboxFilter, { cascadeSelection: true, customSearch: {
5841
- value: searchText,
5842
- onChange: setSearchText,
5843
- }, filterBarActions: props.filterBarActions, filterDefinition: valueNameArrayFilterDefinition, filterState: props.filterState, loading: loading, options: hierarchicalOptions, setValue: props.setValue, showCount: hasCount, value: props.value }));
5865
+ return (jsx(HierarchicalCheckboxFilter, { cascadeSelection: true, customSearch: customSearch, filterBarActions: props.filterBarActions, filterDefinition: valueNameArrayFilterDefinition, filterState: props.filterState, loading: loading, options: hierarchicalOptions, setValue: props.setValue, showCount: hasCount, value: props.value }));
5844
5866
  };
5845
5867
  /**
5846
5868
  * Custom hook to create and configure a customer IDs filter definition.
@@ -6021,6 +6043,21 @@ const useDeviceHealthIssueStatusFilter = (hookProps) => {
6021
6043
  }, [t, hookProps?.deviceHealthStates, hookProps?.deviceHealthDateTimeRange]);
6022
6044
  };
6023
6045
 
6046
+ /**
6047
+ * Supplies a `DefaultCheckboxFilter` whose options are all fetched up front and searched locally.
6048
+ * Matching is on the label, trimmed and case-insensitive, once the search is debounced.
6049
+ *
6050
+ * @param allOptions every option the facet can show
6051
+ * @param loading whether the query behind `allOptions` is loading
6052
+ * @returns {object} props to spread onto `DefaultCheckboxFilter`; `loading` is only true while there are no options yet
6053
+ */
6054
+ const useFacetLocalOptions = (allOptions, loading) => {
6055
+ const { debouncedSearch, customSearch } = useFilterSearch();
6056
+ const needle = debouncedSearch.trim().toLocaleLowerCase();
6057
+ const options = useMemo(() => (needle ? allOptions.filter(option => option.label.toLowerCase().includes(needle)) : allOptions), [allOptions, needle]);
6058
+ return useMemo(() => ({ customSearch, loading: loading && allOptions.length === 0, options }), [customSearch, loading, allOptions.length, options]);
6059
+ };
6060
+
6024
6061
  /**
6025
6062
  * Get a record of device health issue type display names
6026
6063
  *
@@ -6054,8 +6091,6 @@ const useDeviceHealthIssueTypeDisplayNames = () => {
6054
6091
  const DeviceHealthIssueTypeFilter = ({ deviceHealthStates, deviceHealthDateTimeRange, ...props }) => {
6055
6092
  const issueTypeDisplayNames = useDeviceHealthIssueTypeDisplayNames();
6056
6093
  const filters = useActiveAssetFilters(props.filterState.values);
6057
- const [searchQuery, setSearchQuery] = useState("");
6058
- const debouncedSearchQuery = useDebounce(searchQuery.trim().toLocaleLowerCase(), { delay: 300 });
6059
6094
  const { data, loading } = useQuery(DeviceHealthIssueTypeSummariesDocument, {
6060
6095
  variables: {
6061
6096
  filters: {
@@ -6067,11 +6102,12 @@ const DeviceHealthIssueTypeFilter = ({ deviceHealthStates, deviceHealthDateTimeR
6067
6102
  },
6068
6103
  },
6069
6104
  });
6070
- const { options } = useFleetHealthFilterUtils({
6105
+ const { options: allOptions } = useFleetHealthFilterUtils({
6071
6106
  filterSummaries: data?.assetSummary?.deviceHealthTypesSummary.summary,
6072
6107
  filterTranslations: issueTypeDisplayNames,
6073
6108
  });
6074
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchQuery, onChange: setSearchQuery }, loading: loading, options: options.filter(option => option.label.toLowerCase().includes(debouncedSearchQuery)) }));
6109
+ const facet = useFacetLocalOptions(allOptions, loading);
6110
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
6075
6111
  };
6076
6112
 
6077
6113
  /**
@@ -6102,16 +6138,15 @@ const useDeviceHealthIssueTypeFilter = (hookProps) => {
6102
6138
  const DeviceTypesFilter = (props) => {
6103
6139
  const { deviceTypeDisplayNames } = useDeviceTypeTranslations();
6104
6140
  const filters = useActiveAssetFilters(props.filterState.values);
6105
- const [searchQuery, setSearchQuery] = useState("");
6106
- const debouncedSearchQuery = useDebounce(searchQuery.trim().toLocaleLowerCase(), { delay: 300 });
6107
6141
  const { data, loading } = useQuery(DeviceTypesSummaryDocument, {
6108
6142
  variables: { filters: { ...filters, deviceTypes: undefined } },
6109
6143
  });
6110
- const { options } = useFleetHealthFilterUtils({
6144
+ const { options: allOptions } = useFleetHealthFilterUtils({
6111
6145
  filterSummaries: data?.assetSummary?.deviceTypesSummary?.summary,
6112
6146
  filterTranslations: deviceTypeDisplayNames,
6113
6147
  });
6114
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchQuery, onChange: setSearchQuery }, loading: loading, options: options.filter(option => option.label.toLowerCase().includes(debouncedSearchQuery)) }));
6148
+ const facet = useFacetLocalOptions(allOptions, loading);
6149
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
6115
6150
  };
6116
6151
 
6117
6152
  /**
@@ -6138,24 +6173,17 @@ const useDeviceTypesFilter = (showInFilterBar) => {
6138
6173
  */
6139
6174
  const FirmwareVersionFilter = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
6140
6175
  const [t] = useTranslation();
6141
- const activeFilters = useActiveAssetFilters(filterState.values);
6142
- const [searchText, setSearchText] = useState("");
6143
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
6144
- const filters = { ...activeFilters, firmwareVersion: null };
6145
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetFirmwareVersionSummaryConnectionDocument, "firmwareVersionSummaryConnection", {
6146
- search: debouncedSearch,
6147
- filters,
6148
- });
6149
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetFirmwareVersionSummaryMissingDocument, "firmwareVersionSummaryConnection", filters);
6150
- const loading = loadingValues || loadingMissing;
6151
- const options = useMemo(() => {
6152
- return toSummaryEntries(edges, missing, loading).map(entry => ({
6153
- key: entry.key,
6154
- count: entry.count,
6176
+ const facet = useFacetConnectionOptions(filterState, {
6177
+ document: GetFleetFirmwareVersionSummaryConnectionDocument,
6178
+ connectionField: "firmwareVersionSummaryConnection",
6179
+ scope: filters => ({ ...filters, firmwareVersion: null }),
6180
+ missing: { document: GetFleetFirmwareVersionSummaryMissingDocument },
6181
+ toOption: entry => ({
6182
+ ...entry,
6155
6183
  label: entry.key === UNDEFINED_SUMMARY_KEY ? t(`machine.types.Unknown`) : entry.key,
6156
- }));
6157
- }, [edges, missing, loading, t]);
6158
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
6184
+ }),
6185
+ });
6186
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
6159
6187
  };
6160
6188
 
6161
6189
  /**
@@ -6225,38 +6253,22 @@ const useFollowedFilter = () => {
6225
6253
  */
6226
6254
  const GroupIdsFilterView = (props) => {
6227
6255
  const [t] = useTranslation();
6228
- const activeFilters = useActiveAssetFilters(props.filterState.values);
6229
- const [searchText, setSearchText] = useState("");
6230
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
6231
- const filters = { ...activeFilters, groups: null };
6232
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetGroupSummaryConnectionDocument, "groupsConnection", {
6233
- search: debouncedSearch,
6234
- filters,
6235
- });
6236
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetGroupSummaryMissingDocument, "groupsConnection", filters);
6237
- const loading = loadingValues || loadingMissing;
6238
- const options = useMemo(() => {
6239
- if (loading && edges.length === 0) {
6240
- return [];
6241
- }
6242
- const result = edges.map(edge => {
6243
- const node = asGroupConnectionNode(edge.node);
6244
- return {
6256
+ const facet = useFacetConnectionOptions(props.filterState, {
6257
+ document: GetFleetGroupSummaryConnectionDocument,
6258
+ connectionField: "groupsConnection",
6259
+ scope: filters => ({ ...filters, groups: null }),
6260
+ missing: { document: GetFleetGroupSummaryMissingDocument, label: t("assetFilters.groupFilter.missingGroup") },
6261
+ node: {
6262
+ read: asGroupConnectionNode,
6263
+ toOption: node => ({
6245
6264
  key: node.group?.groupId || "unknown",
6246
- count: props.hasCount ? node.count || 0 : undefined,
6265
+ count: node.count || 0,
6247
6266
  label: node.group?.name || t("machine.types.Unknown"),
6248
- };
6249
- });
6250
- if (typeof missing === "number" && missing > 0) {
6251
- result.push({
6252
- key: UNDEFINED_SUMMARY_KEY,
6253
- count: props.hasCount ? missing : undefined,
6254
- label: t("assetFilters.groupFilter.missingGroup"),
6255
- });
6256
- }
6257
- return result;
6258
- }, [edges, missing, loading, props.hasCount, t]);
6259
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
6267
+ }),
6268
+ },
6269
+ showCount: Boolean(props.hasCount),
6270
+ });
6271
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
6260
6272
  };
6261
6273
  /**
6262
6274
  * GroupIds filter definition
@@ -7045,16 +7057,6 @@ const useMetadataCompletenessFilter = ({ isDefault } = {}) => {
7045
7057
  */
7046
7058
  const ModbusProfileFilter = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
7047
7059
  const [t] = useTranslation();
7048
- const activeFilters = useActiveAssetFilters(filterState.values);
7049
- const [searchText, setSearchText] = useState("");
7050
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7051
- const filters = { ...activeFilters, modbusProfile: null };
7052
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetModbusProfileSummaryConnectionDocument, "modbusProfileSummaryConnection", {
7053
- search: debouncedSearch,
7054
- filters,
7055
- });
7056
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetModbusProfileSummaryMissingDocument, "modbusProfileSummaryConnection", filters);
7057
- const loading = loadingValues || loadingMissing;
7058
7060
  const { data: profileNamesData } = useQuery(TelematicsDeviceModbusProfileNamesDocument, {
7059
7061
  context: { headers: { "TU-PREVIEW": "TELEMATICS_DEVICE_PREVIEW" } },
7060
7062
  fetchPolicy: "cache-first",
@@ -7063,19 +7065,19 @@ const ModbusProfileFilter = ({ filterDefinition, filterState, filterBarActions,
7063
7065
  profile.key,
7064
7066
  profile.name,
7065
7067
  ]) ?? []), [profileNamesData?.telematicsDeviceSummary?.modbusProfiles?.summary]);
7066
- const options = useMemo(() => {
7067
- return toSummaryEntries(edges, missing, loading).map(entry => {
7068
- if (entry.key === UNDEFINED_SUMMARY_KEY) {
7069
- return { key: entry.key, count: entry.count, label: t(`machine.types.Unknown`) };
7070
- }
7071
- return {
7072
- key: entry.key,
7073
- count: entry.count,
7074
- label: profileNameByKey.get(entry.key) ?? entry.key,
7075
- };
7076
- });
7077
- }, [edges, missing, loading, profileNameByKey, t]);
7078
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7068
+ const facet = useFacetConnectionOptions(filterState, {
7069
+ document: GetFleetModbusProfileSummaryConnectionDocument,
7070
+ connectionField: "modbusProfileSummaryConnection",
7071
+ scope: filters => ({ ...filters, modbusProfile: null }),
7072
+ missing: { document: GetFleetModbusProfileSummaryMissingDocument },
7073
+ toOption: entry => ({
7074
+ ...entry,
7075
+ label: entry.key === UNDEFINED_SUMMARY_KEY
7076
+ ? t(`machine.types.Unknown`)
7077
+ : (profileNameByKey.get(entry.key) ?? entry.key),
7078
+ }),
7079
+ });
7080
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
7079
7081
  };
7080
7082
 
7081
7083
  /**
@@ -7105,24 +7107,14 @@ const useModbusProfileFilter = () => {
7105
7107
  */
7106
7108
  const ModelsFilterView = (props) => {
7107
7109
  const { getMachineTypeTranslation } = useMachineTypeTranslations();
7108
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7109
- const [searchText, setSearchText] = useState("");
7110
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7111
- const filters = { ...activeFilters, models: null };
7112
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetModelsSummaryConnectionDocument, "modelsConnection", {
7113
- search: debouncedSearch,
7114
- filters,
7110
+ const facet = useFacetConnectionOptions(props.filterState, {
7111
+ document: GetFleetModelsSummaryConnectionDocument,
7112
+ connectionField: "modelsConnection",
7113
+ scope: filters => ({ ...filters, models: null }),
7114
+ missing: { document: GetFleetModelsSummaryMissingDocument },
7115
+ toOption: entry => ({ ...entry, label: getMachineTypeTranslation(entry.key) }),
7115
7116
  });
7116
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetModelsSummaryMissingDocument, "modelsConnection", filters);
7117
- const loading = loadingValues || loadingMissing;
7118
- const options = useMemo(() => {
7119
- return toSummaryEntries(edges, missing, loading).map(entry => ({
7120
- key: entry.key,
7121
- count: entry.count,
7122
- label: getMachineTypeTranslation(entry.key),
7123
- }));
7124
- }, [edges, missing, loading, getMachineTypeTranslation]);
7125
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7117
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7126
7118
  };
7127
7119
  /**
7128
7120
  *
@@ -7285,7 +7277,6 @@ const useNameFilter = (props) => {
7285
7277
  return result;
7286
7278
  };
7287
7279
 
7288
- const FETCH_LIMIT$3 = 1000;
7289
7280
  /**
7290
7281
  * Maps a network-technology summary key to its localized label.
7291
7282
  * Falls back to the raw key for values that have no translation yet (e.g. future technologies).
@@ -7320,31 +7311,13 @@ const networkTechnologyLabel = (t, key) => {
7320
7311
  */
7321
7312
  const NetworkTechnologyFilter = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
7322
7313
  const [t] = useTranslation();
7323
- const activeFilters = useActiveAssetFilters(filterState.values);
7324
- const [showRequestMoreUseSearch, setShowRequestMoreUseSearch] = useState(false);
7325
- const [searchText, setSearchText] = useState("");
7326
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7327
- const { data, loading } = useQuery(GetFleetNetworkTechnologySummaryDocument, {
7328
- variables: {
7329
- limit: FETCH_LIMIT$3,
7330
- search: debouncedSearch,
7331
- filters: {
7332
- ...activeFilters,
7333
- networkTechnology: null, // Omit the filter's own values so the list shows all options correctly
7334
- },
7335
- },
7336
- fetchPolicy: "cache-first",
7314
+ const facet = useFacetLimitedOptions(filterState, {
7315
+ document: GetFleetNetworkTechnologySummaryDocument,
7316
+ scope: filters => ({ ...filters, networkTechnology: null }),
7317
+ read: data => data.assetSummary?.networkTechnologySummary?.summary,
7318
+ toOption: networkTechnology => ({ ...networkTechnology, label: networkTechnologyLabel(t, networkTechnology.key) }),
7337
7319
  });
7338
- const options = useMemo(() => {
7339
- return (data?.assetSummary?.networkTechnologySummary?.summary.map(networkTechnology => ({
7340
- ...networkTechnology,
7341
- label: networkTechnologyLabel(t, networkTechnology.key),
7342
- })) ?? []);
7343
- }, [data?.assetSummary?.networkTechnologySummary?.summary, t]);
7344
- useEffect(() => {
7345
- setShowRequestMoreUseSearch(options.length === FETCH_LIMIT$3);
7346
- }, [options]);
7347
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: loading, options: options, showRequestMoreUseSearch: showRequestMoreUseSearch }));
7320
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
7348
7321
  };
7349
7322
 
7350
7323
  /**
@@ -7373,27 +7346,20 @@ const useNetworkTechnologyFilter = () => {
7373
7346
  */
7374
7347
  const OwnerAccountIdsFilterView = (props) => {
7375
7348
  const [t] = useTranslation();
7376
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7377
- const [searchText, setSearchText] = useState("");
7378
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7379
- const { edges, loading, pagination } = useFleetSummaryConnection(GetFleetOwnerAccountSummaryConnectionDocument, "ownerAccountsConnection", {
7380
- search: debouncedSearch,
7381
- filters: {
7382
- ...activeFilters,
7383
- ownerAccountIds: null,
7384
- },
7385
- });
7386
- const options = useMemo(() => {
7387
- return edges.map(edge => {
7388
- const node = asOwnerAccountConnectionNode(edge.node);
7389
- return {
7349
+ const facet = useFacetConnectionOptions(props.filterState, {
7350
+ document: GetFleetOwnerAccountSummaryConnectionDocument,
7351
+ connectionField: "ownerAccountsConnection",
7352
+ scope: filters => ({ ...filters, ownerAccountIds: null }),
7353
+ node: {
7354
+ read: asOwnerAccountConnectionNode,
7355
+ toOption: node => ({
7390
7356
  key: node.ownerAccount?.accountId || "unknown",
7391
7357
  count: node.count || 0,
7392
7358
  label: node.ownerAccount?.name || t("machine.types.Unknown"),
7393
- };
7394
- });
7395
- }, [edges, t]);
7396
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7359
+ }),
7360
+ },
7361
+ });
7362
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7397
7363
  };
7398
7364
  /**
7399
7365
  * OwnerAccountIds filter definition
@@ -7525,7 +7491,6 @@ const usePeriodFilter = () => {
7525
7491
  return result;
7526
7492
  };
7527
7493
 
7528
- const FETCH_LIMIT$2 = 1000;
7529
7494
  /**
7530
7495
  * Production Year Filter View component.
7531
7496
  *
@@ -7540,32 +7505,16 @@ const FETCH_LIMIT$2 = 1000;
7540
7505
  */
7541
7506
  const ProductionYearFilterView = ({ filterDefinition, filterState, filterBarActions, ...props }) => {
7542
7507
  const [t] = useTranslation();
7543
- const activeFilters = useActiveAssetFilters(filterState.values);
7544
- const [showRequestMoreUseSearch, setShowRequestMoreUseSearch] = useState(false);
7545
- const [searchText, setSearchText] = useState("");
7546
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7547
- const { data, loading } = useQuery(GetFleetProductionYearsSummaryDocument, {
7548
- variables: {
7549
- limit: FETCH_LIMIT$2,
7550
- search: debouncedSearch,
7551
- filters: {
7552
- ...activeFilters,
7553
- productionYears: null, // Omit the filters own values so list shows options correctly
7554
- },
7555
- },
7556
- fetchPolicy: "cache-first",
7557
- });
7558
- const options = useMemo(() => {
7559
- const result = data?.assetSummary?.productionYears?.summary.map(productionYear => ({
7508
+ const facet = useFacetLimitedOptions(filterState, {
7509
+ document: GetFleetProductionYearsSummaryDocument,
7510
+ scope: filters => ({ ...filters, productionYears: null }),
7511
+ read: data => data.assetSummary?.productionYears?.summary,
7512
+ toOption: productionYear => ({
7560
7513
  ...productionYear,
7561
7514
  label: productionYear.key.toUpperCase() === "UNDEFINED" ? t(`machine.types.Unknown`) : productionYear.key,
7562
- })) ?? [];
7563
- return result;
7564
- }, [data?.assetSummary?.productionYears?.summary, t]);
7565
- useEffect(() => {
7566
- setShowRequestMoreUseSearch(options.length === FETCH_LIMIT$2);
7567
- }, [options]);
7568
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState, loading: loading, options: options, showRequestMoreUseSearch: showRequestMoreUseSearch }));
7515
+ }),
7516
+ });
7517
+ return (jsx(DefaultCheckboxFilter, { ...props, ...facet, filterBarActions: filterBarActions, filterDefinition: filterDefinition, filterState: filterState }));
7569
7518
  };
7570
7519
  /**
7571
7520
  * Production year filter definition
@@ -7651,10 +7600,8 @@ const useRentalActiveContractItemOnRentDatesDateRangeFilter = ({ showInFilterBar
7651
7600
  };
7652
7601
 
7653
7602
  const RENTAL_PREVIEW_CONTEXT$3 = {
7654
- context: {
7655
- headers: {
7656
- "TU-PREVIEW": "dragonfruit-monty",
7657
- },
7603
+ headers: {
7604
+ "TU-PREVIEW": "dragonfruit-monty",
7658
7605
  },
7659
7606
  };
7660
7607
  /**
@@ -7662,27 +7609,22 @@ const RENTAL_PREVIEW_CONTEXT$3 = {
7662
7609
  */
7663
7610
  const RentalContractCustomerParentExternalReferenceFilterView = (props) => {
7664
7611
  const [t] = useTranslation();
7665
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7666
- const [searchText, setSearchText] = useState("");
7667
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7668
- const filters = {
7669
- ...activeFilters,
7670
- rentalActiveContractFilters: {
7671
- ...activeFilters.rentalActiveContractFilters,
7672
- customerParentExternalReferences: null,
7673
- },
7674
- };
7675
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetRentalCustomerParentExternalReferenceSummaryConnectionDocument, "rentalContractCustomerParentExternalReferencesConnection", { search: debouncedSearch, filters }, RENTAL_PREVIEW_CONTEXT$3);
7676
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetRentalCustomerParentExternalReferenceSummaryMissingDocument, "rentalContractCustomerParentExternalReferencesConnection", filters, RENTAL_PREVIEW_CONTEXT$3);
7677
- const loading = loadingValues || loadingMissing;
7678
- const options = useMemo(() => {
7679
- return toSummaryEntries(edges, missing, loading).map(entry => ({
7612
+ const facet = useFacetConnectionOptions(props.filterState, {
7613
+ document: GetFleetRentalCustomerParentExternalReferenceSummaryConnectionDocument,
7614
+ connectionField: "rentalContractCustomerParentExternalReferencesConnection",
7615
+ scope: filters => ({
7616
+ ...filters,
7617
+ rentalActiveContractFilters: { ...filters.rentalActiveContractFilters, customerParentExternalReferences: null },
7618
+ }),
7619
+ missing: { document: GetFleetRentalCustomerParentExternalReferenceSummaryMissingDocument },
7620
+ toOption: entry => ({
7680
7621
  key: entry.key || "unknown",
7681
7622
  count: entry.count,
7682
7623
  label: entry.key && entry.key !== UNDEFINED_SUMMARY_KEY ? entry.key : t(`machine.types.Unknown`),
7683
- }));
7684
- }, [edges, missing, loading, t]);
7685
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7624
+ }),
7625
+ context: RENTAL_PREVIEW_CONTEXT$3,
7626
+ });
7627
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7686
7628
  };
7687
7629
  /**
7688
7630
  * Rental contract customer parent external reference filter definition
@@ -7704,10 +7646,8 @@ const useRentalContractCustomerParentExternalReferenceFilter = (props) => {
7704
7646
  };
7705
7647
 
7706
7648
  const RENTAL_PREVIEW_CONTEXT$2 = {
7707
- context: {
7708
- headers: {
7709
- "TU-PREVIEW": "dragonfruit-monty",
7710
- },
7649
+ headers: {
7650
+ "TU-PREVIEW": "dragonfruit-monty",
7711
7651
  },
7712
7652
  };
7713
7653
  /**
@@ -7715,27 +7655,22 @@ const RENTAL_PREVIEW_CONTEXT$2 = {
7715
7655
  */
7716
7656
  const RentalContractCustomerParentNameFilterView = (props) => {
7717
7657
  const [t] = useTranslation();
7718
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7719
- const [searchText, setSearchText] = useState("");
7720
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7721
- const filters = {
7722
- ...activeFilters,
7723
- rentalActiveContractFilters: {
7724
- ...activeFilters.rentalActiveContractFilters,
7725
- customerParentNames: null,
7726
- },
7727
- };
7728
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetRentalCustomerParentNameSummaryConnectionDocument, "rentalContractCustomerParentNamesConnection", { search: debouncedSearch, filters }, RENTAL_PREVIEW_CONTEXT$2);
7729
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetRentalCustomerParentNameSummaryMissingDocument, "rentalContractCustomerParentNamesConnection", filters, RENTAL_PREVIEW_CONTEXT$2);
7730
- const loading = loadingValues || loadingMissing;
7731
- const options = useMemo(() => {
7732
- return toSummaryEntries(edges, missing, loading).map(entry => ({
7658
+ const facet = useFacetConnectionOptions(props.filterState, {
7659
+ document: GetFleetRentalCustomerParentNameSummaryConnectionDocument,
7660
+ connectionField: "rentalContractCustomerParentNamesConnection",
7661
+ scope: filters => ({
7662
+ ...filters,
7663
+ rentalActiveContractFilters: { ...filters.rentalActiveContractFilters, customerParentNames: null },
7664
+ }),
7665
+ missing: { document: GetFleetRentalCustomerParentNameSummaryMissingDocument },
7666
+ toOption: entry => ({
7733
7667
  key: entry.key || "unknown",
7734
7668
  count: entry.count,
7735
7669
  label: entry.key && entry.key !== UNDEFINED_SUMMARY_KEY ? entry.key : t(`machine.types.Unknown`),
7736
- }));
7737
- }, [edges, missing, loading, t]);
7738
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7670
+ }),
7671
+ context: RENTAL_PREVIEW_CONTEXT$2,
7672
+ });
7673
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7739
7674
  };
7740
7675
  /**
7741
7676
  * Rental contract customer parent name filter definition
@@ -7757,10 +7692,8 @@ const useRentalContractCustomerParentNameFilter = (props) => {
7757
7692
  };
7758
7693
 
7759
7694
  const RENTAL_PREVIEW_CONTEXT$1 = {
7760
- context: {
7761
- headers: {
7762
- "TU-PREVIEW": "dragonfruit-monty",
7763
- },
7695
+ headers: {
7696
+ "TU-PREVIEW": "dragonfruit-monty",
7764
7697
  },
7765
7698
  };
7766
7699
  /**
@@ -7768,21 +7701,19 @@ const RENTAL_PREVIEW_CONTEXT$1 = {
7768
7701
  */
7769
7702
  const RentalContractOrderNumberFilterView = (props) => {
7770
7703
  const [t] = useTranslation();
7771
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7772
- const [searchText, setSearchText] = useState("");
7773
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7774
- const filters = { ...activeFilters, rentalContractOrderNumbers: null };
7775
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetRentalContractOrderNumberSummaryConnectionDocument, "rentalContractOrderNumbersConnection", { search: debouncedSearch, filters }, RENTAL_PREVIEW_CONTEXT$1);
7776
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetRentalContractOrderNumberSummaryMissingDocument, "rentalContractOrderNumbersConnection", filters, RENTAL_PREVIEW_CONTEXT$1);
7777
- const loading = loadingValues || loadingMissing;
7778
- const options = useMemo(() => {
7779
- return toSummaryEntries(edges, missing, loading).map(entry => ({
7704
+ const facet = useFacetConnectionOptions(props.filterState, {
7705
+ document: GetFleetRentalContractOrderNumberSummaryConnectionDocument,
7706
+ connectionField: "rentalContractOrderNumbersConnection",
7707
+ scope: filters => ({ ...filters, rentalContractOrderNumbers: null }),
7708
+ missing: { document: GetFleetRentalContractOrderNumberSummaryMissingDocument },
7709
+ toOption: entry => ({
7780
7710
  key: entry.key || "unknown",
7781
7711
  count: entry.count,
7782
7712
  label: entry.key && entry.key !== UNDEFINED_SUMMARY_KEY ? entry.key : t(`machine.types.Unknown`),
7783
- }));
7784
- }, [edges, missing, loading, t]);
7785
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7713
+ }),
7714
+ context: RENTAL_PREVIEW_CONTEXT$1,
7715
+ });
7716
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7786
7717
  };
7787
7718
  /**
7788
7719
  * Rental contract order number filter definition
@@ -7834,10 +7765,8 @@ const useRentalContractReferenceCodeDescriptionFilter = (props) => {
7834
7765
  };
7835
7766
 
7836
7767
  const RENTAL_PREVIEW_CONTEXT = {
7837
- context: {
7838
- headers: {
7839
- "TU-PREVIEW": "dragonfruit-monty",
7840
- },
7768
+ headers: {
7769
+ "TU-PREVIEW": "dragonfruit-monty",
7841
7770
  },
7842
7771
  };
7843
7772
  /**
@@ -7845,21 +7774,19 @@ const RENTAL_PREVIEW_CONTEXT = {
7845
7774
  */
7846
7775
  const RentalContractReferenceCodeFilterView = (props) => {
7847
7776
  const [t] = useTranslation();
7848
- const activeFilters = useActiveAssetFilters(props.filterState.values);
7849
- const [searchText, setSearchText] = useState("");
7850
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
7851
- const filters = { ...activeFilters, rentalContractReferenceCodes: null };
7852
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetRentalContractReferenceCodesSummaryConnectionDocument, "rentalContractReferenceCodesConnection", { search: debouncedSearch, filters }, RENTAL_PREVIEW_CONTEXT);
7853
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetRentalContractReferenceCodesSummaryMissingDocument, "rentalContractReferenceCodesConnection", filters, RENTAL_PREVIEW_CONTEXT);
7854
- const loading = loadingValues || loadingMissing;
7855
- const options = useMemo(() => {
7856
- return toSummaryEntries(edges, missing, loading).map(entry => ({
7777
+ const facet = useFacetConnectionOptions(props.filterState, {
7778
+ document: GetFleetRentalContractReferenceCodesSummaryConnectionDocument,
7779
+ connectionField: "rentalContractReferenceCodesConnection",
7780
+ scope: filters => ({ ...filters, rentalContractReferenceCodes: null }),
7781
+ missing: { document: GetFleetRentalContractReferenceCodesSummaryMissingDocument },
7782
+ toOption: entry => ({
7857
7783
  key: entry.key || "unknown",
7858
7784
  count: entry.count,
7859
7785
  label: entry.key && entry.key !== UNDEFINED_SUMMARY_KEY ? entry.key : t(`machine.types.Unknown`),
7860
- }));
7861
- }, [edges, missing, loading, t]);
7862
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
7786
+ }),
7787
+ context: RENTAL_PREVIEW_CONTEXT,
7788
+ });
7789
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
7863
7790
  };
7864
7791
  /**
7865
7792
  * Rental contract reference code filter definition
@@ -8079,7 +8006,6 @@ const useServicePlanStatusFilter = ({ servicePlanStatusToShow = SERVICE_PLAN_STA
8079
8006
  return result;
8080
8007
  };
8081
8008
 
8082
- const FETCH_LIMIT$1 = 1000;
8083
8009
  /**
8084
8010
  * Component for rendering a filter view specific to site depot ownership.
8085
8011
  *
@@ -8088,35 +8014,19 @@ const FETCH_LIMIT$1 = 1000;
8088
8014
  */
8089
8015
  const SiteDepotOwnershipIdsFilterView = (props) => {
8090
8016
  const [t] = useTranslation();
8091
- const activeFilters = useActiveAssetFilters(props.filterState.values);
8092
- const [showRequestMoreUseSearch, setShowRequestMoreUseSearch] = useState(false);
8093
- const [searchText, setSearchText] = useState("");
8094
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
8095
- const { data, loading } = useQuery(GetSiteDepotOwnershipIdSummaryDocument, {
8096
- fetchPolicy: "cache-first",
8097
- variables: {
8098
- limit: FETCH_LIMIT$1,
8099
- search: debouncedSearch,
8100
- filters: {
8101
- ...activeFilters,
8102
- owningDepotSiteIds: null, // Omit the filters own values so list shows options correctly
8103
- },
8104
- },
8105
- });
8106
- const options = useMemo(() => {
8107
- const result = data?.assetSummary?.owningDepots?.summary.map(owningDepotEdge => ({
8108
- key: owningDepotEdge.site?.siteId ? owningDepotEdge.site.siteId || "unknown" : "UNDEFINED",
8017
+ const facet = useFacetLimitedOptions(props.filterState, {
8018
+ document: GetSiteDepotOwnershipIdSummaryDocument,
8019
+ scope: filters => ({ ...filters, owningDepotSiteIds: null }),
8020
+ read: data => data.assetSummary?.owningDepots?.summary,
8021
+ toOption: owningDepotEdge => ({
8022
+ key: owningDepotEdge.site?.siteId || "UNDEFINED",
8109
8023
  count: owningDepotEdge.count || 0,
8110
8024
  label: owningDepotEdge.site?.name === "UNDEFINED"
8111
8025
  ? t("siteOwningDepot.notOwned")
8112
8026
  : owningDepotEdge.site?.name || t("siteOwningDepot.unknown"),
8113
- })) ?? [];
8114
- return result;
8115
- }, [data?.assetSummary?.owningDepots?.summary, t]);
8116
- useEffect(() => {
8117
- setShowRequestMoreUseSearch(options.length === FETCH_LIMIT$1);
8118
- }, [options]);
8119
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: loading, options: options, showRequestMoreUseSearch: showRequestMoreUseSearch }));
8027
+ }),
8028
+ });
8029
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
8120
8030
  };
8121
8031
  /**
8122
8032
  * Site depot ownership filter definition
@@ -8140,7 +8050,6 @@ const useSiteDepotOwnershipIdsFilter = (props) => {
8140
8050
  return result;
8141
8051
  };
8142
8052
 
8143
- const FETCH_LIMIT = 1000;
8144
8053
  /**
8145
8054
  * Filter view component for selecting Site IDs.
8146
8055
  *
@@ -8151,33 +8060,19 @@ const FETCH_LIMIT = 1000;
8151
8060
  * @returns {ReactElement} The rendered Site IDs filter view component.
8152
8061
  */
8153
8062
  const SiteIdsFilterView = (props) => {
8154
- const activeFilters = useActiveAssetFilters(props.filterState.values);
8155
- const [showRequestMoreUseSearch, setShowRequestMoreUseSearch] = useState(false);
8156
- const [searchText, setSearchText] = useState("");
8157
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
8158
- const { data, loading } = useQuery(GetSiteIdSummaryDocument, {
8159
- fetchPolicy: "cache-first",
8160
- variables: {
8161
- limit: FETCH_LIMIT,
8162
- search: debouncedSearch,
8163
- filters: {
8164
- ...activeFilters,
8165
- siteIds: null, // Omit the filters own values so list shows options correctly
8166
- },
8167
- },
8168
- });
8169
- const options = useMemo(() => {
8170
- const result = data?.assetSummary?.sites?.summary.map(siteEdge => ({
8063
+ const [t] = useTranslation();
8064
+ const facet = useFacetLimitedOptions(props.filterState, {
8065
+ document: GetSiteIdSummaryDocument,
8066
+ scope: filters => ({ ...filters, siteIds: null }),
8067
+ read: data => data.assetSummary?.sites?.summary,
8068
+ toOption: siteEdge => ({
8171
8069
  key: siteEdge.site?.siteId || "unknown",
8172
- count: props.hasCount ? siteEdge.count || 0 : undefined,
8173
- label: siteEdge.site?.name || "Unknown",
8174
- })) ?? [];
8175
- return result;
8176
- }, [data?.assetSummary?.sites?.summary, props.hasCount]);
8177
- useEffect(() => {
8178
- setShowRequestMoreUseSearch(options.length === FETCH_LIMIT);
8179
- }, [options]);
8180
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: loading, options: options, showRequestMoreUseSearch: showRequestMoreUseSearch }));
8070
+ count: siteEdge.count || 0,
8071
+ label: siteEdge.site?.name || t("machine.types.Unknown"),
8072
+ }),
8073
+ showCount: Boolean(props.hasCount),
8074
+ });
8075
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
8181
8076
  };
8182
8077
  /**
8183
8078
  *
@@ -8441,24 +8336,14 @@ const useTelematicsConnectedFilter = () => {
8441
8336
  */
8442
8337
  const TypesFilterView = (props) => {
8443
8338
  const { getMachineTypeTranslation } = useMachineTypeTranslations();
8444
- const activeFilters = useActiveAssetFilters(props.filterState.values);
8445
- const [searchText, setSearchText] = useState("");
8446
- const debouncedSearch = useDebounce(searchText, { delay: 500 });
8447
- const filters = { ...activeFilters, types: null };
8448
- const { edges, loading: loadingValues, pagination, } = useFleetSummaryConnection(GetFleetTypesSummaryConnectionDocument, "typesConnection", {
8449
- search: debouncedSearch,
8450
- filters,
8339
+ const facet = useFacetConnectionOptions(props.filterState, {
8340
+ document: GetFleetTypesSummaryConnectionDocument,
8341
+ connectionField: "typesConnection",
8342
+ scope: filters => ({ ...filters, types: null }),
8343
+ missing: { document: GetFleetTypesSummaryMissingDocument },
8344
+ toOption: entry => ({ ...entry, label: getMachineTypeTranslation(entry.key) }),
8451
8345
  });
8452
- const { missing, loading: loadingMissing } = useFacetMissingCount(GetFleetTypesSummaryMissingDocument, "typesConnection", filters);
8453
- const loading = loadingValues || loadingMissing;
8454
- const options = useMemo(() => {
8455
- return toSummaryEntries(edges, missing, loading).map(entry => ({
8456
- key: entry.key,
8457
- count: entry.count,
8458
- label: getMachineTypeTranslation(entry.key),
8459
- }));
8460
- }, [edges, missing, loading, getMachineTypeTranslation]);
8461
- return (jsx(DefaultCheckboxFilter, { ...props, customSearch: { value: searchText, onChange: setSearchText, onClear: () => setSearchText("") }, loading: Boolean(loading && options.length === 0), options: options, pagination: pagination }));
8346
+ return jsx(DefaultCheckboxFilter, { ...props, ...facet });
8462
8347
  };
8463
8348
  /**
8464
8349
  * Types filter definition