@richardmcquiston01/dashboard-widgets-toolkit 0.2.0 → 0.4.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 +90 -8
- package/dist/core.cjs +642 -69
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +61 -18
- package/dist/core.d.ts +61 -18
- package/dist/core.js +623 -70
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +642 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +623 -70
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1516 -86
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +155 -14
- package/dist/react.d.ts +155 -14
- package/dist/react.js +1514 -88
- package/dist/react.js.map +1 -1
- package/dist/{scale-Bhjc5Eqt.d.cts → scale-dWDGE1zW.d.cts} +327 -118
- package/dist/{scale-Bhjc5Eqt.d.ts → scale-dWDGE1zW.d.ts} +327 -118
- package/dist/styles.css +152 -6
- package/package.json +1 -1
|
@@ -37,7 +37,7 @@ interface KpiWidgetData {
|
|
|
37
37
|
readonly label: string;
|
|
38
38
|
/** Short context under the value, e.g. "Incl. shipping and tax". */
|
|
39
39
|
readonly hint?: string;
|
|
40
|
-
/** Whether a rise is good news (default true).
|
|
40
|
+
/** Whether a rise is good news (default true). Colors the change. */
|
|
41
41
|
readonly higherIsBetter?: boolean;
|
|
42
42
|
}
|
|
43
43
|
/** A value against a maximum, drawn as a meter. */
|
|
@@ -155,48 +155,6 @@ declare function isWidgetEmptyState(payload: WidgetPayload): payload is WidgetEm
|
|
|
155
155
|
*/
|
|
156
156
|
declare function emptyTextFor(payload: WidgetPayload): string | null;
|
|
157
157
|
|
|
158
|
-
/** A size hint for grid layouts; renderers may map it to column spans. */
|
|
159
|
-
declare const WIDGET_SIZES: readonly ["small", "medium", "large", "full"];
|
|
160
|
-
type WidgetSize = (typeof WIDGET_SIZES)[number];
|
|
161
|
-
/**
|
|
162
|
-
* How a widget fills free space in a grid layout. `height` stretches it to
|
|
163
|
-
* the height of its row; `width` widens it to take the columns left over in
|
|
164
|
-
* its row; `both` does both. Absent, a widget is only as big as its content
|
|
165
|
-
* and `defaultSize`.
|
|
166
|
-
*/
|
|
167
|
-
declare const WIDGET_FILLS: readonly ["height", "width", "both"];
|
|
168
|
-
type WidgetFill = (typeof WIDGET_FILLS)[number];
|
|
169
|
-
/**
|
|
170
|
-
* What a widget is, independent of its data. Mirrors Maker Toolkit's
|
|
171
|
-
* `widget` table (`widget_key`, `title`, `description`, `view_type`,
|
|
172
|
-
* `roles`, `sort_order`, `active`).
|
|
173
|
-
*/
|
|
174
|
-
interface WidgetDefinition {
|
|
175
|
-
/** Stable, unique id. Layouts and providers are keyed by it. */
|
|
176
|
-
readonly key: string;
|
|
177
|
-
readonly title: string;
|
|
178
|
-
readonly description?: string;
|
|
179
|
-
readonly kind: WidgetKind;
|
|
180
|
-
/** Lower comes first. Default 0; ties keep definition order. */
|
|
181
|
-
readonly sortOrder?: number;
|
|
182
|
-
/** Roles allowed to see it. Absent or empty means everyone. */
|
|
183
|
-
readonly roles?: readonly string[];
|
|
184
|
-
/** False hides it from every user. Default true. */
|
|
185
|
-
readonly active?: boolean;
|
|
186
|
-
readonly defaultSize?: WidgetSize;
|
|
187
|
-
/** Fill free space in the row (height, width or both). Default: none. */
|
|
188
|
-
readonly fill?: WidgetFill;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Identity helper that keeps the literal `kind` (so typed providers can be
|
|
192
|
-
* checked against it) and gives a definition its type without a cast.
|
|
193
|
-
*/
|
|
194
|
-
declare function defineWidget<const D extends WidgetDefinition>(definition: D): D;
|
|
195
|
-
/** Definitions sorted by `sortOrder` (stable: ties keep their input order). */
|
|
196
|
-
declare function sortDefinitions<D extends WidgetDefinition>(definitions: readonly D[]): D[];
|
|
197
|
-
/** Whether a widget is active and visible to someone with these roles. */
|
|
198
|
-
declare function isWidgetVisibleTo(definition: WidgetDefinition, roles: readonly string[] | undefined): boolean;
|
|
199
|
-
|
|
200
158
|
/**
|
|
201
159
|
* Number formatting via `Intl`, with an injectable locale (undefined uses
|
|
202
160
|
* the runtime's default), plus KPI period-over-period deltas.
|
|
@@ -258,77 +216,6 @@ declare const DEFAULT_COMPARISON_LABEL = "previous period";
|
|
|
258
216
|
*/
|
|
259
217
|
declare function kpiDelta(current: number, previous: number | null | undefined, options?: KpiDeltaOptions): KpiDelta | null;
|
|
260
218
|
|
|
261
|
-
/**
|
|
262
|
-
* A viewer's dashboard customisation: order, hidden and minimised widgets.
|
|
263
|
-
* Pure functions over a small JSON-serialisable object. Persist it however
|
|
264
|
-
* you like (a settings table, localStorage); `parseLayout` tolerates
|
|
265
|
-
* anything, so a corrupt saved value never breaks the dashboard.
|
|
266
|
-
*
|
|
267
|
-
* Generalised from Maker Toolkit's desktop `dashboard-layout.ts`.
|
|
268
|
-
*/
|
|
269
|
-
/** What layout functions need from a widget definition. */
|
|
270
|
-
interface LayoutItem {
|
|
271
|
-
readonly key: string;
|
|
272
|
-
readonly sortOrder?: number;
|
|
273
|
-
}
|
|
274
|
-
interface DashboardLayout {
|
|
275
|
-
/** Widget keys in display order. Keys not listed follow, by sortOrder. */
|
|
276
|
-
readonly order: readonly string[];
|
|
277
|
-
/** Widget keys removed from the dashboard (restorable). */
|
|
278
|
-
readonly hidden: readonly string[];
|
|
279
|
-
/** Widget keys collapsed to their header. */
|
|
280
|
-
readonly minimized: readonly string[];
|
|
281
|
-
}
|
|
282
|
-
declare const EMPTY_LAYOUT: DashboardLayout;
|
|
283
|
-
/**
|
|
284
|
-
* Reads a saved layout: a JSON string or an already-parsed object. Missing,
|
|
285
|
-
* corrupt or wrongly typed values give the empty layout (or empty lists for
|
|
286
|
-
* the fields that are wrong); non-string and duplicate keys are dropped.
|
|
287
|
-
*/
|
|
288
|
-
declare function parseLayout(raw: unknown): DashboardLayout;
|
|
289
|
-
/** The JSON string to persist. */
|
|
290
|
-
declare function serializeLayout(layout: DashboardLayout): string;
|
|
291
|
-
/**
|
|
292
|
-
* The widgets to show, in order: saved keys first (when still present),
|
|
293
|
-
* then widgets the layout doesn't know yet, by sortOrder. Hidden widgets
|
|
294
|
-
* are left out.
|
|
295
|
-
*/
|
|
296
|
-
declare function visibleWidgets<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): T[];
|
|
297
|
-
/** Hidden widgets, by sortOrder, for a "restore" menu. */
|
|
298
|
-
declare function hiddenWidgets<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): T[];
|
|
299
|
-
/**
|
|
300
|
-
* Moves `key` to `toIndex` within the current visible order. Returns the
|
|
301
|
-
* same layout object when the key isn't visible or the index is out of
|
|
302
|
-
* range, so callers can skip a save.
|
|
303
|
-
*/
|
|
304
|
-
declare function moveWidget<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string, toIndex: number): DashboardLayout;
|
|
305
|
-
/** Moves `key` by `offset` places (negative is earlier). Clamped at the ends. */
|
|
306
|
-
declare function moveWidgetBy<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string, offset: number): DashboardLayout;
|
|
307
|
-
/** Moves `key` one place earlier. */
|
|
308
|
-
declare function moveWidgetUp<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string): DashboardLayout;
|
|
309
|
-
/** Moves `key` one place later. */
|
|
310
|
-
declare function moveWidgetDown<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string): DashboardLayout;
|
|
311
|
-
declare function isHidden(layout: DashboardLayout, key: string): boolean;
|
|
312
|
-
declare function isMinimized(layout: DashboardLayout, key: string): boolean;
|
|
313
|
-
/** Hides `key`. No-op (same object) if already hidden. */
|
|
314
|
-
declare function hideWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
315
|
-
/** Shows `key` again, expanded. No-op (same object) if not hidden. */
|
|
316
|
-
declare function showWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
317
|
-
/** Hides or shows `key` (showing also clears its minimised state). */
|
|
318
|
-
declare function toggleHidden(layout: DashboardLayout, key: string): DashboardLayout;
|
|
319
|
-
/** Collapses `key` to its header. No-op (same object) if already minimised. */
|
|
320
|
-
declare function minimizeWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
321
|
-
/** Expands `key`. No-op (same object) if not minimised. */
|
|
322
|
-
declare function restoreWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
323
|
-
/** Minimises or restores `key`. */
|
|
324
|
-
declare function toggleMinimized(layout: DashboardLayout, key: string): DashboardLayout;
|
|
325
|
-
/**
|
|
326
|
-
* Drops keys for widgets that no longer exist. Only pass the full list of
|
|
327
|
-
* definitions (not a role-filtered one), or a viewer's settings for widgets
|
|
328
|
-
* they temporarily can't see are lost.
|
|
329
|
-
*/
|
|
330
|
-
declare function pruneLayout<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): DashboardLayout;
|
|
331
|
-
|
|
332
219
|
/**
|
|
333
220
|
* Runs each widget's data provider and collects the outcome per widget, so
|
|
334
221
|
* one failing provider never breaks the rest of the dashboard. The package
|
|
@@ -341,14 +228,31 @@ interface WidgetContext {
|
|
|
341
228
|
/** The viewer's roles. Widgets with `roles` need at least one of them. */
|
|
342
229
|
readonly roles?: readonly string[];
|
|
343
230
|
}
|
|
344
|
-
/**
|
|
345
|
-
|
|
231
|
+
/** What the resolver hands every provider, after the context and definition. */
|
|
232
|
+
interface ProviderOptions {
|
|
233
|
+
/**
|
|
234
|
+
* Aborted when the widget times out, is refreshed, or the dashboard is torn
|
|
235
|
+
* down. Pass it to `fetch` (or any cancellable call) to stop the work; a
|
|
236
|
+
* provider that ignores it is still abandoned, just not stopped.
|
|
237
|
+
*/
|
|
238
|
+
readonly signal: AbortSignal;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Loads one widget's payload. May be sync or async; may throw. The third
|
|
242
|
+
* argument is optional to use: a provider that takes only `(context,
|
|
243
|
+
* definition)` keeps working.
|
|
244
|
+
*/
|
|
245
|
+
type WidgetProvider<C = WidgetContext> = (context: C, definition: WidgetDefinition, options: ProviderOptions) => WidgetPayload | Promise<WidgetPayload>;
|
|
346
246
|
/** Providers keyed by widget key. */
|
|
347
247
|
type WidgetProviders<C = WidgetContext> = Readonly<Record<string, WidgetProvider<C>>>;
|
|
348
248
|
interface OkWidget {
|
|
349
249
|
readonly definition: WidgetDefinition;
|
|
350
250
|
readonly status: 'ok';
|
|
351
251
|
readonly data: WidgetData;
|
|
252
|
+
/** When the data was produced (epoch ms), set when a provider resolved it. */
|
|
253
|
+
readonly updatedAt?: number;
|
|
254
|
+
/** True while cached data is shown and a fresh load is still running. */
|
|
255
|
+
readonly stale?: boolean;
|
|
352
256
|
}
|
|
353
257
|
interface EmptyWidget {
|
|
354
258
|
readonly definition: WidgetDefinition;
|
|
@@ -372,6 +276,20 @@ interface LoadingWidget {
|
|
|
372
276
|
/** Anything a dashboard can render: resolved, or still loading. */
|
|
373
277
|
type DashboardWidget = ResolvedWidget | LoadingWidget;
|
|
374
278
|
type WidgetStatus = DashboardWidget['status'];
|
|
279
|
+
/** A payload the cache holds, with when it was stored (epoch ms). */
|
|
280
|
+
interface CachedPayload {
|
|
281
|
+
readonly payload: unknown;
|
|
282
|
+
readonly storedAt: number;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Consumer-supplied storage for widget payloads (memory, localStorage, a
|
|
286
|
+
* database). The package never stores anything itself. Payloads read back
|
|
287
|
+
* are validated again, so a corrupt entry cannot break a widget.
|
|
288
|
+
*/
|
|
289
|
+
interface WidgetCache {
|
|
290
|
+
get(key: string): CachedPayload | undefined | Promise<CachedPayload | undefined>;
|
|
291
|
+
set(key: string, entry: CachedPayload): void | Promise<void>;
|
|
292
|
+
}
|
|
375
293
|
interface ResolveOptions {
|
|
376
294
|
/**
|
|
377
295
|
* Validate each provider's payload with `validateWidgetData` (and check
|
|
@@ -379,6 +297,17 @@ interface ResolveOptions {
|
|
|
379
297
|
* trusted, typed providers.
|
|
380
298
|
*/
|
|
381
299
|
readonly validate?: boolean;
|
|
300
|
+
/**
|
|
301
|
+
* Give each provider this many milliseconds. A timeout aborts the
|
|
302
|
+
* provider's signal and yields an `error` widget naming the key.
|
|
303
|
+
*/
|
|
304
|
+
readonly timeoutMs?: number;
|
|
305
|
+
/** Cancels loading; affected widgets resolve as `error` (canceled). */
|
|
306
|
+
readonly signal?: AbortSignal;
|
|
307
|
+
/** Where to store successful payloads (see `WidgetCache`). */
|
|
308
|
+
readonly cache?: WidgetCache;
|
|
309
|
+
/** Cache key for a widget. Default: the widget's `key`. */
|
|
310
|
+
readonly cacheKey?: (definition: WidgetDefinition) => string;
|
|
382
311
|
}
|
|
383
312
|
/**
|
|
384
313
|
* Turns a payload (typically JSON from an API) into a resolved widget:
|
|
@@ -390,7 +319,12 @@ declare function resolvePayload(definition: WidgetDefinition, payload: unknown,
|
|
|
390
319
|
declare function failedWidget(definition: WidgetDefinition, error: string): ErrorWidget;
|
|
391
320
|
/** Loading placeholders for definitions, before their data arrives. */
|
|
392
321
|
declare function loadingWidgets(definitions: readonly WidgetDefinition[]): LoadingWidget[];
|
|
393
|
-
/**
|
|
322
|
+
/** The cache key for a widget under these options. */
|
|
323
|
+
declare function cacheKeyFor(definition: WidgetDefinition, options: ResolveOptions): string;
|
|
324
|
+
/**
|
|
325
|
+
* Runs one widget's provider, capturing a throw, a timeout, a cancellation or
|
|
326
|
+
* a bad payload as an error widget. Never rejects.
|
|
327
|
+
*/
|
|
394
328
|
declare function resolveWidget<C extends WidgetContext>(definition: WidgetDefinition, provider: WidgetProvider<C> | undefined, context: C, options?: ResolveOptions): Promise<ResolvedWidget>;
|
|
395
329
|
/**
|
|
396
330
|
* The widgets a viewer can see: active, allowed for `roles`, in sort order.
|
|
@@ -404,6 +338,281 @@ declare function widgetsFor(definitions: readonly WidgetDefinition[], roles: rea
|
|
|
404
338
|
*/
|
|
405
339
|
declare function resolveWidgets<C extends WidgetContext>(definitions: readonly WidgetDefinition[], providers: WidgetProviders<C>, context: C, options?: ResolveOptions): Promise<ResolvedWidget[]>;
|
|
406
340
|
|
|
341
|
+
/**
|
|
342
|
+
* A small Result type. Functions in this package return a Result rather than
|
|
343
|
+
* throwing, so the caller has to look at the outcome. `throw` is reserved for
|
|
344
|
+
* programmer error.
|
|
345
|
+
*/
|
|
346
|
+
interface Ok<T> {
|
|
347
|
+
readonly ok: true;
|
|
348
|
+
readonly value: T;
|
|
349
|
+
}
|
|
350
|
+
interface Err {
|
|
351
|
+
readonly ok: false;
|
|
352
|
+
/** Specific enough to act on: names the field, the widget and the problem. */
|
|
353
|
+
readonly error: string;
|
|
354
|
+
}
|
|
355
|
+
type Result<T> = Ok<T> | Err;
|
|
356
|
+
declare function ok<T>(value: T): Ok<T>;
|
|
357
|
+
declare function err(error: string): Err;
|
|
358
|
+
/** Turns an unknown thrown value into a readable message. */
|
|
359
|
+
declare function describeUnknownError(cause: unknown): string;
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Detail view, core part: the data and query types, sorting, filtering and
|
|
363
|
+
* paging, query (de)serialisation for URLs, and validation. Pure functions;
|
|
364
|
+
* nothing here renders, fetches or reads `location`. See
|
|
365
|
+
* `docs/design/detail-view.md`.
|
|
366
|
+
*/
|
|
367
|
+
|
|
368
|
+
/** `client`: the provider returns every row; `server`: it honors the query. */
|
|
369
|
+
declare const DETAIL_MODES: readonly ["client", "server"];
|
|
370
|
+
type DetailMode = (typeof DETAIL_MODES)[number];
|
|
371
|
+
declare const DEFAULT_DETAIL_PAGE_SIZE = 25;
|
|
372
|
+
declare const MAX_DETAIL_PAGE_SIZE = 200;
|
|
373
|
+
/** The `detail` setting on a widget definition. `true` means all defaults. */
|
|
374
|
+
interface WidgetDetailOptions {
|
|
375
|
+
/** Heading of the detail view. Default: the widget's title. */
|
|
376
|
+
readonly title?: string;
|
|
377
|
+
/** Rows per page, 1 to 200. Default 25. */
|
|
378
|
+
readonly pageSize?: number;
|
|
379
|
+
/** Default `client`. */
|
|
380
|
+
readonly mode?: DetailMode;
|
|
381
|
+
}
|
|
382
|
+
/** `WidgetDetailOptions` with every default filled in. */
|
|
383
|
+
interface ResolvedDetailOptions {
|
|
384
|
+
readonly title: string;
|
|
385
|
+
readonly pageSize: number;
|
|
386
|
+
readonly mode: DetailMode;
|
|
387
|
+
}
|
|
388
|
+
interface DetailColumn {
|
|
389
|
+
/** Stable id used by sort, filters and URLs. Unique within the data. */
|
|
390
|
+
readonly key: string;
|
|
391
|
+
readonly label: string;
|
|
392
|
+
/** Right-aligned, and sorted as numbers when cell values are numbers. */
|
|
393
|
+
readonly numeric?: boolean;
|
|
394
|
+
/** Default true. */
|
|
395
|
+
readonly sortable?: boolean;
|
|
396
|
+
/** Default false: gets its own filter input when true. */
|
|
397
|
+
readonly filterable?: boolean;
|
|
398
|
+
}
|
|
399
|
+
interface DetailCell {
|
|
400
|
+
/** What is shown. */
|
|
401
|
+
readonly text: string;
|
|
402
|
+
/** What sorts and filters. Default: `text`. */
|
|
403
|
+
readonly value?: string | number;
|
|
404
|
+
/** Renders the cell as a link (http, https, mailto or relative only). */
|
|
405
|
+
readonly href?: string;
|
|
406
|
+
}
|
|
407
|
+
interface DetailData {
|
|
408
|
+
readonly columns: readonly DetailColumn[];
|
|
409
|
+
/** One array of cells per row, each as long as `columns`. */
|
|
410
|
+
readonly rows: readonly (readonly DetailCell[])[];
|
|
411
|
+
/** Server mode: rows matching the query across all pages. */
|
|
412
|
+
readonly totalRows?: number;
|
|
413
|
+
}
|
|
414
|
+
type SortDirection = 'asc' | 'desc';
|
|
415
|
+
interface DetailSort {
|
|
416
|
+
readonly column: string;
|
|
417
|
+
readonly direction: SortDirection;
|
|
418
|
+
}
|
|
419
|
+
interface DetailQuery {
|
|
420
|
+
/** Free text, matched against every column. */
|
|
421
|
+
readonly search?: string;
|
|
422
|
+
/** Per-column text, keyed by column key. Blank entries are ignored. */
|
|
423
|
+
readonly filters?: Readonly<Record<string, string>>;
|
|
424
|
+
readonly sort?: DetailSort;
|
|
425
|
+
/** 1-based. */
|
|
426
|
+
readonly page: number;
|
|
427
|
+
readonly pageSize: number;
|
|
428
|
+
}
|
|
429
|
+
/** What a detail provider receives beyond the usual arguments. */
|
|
430
|
+
interface DetailProviderOptions extends ProviderOptions {
|
|
431
|
+
readonly query: DetailQuery;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Loads the full data for one widget's detail view. In client mode it may
|
|
435
|
+
* ignore `options.query`; in server mode it returns one page and `totalRows`.
|
|
436
|
+
*/
|
|
437
|
+
type DetailProvider<C = WidgetContext> = (context: C, definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | Promise<DetailData>;
|
|
438
|
+
/** Detail providers keyed by widget key. */
|
|
439
|
+
type DetailProviders<C = WidgetContext> = Readonly<Record<string, DetailProvider<C>>>;
|
|
440
|
+
interface DetailPage {
|
|
441
|
+
/** The rows of the requested page (after filtering and sorting). */
|
|
442
|
+
readonly rows: readonly (readonly DetailCell[])[];
|
|
443
|
+
/** Rows matching the query, across all pages. */
|
|
444
|
+
readonly totalRows: number;
|
|
445
|
+
/** The page shown: the requested one, clamped into range. */
|
|
446
|
+
readonly page: number;
|
|
447
|
+
readonly pageCount: number;
|
|
448
|
+
}
|
|
449
|
+
/** Reads `definition.detail` with defaults; undefined when there is none. */
|
|
450
|
+
declare function resolveDetailOptions(definition: Pick<WidgetDefinition, 'title' | 'detail'>): ResolvedDetailOptions | undefined;
|
|
451
|
+
/** The first page, unsorted and unfiltered. */
|
|
452
|
+
declare function defaultDetailQuery(pageSize?: number): DetailQuery;
|
|
453
|
+
/**
|
|
454
|
+
* Filters, sorts and pages `data` in memory (client mode). Matching is
|
|
455
|
+
* case- and accent-insensitive substring matching on each cell's `value`
|
|
456
|
+
* (else `text`). Sorting is stable, locale-aware (`locale`, default the
|
|
457
|
+
* runtime's) and numeric for number values. `page` is clamped into range.
|
|
458
|
+
* Fails, naming the column, when the query names a column that does not
|
|
459
|
+
* exist or cannot be sorted.
|
|
460
|
+
*/
|
|
461
|
+
declare function queryRows(data: DetailData, query: DetailQuery, locale?: string): Result<DetailPage>;
|
|
462
|
+
/**
|
|
463
|
+
* The query as a URL query string without the leading `?`: `q` (search),
|
|
464
|
+
* `sort` (`column:asc|desc`), `page` and `f.<column>` filters. `pageSize` is
|
|
465
|
+
* not included: the widget definition owns it. Defaults are left out.
|
|
466
|
+
*/
|
|
467
|
+
declare function serializeDetailQuery(query: DetailQuery): string;
|
|
468
|
+
/**
|
|
469
|
+
* Reads a query string (with or without the leading `?`) written by
|
|
470
|
+
* `serializeDetailQuery`. Unknown parameters are ignored, so it can share a
|
|
471
|
+
* URL with the rest of an app. A malformed value fails with a message naming
|
|
472
|
+
* the parameter. When `data` is given, column keys are checked against it.
|
|
473
|
+
*/
|
|
474
|
+
declare function parseDetailQuery(queryString: string, pageSize?: number, data?: Pick<DetailData, 'columns'>): Result<DetailQuery>;
|
|
475
|
+
/**
|
|
476
|
+
* Checks data from a detail provider: unique non-empty column keys, labels,
|
|
477
|
+
* every row as long as `columns`, cell `text` strings, `value` a string or
|
|
478
|
+
* finite number, safe `href`s, and `totalRows` a non-negative integer.
|
|
479
|
+
* Reports every problem, naming the column or row and cell.
|
|
480
|
+
*/
|
|
481
|
+
declare function validateDetailData(data: unknown, subject?: string): Result<DetailData>;
|
|
482
|
+
/**
|
|
483
|
+
* The detail data for a widget whose card payload is already complete, so a
|
|
484
|
+
* detail view needs no provider: a TABLE without a `footer` (a footer means
|
|
485
|
+
* rows were left out) and a BAR_LIST. Returns undefined for everything else
|
|
486
|
+
* (alert lists, gauges, KPIs, text and charts): those need a detail provider.
|
|
487
|
+
*/
|
|
488
|
+
declare function deriveDetailData(data: WidgetData, locale?: Locale): DetailData | undefined;
|
|
489
|
+
|
|
490
|
+
/** A size hint for grid layouts; renderers may map it to column spans. */
|
|
491
|
+
declare const WIDGET_SIZES: readonly ["small", "medium", "large", "full"];
|
|
492
|
+
type WidgetSize = (typeof WIDGET_SIZES)[number];
|
|
493
|
+
/**
|
|
494
|
+
* How a widget fills free space in a grid layout. `height` stretches it to
|
|
495
|
+
* the height of its row; `width` widens it to take the columns left over in
|
|
496
|
+
* its row; `both` does both. Absent, a widget is only as big as its content
|
|
497
|
+
* and `defaultSize`.
|
|
498
|
+
*/
|
|
499
|
+
declare const WIDGET_FILLS: readonly ["height", "width", "both"];
|
|
500
|
+
type WidgetFill = (typeof WIDGET_FILLS)[number];
|
|
501
|
+
/**
|
|
502
|
+
* What a widget is, independent of its data. Mirrors Maker Toolkit's
|
|
503
|
+
* `widget` table (`widget_key`, `title`, `description`, `view_type`,
|
|
504
|
+
* `roles`, `sort_order`, `active`).
|
|
505
|
+
*/
|
|
506
|
+
interface WidgetDefinition {
|
|
507
|
+
/** Stable, unique id. Layouts and providers are keyed by it. */
|
|
508
|
+
readonly key: string;
|
|
509
|
+
readonly title: string;
|
|
510
|
+
readonly description?: string;
|
|
511
|
+
readonly kind: WidgetKind;
|
|
512
|
+
/** Lower comes first. Default 0; ties keep definition order. */
|
|
513
|
+
readonly sortOrder?: number;
|
|
514
|
+
/** Roles allowed to see it. Absent or empty means everyone. */
|
|
515
|
+
readonly roles?: readonly string[];
|
|
516
|
+
/** False hides it from every user. Default true. */
|
|
517
|
+
readonly active?: boolean;
|
|
518
|
+
readonly defaultSize?: WidgetSize;
|
|
519
|
+
/**
|
|
520
|
+
* Share of the row the widget takes, in twelfths: an integer from 2 to 12
|
|
521
|
+
* (6 is half the row, 12 the whole row). When any widget in a grid sets
|
|
522
|
+
* it, the grid becomes 12 columns wide and widgets without a `width` use
|
|
523
|
+
* the one their `defaultSize` implies (see `widthForSize`). Narrow grids
|
|
524
|
+
* give widgets more room automatically.
|
|
525
|
+
*/
|
|
526
|
+
readonly width?: number;
|
|
527
|
+
/**
|
|
528
|
+
* Gives the widget a detail view: a full list with sorting, filtering and
|
|
529
|
+
* paging. `true` uses defaults. The data comes from a detail provider.
|
|
530
|
+
*/
|
|
531
|
+
readonly detail?: boolean | WidgetDetailOptions;
|
|
532
|
+
/** Fill free space in the row (height, width or both). Default: none. */
|
|
533
|
+
readonly fill?: WidgetFill;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Identity helper that keeps the literal `kind` (so typed providers can be
|
|
537
|
+
* checked against it) and gives a definition its type without a cast.
|
|
538
|
+
*/
|
|
539
|
+
declare function defineWidget<const D extends WidgetDefinition>(definition: D): D;
|
|
540
|
+
/** Definitions sorted by `sortOrder` (stable: ties keep their input order). */
|
|
541
|
+
declare function sortDefinitions<D extends WidgetDefinition>(definitions: readonly D[]): D[];
|
|
542
|
+
/** Whether a widget is active and visible to someone with these roles. */
|
|
543
|
+
declare function isWidgetVisibleTo(definition: WidgetDefinition, roles: readonly string[] | undefined): boolean;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* A viewer's dashboard customization: order, hidden and minimized widgets.
|
|
547
|
+
* Pure functions over a small JSON-serialisable object. Persist it however
|
|
548
|
+
* you like (a settings table, localStorage); `parseLayout` tolerates
|
|
549
|
+
* anything, so a corrupt saved value never breaks the dashboard.
|
|
550
|
+
*
|
|
551
|
+
* Generalised from Maker Toolkit's desktop `dashboard-layout.ts`.
|
|
552
|
+
*/
|
|
553
|
+
/** What layout functions need from a widget definition. */
|
|
554
|
+
interface LayoutItem {
|
|
555
|
+
readonly key: string;
|
|
556
|
+
readonly sortOrder?: number;
|
|
557
|
+
}
|
|
558
|
+
interface DashboardLayout {
|
|
559
|
+
/** Widget keys in display order. Keys not listed follow, by sortOrder. */
|
|
560
|
+
readonly order: readonly string[];
|
|
561
|
+
/** Widget keys removed from the dashboard (restorable). */
|
|
562
|
+
readonly hidden: readonly string[];
|
|
563
|
+
/** Widget keys collapsed to their header. */
|
|
564
|
+
readonly minimized: readonly string[];
|
|
565
|
+
}
|
|
566
|
+
declare const EMPTY_LAYOUT: DashboardLayout;
|
|
567
|
+
/**
|
|
568
|
+
* Reads a saved layout: a JSON string or an already-parsed object. Missing,
|
|
569
|
+
* corrupt or wrongly typed values give the empty layout (or empty lists for
|
|
570
|
+
* the fields that are wrong); non-string and duplicate keys are dropped.
|
|
571
|
+
*/
|
|
572
|
+
declare function parseLayout(raw: unknown): DashboardLayout;
|
|
573
|
+
/** The JSON string to persist. */
|
|
574
|
+
declare function serializeLayout(layout: DashboardLayout): string;
|
|
575
|
+
/**
|
|
576
|
+
* The widgets to show, in order: saved keys first (when still present),
|
|
577
|
+
* then widgets the layout doesn't know yet, by sortOrder. Hidden widgets
|
|
578
|
+
* are left out.
|
|
579
|
+
*/
|
|
580
|
+
declare function visibleWidgets<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): T[];
|
|
581
|
+
/** Hidden widgets, by sortOrder, for a "restore" menu. */
|
|
582
|
+
declare function hiddenWidgets<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): T[];
|
|
583
|
+
/**
|
|
584
|
+
* Moves `key` to `toIndex` within the current visible order. Returns the
|
|
585
|
+
* same layout object when the key isn't visible or the index is out of
|
|
586
|
+
* range, so callers can skip a save.
|
|
587
|
+
*/
|
|
588
|
+
declare function moveWidget<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string, toIndex: number): DashboardLayout;
|
|
589
|
+
/** Moves `key` by `offset` places (negative is earlier). Clamped at the ends. */
|
|
590
|
+
declare function moveWidgetBy<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string, offset: number): DashboardLayout;
|
|
591
|
+
/** Moves `key` one place earlier. */
|
|
592
|
+
declare function moveWidgetUp<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string): DashboardLayout;
|
|
593
|
+
/** Moves `key` one place later. */
|
|
594
|
+
declare function moveWidgetDown<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout, key: string): DashboardLayout;
|
|
595
|
+
declare function isHidden(layout: DashboardLayout, key: string): boolean;
|
|
596
|
+
declare function isMinimized(layout: DashboardLayout, key: string): boolean;
|
|
597
|
+
/** Hides `key`. No-op (same object) if already hidden. */
|
|
598
|
+
declare function hideWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
599
|
+
/** Shows `key` again, expanded. No-op (same object) if not hidden. */
|
|
600
|
+
declare function showWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
601
|
+
/** Hides or shows `key` (showing also clears its minimized state). */
|
|
602
|
+
declare function toggleHidden(layout: DashboardLayout, key: string): DashboardLayout;
|
|
603
|
+
/** Collapses `key` to its header. No-op (same object) if already minimized. */
|
|
604
|
+
declare function minimizeWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
605
|
+
/** Expands `key`. No-op (same object) if not minimized. */
|
|
606
|
+
declare function restoreWidget(layout: DashboardLayout, key: string): DashboardLayout;
|
|
607
|
+
/** Minimizes or restores `key`. */
|
|
608
|
+
declare function toggleMinimized(layout: DashboardLayout, key: string): DashboardLayout;
|
|
609
|
+
/**
|
|
610
|
+
* Drops keys for widgets that no longer exist. Only pass the full list of
|
|
611
|
+
* definitions (not a role-filtered one), or a viewer's settings for widgets
|
|
612
|
+
* they temporarily can't see are lost.
|
|
613
|
+
*/
|
|
614
|
+
declare function pruneLayout<T extends LayoutItem>(definitions: readonly T[], layout: DashboardLayout): DashboardLayout;
|
|
615
|
+
|
|
407
616
|
/** Axis maths for charts: clean domains and tick values. Pure. */
|
|
408
617
|
/** The smallest 1, 2 or 5 × 10^n that is at least `value` (1 for 0 or less). */
|
|
409
618
|
declare function niceStep(value: number): number;
|
|
@@ -423,4 +632,4 @@ declare function niceDomain(values: readonly number[], tickCount?: number): Nice
|
|
|
423
632
|
*/
|
|
424
633
|
declare function labelStride(count: number, maxLabels?: number): number;
|
|
425
634
|
|
|
426
|
-
export {
|
|
635
|
+
export { MAX_GRAPH_SERIES as $, type AlertListWidgetData as A, type BarListWidgetData as B, type CachedPayload as C, type DashboardWidget as D, type DetailPage as E, type DetailProvider as F, type GraphWidgetData as G, type DetailProviders as H, type DetailSort as I, EMPTY_LAYOUT as J, type KpiWidgetData as K, type Locale as L, type EmptyWidget as M, type NiceDomain as N, type Err as O, type ErrorWidget as P, type FormatOptions as Q, type ResolveOptions as R, type GraphPoint as S, type TableWidgetData as T, type GraphSeries as U, type KpiDelta as V, type WidgetSize as W, type KpiDeltaOptions as X, type LayoutItem as Y, type LoadingWidget as Z, MAX_DETAIL_PAGE_SIZE as _, type WidgetFill as a, sortDefinitions as a$, type Ok as a0, type OkWidget as a1, type ProviderOptions as a2, type ResolvedDetailOptions as a3, type ResolvedWidget as a4, type SortDirection as a5, type TableCell as a6, type TableColumn as a7, VALUE_FORMATS as a8, type ValueFormat as a9, isWidgetKind as aA, isWidgetVisibleTo as aB, kpiDelta as aC, labelStride as aD, loadingWidgets as aE, minimizeWidget as aF, moveWidget as aG, moveWidgetBy as aH, moveWidgetDown as aI, moveWidgetUp as aJ, niceDomain as aK, niceStep as aL, ok as aM, parseDetailQuery as aN, parseLayout as aO, percentChange as aP, pruneLayout as aQ, queryRows as aR, resolveDetailOptions as aS, resolvePayload as aT, resolveWidget as aU, resolveWidgets as aV, restoreWidget as aW, serializeDetailQuery as aX, serializeLayout as aY, shareOf as aZ, showWidget as a_, WIDGET_FILLS as aa, WIDGET_KINDS as ab, WIDGET_SIZES as ac, type WidgetCache as ad, type WidgetDataOf as ae, type WidgetDetailOptions as af, type WidgetEmptyState as ag, type WidgetProvider as ah, type WidgetStatus as ai, cacheKeyFor as aj, defaultDetailQuery as ak, defineWidget as al, deriveDetailData as am, describeUnknownError as an, emptyTextFor as ao, emptyWidget as ap, err as aq, failedWidget as ar, formatCount as as, formatPercentChange as at, formatValue as au, hiddenWidgets as av, hideWidget as aw, isHidden as ax, isMinimized as ay, isWidgetEmptyState as az, type WidgetDefinition as b, toggleHidden as b0, toggleMinimized as b1, validateDetailData as b2, visibleWidgets as b3, widgetsFor as b4, type DetailProviderOptions as c, type DetailData as d, type DetailQuery as e, type DashboardLayout as f, type GaugeWidgetData as g, type TextWidgetData as h, type WidgetData as i, type WidgetContext as j, type WidgetProviders as k, type WidgetKind as l, type Result as m, type WidgetPayload as n, type AlertListItem as o, type BarListItem as p, DEFAULT_COMPARISON_LABEL as q, DEFAULT_CURRENCY as r, DEFAULT_DETAIL_PAGE_SIZE as s, DEFAULT_EMPTY_TEXT as t, DETAIL_MODES as u, type DeltaDirection as v, type DeltaSentiment as w, type DetailCell as x, type DetailColumn as y, type DetailMode as z };
|