nuxt-ui-tools 1.2.0 → 1.3.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/module.json +1 -1
- package/dist/module.mjs +10 -1
- package/dist/runtime/dashboard/components/block/dashboard-block-state.d.vue.ts +2 -0
- package/dist/runtime/dashboard/components/block/dashboard-block-state.vue +4 -1
- package/dist/runtime/dashboard/components/block/dashboard-block-state.vue.d.ts +2 -0
- package/dist/runtime/dashboard/components/block/dashboard-chips.d.vue.ts +20 -0
- package/dist/runtime/dashboard/components/block/dashboard-chips.vue +42 -0
- package/dist/runtime/dashboard/components/block/dashboard-chips.vue.d.ts +20 -0
- package/dist/runtime/dashboard/components/block/dashboard-series-picker.d.vue.ts +8 -0
- package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue +29 -0
- package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue.d.ts +8 -0
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.d.vue.ts +1 -1
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue.d.ts +1 -1
- package/dist/runtime/dashboard/components/block/dashboard-view-scope.d.vue.ts +21 -0
- package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue +12 -0
- package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue.d.ts +21 -0
- package/dist/runtime/dashboard/components/dashboard-alerts.vue +3 -3
- package/dist/runtime/dashboard/components/dashboard-bar-chart.d.vue.ts +14 -3
- package/dist/runtime/dashboard/components/dashboard-bar-chart.vue +30 -9
- package/dist/runtime/dashboard/components/dashboard-bar-chart.vue.d.ts +14 -3
- package/dist/runtime/dashboard/components/dashboard-bars.vue +4 -4
- package/dist/runtime/dashboard/components/dashboard-card.vue +28 -6
- package/dist/runtime/dashboard/components/dashboard-combo-chart.d.vue.ts +6 -1
- package/dist/runtime/dashboard/components/dashboard-combo-chart.vue +13 -3
- package/dist/runtime/dashboard/components/dashboard-combo-chart.vue.d.ts +6 -1
- package/dist/runtime/dashboard/components/dashboard-donut-chart.vue +5 -5
- package/dist/runtime/dashboard/components/dashboard-feed.vue +1 -1
- package/dist/runtime/dashboard/components/dashboard-filter.d.vue.ts +67 -0
- package/dist/runtime/dashboard/components/dashboard-filter.vue +134 -0
- package/dist/runtime/dashboard/components/dashboard-filter.vue.d.ts +67 -0
- package/dist/runtime/dashboard/components/dashboard-filters.d.vue.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-filters.vue +96 -0
- package/dist/runtime/dashboard/components/dashboard-filters.vue.d.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-funnel.vue +5 -5
- package/dist/runtime/dashboard/components/dashboard-gauge.vue +3 -3
- package/dist/runtime/dashboard/components/dashboard-grid.d.vue.ts +10 -3
- package/dist/runtime/dashboard/components/dashboard-grid.vue +24 -9
- package/dist/runtime/dashboard/components/dashboard-grid.vue.d.ts +10 -3
- package/dist/runtime/dashboard/components/dashboard-line-chart.d.vue.ts +14 -3
- package/dist/runtime/dashboard/components/dashboard-line-chart.vue +30 -9
- package/dist/runtime/dashboard/components/dashboard-line-chart.vue.d.ts +14 -3
- package/dist/runtime/dashboard/components/dashboard-list.d.vue.ts +3 -0
- package/dist/runtime/dashboard/components/dashboard-list.vue +18 -6
- package/dist/runtime/dashboard/components/dashboard-list.vue.d.ts +3 -0
- package/dist/runtime/dashboard/components/dashboard-page.d.vue.ts +53 -0
- package/dist/runtime/dashboard/components/dashboard-page.vue +156 -0
- package/dist/runtime/dashboard/components/dashboard-page.vue.d.ts +53 -0
- package/dist/runtime/dashboard/components/dashboard-paired-bars.vue +4 -4
- package/dist/runtime/dashboard/components/dashboard-refresh.d.vue.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-refresh.vue +1 -0
- package/dist/runtime/dashboard/components/dashboard-refresh.vue.d.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-stack-bar.vue +4 -4
- package/dist/runtime/dashboard/components/dashboard-stat.d.vue.ts +14 -2
- package/dist/runtime/dashboard/components/dashboard-stat.vue +28 -10
- package/dist/runtime/dashboard/components/dashboard-stat.vue.d.ts +14 -2
- package/dist/runtime/dashboard/components/dashboard-stats.vue +3 -3
- package/dist/runtime/dashboard/components/dashboard-table.d.vue.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-table.vue +3 -3
- package/dist/runtime/dashboard/components/dashboard-table.vue.d.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-tabs.d.vue.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-tabs.vue.d.ts +1 -1
- package/dist/runtime/dashboard/components/dashboard-total.d.vue.ts +7 -2
- package/dist/runtime/dashboard/components/dashboard-total.vue +10 -2
- package/dist/runtime/dashboard/components/dashboard-total.vue.d.ts +7 -2
- package/dist/runtime/dashboard/components/dashboard-view-tabs.d.vue.ts +33 -0
- package/dist/runtime/dashboard/components/dashboard-view-tabs.vue +66 -0
- package/dist/runtime/dashboard/components/dashboard-view-tabs.vue.d.ts +33 -0
- package/dist/runtime/dashboard/components/dashboard-widget.vue +1 -1
- package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.d.vue.ts +44 -0
- package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue +220 -0
- package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue.d.ts +44 -0
- package/dist/runtime/dashboard/composables/use-dashboard-api.d.ts +6 -1
- package/dist/runtime/dashboard/composables/use-dashboard-api.js +29 -6
- package/dist/runtime/dashboard/composables/use-dashboard-block.d.ts +5 -4
- package/dist/runtime/dashboard/composables/use-dashboard-block.js +32 -15
- package/dist/runtime/dashboard/composables/use-dashboard-chart.d.ts +8 -1
- package/dist/runtime/dashboard/composables/use-dashboard-chart.js +16 -4
- package/dist/runtime/dashboard/composables/use-dashboard-context.d.ts +50 -0
- package/dist/runtime/dashboard/composables/use-dashboard-context.js +56 -0
- package/dist/runtime/dashboard/composables/use-dashboard-derived.js +6 -1
- package/dist/runtime/dashboard/composables/use-dashboard-filter-control.d.ts +16 -0
- package/dist/runtime/dashboard/composables/use-dashboard-filter-control.js +161 -0
- package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.d.ts +37 -0
- package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.js +107 -0
- package/dist/runtime/dashboard/composables/use-dashboard-format.d.ts +46 -6
- package/dist/runtime/dashboard/composables/use-dashboard-format.js +51 -8
- package/dist/runtime/dashboard/composables/use-dashboard-options.d.ts +11 -4
- package/dist/runtime/dashboard/composables/use-dashboard-options.js +33 -47
- package/dist/runtime/dashboard/composables/use-dashboard-remote-options.d.ts +8 -5
- package/dist/runtime/dashboard/composables/use-dashboard-remote-options.js +59 -70
- package/dist/runtime/dashboard/composables/use-dashboard-resource.d.ts +15 -4
- package/dist/runtime/dashboard/composables/use-dashboard-resource.js +52 -17
- package/dist/runtime/dashboard/composables/use-dashboard-scope.d.ts +10 -7
- package/dist/runtime/dashboard/composables/use-dashboard-scope.js +26 -16
- package/dist/runtime/dashboard/composables/use-dashboard-series-picker.d.ts +20 -0
- package/dist/runtime/dashboard/composables/use-dashboard-series-picker.js +30 -0
- package/dist/runtime/dashboard/composables/use-dashboard-time.d.ts +2 -0
- package/dist/runtime/dashboard/composables/use-dashboard-time.js +4 -1
- package/dist/runtime/dashboard/composables/use-dashboard-ui.d.ts +12 -2
- package/dist/runtime/dashboard/composables/use-dashboard-ui.js +3 -0
- package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +15 -3
- package/dist/runtime/dashboard/composables/use-dashboard-views.js +33 -10
- package/dist/runtime/dashboard/composables/use-dashboard.d.ts +18 -12
- package/dist/runtime/dashboard/composables/use-dashboard.js +98 -9
- package/dist/runtime/dashboard/index.d.ts +3 -1
- package/dist/runtime/dashboard/index.js +3 -1
- package/dist/runtime/dashboard/schema/index.d.ts +62 -30
- package/dist/runtime/dashboard/schema/index.js +3 -0
- package/dist/runtime/dashboard/types/blocks.d.ts +30 -4
- package/dist/runtime/dashboard/types/charts.d.ts +2 -2
- package/dist/runtime/dashboard/types/controls.d.ts +123 -0
- package/dist/runtime/dashboard/types/filters.d.ts +236 -0
- package/dist/runtime/dashboard/types/index.d.ts +3 -2
- package/dist/runtime/dashboard/types/page.d.ts +17 -0
- package/dist/runtime/dashboard/types/page.js +0 -0
- package/dist/runtime/dashboard/types/resource.d.ts +66 -28
- package/dist/runtime/dashboard/types/runtime.d.ts +39 -8
- package/dist/runtime/dashboard/types/schema.d.ts +94 -54
- package/dist/runtime/dashboard/types/ui.d.ts +78 -0
- package/dist/runtime/dashboard/utils/builders/dashboard-filters.d.ts +142 -0
- package/dist/runtime/dashboard/utils/builders/dashboard-filters.js +135 -0
- package/dist/runtime/dashboard/utils/charts.d.ts +4 -15
- package/dist/runtime/dashboard/utils/charts.js +26 -28
- package/dist/runtime/dashboard/utils/{params/codecs.d.ts → codecs.d.ts} +2 -2
- package/dist/runtime/dashboard/utils/{params/codecs.js → codecs.js} +1 -1
- package/dist/runtime/dashboard/utils/environment.d.ts +36 -0
- package/dist/runtime/dashboard/utils/environment.js +30 -0
- package/dist/runtime/dashboard/utils/filters.d.ts +44 -0
- package/dist/runtime/dashboard/utils/filters.js +62 -0
- package/dist/runtime/dashboard/utils/format.d.ts +25 -0
- package/dist/runtime/dashboard/utils/format.js +66 -0
- package/dist/runtime/dashboard/utils/grid.d.ts +17 -0
- package/dist/runtime/dashboard/utils/grid.js +14 -0
- package/dist/runtime/dashboard/utils/options.d.ts +3 -1
- package/dist/runtime/dashboard/utils/options.js +6 -0
- package/dist/runtime/dashboard/utils/remote.d.ts +7 -0
- package/dist/runtime/dashboard/utils/remote.js +14 -0
- package/dist/runtime/dashboard/utils/resource.d.ts +16 -7
- package/dist/runtime/dashboard/utils/resource.js +15 -9
- package/dist/runtime/dashboard/utils/schema.d.ts +8 -3
- package/dist/runtime/dashboard/utils/schema.js +9 -4
- package/dist/runtime/dashboard/utils/state.d.ts +11 -6
- package/dist/runtime/dashboard/utils/state.js +10 -5
- package/dist/runtime/dashboard/utils/time.d.ts +2 -0
- package/dist/runtime/dashboard/utils/time.js +11 -1
- package/dist/runtime/dashboard/utils/ui.d.ts +1 -1
- package/dist/runtime/dashboard/utils/ui.js +1 -1
- package/dist/runtime/form/components/root/form.vue +1 -1
- package/dist/runtime/form/fields/card-selection.d.ts +1 -0
- package/dist/runtime/form/fields/card-selection.js +1 -0
- package/dist/runtime/form/fields/checkbox-card/component.vue +3 -1
- package/dist/runtime/form/fields/checkbox-group/component.vue +5 -0
- package/dist/runtime/form/fields/radio/component.vue +10 -0
- package/dist/runtime/form/fields/radio-card/component.vue +3 -1
- package/dist/runtime/form/types/options.d.ts +1 -11
- package/dist/runtime/form/utils/focus.js +1 -1
- package/dist/runtime/i18n/locales/en.js +29 -0
- package/dist/runtime/i18n/locales/fr.js +29 -0
- package/dist/runtime/i18n/types.d.ts +41 -0
- package/dist/runtime/shared/styles/tokens.css +1 -1
- package/dist/runtime/shared/types/query.d.ts +8 -0
- package/dist/runtime/table/types/index.d.ts +1 -0
- package/dist/runtime/table/types/remote-options.d.ts +64 -0
- package/dist/runtime/table/types/remote-options.js +0 -0
- package/dist/runtime/table/types/source.d.ts +10 -1
- package/dist/runtime/table/utils/builders/table-source.d.ts +2 -6
- package/dist/runtime/table/utils/index.d.ts +1 -0
- package/dist/runtime/table/utils/index.js +1 -0
- package/dist/runtime/table/utils/remote-table-options.d.ts +26 -0
- package/dist/runtime/table/utils/remote-table-options.js +88 -0
- package/package.json +4 -1
- package/dist/runtime/dashboard/composables/use-dashboard-param-scope.d.ts +0 -30
- package/dist/runtime/dashboard/composables/use-dashboard-param-scope.js +0 -71
- package/dist/runtime/dashboard/types/options.d.ts +0 -46
- package/dist/runtime/dashboard/types/params.d.ts +0 -115
- package/dist/runtime/dashboard/utils/builders/dashboard-params.d.ts +0 -85
- package/dist/runtime/dashboard/utils/builders/dashboard-params.js +0 -87
- /package/dist/runtime/dashboard/types/{options.js → controls.js} +0 -0
- /package/dist/runtime/dashboard/types/{params.js → filters.js} +0 -0
|
@@ -1,34 +1,51 @@
|
|
|
1
|
-
import { computed, onBeforeUnmount,
|
|
1
|
+
import { computed, onBeforeUnmount, watch } from "vue";
|
|
2
2
|
import { useResponsiveValue } from "../../shared/composables/use-responsive-value.js";
|
|
3
|
+
import { parseDashboardSpan, resolveDashboardCellStyle } from "../utils/grid.js";
|
|
3
4
|
import { observeDashboardVisibility } from "../utils/visibility.js";
|
|
5
|
+
import { useDashboardGridContext } from "./use-dashboard-ui.js";
|
|
4
6
|
export function useDashboardBlock(params) {
|
|
7
|
+
const hidden = computed(() => params.source()?.state === "disabled");
|
|
5
8
|
const phase = computed(() => {
|
|
6
9
|
const source = params.source();
|
|
7
10
|
if (!source) return "content";
|
|
11
|
+
if (source.state === "disabled") return "idle";
|
|
8
12
|
if (source.state !== "ready") return source.state;
|
|
9
13
|
return params.empty() ? "empty" : "content";
|
|
10
14
|
});
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const fetching = computed(() => {
|
|
16
|
+
const source = params.source();
|
|
17
|
+
return source ? source.fetching ?? source.refreshing : false;
|
|
18
|
+
});
|
|
19
|
+
const grid = useDashboardGridContext();
|
|
20
|
+
const span = useResponsiveValue(() => params.size() ?? "", "integer");
|
|
14
21
|
const style = computed(
|
|
15
|
-
() =>
|
|
22
|
+
() => grid ? resolveDashboardCellStyle({
|
|
23
|
+
columns: grid.columns.value,
|
|
24
|
+
fill: grid.fill.value,
|
|
25
|
+
gap: grid.gap.value,
|
|
26
|
+
span: parseDashboardSpan(span.value)
|
|
27
|
+
}) : ""
|
|
16
28
|
);
|
|
17
29
|
let stopObserving;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
watch(
|
|
31
|
+
() => params.root.value,
|
|
32
|
+
(element) => {
|
|
33
|
+
stopObserving?.();
|
|
34
|
+
stopObserving = void 0;
|
|
35
|
+
const source = params.source();
|
|
36
|
+
const activation = params.activation() ?? "visible";
|
|
37
|
+
if (!element || !source || activation === "manual" || !waitsForActivation(source)) return;
|
|
38
|
+
if (activation === "mount" || typeof IntersectionObserver === "undefined")
|
|
39
|
+
return source.activate();
|
|
40
|
+
stopObserving = observeDashboardVisibility(element, () => params.source()?.activate());
|
|
41
|
+
},
|
|
42
|
+
{ flush: "post", immediate: true }
|
|
43
|
+
);
|
|
27
44
|
onBeforeUnmount(() => stopObserving?.());
|
|
28
45
|
function retry() {
|
|
29
46
|
params.source()?.refresh().catch(() => void 0);
|
|
30
47
|
}
|
|
31
|
-
return {
|
|
48
|
+
return { fetching, hidden, phase, retry, style };
|
|
32
49
|
}
|
|
33
50
|
function waitsForActivation(source) {
|
|
34
51
|
return !("stage" in source) || source.stage === "deferred";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LazyTextValue } from '../../shared/types/utils.js';
|
|
2
|
-
import type { DashboardAxisOptions, DashboardChartFrame, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardValueFormat } from '../types/index.js';
|
|
2
|
+
import type { DashboardAxisOptions, DashboardChartFrame, DashboardChartTotals, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardValueFormat } from '../types/index.js';
|
|
3
3
|
/** A chart drawn taller in the expand dialog. */
|
|
4
4
|
export declare function resolveDashboardExpandedHeight(height: number): number;
|
|
5
5
|
/**
|
|
@@ -27,10 +27,17 @@ export declare function useDashboardChart<TRow>(params: {
|
|
|
27
27
|
selected?: () => DashboardSelected<TRow> | undefined;
|
|
28
28
|
/** Bar charts: prints each group's value above its bars. */
|
|
29
29
|
labels?: () => boolean;
|
|
30
|
+
/** Footer totals of the solid series: their sum, or their average. */
|
|
31
|
+
totals?: () => DashboardChartTotals | undefined;
|
|
30
32
|
}): {
|
|
31
33
|
frame: import("vue").ComputedRef<DashboardChartFrame>;
|
|
32
34
|
legend: import("vue").ComputedRef<import("../types/index.js").DashboardLegendItem[]>;
|
|
33
35
|
select: (index: number) => void;
|
|
34
36
|
selectable: import("vue").ComputedRef<boolean>;
|
|
35
37
|
tabulate: () => import("../types/index.js").DashboardDataTable;
|
|
38
|
+
totals: import("vue").ComputedRef<{
|
|
39
|
+
key: string;
|
|
40
|
+
label: string;
|
|
41
|
+
text: string;
|
|
42
|
+
}[]>;
|
|
36
43
|
};
|
|
@@ -58,7 +58,7 @@ export function useDashboardChart(params) {
|
|
|
58
58
|
const values = stacked && axis === "left" ? data.map((datum) => indexes.reduce((sum, index) => sum + (datum.values[index] ?? 0), 0)) : data.flatMap((datum) => indexes.map((index) => datum.values[index]));
|
|
59
59
|
return [...values, ...references.filter((ref) => ref.axis === axis).map((ref) => ref.value)];
|
|
60
60
|
};
|
|
61
|
-
const format = params.format()
|
|
61
|
+
const format = formats.resolve(params.format());
|
|
62
62
|
const yAxis = params.yAxis();
|
|
63
63
|
const y2Axis = params.y2Axis?.();
|
|
64
64
|
const hasRight = resolved.some((entry) => entry.axis === "right");
|
|
@@ -70,7 +70,7 @@ export function useDashboardChart(params) {
|
|
|
70
70
|
);
|
|
71
71
|
const selected = params.selected?.();
|
|
72
72
|
const emphasis = hasBars ? resolveDashboardEmphasis(rows, barTotals, params.highlight?.(), selected) : null;
|
|
73
|
-
const leftFormat = yAxis?.format
|
|
73
|
+
const leftFormat = yAxis?.format ? formats.resolve(yAxis.format) : format;
|
|
74
74
|
return {
|
|
75
75
|
data,
|
|
76
76
|
emphasis,
|
|
@@ -82,7 +82,7 @@ export function useDashboardChart(params) {
|
|
|
82
82
|
references,
|
|
83
83
|
right: hasRight ? {
|
|
84
84
|
...resolveDashboardAxis(axisValues("right"), y2Axis, headroom),
|
|
85
|
-
format: y2Axis?.format
|
|
85
|
+
format: y2Axis?.format ? formats.resolve(y2Axis.format) : format
|
|
86
86
|
} : null,
|
|
87
87
|
series: resolved.map(({ axis, color, dashed, key, label, type }, index) => ({
|
|
88
88
|
axis,
|
|
@@ -105,6 +105,18 @@ export function useDashboardChart(params) {
|
|
|
105
105
|
xDomain: hasBars || last === 0 ? [-0.5, last + 0.5] : [0, last]
|
|
106
106
|
};
|
|
107
107
|
});
|
|
108
|
+
const totals = computed(() => {
|
|
109
|
+
const mode = params.totals?.();
|
|
110
|
+
if (!mode) return [];
|
|
111
|
+
const { data, left, right, series: entries } = frame.value;
|
|
112
|
+
return entries.filter((entry) => !entry.dashed && !entry.key.endsWith(":compare")).map((entry) => {
|
|
113
|
+
const values = data.flatMap((datum) => datum.values[entry.index] ?? []);
|
|
114
|
+
const sum = values.reduce((total, value2) => total + value2, 0);
|
|
115
|
+
const value = mode === "average" ? values.length ? sum / values.length : 0 : sum;
|
|
116
|
+
const format = (entry.axis === "right" ? right?.format : void 0) ?? left.format;
|
|
117
|
+
return { key: entry.key, label: entry.label, text: format(value) };
|
|
118
|
+
});
|
|
119
|
+
});
|
|
108
120
|
const tabulate = () => tabulateDashboardFrame(
|
|
109
121
|
frame.value,
|
|
110
122
|
resolveTextValue(params.xLabel(), t("dashboard.table.category"))
|
|
@@ -114,5 +126,5 @@ export function useDashboardChart(params) {
|
|
|
114
126
|
const row = params.rows()[index];
|
|
115
127
|
if (row !== void 0) params.onSelect()?.({ index, row });
|
|
116
128
|
}
|
|
117
|
-
return { frame, legend, select, selectable, tabulate };
|
|
129
|
+
return { frame, legend, select, selectable, tabulate, totals };
|
|
118
130
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DashboardSchemaInput, DashboardSchemaLike, DashboardViewInput, InferDashboard, InferDashboardView } from '../types/index.js';
|
|
2
|
+
/** One dashboard created by `useDashboard`, as its descendants find it. */
|
|
3
|
+
export interface DashboardContextEntry {
|
|
4
|
+
/** What `useDashboard` received: a schema, or a function returning one. */
|
|
5
|
+
readonly source: unknown;
|
|
6
|
+
/** The schema the dashboard currently runs. */
|
|
7
|
+
schema(): DashboardSchemaLike;
|
|
8
|
+
/** The dashboard object `useDashboard` returned. */
|
|
9
|
+
readonly api: object;
|
|
10
|
+
/** Handle of a view, stable across rebuilds. */
|
|
11
|
+
view(key: string): object | undefined;
|
|
12
|
+
/** Key of the view declared with this object, if the current schema has one. */
|
|
13
|
+
findView(declaration: object): string | undefined;
|
|
14
|
+
/** Key of the view on screen. */
|
|
15
|
+
current(): string | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Makes a dashboard available to descendant components. */
|
|
18
|
+
export declare function provideDashboard(entry: DashboardContextEntry): void;
|
|
19
|
+
/**
|
|
20
|
+
* Marks the components below as rendering one view of a dashboard, so `useDashboardView` resolves
|
|
21
|
+
* a view function to it. `UiDashboardPage` does it around the current view's slot.
|
|
22
|
+
*/
|
|
23
|
+
export declare function provideDashboardView(dashboard: object, key: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Returns the dashboard an ancestor component created with `useDashboard`, fully typed, so nested
|
|
26
|
+
* components read it without props. Pass the schema, or the schema function: the nearest dashboard
|
|
27
|
+
* built from it answers (for a function, the nearest dashboard).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const account = injectDashboard(accountSchema)
|
|
32
|
+
* account.filters.year
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function injectDashboard<const TInput extends DashboardSchemaInput>(input: TInput): InferDashboard<TInput>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the handle of a view: its queries, derived values, filters and controls, fully typed. A
|
|
38
|
+
* tab component needs nothing else.
|
|
39
|
+
*
|
|
40
|
+
* Pass the view, or the view function. Under `UiDashboardPage`, the view is the one whose slot
|
|
41
|
+
* renders the component; elsewhere, a view object is found by identity and a view function reads
|
|
42
|
+
* the view on screen.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const consumption = useDashboardView(consumptionView)
|
|
47
|
+
* consumption.filters.year
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function useDashboardView<const TInput extends DashboardViewInput>(input: TInput): InferDashboardView<TInput>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { getCurrentInstance, inject, provide } from "vue";
|
|
2
|
+
const dashboardContextKey = Symbol("nuxt-ui-tools.dashboard");
|
|
3
|
+
function injectDashboardContext() {
|
|
4
|
+
return getCurrentInstance() ? inject(dashboardContextKey, null) : null;
|
|
5
|
+
}
|
|
6
|
+
export function provideDashboard(entry) {
|
|
7
|
+
if (!getCurrentInstance()) return;
|
|
8
|
+
const parent = injectDashboardContext();
|
|
9
|
+
provide(dashboardContextKey, { dashboards: [...parent?.dashboards ?? [], entry] });
|
|
10
|
+
}
|
|
11
|
+
export function provideDashboardView(dashboard, key) {
|
|
12
|
+
const parent = injectDashboardContext();
|
|
13
|
+
const entry = parent ? findLastEntry(parent.dashboards, (candidate) => candidate.api === dashboard) : void 0;
|
|
14
|
+
if (!parent || !entry) return;
|
|
15
|
+
provide(dashboardContextKey, { dashboards: parent.dashboards, view: { entry, key } });
|
|
16
|
+
}
|
|
17
|
+
export function injectDashboard(input) {
|
|
18
|
+
const dashboards = injectDashboardContext()?.dashboards ?? [];
|
|
19
|
+
const entry = findLastEntry(
|
|
20
|
+
dashboards,
|
|
21
|
+
(candidate) => candidate.source === input || candidate.schema() === input
|
|
22
|
+
) ?? (typeof input === "function" ? dashboards.at(-1) : void 0);
|
|
23
|
+
if (!entry)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"[dashboard] injectDashboard() found no dashboard. Call useDashboard() in a parent component."
|
|
26
|
+
);
|
|
27
|
+
return entry.api;
|
|
28
|
+
}
|
|
29
|
+
export function useDashboardView(input) {
|
|
30
|
+
const context = injectDashboardContext();
|
|
31
|
+
const handle = resolveView(context, input);
|
|
32
|
+
if (!handle)
|
|
33
|
+
throw new Error(
|
|
34
|
+
"[dashboard] useDashboardView() found no view. Render the component in a view slot of UiDashboardPage, under a dashboard created with useDashboard() whose schema declares the view."
|
|
35
|
+
);
|
|
36
|
+
return handle;
|
|
37
|
+
}
|
|
38
|
+
function resolveView(context, input) {
|
|
39
|
+
if (!context) return void 0;
|
|
40
|
+
const enclosing = context.view;
|
|
41
|
+
if (enclosing && (typeof input === "function" || enclosing.entry.findView(input) === enclosing.key))
|
|
42
|
+
return enclosing.entry.view(enclosing.key);
|
|
43
|
+
for (let index = context.dashboards.length - 1; index >= 0; index--) {
|
|
44
|
+
const entry = context.dashboards[index];
|
|
45
|
+
const key = typeof input === "function" ? entry?.current() : entry?.findView(input);
|
|
46
|
+
if (entry && key !== void 0) return entry.view(key);
|
|
47
|
+
}
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
function findLastEntry(dashboards, match) {
|
|
51
|
+
for (let index = dashboards.length - 1; index >= 0; index--) {
|
|
52
|
+
const entry = dashboards[index];
|
|
53
|
+
if (entry && match(entry)) return entry;
|
|
54
|
+
}
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
@@ -21,16 +21,20 @@ export function useDashboardDerived(params) {
|
|
|
21
21
|
if (sourcesState.value !== "ready") return sourcesState.value;
|
|
22
22
|
return evaluation.value.error === void 0 ? "ready" : "error";
|
|
23
23
|
});
|
|
24
|
-
|
|
24
|
+
const derived = markRaw({
|
|
25
25
|
activate() {
|
|
26
26
|
for (const source of evaluation.value.sources) source.activate();
|
|
27
27
|
},
|
|
28
28
|
get data() {
|
|
29
|
+
params.tracker.record(derived);
|
|
29
30
|
return evaluation.value.value;
|
|
30
31
|
},
|
|
31
32
|
get error() {
|
|
32
33
|
return evaluation.value.error ?? evaluation.value.sources.find((source) => source.state === "error")?.error;
|
|
33
34
|
},
|
|
35
|
+
get fetching() {
|
|
36
|
+
return evaluation.value.sources.some((source) => source.fetching ?? source.refreshing);
|
|
37
|
+
},
|
|
34
38
|
id: params.id,
|
|
35
39
|
kind: "derived",
|
|
36
40
|
refresh: () => refreshDashboardSources(evaluation.value.sources),
|
|
@@ -44,4 +48,5 @@ export function useDashboardDerived(params) {
|
|
|
44
48
|
return resolveDashboardUpdatedAt(evaluation.value.sources.map((source) => source.updatedAt));
|
|
45
49
|
}
|
|
46
50
|
});
|
|
51
|
+
return derived;
|
|
47
52
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QueryKey } from '@tanstack/vue-query';
|
|
2
|
+
import type { DashboardFilterControl, DashboardRuntimeFilter } from '../types/index.js';
|
|
3
|
+
import type { DashboardLocale } from '../utils/environment.js';
|
|
4
|
+
/**
|
|
5
|
+
* Control of one filter: its value and presentation (label, display text, option list) plus the
|
|
6
|
+
* actions pickers perform (`toggle`, `reset`). It owns no state of its own besides the option list;
|
|
7
|
+
* the value lives wherever the filter syncs it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useDashboardFilterControl(params: {
|
|
10
|
+
key: string;
|
|
11
|
+
definition: DashboardRuntimeFilter;
|
|
12
|
+
queryKey: QueryKey;
|
|
13
|
+
locale: DashboardLocale;
|
|
14
|
+
get: () => unknown;
|
|
15
|
+
set: (value: unknown) => void;
|
|
16
|
+
}): DashboardFilterControl;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { computed, markRaw } from "vue";
|
|
2
|
+
import { isNullish } from "../../shared/utils/predicate.js";
|
|
3
|
+
import { resolveTextValue } from "../../shared/utils/render.js";
|
|
4
|
+
import {
|
|
5
|
+
formatDashboardFilterValue,
|
|
6
|
+
isDashboardOptionValue,
|
|
7
|
+
isDashboardFilterHeadless
|
|
8
|
+
} from "../utils/filters.js";
|
|
9
|
+
import { resolveDashboardCondition } from "../utils/state.js";
|
|
10
|
+
import { useDashboardOptions } from "./use-dashboard-options.js";
|
|
11
|
+
export function useDashboardFilterControl(params) {
|
|
12
|
+
const { definition, get, set } = params;
|
|
13
|
+
const { code, t } = params.locale;
|
|
14
|
+
const options = useDashboardOptions({
|
|
15
|
+
definition,
|
|
16
|
+
locale: params.locale,
|
|
17
|
+
queryKey: params.queryKey,
|
|
18
|
+
value: get
|
|
19
|
+
});
|
|
20
|
+
const listed = definition.items !== void 0 || definition.remote !== void 0;
|
|
21
|
+
const label = computed(() => resolveTextValue(definition.label, params.key));
|
|
22
|
+
const placeholder = computed(
|
|
23
|
+
() => resolveTextValue(definition.placeholder, t("dashboard.filters.all"))
|
|
24
|
+
);
|
|
25
|
+
const changed = computed(
|
|
26
|
+
() => definition.codec.serialize(get()) !== definition.codec.serialize(definition.resolveDefault())
|
|
27
|
+
);
|
|
28
|
+
const values = computed(() => {
|
|
29
|
+
const value = get();
|
|
30
|
+
const list = Array.isArray(value) ? value : [value];
|
|
31
|
+
return list.filter(isDashboardOptionValue);
|
|
32
|
+
});
|
|
33
|
+
const keys = computed(() => new Set(values.value.map(String)));
|
|
34
|
+
const selected = computed(
|
|
35
|
+
() => values.value.map(
|
|
36
|
+
(value) => options.known.value.get(String(value)) ?? {
|
|
37
|
+
label: options.resolving.value ? "\u2026" : describe(value),
|
|
38
|
+
value
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
const display = computed(() => {
|
|
43
|
+
const value = get();
|
|
44
|
+
if (isNullish(value) || Array.isArray(value) && value.length === 0) return placeholder.value;
|
|
45
|
+
const [first, second] = selected.value;
|
|
46
|
+
if (!first) return describe(value);
|
|
47
|
+
if (!second) return first.label;
|
|
48
|
+
return selected.value.length === 2 ? `${first.label}, ${second.label}` : t("dashboard.filters.more", { count: selected.value.length - 1, label: first.label });
|
|
49
|
+
});
|
|
50
|
+
function describe(value) {
|
|
51
|
+
return definition.format ? definition.format(value) : formatDashboardFilterValue(value, code.value);
|
|
52
|
+
}
|
|
53
|
+
const presets = computed(() => {
|
|
54
|
+
const current = definition.codec.serialize(get());
|
|
55
|
+
return (definition.presets?.() ?? []).map((preset) => ({
|
|
56
|
+
active: definition.codec.serialize(preset.value) === current,
|
|
57
|
+
apply: () => set(preset.value),
|
|
58
|
+
hint: preset.hint,
|
|
59
|
+
icon: preset.icon,
|
|
60
|
+
label: resolveTextValue(preset.label),
|
|
61
|
+
value: preset.value
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
const menu = computed(() => ({
|
|
65
|
+
items: [...options.items.value],
|
|
66
|
+
labelKey: "label",
|
|
67
|
+
multiple: definition.multiple,
|
|
68
|
+
valueKey: "value",
|
|
69
|
+
...options.menu.value
|
|
70
|
+
}));
|
|
71
|
+
function toggle(value) {
|
|
72
|
+
if (!definition.multiple) return set(value);
|
|
73
|
+
const current = Array.isArray(get()) ? values.value : [];
|
|
74
|
+
const key = String(value);
|
|
75
|
+
if (keys.value.has(key)) return set(current.filter((entry) => String(entry) !== key));
|
|
76
|
+
if (definition.max !== void 0 && current.length >= definition.max) return;
|
|
77
|
+
const order = options.order.value;
|
|
78
|
+
const next = [...current, value];
|
|
79
|
+
if (order) {
|
|
80
|
+
const rank = (entry) => order.get(String(entry)) ?? order.size;
|
|
81
|
+
next.sort((first, second) => rank(first) - rank(second));
|
|
82
|
+
}
|
|
83
|
+
set(next);
|
|
84
|
+
}
|
|
85
|
+
return markRaw({
|
|
86
|
+
get changed() {
|
|
87
|
+
return changed.value;
|
|
88
|
+
},
|
|
89
|
+
get columns() {
|
|
90
|
+
return definition.columns;
|
|
91
|
+
},
|
|
92
|
+
get defaultValue() {
|
|
93
|
+
return definition.resolveDefault();
|
|
94
|
+
},
|
|
95
|
+
get display() {
|
|
96
|
+
return display.value;
|
|
97
|
+
},
|
|
98
|
+
get error() {
|
|
99
|
+
return options.error.value;
|
|
100
|
+
},
|
|
101
|
+
get hasMore() {
|
|
102
|
+
return options.hasMore.value;
|
|
103
|
+
},
|
|
104
|
+
get enabled() {
|
|
105
|
+
return resolveDashboardCondition(definition.enabled);
|
|
106
|
+
},
|
|
107
|
+
headless: isDashboardFilterHeadless(definition),
|
|
108
|
+
isSelected: (value) => keys.value.has(String(value)),
|
|
109
|
+
get items() {
|
|
110
|
+
return listed ? options.items.value : [];
|
|
111
|
+
},
|
|
112
|
+
key: params.key,
|
|
113
|
+
kind: definition.kind,
|
|
114
|
+
get label() {
|
|
115
|
+
return label.value;
|
|
116
|
+
},
|
|
117
|
+
get loading() {
|
|
118
|
+
return options.loading.value;
|
|
119
|
+
},
|
|
120
|
+
get loadingMore() {
|
|
121
|
+
return options.loadingMore.value;
|
|
122
|
+
},
|
|
123
|
+
loadMore: options.loadMore,
|
|
124
|
+
max: definition.max,
|
|
125
|
+
get menu() {
|
|
126
|
+
return menu.value;
|
|
127
|
+
},
|
|
128
|
+
multiple: definition.multiple,
|
|
129
|
+
get open() {
|
|
130
|
+
return options.open.value;
|
|
131
|
+
},
|
|
132
|
+
set open(next) {
|
|
133
|
+
options.open.value = next;
|
|
134
|
+
},
|
|
135
|
+
get placeholder() {
|
|
136
|
+
return placeholder.value;
|
|
137
|
+
},
|
|
138
|
+
get presets() {
|
|
139
|
+
return presets.value;
|
|
140
|
+
},
|
|
141
|
+
refresh: options.refresh,
|
|
142
|
+
reset: () => set(definition.resolveDefault()),
|
|
143
|
+
get search() {
|
|
144
|
+
return options.search.value;
|
|
145
|
+
},
|
|
146
|
+
set search(next) {
|
|
147
|
+
options.search.value = next;
|
|
148
|
+
},
|
|
149
|
+
searchable: definition.searchable === true,
|
|
150
|
+
get selected() {
|
|
151
|
+
return selected.value;
|
|
152
|
+
},
|
|
153
|
+
toggle,
|
|
154
|
+
get value() {
|
|
155
|
+
return get();
|
|
156
|
+
},
|
|
157
|
+
set value(next) {
|
|
158
|
+
set(next);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { QueryKey } from '@tanstack/vue-query';
|
|
2
|
+
import type { DashboardFilterControl, DashboardFilterLike } from '../types/index.js';
|
|
3
|
+
import type { DashboardEnvironment } from '../utils/environment.js';
|
|
4
|
+
/**
|
|
5
|
+
* What one filter scope exposes. Declared rather than inferred: the inferred type would carry Vue's
|
|
6
|
+
* `Raw<…>` marker, which declaration files cannot name.
|
|
7
|
+
*/
|
|
8
|
+
export interface DashboardFilterScope {
|
|
9
|
+
keys: readonly string[];
|
|
10
|
+
/** Controls, by filter key. */
|
|
11
|
+
controls: Readonly<Record<string, DashboardFilterControl>>;
|
|
12
|
+
/** URL segments of this scope's URL-synced filters, before the dashboard prefix. */
|
|
13
|
+
urlKeys: readonly string[];
|
|
14
|
+
/** Writable facade: one getter / setter per filter. */
|
|
15
|
+
values: object;
|
|
16
|
+
/** A filter that is enabled and not headless differs from its default. */
|
|
17
|
+
changed: () => boolean;
|
|
18
|
+
/** Restores the default of every filter that is enabled and not headless. */
|
|
19
|
+
reset: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Owns the filters of one scope (dashboard root, a view, or a query): where each value lives (one
|
|
23
|
+
* `useQueryStates` for the URL-synced ones, a ref per memory filter, the external ref or getter of
|
|
24
|
+
* synced ones), a writable values facade, and one control per filter. Scopes without filters
|
|
25
|
+
* allocate nothing.
|
|
26
|
+
*
|
|
27
|
+
* A URL key names one filter across the dashboard: scopes declaring the same key read and write the
|
|
28
|
+
* same value, and must declare it the same way.
|
|
29
|
+
*/
|
|
30
|
+
export declare function useDashboardFilterScope(params: {
|
|
31
|
+
definitions: Readonly<Record<string, DashboardFilterLike>>;
|
|
32
|
+
/** Where the scope sits, for error messages: `view "consumption"`. */
|
|
33
|
+
owner: string;
|
|
34
|
+
prefix: string;
|
|
35
|
+
queryKey: QueryKey;
|
|
36
|
+
environment: DashboardEnvironment;
|
|
37
|
+
}): DashboardFilterScope;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { computed, isRef, markRaw, shallowRef } from "vue";
|
|
2
|
+
import { useQueryStates } from "../../query-state/index.js";
|
|
3
|
+
import { hasProperty, isNullish } from "../../shared/utils/predicate.js";
|
|
4
|
+
import { registerDashboardFilter } from "../utils/environment.js";
|
|
5
|
+
import { joinDashboardUrlKey, resolveDashboardCondition } from "../utils/state.js";
|
|
6
|
+
import { useDashboardFilterControl } from "./use-dashboard-filter-control.js";
|
|
7
|
+
const emptyFacade = markRaw({});
|
|
8
|
+
const noUrlKeys = [];
|
|
9
|
+
export function useDashboardFilterScope(params) {
|
|
10
|
+
const entries = Object.entries(params.definitions).flatMap(
|
|
11
|
+
([key, definition]) => isRuntimeFilter(definition) ? [[key, definition]] : []
|
|
12
|
+
);
|
|
13
|
+
if (entries.length === 0)
|
|
14
|
+
return {
|
|
15
|
+
changed: () => false,
|
|
16
|
+
controls: emptyFacade,
|
|
17
|
+
keys: [],
|
|
18
|
+
reset() {
|
|
19
|
+
},
|
|
20
|
+
urlKeys: noUrlKeys,
|
|
21
|
+
values: emptyFacade
|
|
22
|
+
};
|
|
23
|
+
const urlEntries = entries.filter(([, definition]) => (definition.sync ?? "url") === "url");
|
|
24
|
+
const schema = {};
|
|
25
|
+
for (const [key, definition] of urlEntries) {
|
|
26
|
+
registerDashboardFilter(params.environment.registry, {
|
|
27
|
+
definition,
|
|
28
|
+
owner: `${params.owner} ("${key}")`,
|
|
29
|
+
urlKey: joinDashboardUrlKey(params.prefix, definition.urlKey ?? key)
|
|
30
|
+
});
|
|
31
|
+
schema[key] = {
|
|
32
|
+
codec: definition.codec,
|
|
33
|
+
defaultValue: definition.defaultValue,
|
|
34
|
+
historyMode: definition.historyMode,
|
|
35
|
+
omitDefault: definition.omitDefault,
|
|
36
|
+
urlKey: definition.urlKey
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const state = urlEntries.length > 0 ? useQueryStates({ historyMode: "replace", prefix: params.prefix, schema }) : null;
|
|
40
|
+
function createAccessor(key, definition) {
|
|
41
|
+
const { defaultValue, sync = "url" } = definition;
|
|
42
|
+
if (sync === "url" && state) {
|
|
43
|
+
return {
|
|
44
|
+
get: () => {
|
|
45
|
+
const current = state.value;
|
|
46
|
+
return current[key];
|
|
47
|
+
},
|
|
48
|
+
set: (value) => {
|
|
49
|
+
state.value = { ...state.value, [key]: value };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (sync === "url" || sync === "memory") {
|
|
54
|
+
const cell = shallowRef(defaultValue);
|
|
55
|
+
return { get: () => cell.value, set: (value) => cell.value = value };
|
|
56
|
+
}
|
|
57
|
+
if (isRef(sync)) return { get: () => sync.value, set: (value) => sync.value = value };
|
|
58
|
+
return { get: () => sync(), set() {
|
|
59
|
+
} };
|
|
60
|
+
}
|
|
61
|
+
const values = {};
|
|
62
|
+
const controls = {};
|
|
63
|
+
for (const [key, definition] of entries) {
|
|
64
|
+
const accessor = createAccessor(key, definition);
|
|
65
|
+
const { codec, multiple } = definition;
|
|
66
|
+
const enabled = () => resolveDashboardCondition(definition.enabled);
|
|
67
|
+
const get = () => {
|
|
68
|
+
if (!enabled()) return definition.resolveDefault();
|
|
69
|
+
const value = accessor.get();
|
|
70
|
+
const unset = isNullish(value) || multiple && Array.isArray(value) && value.length === 0;
|
|
71
|
+
return unset ? definition.resolveDefault() : value;
|
|
72
|
+
};
|
|
73
|
+
const set = (value) => {
|
|
74
|
+
if (!enabled()) return;
|
|
75
|
+
const next = value ?? definition.resolveDefault();
|
|
76
|
+
const isDefault = codec.serialize(next) === codec.serialize(definition.resolveDefault());
|
|
77
|
+
accessor.set(isDefault ? definition.defaultValue : next);
|
|
78
|
+
};
|
|
79
|
+
Object.defineProperty(values, key, { enumerable: true, get, set });
|
|
80
|
+
definition.bind(get);
|
|
81
|
+
controls[key] = useDashboardFilterControl({
|
|
82
|
+
definition,
|
|
83
|
+
get,
|
|
84
|
+
key,
|
|
85
|
+
locale: params.environment.locale,
|
|
86
|
+
queryKey: [...params.queryKey, key],
|
|
87
|
+
set
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const visible = Object.values(controls).filter((control) => !control.headless);
|
|
91
|
+
const changed = computed(
|
|
92
|
+
() => visible.some((control) => control.enabled && control.changed)
|
|
93
|
+
);
|
|
94
|
+
return {
|
|
95
|
+
changed: () => changed.value,
|
|
96
|
+
controls: markRaw(controls),
|
|
97
|
+
keys: entries.map(([key]) => key),
|
|
98
|
+
reset() {
|
|
99
|
+
for (const control of visible) if (control.enabled) control.reset();
|
|
100
|
+
},
|
|
101
|
+
urlKeys: urlEntries.map(([key, definition]) => definition.urlKey ?? key),
|
|
102
|
+
values: markRaw(values)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function isRuntimeFilter(definition) {
|
|
106
|
+
return hasProperty(definition, "codec");
|
|
107
|
+
}
|
|
@@ -1,6 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { DashboardFormatPreset, DashboardValueFormat, DashboardValueFormatter } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The number and month formatters dashboard blocks use, in the dashboard locale (the Nuxt UI locale
|
|
4
|
+
* unless overridden). Use them for captions, labels, and any text next to a block so everything on
|
|
5
|
+
* screen reads the same way. Reads are reactive: a locale switch re-renders what used them.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const format = useDashboardFormat()
|
|
10
|
+
* format.integer(12345) // "12,345"
|
|
11
|
+
* format.percent(57) // "57%"
|
|
12
|
+
* format.points(2.1) // "+2.1 pts"
|
|
13
|
+
* format.currency(1200, 'EUR') // "€1,200"
|
|
14
|
+
* format.month(3) // "Mar"
|
|
15
|
+
* format.ratio(null) // "—"
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Every number formatter takes `null` / `undefined` too, and prints "—" for them, so a missing rate
|
|
19
|
+
* or an empty period needs no fallback in the template.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useDashboardFormat(): import("vue").Raw<{
|
|
22
|
+
/** `12600` → "12.6K". */
|
|
23
|
+
compact: (value: number | null | undefined) => string;
|
|
24
|
+
/** An amount in a currency, rounded to units unless `options` say otherwise. */
|
|
25
|
+
currency: (value: number | null | undefined, currency: string, options?: Intl.NumberFormatOptions) => string;
|
|
26
|
+
/** One decimal at most. */
|
|
27
|
+
decimal: (value: number | null | undefined) => string;
|
|
28
|
+
/** Signed percent change: `12.4` → "+12.4%". */
|
|
29
|
+
delta: (value: number | null | undefined) => string;
|
|
30
|
+
/** Grouped, no decimals. */
|
|
31
|
+
integer: (value: number | null | undefined) => string;
|
|
32
|
+
/** Month name, capitalized: `3` (1–12) or a date → "Mar" (`'long'`: "March"). */
|
|
33
|
+
month: (value: number | Date, width?: "short" | "long") => string;
|
|
34
|
+
/** Grouped, one decimal at most, compact from 10,000. */
|
|
35
|
+
number: (value: number | null | undefined) => string;
|
|
36
|
+
/** A share out of 100: `57` → "57%". */
|
|
37
|
+
percent: (value: number | null | undefined) => string;
|
|
38
|
+
points: (value: number | null | undefined) => string;
|
|
39
|
+
/** A share out of 1: `0.57` → "57%". */
|
|
40
|
+
ratio: (value: number | null | undefined) => string;
|
|
41
|
+
resolve: (format: DashboardValueFormat | undefined, fallback?: DashboardFormatPreset) => DashboardValueFormatter;
|
|
42
|
+
/** Signed number: `3` → "+3". */
|
|
43
|
+
signed: (value: number | null | undefined) => string;
|
|
44
|
+
}>;
|
|
45
|
+
/** Text of a missing number: an empty period, a rate without a base. */
|
|
46
|
+
export declare const DASHBOARD_MISSING_VALUE = "\u2014";
|