@commercelayer/app-elements 7.11.1 → 7.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CodeEditorComponent-YX37xlgL.js → CodeEditorComponent-aj99riRd.js} +2 -2
- package/dist/{InputDateComponent-BDDdyk6q.js → InputDateComponent-IsJB6qOP.js} +359 -356
- package/dist/{RuleEngineComponent-CLMJbVUz.js → RuleEngineComponent-DZhv94I7.js} +3 -3
- package/dist/{en-CcBUYKzR.js → en-Ccxurm3G.js} +1 -0
- package/dist/{fetchCoreResourcesSuggestions-D1U2_gW3.js → fetchCoreResourcesSuggestions-DuyGOmZK.js} +1 -1
- package/dist/{it-y1Q1-MMT.js → it-C8-LXpKU.js} +1 -0
- package/dist/locales/en.d.ts +1 -0
- package/dist/{main-DXTR8pxH.js → main-DoRznkuw.js} +21271 -18498
- package/dist/main.d.ts +1 -0
- package/dist/main.js +9 -8
- package/dist/{parseISO-D3w6A-Zg.js → parseISO-Byyj1mNB.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/ui/atoms/ButtonFilter.d.ts +17 -1
- package/dist/ui/atoms/Container.d.ts +10 -0
- package/dist/ui/composite/HomePageLayout.d.ts +3 -2
- package/dist/ui/composite/PageLayout.d.ts +52 -1
- package/dist/ui/resources/useResourceFilters/FieldOptionsSelect.d.ts +20 -0
- package/dist/ui/resources/useResourceFilters/FiltersBar.d.ts +64 -0
- package/dist/ui/resources/useResourceFilters/FiltersDrawer.d.ts +35 -0
- package/dist/ui/resources/useResourceFilters/FiltersSearchBar.d.ts +2 -2
- package/dist/ui/resources/useResourceFilters/activeFilters.d.ts +111 -0
- package/dist/ui/resources/useResourceFilters/activeFilters.test.d.ts +1 -0
- package/dist/ui/resources/useResourceFilters/types.d.ts +26 -0
- package/dist/ui/resources/useResourceFilters/useResourceFilters.d.ts +48 -0
- package/dist/ui/resources/useResourceList/adaptMetricsOrderToCore.d.ts +5 -0
- package/dist/ui/resources/useResourceList/listFetcher.d.ts +7 -1
- package/dist/ui/resources/useResourceList/useResourceList.d.ts +3 -1
- package/dist/ui/resources/useResourceTable/index.d.ts +2 -0
- package/dist/ui/resources/useResourceTable/types.d.ts +182 -0
- package/dist/ui/resources/useResourceTable/useResourceTable.d.ts +11 -0
- package/package.json +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JSX } from 'react';
|
|
2
2
|
import { SearchBarProps } from '../../composite/SearchBar';
|
|
3
3
|
import { FiltersInstructions } from './types';
|
|
4
|
-
export interface FilterSearchBarProps extends Pick<SearchBarProps, "placeholder" | "debounceMs"> {
|
|
4
|
+
export interface FilterSearchBarProps extends Pick<SearchBarProps, "placeholder" | "debounceMs" | "variant"> {
|
|
5
5
|
/**
|
|
6
6
|
* Array of instruction items to build the filters behaviors
|
|
7
7
|
*/
|
|
@@ -31,7 +31,7 @@ export interface FilterSearchBarProps extends Pick<SearchBarProps, "placeholder"
|
|
|
31
31
|
*/
|
|
32
32
|
predicateWhitelist: string[];
|
|
33
33
|
}
|
|
34
|
-
declare function FiltersSearchBar({ instructions, placeholder, onUpdate, queryString, predicateWhitelist, debounceMs, }: FilterSearchBarProps): JSX.Element;
|
|
34
|
+
declare function FiltersSearchBar({ instructions, placeholder, onUpdate, queryString, predicateWhitelist, debounceMs, variant, }: FilterSearchBarProps): JSX.Element;
|
|
35
35
|
declare namespace FiltersSearchBar {
|
|
36
36
|
var displayName: string;
|
|
37
37
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ListableResourceType } from '@commercelayer/sdk';
|
|
2
|
+
import { formatDateRange } from '../../../helpers/date';
|
|
3
|
+
import { CurrencyRangeFieldValue, FiltersInstructionItem, FiltersInstructions, FormFullValues, UiFilterValue } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Shared helpers to read the active filters out of a url query string and turn
|
|
6
|
+
* them into human readable labels.
|
|
7
|
+
*
|
|
8
|
+
* Used by both `FiltersNav` (legacy `ButtonFilter` look) and `FiltersBar`
|
|
9
|
+
* (metrics-style pills), so label resolution only ever has one implementation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getInstructionItemByFilterPredicate({ instructions, filterPredicate, }: {
|
|
12
|
+
instructions: FiltersInstructions;
|
|
13
|
+
filterPredicate: string;
|
|
14
|
+
}): FiltersInstructionItem | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Get label for user defined ButtonFilter component by reading the `instructionItem` object.
|
|
17
|
+
* If the filter has options and only one value is selected, the label will be the option label.
|
|
18
|
+
* Otherwise, the label will be the filter group label plus the number of selected values.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getButtonFilterLabel({ values, instructionItem, }: {
|
|
21
|
+
values: string | string[];
|
|
22
|
+
instructionItem: FiltersInstructionItem;
|
|
23
|
+
}): string;
|
|
24
|
+
export declare function extractCurrencyRangeFilterValues({ activeFilters, instructions, }: {
|
|
25
|
+
activeFilters: Array<[string, UiFilterValue]>;
|
|
26
|
+
instructions: FiltersInstructions;
|
|
27
|
+
}): Array<[string, CurrencyRangeFieldValue]>;
|
|
28
|
+
/**
|
|
29
|
+
* Checks if a filter predicate belongs to a currency range filter
|
|
30
|
+
* by checking the instructions
|
|
31
|
+
*/
|
|
32
|
+
export declare function predicateBelongsToCurrencyRange({ filterPredicate, instructions, }: {
|
|
33
|
+
filterPredicate: string;
|
|
34
|
+
instructions: FiltersInstructions;
|
|
35
|
+
}): boolean;
|
|
36
|
+
export declare function makeCurrencyRangeFilterButtonLabel(value: CurrencyRangeFieldValue): string;
|
|
37
|
+
/**
|
|
38
|
+
* Resolves every selected value to its option label and joins them.
|
|
39
|
+
*
|
|
40
|
+
* Unlike {@link getButtonFilterLabel}, which collapses multiple values into a
|
|
41
|
+
* counter (`Markets · 2`), this spells them all out (`Europe, Italy`) because a
|
|
42
|
+
* pill already shows the filter name separately.
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatPillFilterValue({ values, instructionItem, }: {
|
|
45
|
+
values: string | string[];
|
|
46
|
+
instructionItem: FiltersInstructionItem;
|
|
47
|
+
}): string;
|
|
48
|
+
/**
|
|
49
|
+
* Compares two filter values ignoring array wrapping and ordering, so that
|
|
50
|
+
* `"placed"`, `["placed"]` and `["placed"]` in a different order all match.
|
|
51
|
+
* Range values (objects) are compared as-is.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isSameFilterValue(a: unknown, b: unknown): boolean;
|
|
54
|
+
export interface PillFilter {
|
|
55
|
+
/**
|
|
56
|
+
* Predicate of the filter, or `timePreset` for the time range.
|
|
57
|
+
* Used as react key and to know what to reset when removing the pill.
|
|
58
|
+
*/
|
|
59
|
+
id: string;
|
|
60
|
+
/** Filter group label, e.g. `Payment status`. */
|
|
61
|
+
label: string;
|
|
62
|
+
/**
|
|
63
|
+
* Formatted value(s), e.g. `Paid, Authorized`.
|
|
64
|
+
* `undefined` when it has to be resolved by fetching the resource, see `fetch`.
|
|
65
|
+
*/
|
|
66
|
+
value?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Set for filters backed by a resource (`inputResourceGroup`, `inputSelect`),
|
|
69
|
+
* whose labels live on the resources themselves and have to be retrieved.
|
|
70
|
+
*/
|
|
71
|
+
fetch?: {
|
|
72
|
+
resource: ListableResourceType;
|
|
73
|
+
ids: string[];
|
|
74
|
+
fieldForLabel: string;
|
|
75
|
+
fieldForValue: string;
|
|
76
|
+
};
|
|
77
|
+
/** Which reset strategy the remove button has to apply. */
|
|
78
|
+
kind: "group" | "timeRange";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Reads the url query string and returns one descriptor per active filter, ready
|
|
82
|
+
* to be rendered as a pill.
|
|
83
|
+
*
|
|
84
|
+
* Filters matching `defaultValues` are omitted: on a page where the current view
|
|
85
|
+
* (e.g. a tab) already implies a set of filters, only the user's additions are
|
|
86
|
+
* worth showing as removable pills.
|
|
87
|
+
*
|
|
88
|
+
* The free text filter is always omitted, since it is already visible in the
|
|
89
|
+
* search bar, and so are hidden filters and `viewTitle`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function getPillFilters({ instructions, queryString, predicateWhitelist, defaultValues, timezone, locale, }: {
|
|
92
|
+
instructions: FiltersInstructions;
|
|
93
|
+
queryString: string;
|
|
94
|
+
predicateWhitelist: string[];
|
|
95
|
+
defaultValues?: FormFullValues;
|
|
96
|
+
timezone?: string;
|
|
97
|
+
locale?: Parameters<typeof formatDateRange>[0]["locale"];
|
|
98
|
+
}): PillFilter[];
|
|
99
|
+
/**
|
|
100
|
+
* Form values to apply when clearing all the filters at once.
|
|
101
|
+
*
|
|
102
|
+
* Hidden filters, `viewTitle` and the free text search are preserved — they are
|
|
103
|
+
* not represented as pills, so wiping them would be an invisible side effect.
|
|
104
|
+
* Everything else goes back to `defaultValues` (empty when not provided).
|
|
105
|
+
*/
|
|
106
|
+
export declare function getClearedFormValues({ instructions, queryString, predicateWhitelist, defaultValues, }: {
|
|
107
|
+
instructions: FiltersInstructions;
|
|
108
|
+
queryString: string;
|
|
109
|
+
predicateWhitelist: string[];
|
|
110
|
+
defaultValues?: FormFullValues;
|
|
111
|
+
}): FormFullValues;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -138,6 +138,32 @@ export type FilterItemOptions = BaseFilterItem & {
|
|
|
138
138
|
* props required for the UI component
|
|
139
139
|
*/
|
|
140
140
|
props: Omit<InputResourceGroupProps, "onChange" | "defaultValues" | "title">;
|
|
141
|
+
} | {
|
|
142
|
+
/**
|
|
143
|
+
* UI component to render: a select dropdown, matching the style of the
|
|
144
|
+
* dashboard metrics filters. Prefer it over `inputResourceGroup` when the
|
|
145
|
+
* options are many, since it searches server-side instead of showing a
|
|
146
|
+
* checkbox list with a "see all" overlay.
|
|
147
|
+
*/
|
|
148
|
+
component: "inputSelect";
|
|
149
|
+
/**
|
|
150
|
+
* props required for the UI component
|
|
151
|
+
*/
|
|
152
|
+
props: Pick<InputResourceGroupProps, "resource" | "fieldForLabel" | "fieldForValue" | "searchBy" | "sortBy" | "filters" | "hideWhenSingleItem"> & {
|
|
153
|
+
/**
|
|
154
|
+
* How many options to load upfront. Capped at 25 by the Core API, which
|
|
155
|
+
* is why `searchBy` should be set when more options exist.
|
|
156
|
+
* @default 25
|
|
157
|
+
*/
|
|
158
|
+
limit?: number;
|
|
159
|
+
placeholder?: string;
|
|
160
|
+
isClearable?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Filter predicates are usually `_in`, so multiple values are expected.
|
|
163
|
+
* @default true
|
|
164
|
+
*/
|
|
165
|
+
isMulti?: boolean;
|
|
166
|
+
};
|
|
141
167
|
};
|
|
142
168
|
};
|
|
143
169
|
export interface FilterItemTextSearch extends Omit<BaseFilterItem, "sdk"> {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ListableResourceType, QueryFilter } from '@commercelayer/sdk';
|
|
2
|
+
import { SearchBarProps } from '../../composite/SearchBar';
|
|
2
3
|
import { UseResourceListConfig } from '../useResourceList';
|
|
3
4
|
import { ResourceListProps } from '../useResourceList/useResourceList';
|
|
5
|
+
import { ResourceTableProps, UseResourceTableConfig } from '../useResourceTable/types';
|
|
4
6
|
import { makeFilterAdapters } from './adapters';
|
|
7
|
+
import { FiltersBarProps } from './FiltersBar';
|
|
8
|
+
import { FiltersDrawerProps } from './FiltersDrawer';
|
|
5
9
|
import { FiltersFormProps } from './FiltersForm';
|
|
6
10
|
import { FiltersNavProps } from './FiltersNav';
|
|
7
11
|
import { FiltersInstructions } from './types';
|
|
@@ -29,8 +33,34 @@ interface UseResourceFiltersHook {
|
|
|
29
33
|
* Helper methods to transform filters from/to url query string, sdk and form values
|
|
30
34
|
*/
|
|
31
35
|
adapters: ReturnType<typeof makeFilterAdapters>;
|
|
36
|
+
/**
|
|
37
|
+
* Search bar with the filters button on the right and the applied filters
|
|
38
|
+
* rendered as removable pills below.
|
|
39
|
+
*
|
|
40
|
+
* Clicking the filters button opens the drawer rendered by `FiltersDrawer`,
|
|
41
|
+
* unless an `onFilterClick` prop is provided.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```jsx
|
|
45
|
+
* const { FiltersBar, FiltersDrawer, FilteredTable } = useResourceFilters({ instructions })
|
|
46
|
+
*
|
|
47
|
+
* <FiltersBar queryString={queryString} onUpdate={onUpdate} />
|
|
48
|
+
* <FilteredTable type='orders' columns={columns} />
|
|
49
|
+
* <FiltersDrawer onUpdate={onUpdate} />
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
FiltersBar: (props: FiltersBarProps) => React.ReactNode;
|
|
53
|
+
/**
|
|
54
|
+
* Side drawer with the filters form, opened by the `FiltersBar` filters button.
|
|
55
|
+
* Render it once per page as a sibling of `FiltersBar`.
|
|
56
|
+
*/
|
|
57
|
+
FiltersDrawer: (props: FiltersDrawerProps) => React.ReactNode;
|
|
32
58
|
/**
|
|
33
59
|
* Search bar component with filters navigation buttons
|
|
60
|
+
*
|
|
61
|
+
* @deprecated Use `FiltersBar` together with `FiltersDrawer` instead, they
|
|
62
|
+
* render the search bar and the filters as pills in the style used by the
|
|
63
|
+
* dashboard. This component will be removed in a future major release.
|
|
34
64
|
*/
|
|
35
65
|
SearchWithNav: (props: Pick<FiltersNavProps, "onFilterClick" | "queryString"> & {
|
|
36
66
|
/**
|
|
@@ -44,6 +74,11 @@ interface UseResourceFiltersHook {
|
|
|
44
74
|
* @default 'Search...'
|
|
45
75
|
*/
|
|
46
76
|
searchBarPlaceholder?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Visual variant of the search bar. Use `outline` to match the style used
|
|
79
|
+
* in the dashboard (metrics) pages.
|
|
80
|
+
*/
|
|
81
|
+
searchBarVariant?: SearchBarProps["variant"];
|
|
47
82
|
/**
|
|
48
83
|
* Milliseconds to wait before triggering the search bar callback
|
|
49
84
|
* @default 500
|
|
@@ -65,6 +100,19 @@ interface UseResourceFiltersHook {
|
|
|
65
100
|
};
|
|
66
101
|
hideTitle?: boolean;
|
|
67
102
|
}) => React.ReactNode;
|
|
103
|
+
/**
|
|
104
|
+
* Filtered ResourceTable component based on current active filters.
|
|
105
|
+
* Table sibling of `FilteredList`: renders a column-model data table wired
|
|
106
|
+
* to the active search/filters and pagination.
|
|
107
|
+
*/
|
|
108
|
+
FilteredTable: <TResource extends ListableResourceType>(props: Omit<UseResourceTableConfig<TResource>, "query" | "metricsQuery"> & ResourceTableProps & {
|
|
109
|
+
query?: Omit<NonNullable<UseResourceTableConfig<TResource>["query"]>, "filters">;
|
|
110
|
+
metricsQuery?: Omit<NonNullable<UseResourceTableConfig<TResource>["metricsQuery"]>, "filter"> & {
|
|
111
|
+
/** Filters need to be configured within the `useResourceFilters` options. */
|
|
112
|
+
filter?: never;
|
|
113
|
+
};
|
|
114
|
+
hideTitle?: boolean;
|
|
115
|
+
}) => React.ReactNode;
|
|
68
116
|
/**
|
|
69
117
|
* SDK filters object to be used in the sdk query
|
|
70
118
|
*/
|
|
@@ -70,5 +70,10 @@ export interface MetricsResourceOrder {
|
|
|
70
70
|
first_name?: string;
|
|
71
71
|
last_name?: string;
|
|
72
72
|
};
|
|
73
|
+
customer?: {
|
|
74
|
+
id?: string;
|
|
75
|
+
email?: string;
|
|
76
|
+
total_orders_count?: number;
|
|
77
|
+
};
|
|
73
78
|
}
|
|
74
79
|
export declare function adaptMetricsOrderToCore(metricsOrder: MetricsResourceOrder): Order;
|
|
@@ -12,11 +12,17 @@ export interface FetcherResponse<TResource> {
|
|
|
12
12
|
cursor?: string | null;
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export declare function listFetcher<TResource extends ListableResourceType>({ currentData, resourceType, client, clientType, query, mode, pageNumber, }: {
|
|
15
|
+
export declare function listFetcher<TResource extends ListableResourceType>({ currentData, resourceType, client, clientType, query, mode, pageNumber, cursor, }: {
|
|
16
16
|
currentData?: FetcherResponse<Resource<TResource>>;
|
|
17
17
|
resourceType: TResource;
|
|
18
18
|
mode?: "infinite" | "pagination";
|
|
19
19
|
pageNumber?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Metrics API only: the cursor that opens the requested page. Used in
|
|
22
|
+
* `pagination` mode, where the caller keeps track of one cursor per page
|
|
23
|
+
* (the metrics API can only move forward on its own).
|
|
24
|
+
*/
|
|
25
|
+
cursor?: string | null;
|
|
20
26
|
} & ({
|
|
21
27
|
client: CommerceLayerBundle;
|
|
22
28
|
clientType: "coreSdkClient";
|
|
@@ -79,7 +79,9 @@ export type UseResourceListConfig<TResource extends ListableResourceType> = {
|
|
|
79
79
|
preProcess?: (list: Array<Resource<TResource>>) => Array<Resource<TResource>>;
|
|
80
80
|
/**
|
|
81
81
|
* Pagination type: 'infinite' for infinite scrolling (default), 'pagination' for classic prev/next pagination.
|
|
82
|
-
*
|
|
82
|
+
* Works with both the Core API and the Metrics API. Since the Metrics API is
|
|
83
|
+
* cursor-based, prev/next works by remembering the cursor that opens each
|
|
84
|
+
* visited page; arbitrary page jumps are not possible there.
|
|
83
85
|
*/
|
|
84
86
|
paginationType?: "infinite" | "pagination";
|
|
85
87
|
/**
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { ListableResourceType } from '@commercelayer/sdk';
|
|
2
|
+
import { FC, ReactNode } from 'react';
|
|
3
|
+
import { SectionProps } from '../../atoms/Section';
|
|
4
|
+
import { Resource } from '../useResourceList/listFetcher';
|
|
5
|
+
import { UseResourceListConfig } from '../useResourceList/useResourceList';
|
|
6
|
+
/**
|
|
7
|
+
* A single column definition for a `ResourceTable`.
|
|
8
|
+
*
|
|
9
|
+
* This is app-elements' own column type: TanStack Table is an implementation
|
|
10
|
+
* detail and its `ColumnDef` is intentionally not exposed here (see
|
|
11
|
+
* `docs/adr/0001-encapsulate-tanstack-table.md`).
|
|
12
|
+
*/
|
|
13
|
+
export interface ResourceTableColumn<TResource extends ListableResourceType> {
|
|
14
|
+
/**
|
|
15
|
+
* Header content. A plain string or any node (icon, tooltip, …).
|
|
16
|
+
*/
|
|
17
|
+
header: ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Cell renderer for this column. Receives the fetched resource for the row
|
|
20
|
+
* and returns whatever should be displayed in the cell.
|
|
21
|
+
*/
|
|
22
|
+
cell: (props: {
|
|
23
|
+
resource: Resource<TResource>;
|
|
24
|
+
}) => ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Stable, unique column id.
|
|
27
|
+
* When omitted it falls back to `sortBy`, then to a positional `col-<index>`.
|
|
28
|
+
* Provide one explicitly when two columns would otherwise collide.
|
|
29
|
+
*/
|
|
30
|
+
id?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Horizontal alignment applied to both the header and the cells.
|
|
33
|
+
* @default 'left'
|
|
34
|
+
*/
|
|
35
|
+
align?: "left" | "right" | "center";
|
|
36
|
+
/**
|
|
37
|
+
* Optional CSS class applied to the column header, typically for width
|
|
38
|
+
* control (e.g. `"w-1/2"`).
|
|
39
|
+
*/
|
|
40
|
+
width?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Hide this column below the given breakpoint; it is shown at that width and
|
|
43
|
+
* up. These are app-elements' own breakpoints (see `styles/global.css`, which
|
|
44
|
+
* resets Tailwind's defaults): `md` 768px, `lg` 992px, `xl` 1280px. There is
|
|
45
|
+
* deliberately no `sm`.
|
|
46
|
+
*
|
|
47
|
+
* Common cases: `"md"` hides on mobile (shown on tablet + desktop), `"lg"`
|
|
48
|
+
* shows on desktop only. The column's data is still fetched; only its
|
|
49
|
+
* rendering is suppressed via CSS, so there is no layout shift on resize.
|
|
50
|
+
*/
|
|
51
|
+
hideBelow?: "md" | "lg" | "xl";
|
|
52
|
+
/**
|
|
53
|
+
* When set, the column becomes sortable and this value is the CommerceLayer
|
|
54
|
+
* SDK sort attribute it sorts by (e.g. `"created_at"`).
|
|
55
|
+
*
|
|
56
|
+
* Sorting is server-side: clicking the header drives the SDK `sort` query
|
|
57
|
+
* param and refetches. Rows are never reordered client-side.
|
|
58
|
+
*/
|
|
59
|
+
sortBy?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* SDK sort expression, e.g. `"created_at"` (asc) or `"-created_at"` (desc).
|
|
63
|
+
* `undefined` means no explicit table sort is applied.
|
|
64
|
+
*/
|
|
65
|
+
export type ResourceTableSort = string | undefined;
|
|
66
|
+
export type UseResourceTableConfig<TResource extends ListableResourceType> = Omit<UseResourceListConfig<TResource>, "metricsQuery" | "query"> & {
|
|
67
|
+
/** The columns to render, in display order. */
|
|
68
|
+
columns: Array<ResourceTableColumn<TResource>>;
|
|
69
|
+
/**
|
|
70
|
+
* SDK query object, excluding `pageNumber` (handled internally) and
|
|
71
|
+
* `sort` (owned by the table's sorting state — set the initial sort with
|
|
72
|
+
* `sort` instead).
|
|
73
|
+
*/
|
|
74
|
+
query?: Omit<NonNullable<UseResourceListConfig<TResource>["query"]>, "sort">;
|
|
75
|
+
/**
|
|
76
|
+
* When set, data is fetched from the Metrics API instead of the Core API.
|
|
77
|
+
*
|
|
78
|
+
* Sorting still works: a column's `sortBy` is sent as the metrics
|
|
79
|
+
* `search.sort_by` (so use metrics attribute names, e.g. `"order.placed_at"`)
|
|
80
|
+
* together with the matching `search.sort` direction — omit `search.sort_by`
|
|
81
|
+
* here and let the table own it.
|
|
82
|
+
*/
|
|
83
|
+
metricsQuery?: {
|
|
84
|
+
search: {
|
|
85
|
+
limit?: number;
|
|
86
|
+
fields?: string[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Metrics filters. When the table is rendered through
|
|
90
|
+
* `useResourceFilters`' `FilteredTable`, this is injected from the active
|
|
91
|
+
* filters and must not be set here.
|
|
92
|
+
*/
|
|
93
|
+
filter?: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Optional row-level click handler. When provided the whole row becomes
|
|
97
|
+
* interactive (hover affordance + click). Use it to navigate with your
|
|
98
|
+
* app's router.
|
|
99
|
+
*
|
|
100
|
+
* The click event is passed as second argument, so it can be forwarded to
|
|
101
|
+
* helpers that need it (e.g. `navigateTo(...).onClick`).
|
|
102
|
+
*/
|
|
103
|
+
onRowClick?: (resource: Resource<TResource>, event: React.MouseEvent<HTMLElement>) => void;
|
|
104
|
+
/**
|
|
105
|
+
* Return an href to make each row a real link (rendered as a stretched
|
|
106
|
+
* anchor over the row). This enables native link behavior — cmd/ctrl/middle
|
|
107
|
+
* click opens the row in a new tab, and the URL shows on hover.
|
|
108
|
+
*
|
|
109
|
+
* Combine with `onRowClick` for client-side navigation: a plain click calls
|
|
110
|
+
* `onRowClick` (and suppresses the default navigation), while modified
|
|
111
|
+
* clicks fall through to the browser. Return `undefined` to leave a row
|
|
112
|
+
* non-navigable.
|
|
113
|
+
*
|
|
114
|
+
* Note: avoid interactive elements in the first column when using this — the
|
|
115
|
+
* stretched anchor sits over the row (in-cell controls would need their own
|
|
116
|
+
* `relative`/`z-10` to stay clickable).
|
|
117
|
+
*/
|
|
118
|
+
getRowHref?: (resource: Resource<TResource>) => string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Controlled sort value (SDK sort expression, e.g. `"-created_at"`).
|
|
121
|
+
* Pass together with `onSortChange` to own the sort state (e.g. persist it
|
|
122
|
+
* in the URL). When omitted the table manages sort internally.
|
|
123
|
+
*/
|
|
124
|
+
sort?: ResourceTableSort;
|
|
125
|
+
/**
|
|
126
|
+
* Called when the user changes the sort. Provide together with `sort` for
|
|
127
|
+
* controlled mode; the callback receives the new SDK sort expression (or
|
|
128
|
+
* `undefined` when sorting is cleared).
|
|
129
|
+
*/
|
|
130
|
+
onSortChange?: (sort: ResourceTableSort) => void;
|
|
131
|
+
/**
|
|
132
|
+
* Initial sort used only when the table manages sort internally
|
|
133
|
+
* (uncontrolled). Ignored when `sort`/`onSortChange` are provided.
|
|
134
|
+
*/
|
|
135
|
+
defaultSort?: ResourceTableSort;
|
|
136
|
+
};
|
|
137
|
+
/** Props of the `ResourceTable` component returned by the hook. */
|
|
138
|
+
export interface ResourceTableProps {
|
|
139
|
+
/** Title. Can be a node or a function receiving the record count. */
|
|
140
|
+
title?: ((recordCount: number | undefined) => ReactNode) | ReactNode;
|
|
141
|
+
/** Action button rendered next to the title. */
|
|
142
|
+
actionButton?: SectionProps["actionButton"];
|
|
143
|
+
/**
|
|
144
|
+
* Rendered when the table has no rows.
|
|
145
|
+
* When omitted, a default message based on the resource name is shown.
|
|
146
|
+
*/
|
|
147
|
+
emptyState?: ReactNode;
|
|
148
|
+
/** Force the title size. Defaults to `normal`. */
|
|
149
|
+
titleSize?: SectionProps["titleSize"];
|
|
150
|
+
/** `boxed` wraps the table in a bordered card. */
|
|
151
|
+
variant?: "boxed";
|
|
152
|
+
/**
|
|
153
|
+
* How the table behaves when its content is wider than the container.
|
|
154
|
+
* - `"fit"` (default): the table fills the container width; columns share the
|
|
155
|
+
* available space (and wrap/shrink). Pair with `hideBelow` on columns to
|
|
156
|
+
* drop low-value columns on small screens.
|
|
157
|
+
* - `"scroll"`: the table keeps its natural (unwrapped) width and scrolls
|
|
158
|
+
* horizontally inside its own container; the title/action button stay fixed.
|
|
159
|
+
* @default 'fit'
|
|
160
|
+
*/
|
|
161
|
+
layout?: "fit" | "scroll";
|
|
162
|
+
}
|
|
163
|
+
export interface UseResourceTableReturn<TResource extends ListableResourceType> {
|
|
164
|
+
/** The component that renders the data table. */
|
|
165
|
+
ResourceTable: FC<ResourceTableProps>;
|
|
166
|
+
/** Prev/next pagination controls. Renders `null` unless in `pagination` mode with more than one page. */
|
|
167
|
+
Pagination: FC;
|
|
168
|
+
/** The rows currently displayed (current page, or accumulated in infinite mode). */
|
|
169
|
+
list?: Array<Resource<TResource>>;
|
|
170
|
+
/** SDK pagination metadata. */
|
|
171
|
+
meta?: import('../useResourceList/listFetcher').FetcherResponse<Resource<TResource>>["meta"];
|
|
172
|
+
isLoading: boolean;
|
|
173
|
+
isFirstLoading: boolean;
|
|
174
|
+
error?: string;
|
|
175
|
+
/** Removes a row from the UI only (call after a successful delete API call). */
|
|
176
|
+
removeItem: (resourceId: string) => void;
|
|
177
|
+
/** Clears fetched data and refetches from the first page. */
|
|
178
|
+
refresh: () => void;
|
|
179
|
+
hasMorePages?: boolean;
|
|
180
|
+
/** The active sort (SDK sort expression), whether controlled or internal. */
|
|
181
|
+
sort: ResourceTableSort;
|
|
182
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ListableResourceType } from '@commercelayer/sdk';
|
|
2
|
+
import { UseResourceTableConfig, UseResourceTableReturn } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* `useResourceTable` fetches a CommerceLayer resource type and renders it as a
|
|
5
|
+
* data table driven by a column model, backed by TanStack Table v9.
|
|
6
|
+
*
|
|
7
|
+
* It reuses `useResourceList`'s fetch/pagination layer verbatim and only
|
|
8
|
+
* replaces item rendering with a TanStack-driven table. Sorting, filtering,
|
|
9
|
+
* search and pagination are all resolved server-side.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useResourceTable<TResource extends ListableResourceType>(config: UseResourceTableConfig<TResource>): UseResourceTableReturn<TResource>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercelayer/app-elements",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@commercelayer/sdk": "8.0.0-beta.11",
|
|
39
39
|
"@date-fns/tz": "^1.5.0",
|
|
40
40
|
"@monaco-editor/react": "~4.7.0",
|
|
41
|
+
"@tanstack/react-table": "^9.0.0",
|
|
41
42
|
"@types/lodash-es": "^4.17.12",
|
|
42
43
|
"@types/react": "19.2.13",
|
|
43
44
|
"@types/react-datepicker": "^7.0.0",
|