@richardmcquiston01/dashboard-widgets-toolkit 0.4.1 → 0.5.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/README.md +3 -370
- package/dist/react.cjs +23 -14
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +12 -6
- package/dist/react.d.ts +12 -6
- package/dist/react.js +23 -14
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.d.cts
CHANGED
|
@@ -88,8 +88,10 @@ declare function GraphWidget({ data, title, }: {
|
|
|
88
88
|
/**
|
|
89
89
|
* Loads a widget's full detail data. Close over your own context (a Prisma
|
|
90
90
|
* client, a fetch) here; the package never fetches. See `DetailProvider`.
|
|
91
|
+
* Return `undefined` for a widget you have no extra data for: the card's own
|
|
92
|
+
* data is used when it is complete (see `deriveDetailData`).
|
|
91
93
|
*/
|
|
92
|
-
type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | Promise<DetailData>;
|
|
94
|
+
type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | undefined | Promise<DetailData | undefined>;
|
|
93
95
|
interface WidgetDetailProps {
|
|
94
96
|
/** Table caption: the widget's title. */
|
|
95
97
|
readonly title: string;
|
|
@@ -135,9 +137,12 @@ interface DetailLoadState {
|
|
|
135
137
|
/**
|
|
136
138
|
* Loads a widget's detail data while `enabled`: calls `load` with an abort
|
|
137
139
|
* signal (aborted on close, retry or unmount), validates the result and
|
|
138
|
-
* reports loading, ok or error. `
|
|
140
|
+
* reports loading, ok or error. When `load` is missing or returns
|
|
141
|
+
* `undefined`, `fallback` (for example the card's own complete data) is used
|
|
142
|
+
* instead. `reload` runs it again. Keep `load` and `fallback` referentially
|
|
143
|
+
* stable (`useCallback` / `useMemo`): a new value restarts the load.
|
|
139
144
|
*/
|
|
140
|
-
declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean): {
|
|
145
|
+
declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean, fallback?: DetailData): {
|
|
141
146
|
readonly state: DetailLoadState;
|
|
142
147
|
readonly reload: () => void;
|
|
143
148
|
};
|
|
@@ -228,9 +233,10 @@ interface DashboardProps extends WidgetSettings {
|
|
|
228
233
|
readonly onRetry?: (key: string) => void;
|
|
229
234
|
/**
|
|
230
235
|
* Loads the full data for a widget's detail view (widgets whose definition
|
|
231
|
-
* sets `detail`). Close over your own context.
|
|
232
|
-
*
|
|
233
|
-
*
|
|
236
|
+
* sets `detail`). Close over your own context. Return `undefined` for a
|
|
237
|
+
* widget you have no extra data for: a TABLE with no footer or a BAR_LIST
|
|
238
|
+
* then shows its card data. Without `loadDetail`, those two still work and
|
|
239
|
+
* other widgets get no View button.
|
|
234
240
|
*/
|
|
235
241
|
readonly loadDetail?: DetailLoader;
|
|
236
242
|
/**
|
package/dist/react.d.ts
CHANGED
|
@@ -88,8 +88,10 @@ declare function GraphWidget({ data, title, }: {
|
|
|
88
88
|
/**
|
|
89
89
|
* Loads a widget's full detail data. Close over your own context (a Prisma
|
|
90
90
|
* client, a fetch) here; the package never fetches. See `DetailProvider`.
|
|
91
|
+
* Return `undefined` for a widget you have no extra data for: the card's own
|
|
92
|
+
* data is used when it is complete (see `deriveDetailData`).
|
|
91
93
|
*/
|
|
92
|
-
type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | Promise<DetailData>;
|
|
94
|
+
type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | undefined | Promise<DetailData | undefined>;
|
|
93
95
|
interface WidgetDetailProps {
|
|
94
96
|
/** Table caption: the widget's title. */
|
|
95
97
|
readonly title: string;
|
|
@@ -135,9 +137,12 @@ interface DetailLoadState {
|
|
|
135
137
|
/**
|
|
136
138
|
* Loads a widget's detail data while `enabled`: calls `load` with an abort
|
|
137
139
|
* signal (aborted on close, retry or unmount), validates the result and
|
|
138
|
-
* reports loading, ok or error. `
|
|
140
|
+
* reports loading, ok or error. When `load` is missing or returns
|
|
141
|
+
* `undefined`, `fallback` (for example the card's own complete data) is used
|
|
142
|
+
* instead. `reload` runs it again. Keep `load` and `fallback` referentially
|
|
143
|
+
* stable (`useCallback` / `useMemo`): a new value restarts the load.
|
|
139
144
|
*/
|
|
140
|
-
declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean): {
|
|
145
|
+
declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean, fallback?: DetailData): {
|
|
141
146
|
readonly state: DetailLoadState;
|
|
142
147
|
readonly reload: () => void;
|
|
143
148
|
};
|
|
@@ -228,9 +233,10 @@ interface DashboardProps extends WidgetSettings {
|
|
|
228
233
|
readonly onRetry?: (key: string) => void;
|
|
229
234
|
/**
|
|
230
235
|
* Loads the full data for a widget's detail view (widgets whose definition
|
|
231
|
-
* sets `detail`). Close over your own context.
|
|
232
|
-
*
|
|
233
|
-
*
|
|
236
|
+
* sets `detail`). Close over your own context. Return `undefined` for a
|
|
237
|
+
* widget you have no extra data for: a TABLE with no footer or a BAR_LIST
|
|
238
|
+
* then shows its card data. Without `loadDetail`, those two still work and
|
|
239
|
+
* other widgets get no View button.
|
|
234
240
|
*/
|
|
235
241
|
readonly loadDetail?: DetailLoader;
|
|
236
242
|
/**
|
package/dist/react.js
CHANGED
|
@@ -1783,22 +1783,30 @@ function WidgetDetailDialog({
|
|
|
1783
1783
|
}
|
|
1784
1784
|
);
|
|
1785
1785
|
}
|
|
1786
|
-
function useDetailData(definition, load, enabled) {
|
|
1786
|
+
function useDetailData(definition, load, enabled, fallback) {
|
|
1787
1787
|
const [state, setState] = useState({ status: "loading" });
|
|
1788
1788
|
const [attempt, setAttempt] = useState(0);
|
|
1789
1789
|
useEffect(() => {
|
|
1790
|
-
if (!enabled
|
|
1790
|
+
if (!enabled) return void 0;
|
|
1791
1791
|
const controller = new AbortController();
|
|
1792
1792
|
setState({ status: "loading" });
|
|
1793
1793
|
Promise.resolve().then(
|
|
1794
|
-
() => load(definition, {
|
|
1794
|
+
() => load === void 0 ? void 0 : load(definition, {
|
|
1795
1795
|
signal: controller.signal,
|
|
1796
1796
|
query: defaultDetailQuery()
|
|
1797
1797
|
})
|
|
1798
1798
|
).then((raw) => {
|
|
1799
1799
|
if (controller.signal.aborted) return;
|
|
1800
|
+
const data = raw ?? fallback;
|
|
1801
|
+
if (data === void 0) {
|
|
1802
|
+
setState({
|
|
1803
|
+
status: "error",
|
|
1804
|
+
error: `Widget "${definition.key}" detail: no data. The loader returned nothing for this widget and its card does not hold the full data (use a loader that returns rows, or a TABLE without a footer or a BAR_LIST).`
|
|
1805
|
+
});
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1800
1808
|
const checked = validateDetailData(
|
|
1801
|
-
|
|
1809
|
+
data,
|
|
1802
1810
|
`Widget "${definition.key}" detail`
|
|
1803
1811
|
);
|
|
1804
1812
|
setState(
|
|
@@ -1812,7 +1820,7 @@ function useDetailData(definition, load, enabled) {
|
|
|
1812
1820
|
});
|
|
1813
1821
|
});
|
|
1814
1822
|
return () => controller.abort();
|
|
1815
|
-
}, [enabled, load, definition, attempt]);
|
|
1823
|
+
}, [enabled, load, fallback, definition, attempt]);
|
|
1816
1824
|
return { state, reload: () => setAttempt((count) => count + 1) };
|
|
1817
1825
|
}
|
|
1818
1826
|
var NARROW_VIEWPORT_QUERY = "(max-width: 640px)";
|
|
@@ -1910,12 +1918,16 @@ function DetailHost({
|
|
|
1910
1918
|
const options = resolveDetailOptions(definition);
|
|
1911
1919
|
const pageSize = options?.pageSize ?? 25;
|
|
1912
1920
|
const [query, setQuery] = useState(defaultDetailQuery(pageSize));
|
|
1913
|
-
const derived =
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1921
|
+
const derived = useMemo(
|
|
1922
|
+
() => widget.status === "ok" ? deriveDetailData(widget.data, locale) : void 0,
|
|
1923
|
+
[widget, locale]
|
|
1924
|
+
);
|
|
1925
|
+
const { state, reload } = useDetailData(
|
|
1926
|
+
definition,
|
|
1927
|
+
loadDetail,
|
|
1928
|
+
true,
|
|
1929
|
+
derived
|
|
1917
1930
|
);
|
|
1918
|
-
const { state, reload } = useDetailData(definition, load, true);
|
|
1919
1931
|
const title = options?.title ?? definition.title;
|
|
1920
1932
|
return /* @__PURE__ */ jsx(WidgetDetailDialog, { title, open: true, onClose, children: /* @__PURE__ */ jsx(
|
|
1921
1933
|
WidgetDetail,
|
|
@@ -1923,10 +1935,7 @@ function DetailHost({
|
|
|
1923
1935
|
title,
|
|
1924
1936
|
query,
|
|
1925
1937
|
onQueryChange: setQuery,
|
|
1926
|
-
status:
|
|
1927
|
-
...load === void 0 ? {
|
|
1928
|
-
error: `Widget "${definition.key}" has no detail data: pass loadDetail, or use a TABLE without a footer or a BAR_LIST.`
|
|
1929
|
-
} : {},
|
|
1938
|
+
status: state.status,
|
|
1930
1939
|
...state.data === void 0 ? {} : { data: state.data },
|
|
1931
1940
|
...state.error === void 0 ? {} : { error: state.error },
|
|
1932
1941
|
onRetry: reload
|