@richardmcquiston01/dashboard-widgets-toolkit 0.16.0 → 0.17.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/react.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ReactElement, RefObject } from 'react';
2
- import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, O as OptionValues, L as Locale, f as DashboardLayout, g as WidgetViewerSettings, h as WidgetSettingsPatch, A as AlertListWidgetData, B as BarListWidgetData, i as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, R as ResolvedTableControls, j as DetailSort, k as TextWidgetData, l as WidgetData, m as LayoutPersistence, S as StoreScope, P as PageItem, n as NormalizeOptions, o as ResolveOptions, p as WidgetContext, q as WidgetProviders } from './storage-oivwB7al.cjs';
2
+ import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, O as OptionValues, L as Locale, f as DashboardLayout, g as WidgetViewerSettings, h as WidgetSettingsPatch, A as AlertListWidgetData, B as BarListWidgetData, i as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, R as ResolvedTableControls, j as DetailSort, k as TextWidgetData, l as WidgetData, m as LayoutPersistence, S as StoreScope, P as PageItem, n as NormalizeOptions, o as ResolveOptions, p as WidgetContext, q as WidgetProviders } from './storage-CRBfjiVZ.cjs';
3
3
 
4
4
  interface WidgetCardProps {
5
5
  readonly title: string;
@@ -566,6 +566,13 @@ interface UseWidgetsOptions extends ResolveOptions {
566
566
  * fresh object each render.
567
567
  */
568
568
  readonly optionValues?: Readonly<Record<string, Readonly<Record<string, unknown>> | undefined>>;
569
+ /**
570
+ * The view each widget shows, by widget key (see `viewValuesFromLayout`).
571
+ * Only views the provider supplies matter: choosing one loads it (the
572
+ * provider is called with `options.view`), and the card shows loading until
573
+ * it arrives. It may be a fresh object each render.
574
+ */
575
+ readonly viewValues?: Readonly<Record<string, string | undefined>>;
569
576
  }
570
577
  interface UseWidgetsResult {
571
578
  /** Pass to `Dashboard` or `WidgetGrid`: placeholders first, then results. */
@@ -574,6 +581,8 @@ interface UseWidgetsResult {
574
581
  readonly refresh: (key?: string) => void;
575
582
  /** Choose option values for one widget; same effect as `optionValues`. */
576
583
  readonly setOptions: (key: string, chosen: Readonly<Record<string, unknown>>) => void;
584
+ /** Choose a widget's view; same effect as `viewValues`. */
585
+ readonly setView: (key: string, view: string | undefined) => void;
577
586
  /**
578
587
  * For `loadWhen: 'visible'`: attach to any element that contains the cards,
579
588
  * for example a wrapper `<div ref={gridRef}>` around `Dashboard`.
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ReactElement, RefObject } from 'react';
2
- import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, O as OptionValues, L as Locale, f as DashboardLayout, g as WidgetViewerSettings, h as WidgetSettingsPatch, A as AlertListWidgetData, B as BarListWidgetData, i as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, R as ResolvedTableControls, j as DetailSort, k as TextWidgetData, l as WidgetData, m as LayoutPersistence, S as StoreScope, P as PageItem, n as NormalizeOptions, o as ResolveOptions, p as WidgetContext, q as WidgetProviders } from './storage-oivwB7al.js';
2
+ import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, O as OptionValues, L as Locale, f as DashboardLayout, g as WidgetViewerSettings, h as WidgetSettingsPatch, A as AlertListWidgetData, B as BarListWidgetData, i as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, R as ResolvedTableControls, j as DetailSort, k as TextWidgetData, l as WidgetData, m as LayoutPersistence, S as StoreScope, P as PageItem, n as NormalizeOptions, o as ResolveOptions, p as WidgetContext, q as WidgetProviders } from './storage-CRBfjiVZ.js';
3
3
 
4
4
  interface WidgetCardProps {
5
5
  readonly title: string;
@@ -566,6 +566,13 @@ interface UseWidgetsOptions extends ResolveOptions {
566
566
  * fresh object each render.
567
567
  */
568
568
  readonly optionValues?: Readonly<Record<string, Readonly<Record<string, unknown>> | undefined>>;
569
+ /**
570
+ * The view each widget shows, by widget key (see `viewValuesFromLayout`).
571
+ * Only views the provider supplies matter: choosing one loads it (the
572
+ * provider is called with `options.view`), and the card shows loading until
573
+ * it arrives. It may be a fresh object each render.
574
+ */
575
+ readonly viewValues?: Readonly<Record<string, string | undefined>>;
569
576
  }
570
577
  interface UseWidgetsResult {
571
578
  /** Pass to `Dashboard` or `WidgetGrid`: placeholders first, then results. */
@@ -574,6 +581,8 @@ interface UseWidgetsResult {
574
581
  readonly refresh: (key?: string) => void;
575
582
  /** Choose option values for one widget; same effect as `optionValues`. */
576
583
  readonly setOptions: (key: string, chosen: Readonly<Record<string, unknown>>) => void;
584
+ /** Choose a widget's view; same effect as `viewValues`. */
585
+ readonly setView: (key: string, view: string | undefined) => void;
577
586
  /**
578
587
  * For `loadWhen: 'visible'`: attach to any element that contains the cards,
579
588
  * for example a wrapper `<div ref={gridRef}>` around `Dashboard`.
package/dist/react.js CHANGED
@@ -2066,6 +2066,9 @@ function viewChoices(item) {
2066
2066
  }))
2067
2067
  ];
2068
2068
  }
2069
+ function isProviderView(view) {
2070
+ return view.convert === void 0;
2071
+ }
2069
2072
  function isKnownView(item, key) {
2070
2073
  return key !== void 0 && (key === BASE_VIEW_KEY || findView(item, key) !== void 0);
2071
2074
  }
@@ -2075,6 +2078,14 @@ function effectiveViewKey(item, chosen) {
2075
2078
  if (isKnownView(item, item.defaultView)) return item.defaultView;
2076
2079
  return BASE_VIEW_KEY;
2077
2080
  }
2081
+ function loadViewKey(item, chosen) {
2082
+ const key = effectiveViewKey(item, chosen);
2083
+ const view = findView(item, key);
2084
+ return view !== void 0 && isProviderView(view) ? key : BASE_VIEW_KEY;
2085
+ }
2086
+ function loadViewKind(item, chosen) {
2087
+ return findView(item, loadViewKey(item, chosen))?.kind ?? item.kind;
2088
+ }
2078
2089
  function cellValue2(cell) {
2079
2090
  const value = cell?.value;
2080
2091
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
@@ -2209,6 +2220,11 @@ function convertView(widgetKey, view, data, options = {}) {
2209
2220
  where: `Widget ${JSON.stringify(widgetKey)} view ${JSON.stringify(view.key)}`,
2210
2221
  ...options.locale === void 0 ? {} : { locale: options.locale }
2211
2222
  };
2223
+ if (conversion === void 0) {
2224
+ return err(
2225
+ `${context.where}: the provider supplies this view, so there is nothing to convert.`
2226
+ );
2227
+ }
2212
2228
  const expected = VIEW_CONVERSIONS[conversion.type]?.from;
2213
2229
  if (expected === void 0) {
2214
2230
  return err(
@@ -2236,14 +2252,29 @@ function convertView(widgetKey, view, data, options = {}) {
2236
2252
  function applyView(widget, chosen, options = {}) {
2237
2253
  const key = effectiveViewKey(widget.definition, chosen);
2238
2254
  const view = findView(widget.definition, key);
2239
- if (view === void 0) return widget;
2255
+ const wanted = loadViewKey(widget.definition, chosen);
2256
+ const loaded = widget.status === "ok" ? widget.view ?? BASE_VIEW_KEY : void 0;
2257
+ const mismatched = loaded !== void 0 && loaded !== wanted;
2258
+ if (view === void 0) {
2259
+ return mismatched ? {
2260
+ definition: widget.definition,
2261
+ status: "loading",
2262
+ ...widget.options === void 0 ? {} : { options: widget.options }
2263
+ } : widget;
2264
+ }
2240
2265
  const definition = {
2241
2266
  ...widget.definition,
2242
2267
  kind: view.kind
2243
2268
  };
2244
- if (widget.status === "loading") return { ...widget, definition };
2245
- if (widget.status === "empty") return { ...widget, definition };
2246
- if (widget.status === "error") return { ...widget, definition };
2269
+ if (widget.status !== "ok") return { ...widget, definition };
2270
+ if (mismatched) {
2271
+ return {
2272
+ definition,
2273
+ status: "loading",
2274
+ ...widget.options === void 0 ? {} : { options: widget.options }
2275
+ };
2276
+ }
2277
+ if (isProviderView(view)) return { ...widget, definition };
2247
2278
  const converted = convertView(
2248
2279
  widget.definition.key,
2249
2280
  view,
@@ -5677,7 +5708,10 @@ function resolvePayload(definition, payload, options = {}) {
5677
5708
  } else {
5678
5709
  const result = validateWidgetData(payload, {
5679
5710
  widgetKey: definition.key,
5680
- expectedKind: definition.kind
5711
+ expectedKind: loadViewKind(
5712
+ definition,
5713
+ options.viewValues?.[definition.key]
5714
+ )
5681
5715
  });
5682
5716
  if (!result.ok) {
5683
5717
  return { definition, status: "error", error: result.error };
@@ -5688,7 +5722,14 @@ function resolvePayload(definition, payload, options = {}) {
5688
5722
  if (emptyText !== null) {
5689
5723
  return { definition, status: "empty", emptyText };
5690
5724
  }
5691
- return { definition, status: "ok", data: checked };
5725
+ return {
5726
+ definition,
5727
+ status: "ok",
5728
+ data: checked,
5729
+ ...hasViews(definition) ? {
5730
+ view: loadViewKey(definition, options.viewValues?.[definition.key])
5731
+ } : {}
5732
+ };
5692
5733
  }
5693
5734
  function failedWidget(definition, error) {
5694
5735
  return { definition, status: "error", error };
@@ -5698,7 +5739,14 @@ function loadingWidgets(definitions) {
5698
5739
  }
5699
5740
  function cacheKeyFor(definition, options, values) {
5700
5741
  const base = options.cacheKey === void 0 ? definition.sourceKey ?? definition.key : options.cacheKey(definition);
5701
- return values === void 0 ? base : `${base}${optionsCacheSuffix(definition, values, options)}`;
5742
+ const view = loadViewKey(
5743
+ definition,
5744
+ options.viewValues?.[definition.key]
5745
+ );
5746
+ const viewPart = view === BASE_VIEW_KEY ? "" : `view=${encodeURIComponent(view)}`;
5747
+ const optionPart = values === void 0 ? "" : optionsCacheSuffix(definition, values, options);
5748
+ if (viewPart === "") return `${base}${optionPart}`;
5749
+ return optionPart === "" ? `${base}?${viewPart}` : `${base}?${viewPart}&${optionPart.slice(1)}`;
5702
5750
  }
5703
5751
  function optionValuesFor(definition, options) {
5704
5752
  return resolveOptionValues(
@@ -5709,6 +5757,9 @@ function optionValuesFor(definition, options) {
5709
5757
  }
5710
5758
  function finalizeWidget(widget, values) {
5711
5759
  if (Object.keys(values).length === 0) return widget;
5760
+ if (widget.status === "ok" && widget.view !== void 0 && widget.view !== BASE_VIEW_KEY) {
5761
+ return { ...widget, options: values };
5762
+ }
5712
5763
  if (widget.status === "ok") {
5713
5764
  const data = applyClientOptions(
5714
5765
  widget.definition,
@@ -5759,7 +5810,8 @@ async function resolveWidgetUnapplied(definition, provider, context, options = {
5759
5810
  if (controller.signal.aborted) throw new LoadInterruption();
5760
5811
  return provider(context, definition, {
5761
5812
  signal: controller.signal,
5762
- options: values
5813
+ options: values,
5814
+ view: loadViewKey(definition, options.viewValues?.[definition.key])
5763
5815
  });
5764
5816
  }),
5765
5817
  interrupted
@@ -5807,9 +5859,18 @@ function createWidgetLoader(options) {
5807
5859
  ([key, values]) => values === void 0 ? [] : [[key, values]]
5808
5860
  )
5809
5861
  );
5862
+ const chosenViews = new Map(
5863
+ Object.entries(baseOptions.viewValues ?? {}).flatMap(
5864
+ ([key, view]) => view === void 0 ? [] : [[key, view]]
5865
+ )
5866
+ );
5810
5867
  const resolveOptions = baseOptions;
5811
5868
  function currentOptions() {
5812
- return { ...resolveOptions, optionValues: Object.fromEntries(chosen) };
5869
+ return {
5870
+ ...resolveOptions,
5871
+ optionValues: Object.fromEntries(chosen),
5872
+ viewValues: Object.fromEntries(chosenViews)
5873
+ };
5813
5874
  }
5814
5875
  const unapplied = /* @__PURE__ */ new Map();
5815
5876
  const visible = widgetsFor(definitions, context.roles);
@@ -5942,6 +6003,23 @@ function createWidgetLoader(options) {
5942
6003
  }
5943
6004
  start(definition, true);
5944
6005
  }
6006
+ function setView(key, view) {
6007
+ if (disposed) return;
6008
+ const definition = definitionFor(key);
6009
+ if (definition === void 0) return;
6010
+ const before = loadViewKey(definition, chosenViews.get(key));
6011
+ if (view === void 0 || view === "") chosenViews.delete(key);
6012
+ else chosenViews.set(key, view);
6013
+ const after = loadViewKey(definition, chosenViews.get(key));
6014
+ if (before === after || !started.has(key)) return;
6015
+ const current = snapshot.find(
6016
+ (widget) => widget.definition.key === key
6017
+ );
6018
+ if (current !== void 0 && current.status !== "loading") {
6019
+ replace(key, { definition, status: "loading" });
6020
+ }
6021
+ start(definition, true);
6022
+ }
5945
6023
  function dispose() {
5946
6024
  disposed = true;
5947
6025
  abortAll(new Error("The widget loader was disposed."));
@@ -5960,6 +6038,7 @@ function createWidgetLoader(options) {
5960
6038
  loadAll,
5961
6039
  refresh,
5962
6040
  setOptions,
6041
+ setView,
5963
6042
  dispose
5964
6043
  };
5965
6044
  }
@@ -5975,7 +6054,8 @@ function useWidgets(definitions, providers, context, options = {}) {
5975
6054
  signal,
5976
6055
  cache,
5977
6056
  cacheKey,
5978
- optionValues
6057
+ optionValues,
6058
+ viewValues
5979
6059
  } = options;
5980
6060
  const placeholders = useMemo(
5981
6061
  () => loadingWidgets(widgetsFor(definitions, context.roles)),
@@ -5987,6 +6067,8 @@ function useWidgets(definitions, providers, context, options = {}) {
5987
6067
  const gridRef = useRef(null);
5988
6068
  const optionValuesRef = useRef(optionValues);
5989
6069
  optionValuesRef.current = optionValues;
6070
+ const viewValuesRef = useRef(viewValues);
6071
+ viewValuesRef.current = viewValues;
5990
6072
  useEffect(() => {
5991
6073
  const created = createWidgetLoader({
5992
6074
  definitions,
@@ -5997,7 +6079,8 @@ function useWidgets(definitions, providers, context, options = {}) {
5997
6079
  ...signal === void 0 ? {} : { signal },
5998
6080
  ...cache === void 0 ? {} : { cache },
5999
6081
  ...cacheKey === void 0 ? {} : { cacheKey },
6000
- ...optionValuesRef.current === void 0 ? {} : { optionValues: optionValuesRef.current }
6082
+ ...optionValuesRef.current === void 0 ? {} : { optionValues: optionValuesRef.current },
6083
+ ...viewValuesRef.current === void 0 ? {} : { viewValues: viewValuesRef.current }
6001
6084
  });
6002
6085
  loaderRef.current = created;
6003
6086
  setWidgets(created.getSnapshot());
@@ -6076,6 +6159,16 @@ function useWidgets(definitions, providers, context, options = {}) {
6076
6159
  if (chosen !== void 0) loader.setOptions(key, chosen);
6077
6160
  }
6078
6161
  }, [loader, optionSignature]);
6162
+ const viewSignature = JSON.stringify(viewValues ?? {});
6163
+ useEffect(() => {
6164
+ if (loader === null) return;
6165
+ for (const [key, view] of Object.entries(viewValuesRef.current ?? {})) {
6166
+ loader.setView(key, view);
6167
+ }
6168
+ }, [loader, viewSignature]);
6169
+ const setView = useCallback((key, view) => {
6170
+ loaderRef.current?.setView(key, view);
6171
+ }, []);
6079
6172
  const setOptions = useCallback(
6080
6173
  (key, chosen) => {
6081
6174
  loaderRef.current?.setOptions(key, chosen);
@@ -6085,7 +6178,7 @@ function useWidgets(definitions, providers, context, options = {}) {
6085
6178
  const refresh = useCallback((key) => {
6086
6179
  loaderRef.current?.refresh(key);
6087
6180
  }, []);
6088
- return { widgets, refresh, setOptions, gridRef };
6181
+ return { widgets, refresh, setOptions, setView, gridRef };
6089
6182
  }
6090
6183
 
6091
6184
  export { AlertListWidget, BarListWidget, DEFAULT_LABELS, DEFAULT_SERIES_COLORS, Dashboard, GaugeWidget, GraphWidget, KpiWidget, ResolvedWidgetCard, TableWidget, TextWidget, Thumbnail, WidgetCard, WidgetContent, WidgetDetail, WidgetDetailDialog, WidgetGrid, WidgetLink, WidgetOptionsDialog, WidgetSettingsProvider, barPath, buildChartModel, describeChart, joinClassNames, seriesColor, useDetailData, useStoredLayout, useWidgetSettings, useWidgets, widgetTitle };