nuxt-ui-tools 1.0.1 → 1.1.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.d.mts +3 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +37 -0
- package/dist/runtime/dashboard/components/block/dashboard-block-state.d.vue.ts +12 -0
- package/dist/runtime/dashboard/components/block/dashboard-block-state.vue +59 -0
- package/dist/runtime/dashboard/components/block/dashboard-block-state.vue.d.ts +12 -0
- package/dist/runtime/dashboard/components/block/dashboard-data-table.d.vue.ts +9 -0
- package/dist/runtime/dashboard/components/block/dashboard-data-table.vue +47 -0
- package/dist/runtime/dashboard/components/block/dashboard-data-table.vue.d.ts +9 -0
- package/dist/runtime/dashboard/components/block/dashboard-ring.d.vue.ts +34 -0
- package/dist/runtime/dashboard/components/block/dashboard-ring.vue +91 -0
- package/dist/runtime/dashboard/components/block/dashboard-ring.vue.d.ts +34 -0
- package/dist/runtime/dashboard/components/block/dashboard-row-actions.d.vue.ts +13 -0
- package/dist/runtime/dashboard/components/block/dashboard-row-actions.vue +49 -0
- package/dist/runtime/dashboard/components/block/dashboard-row-actions.vue.d.ts +13 -0
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.d.vue.ts +34 -0
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue +312 -0
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue.d.ts +34 -0
- package/dist/runtime/dashboard/components/charts/renderer.d.ts +43 -0
- package/dist/runtime/dashboard/components/charts/renderer.js +34 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-donut-chart.d.vue.ts +18 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-donut-chart.vue +45 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-donut-chart.vue.d.ts +18 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-chart.d.vue.ts +14 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-chart.vue +190 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-chart.vue.d.ts +14 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-marks.d.vue.ts +13 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-marks.vue +72 -0
- package/dist/runtime/dashboard/components/charts/unovis/dashboard-xy-marks.vue.d.ts +13 -0
- package/dist/runtime/dashboard/components/charts/unovis/xy-layers.d.ts +43 -0
- package/dist/runtime/dashboard/components/charts/unovis/xy-layers.js +60 -0
- package/dist/runtime/dashboard/components/dashboard-alerts.d.vue.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-alerts.vue +226 -0
- package/dist/runtime/dashboard/components/dashboard-alerts.vue.d.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-bar-chart.d.vue.ts +53 -0
- package/dist/runtime/dashboard/components/dashboard-bar-chart.vue +131 -0
- package/dist/runtime/dashboard/components/dashboard-bar-chart.vue.d.ts +53 -0
- package/dist/runtime/dashboard/components/dashboard-bars.d.vue.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-bars.vue +187 -0
- package/dist/runtime/dashboard/components/dashboard-bars.vue.d.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-card.d.vue.ts +47 -0
- package/dist/runtime/dashboard/components/dashboard-card.vue +316 -0
- package/dist/runtime/dashboard/components/dashboard-card.vue.d.ts +47 -0
- package/dist/runtime/dashboard/components/dashboard-combo-chart.d.vue.ts +52 -0
- package/dist/runtime/dashboard/components/dashboard-combo-chart.vue +128 -0
- package/dist/runtime/dashboard/components/dashboard-combo-chart.vue.d.ts +52 -0
- package/dist/runtime/dashboard/components/dashboard-donut-chart.d.vue.ts +48 -0
- package/dist/runtime/dashboard/components/dashboard-donut-chart.vue +216 -0
- package/dist/runtime/dashboard/components/dashboard-donut-chart.vue.d.ts +48 -0
- package/dist/runtime/dashboard/components/dashboard-feed.d.vue.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-feed.vue +238 -0
- package/dist/runtime/dashboard/components/dashboard-feed.vue.d.ts +49 -0
- package/dist/runtime/dashboard/components/dashboard-funnel.d.vue.ts +34 -0
- package/dist/runtime/dashboard/components/dashboard-funnel.vue +157 -0
- package/dist/runtime/dashboard/components/dashboard-funnel.vue.d.ts +34 -0
- package/dist/runtime/dashboard/components/dashboard-gauge.d.vue.ts +55 -0
- package/dist/runtime/dashboard/components/dashboard-gauge.vue +177 -0
- package/dist/runtime/dashboard/components/dashboard-gauge.vue.d.ts +55 -0
- package/dist/runtime/dashboard/components/dashboard-grid.d.vue.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-grid.vue +49 -0
- package/dist/runtime/dashboard/components/dashboard-grid.vue.d.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-legend.d.vue.ts +8 -0
- package/dist/runtime/dashboard/components/dashboard-legend.vue +37 -0
- package/dist/runtime/dashboard/components/dashboard-legend.vue.d.ts +8 -0
- package/dist/runtime/dashboard/components/dashboard-line-chart.d.vue.ts +46 -0
- package/dist/runtime/dashboard/components/dashboard-line-chart.vue +129 -0
- package/dist/runtime/dashboard/components/dashboard-line-chart.vue.d.ts +46 -0
- package/dist/runtime/dashboard/components/dashboard-list.d.vue.ts +63 -0
- package/dist/runtime/dashboard/components/dashboard-list.vue +239 -0
- package/dist/runtime/dashboard/components/dashboard-list.vue.d.ts +63 -0
- package/dist/runtime/dashboard/components/dashboard-paired-bars.d.vue.ts +43 -0
- package/dist/runtime/dashboard/components/dashboard-paired-bars.vue +194 -0
- package/dist/runtime/dashboard/components/dashboard-paired-bars.vue.d.ts +43 -0
- package/dist/runtime/dashboard/components/dashboard-refresh.d.vue.ts +29 -0
- package/dist/runtime/dashboard/components/dashboard-refresh.vue +86 -0
- package/dist/runtime/dashboard/components/dashboard-refresh.vue.d.ts +29 -0
- package/dist/runtime/dashboard/components/dashboard-relative-time.d.vue.ts +12 -0
- package/dist/runtime/dashboard/components/dashboard-relative-time.vue +23 -0
- package/dist/runtime/dashboard/components/dashboard-relative-time.vue.d.ts +12 -0
- package/dist/runtime/dashboard/components/dashboard-stack-bar.d.vue.ts +36 -0
- package/dist/runtime/dashboard/components/dashboard-stack-bar.vue +162 -0
- package/dist/runtime/dashboard/components/dashboard-stack-bar.vue.d.ts +36 -0
- package/dist/runtime/dashboard/components/dashboard-stat.d.vue.ts +69 -0
- package/dist/runtime/dashboard/components/dashboard-stat.vue +279 -0
- package/dist/runtime/dashboard/components/dashboard-stat.vue.d.ts +69 -0
- package/dist/runtime/dashboard/components/dashboard-stats.d.vue.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-stats.vue +202 -0
- package/dist/runtime/dashboard/components/dashboard-stats.vue.d.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-table.d.vue.ts +52 -0
- package/dist/runtime/dashboard/components/dashboard-table.vue +305 -0
- package/dist/runtime/dashboard/components/dashboard-table.vue.d.ts +52 -0
- package/dist/runtime/dashboard/components/dashboard-tabs.d.vue.ts +35 -0
- package/dist/runtime/dashboard/components/dashboard-tabs.vue +55 -0
- package/dist/runtime/dashboard/components/dashboard-tabs.vue.d.ts +35 -0
- package/dist/runtime/dashboard/components/dashboard-total.d.vue.ts +10 -0
- package/dist/runtime/dashboard/components/dashboard-total.vue +32 -0
- package/dist/runtime/dashboard/components/dashboard-total.vue.d.ts +10 -0
- package/dist/runtime/dashboard/components/dashboard-widget.d.vue.ts +46 -0
- package/dist/runtime/dashboard/components/dashboard-widget.vue +84 -0
- package/dist/runtime/dashboard/components/dashboard-widget.vue.d.ts +46 -0
- package/dist/runtime/dashboard/composables/use-dashboard-api.d.ts +15 -0
- package/dist/runtime/dashboard/composables/use-dashboard-api.js +91 -0
- package/dist/runtime/dashboard/composables/use-dashboard-block.d.ts +22 -0
- package/dist/runtime/dashboard/composables/use-dashboard-block.js +35 -0
- package/dist/runtime/dashboard/composables/use-dashboard-chart.d.ts +36 -0
- package/dist/runtime/dashboard/composables/use-dashboard-chart.js +118 -0
- package/dist/runtime/dashboard/composables/use-dashboard-derived.d.ts +12 -0
- package/dist/runtime/dashboard/composables/use-dashboard-derived.js +47 -0
- package/dist/runtime/dashboard/composables/use-dashboard-format.d.ts +6 -0
- package/dist/runtime/dashboard/composables/use-dashboard-format.js +12 -0
- package/dist/runtime/dashboard/composables/use-dashboard-options.d.ts +8 -0
- package/dist/runtime/dashboard/composables/use-dashboard-options.js +63 -0
- package/dist/runtime/dashboard/composables/use-dashboard-param-scope.d.ts +30 -0
- package/dist/runtime/dashboard/composables/use-dashboard-param-scope.js +71 -0
- package/dist/runtime/dashboard/composables/use-dashboard-remote-options.d.ts +12 -0
- package/dist/runtime/dashboard/composables/use-dashboard-remote-options.js +117 -0
- package/dist/runtime/dashboard/composables/use-dashboard-resource.d.ts +35 -0
- package/dist/runtime/dashboard/composables/use-dashboard-resource.js +80 -0
- package/dist/runtime/dashboard/composables/use-dashboard-scope.d.ts +46 -0
- package/dist/runtime/dashboard/composables/use-dashboard-scope.js +127 -0
- package/dist/runtime/dashboard/composables/use-dashboard-time.d.ts +13 -0
- package/dist/runtime/dashboard/composables/use-dashboard-time.js +40 -0
- package/dist/runtime/dashboard/composables/use-dashboard-ui.d.ts +22 -0
- package/dist/runtime/dashboard/composables/use-dashboard-ui.js +19 -0
- package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +46 -0
- package/dist/runtime/dashboard/composables/use-dashboard-views.js +49 -0
- package/dist/runtime/dashboard/composables/use-dashboard.d.ts +24 -0
- package/dist/runtime/dashboard/composables/use-dashboard.js +42 -0
- package/dist/runtime/dashboard/constants/query.d.ts +16 -0
- package/dist/runtime/dashboard/constants/query.js +15 -0
- package/dist/runtime/dashboard/index.d.ts +4 -0
- package/dist/runtime/dashboard/index.js +3 -0
- package/dist/runtime/dashboard/schema/index.d.ts +57 -0
- package/dist/runtime/dashboard/schema/index.js +3 -0
- package/dist/runtime/dashboard/types/blocks.d.ts +251 -0
- package/dist/runtime/dashboard/types/blocks.js +0 -0
- package/dist/runtime/dashboard/types/charts.d.ts +60 -0
- package/dist/runtime/dashboard/types/charts.js +0 -0
- package/dist/runtime/dashboard/types/index.d.ts +7 -0
- package/dist/runtime/dashboard/types/index.js +0 -0
- package/dist/runtime/dashboard/types/options.d.ts +46 -0
- package/dist/runtime/dashboard/types/options.js +0 -0
- package/dist/runtime/dashboard/types/params.d.ts +115 -0
- package/dist/runtime/dashboard/types/params.js +0 -0
- package/dist/runtime/dashboard/types/resource.d.ts +106 -0
- package/dist/runtime/dashboard/types/resource.js +0 -0
- package/dist/runtime/dashboard/types/runtime.d.ts +44 -0
- package/dist/runtime/dashboard/types/runtime.js +0 -0
- package/dist/runtime/dashboard/types/schema.d.ts +171 -0
- package/dist/runtime/dashboard/types/schema.js +0 -0
- package/dist/runtime/dashboard/types/ui.d.ts +201 -0
- package/dist/runtime/dashboard/types/ui.js +0 -0
- package/dist/runtime/dashboard/utils/builders/dashboard-params.d.ts +85 -0
- package/dist/runtime/dashboard/utils/builders/dashboard-params.js +87 -0
- package/dist/runtime/dashboard/utils/chart-frame.d.ts +5 -0
- package/dist/runtime/dashboard/utils/chart-frame.js +27 -0
- package/dist/runtime/dashboard/utils/charts.d.ts +61 -0
- package/dist/runtime/dashboard/utils/charts.js +142 -0
- package/dist/runtime/dashboard/utils/comparison.d.ts +15 -0
- package/dist/runtime/dashboard/utils/comparison.js +19 -0
- package/dist/runtime/dashboard/utils/export.d.ts +13 -0
- package/dist/runtime/dashboard/utils/export.js +45 -0
- package/dist/runtime/dashboard/utils/options.d.ts +12 -0
- package/dist/runtime/dashboard/utils/options.js +23 -0
- package/dist/runtime/dashboard/utils/params/codecs.d.ts +14 -0
- package/dist/runtime/dashboard/utils/params/codecs.js +69 -0
- package/dist/runtime/dashboard/utils/resource.d.ts +16 -0
- package/dist/runtime/dashboard/utils/resource.js +39 -0
- package/dist/runtime/dashboard/utils/schema.d.ts +9 -0
- package/dist/runtime/dashboard/utils/schema.js +31 -0
- package/dist/runtime/dashboard/utils/sparkline.d.ts +21 -0
- package/dist/runtime/dashboard/utils/sparkline.js +53 -0
- package/dist/runtime/dashboard/utils/state.d.ts +28 -0
- package/dist/runtime/dashboard/utils/state.js +32 -0
- package/dist/runtime/dashboard/utils/time.d.ts +17 -0
- package/dist/runtime/dashboard/utils/time.js +60 -0
- package/dist/runtime/dashboard/utils/tracker.d.ts +12 -0
- package/dist/runtime/dashboard/utils/tracker.js +31 -0
- package/dist/runtime/dashboard/utils/ui.d.ts +38 -0
- package/dist/runtime/dashboard/utils/ui.js +24 -0
- package/dist/runtime/dashboard/utils/visibility.d.ts +2 -0
- package/dist/runtime/dashboard/utils/visibility.js +25 -0
- package/dist/runtime/form/types/options.d.ts +15 -36
- package/dist/runtime/i18n/locales/en.js +62 -0
- package/dist/runtime/i18n/locales/fr.js +62 -0
- package/dist/runtime/i18n/types.d.ts +67 -0
- package/dist/runtime/shared/index.d.ts +2 -0
- package/dist/runtime/shared/styles/tokens.css +1 -1
- package/dist/runtime/shared/types/query.d.ts +10 -0
- package/dist/runtime/shared/types/query.js +0 -0
- package/dist/runtime/shared/types/remote-options.d.ts +37 -0
- package/dist/runtime/shared/types/remote-options.js +0 -0
- package/dist/runtime/spreadsheet/components/layout/spreadsheet-import-footer.d.vue.ts +2 -2
- package/dist/runtime/spreadsheet/components/layout/spreadsheet-import-footer.vue.d.ts +2 -2
- package/dist/runtime/spreadsheet/composables/use-spreadsheet-internals.d.ts +15 -15
- package/dist/runtime/spreadsheet/composables/use-spreadsheet-resolutions.d.ts +2 -2
- package/dist/runtime/spreadsheet/schema/normalize.d.ts +1 -1
- package/dist/runtime/spreadsheet/utils/references/sources.d.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-content.d.vue.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-content.vue.d.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-infinite-loader.d.vue.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-infinite-loader.vue.d.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-layout-switch.d.vue.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-layout-switch.vue.d.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-pagination.d.vue.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-pagination.vue.d.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-sort-menu.d.vue.ts +1 -1
- package/dist/runtime/table/components/data-list/data-list-sort-menu.vue.d.ts +1 -1
- package/dist/runtime/table/components/data-list/sort-menu-panel.d.vue.ts +2 -2
- package/dist/runtime/table/components/data-list/sort-menu-panel.vue.d.ts +2 -2
- package/dist/runtime/table/components/filters/shared/filter-match-mode-button.d.vue.ts +1 -1
- package/dist/runtime/table/components/filters/shared/filter-match-mode-button.vue.d.ts +1 -1
- package/dist/runtime/table/components/layout/table-footer.d.vue.ts +1 -1
- package/dist/runtime/table/components/layout/table-footer.vue.d.ts +1 -1
- package/dist/runtime/table/components/table/table-cell-ellipsis.d.ts +1 -1
- package/dist/runtime/table/composables/use-query-state.d.ts +3 -3
- package/dist/runtime/table/composables/use-table-columns.d.ts +3 -3
- package/dist/runtime/table/composables/use-table-internals.d.ts +27 -27
- package/dist/runtime/table/composables/use-table-pagination.d.ts +2 -2
- package/dist/runtime/table/composables/use-table-selection.d.ts +1 -1
- package/dist/runtime/table/composables/use-table-state.d.ts +3 -3
- package/dist/runtime/table/types/source.d.ts +4 -5
- package/dist/runtime/table/utils/columns/menu.d.ts +1 -1
- package/dist/runtime/table/utils/columns/state.d.ts +1 -1
- package/dist/runtime/table/utils/data-list-ui.d.ts +1 -1
- package/package.json +28 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UButton from "@nuxt/ui/components/Button.vue";
|
|
3
|
+
import UDropdownMenu from "@nuxt/ui/components/DropdownMenu.vue";
|
|
4
|
+
import UFieldGroup from "@nuxt/ui/components/FieldGroup.vue";
|
|
5
|
+
import { computed } from "vue";
|
|
6
|
+
import { useUiToolsLocale } from "#ui-tools/i18n";
|
|
7
|
+
import DashboardRelativeTime from "./dashboard-relative-time.vue";
|
|
8
|
+
const {
|
|
9
|
+
dashboard,
|
|
10
|
+
intervals = [0, 30, 60, 300, 900],
|
|
11
|
+
updated = true,
|
|
12
|
+
label = true,
|
|
13
|
+
size = "sm"
|
|
14
|
+
} = defineProps({
|
|
15
|
+
dashboard: { type: Object, required: true },
|
|
16
|
+
intervals: { type: Array, required: false },
|
|
17
|
+
updated: { type: Boolean, required: false },
|
|
18
|
+
label: { type: Boolean, required: false },
|
|
19
|
+
size: { type: String, required: false }
|
|
20
|
+
});
|
|
21
|
+
const { t, code } = useUiToolsLocale();
|
|
22
|
+
const formatInterval = computed(() => {
|
|
23
|
+
const seconds = new Intl.NumberFormat(code.value, {
|
|
24
|
+
style: "unit",
|
|
25
|
+
unit: "second",
|
|
26
|
+
unitDisplay: "short"
|
|
27
|
+
});
|
|
28
|
+
const minutes = new Intl.NumberFormat(code.value, {
|
|
29
|
+
style: "unit",
|
|
30
|
+
unit: "minute",
|
|
31
|
+
unitDisplay: "short"
|
|
32
|
+
});
|
|
33
|
+
return (value) => value >= 60 && value % 60 === 0 ? minutes.format(value / 60) : seconds.format(value);
|
|
34
|
+
});
|
|
35
|
+
const items = computed(() => [
|
|
36
|
+
[{ label: t("dashboard.refresh.auto"), type: "label" }],
|
|
37
|
+
intervals.map((seconds) => ({
|
|
38
|
+
checked: dashboard.autoRefresh === seconds,
|
|
39
|
+
label: seconds > 0 ? formatInterval.value(seconds) : t("dashboard.refresh.off"),
|
|
40
|
+
onSelect: () => {
|
|
41
|
+
dashboard.autoRefresh = seconds;
|
|
42
|
+
},
|
|
43
|
+
type: "checkbox"
|
|
44
|
+
}))
|
|
45
|
+
]);
|
|
46
|
+
function refresh() {
|
|
47
|
+
dashboard.refresh().catch(() => void 0);
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<div class="flex items-center gap-3" data-dashboard-refresh>
|
|
53
|
+
<span
|
|
54
|
+
v-if="updated && dashboard.updatedAt !== void 0"
|
|
55
|
+
class="text-xs whitespace-nowrap text-muted max-sm:hidden"
|
|
56
|
+
>
|
|
57
|
+
{{ t("dashboard.freshness.prefix") }}
|
|
58
|
+
<DashboardRelativeTime :value="dashboard.updatedAt" />
|
|
59
|
+
</span>
|
|
60
|
+
<UFieldGroup :size>
|
|
61
|
+
<UButton
|
|
62
|
+
color="neutral"
|
|
63
|
+
variant="outline"
|
|
64
|
+
icon="i-lucide-refresh-cw"
|
|
65
|
+
:label="label ? t('dashboard.refresh.label') : void 0"
|
|
66
|
+
:aria-label="label ? void 0 : t('dashboard.refresh.label')"
|
|
67
|
+
:loading="dashboard.refreshing"
|
|
68
|
+
@click="refresh"
|
|
69
|
+
/>
|
|
70
|
+
<UDropdownMenu :items :content="{ align: 'end', side: 'bottom', sideOffset: 6 }">
|
|
71
|
+
<UButton
|
|
72
|
+
color="neutral"
|
|
73
|
+
variant="outline"
|
|
74
|
+
trailing-icon="i-lucide-chevron-down"
|
|
75
|
+
:label="dashboard.autoRefresh > 0 ? formatInterval(dashboard.autoRefresh) : void 0"
|
|
76
|
+
:aria-label="t('dashboard.refresh.auto')"
|
|
77
|
+
:class="dashboard.autoRefresh > 0 && 'text-highlighted'"
|
|
78
|
+
>
|
|
79
|
+
<template v-if="dashboard.autoRefresh > 0" #leading>
|
|
80
|
+
<span aria-hidden="true" class="size-1.5 animate-pulse rounded-full bg-primary" />
|
|
81
|
+
</template>
|
|
82
|
+
</UButton>
|
|
83
|
+
</UDropdownMenu>
|
|
84
|
+
</UFieldGroup>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** What the control drives: the dashboard object returned by `useDashboard`. */
|
|
2
|
+
interface DashboardRefreshTarget {
|
|
3
|
+
refresh: () => Promise<void>;
|
|
4
|
+
readonly refreshing: boolean;
|
|
5
|
+
readonly updatedAt: number | undefined;
|
|
6
|
+
autoRefresh: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Refresh control for a dashboard header: a refresh button, an auto-refresh interval menu (kept in
|
|
10
|
+
* the URL by the dashboard), and "Updated 3 min ago".
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```vue
|
|
14
|
+
* <UiDashboardRefresh :dashboard />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
type __VLS_Props = {
|
|
18
|
+
dashboard: DashboardRefreshTarget;
|
|
19
|
+
/** Auto-refresh choices in seconds; `0` turns it off. */
|
|
20
|
+
intervals?: readonly number[];
|
|
21
|
+
/** Shows when the data on screen was last fetched. */
|
|
22
|
+
updated?: boolean;
|
|
23
|
+
/** Shows the "Refresh" label next to the icon. */
|
|
24
|
+
label?: boolean;
|
|
25
|
+
size?: 'xs' | 'sm' | 'md';
|
|
26
|
+
};
|
|
27
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DashboardTimeValue } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* A time relative to now (`3 min ago`, `yesterday`), kept current by a shared 30-second clock, with
|
|
4
|
+
* the full date as a tooltip. Pairs with `dashboard.updatedAt` for a page-level freshness line.
|
|
5
|
+
*/
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
/** A `Date`, epoch milliseconds, or an ISO string. Renders nothing while `null` / `undefined`. */
|
|
8
|
+
value: DashboardTimeValue | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useDashboardTime } from "../composables/use-dashboard-time";
|
|
4
|
+
import { toDashboardTime } from "../utils/time";
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
value: { type: null, required: true }
|
|
7
|
+
});
|
|
8
|
+
const time = useDashboardTime();
|
|
9
|
+
const at = computed(
|
|
10
|
+
() => props.value === null || props.value === void 0 ? Number.NaN : toDashboardTime(props.value)
|
|
11
|
+
);
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<time
|
|
16
|
+
v-if="Number.isFinite(at)"
|
|
17
|
+
:datetime="new Date(at).toISOString()"
|
|
18
|
+
:title="time.absolute(at)"
|
|
19
|
+
data-allow-mismatch="text"
|
|
20
|
+
>
|
|
21
|
+
{{ time.relative(at) }}
|
|
22
|
+
</time>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DashboardTimeValue } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* A time relative to now (`3 min ago`, `yesterday`), kept current by a shared 30-second clock, with
|
|
4
|
+
* the full date as a tooltip. Pairs with `dashboard.updatedAt` for a page-level freshness line.
|
|
5
|
+
*/
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
/** A `Date`, epoch milliseconds, or an ISO string. Renders nothing while `null` / `undefined`. */
|
|
8
|
+
value: DashboardTimeValue | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LazyTextValue } from '#ui-tools/shared/types/utils';
|
|
2
|
+
import type { DashboardBlockBaseProps, DashboardBlockUi, DashboardSelectEvent, DashboardSeriesColor, DashboardSourceLike, DashboardStackBarUi } from '../types/index.js';
|
|
3
|
+
declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<Omit<DashboardBlockBaseProps, "ui"> & {
|
|
5
|
+
source: DashboardSourceLike<readonly TRow[] | undefined>;
|
|
6
|
+
label: (row: TRow) => LazyTextValue;
|
|
7
|
+
value: (row: TRow) => number;
|
|
8
|
+
/** Legend value text. Defaults to the share in percent. */
|
|
9
|
+
text?: (row: TRow, share: number) => LazyTextValue;
|
|
10
|
+
color?: (row: TRow, index: number) => DashboardSeriesColor | undefined;
|
|
11
|
+
/** Legend columns from the `sm` breakpoint (one column below). */
|
|
12
|
+
legendColumns?: 1 | 2;
|
|
13
|
+
/** Makes each segment and legend entry selectable. */
|
|
14
|
+
onSelect?: (event: DashboardSelectEvent<TRow>) => void;
|
|
15
|
+
ui?: DashboardBlockUi & DashboardStackBarUi;
|
|
16
|
+
}> & (typeof globalThis extends {
|
|
17
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
18
|
+
} ? P : {});
|
|
19
|
+
expose: (exposed: {}) => void;
|
|
20
|
+
attrs: any;
|
|
21
|
+
slots: {
|
|
22
|
+
'header-right'?: () => unknown;
|
|
23
|
+
toolbar?: () => unknown;
|
|
24
|
+
footer?: () => unknown;
|
|
25
|
+
};
|
|
26
|
+
emit: {};
|
|
27
|
+
}>) => import("vue").VNode & {
|
|
28
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
29
|
+
};
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
32
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
33
|
+
[K in keyof T]: T[K];
|
|
34
|
+
} : {
|
|
35
|
+
[K in keyof T as K]: T[K];
|
|
36
|
+
}) & {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useUiToolsLocale } from "#ui-tools/i18n";
|
|
4
|
+
import { resolveTextValue } from "#ui-tools/shared/utils/render";
|
|
5
|
+
import { useDashboardFormat } from "../composables/use-dashboard-format";
|
|
6
|
+
import { useDashboardUi } from "../composables/use-dashboard-ui";
|
|
7
|
+
import { resolveDashboardColor } from "../utils/charts";
|
|
8
|
+
import { toDashboardCell } from "../utils/export";
|
|
9
|
+
import {
|
|
10
|
+
DASHBOARD_ROW_BUTTON,
|
|
11
|
+
DASHBOARD_SELECTABLE_ROW,
|
|
12
|
+
resolveDashboardClasses
|
|
13
|
+
} from "../utils/ui";
|
|
14
|
+
import DashboardSkeleton from "./block/dashboard-skeleton.vue";
|
|
15
|
+
import DashboardCard from "./dashboard-card.vue";
|
|
16
|
+
const {
|
|
17
|
+
source,
|
|
18
|
+
card = true,
|
|
19
|
+
menu = void 0,
|
|
20
|
+
freshness = void 0,
|
|
21
|
+
label,
|
|
22
|
+
value,
|
|
23
|
+
text,
|
|
24
|
+
color,
|
|
25
|
+
legendColumns = 2,
|
|
26
|
+
onSelect,
|
|
27
|
+
ui,
|
|
28
|
+
...block
|
|
29
|
+
} = defineProps({
|
|
30
|
+
title: { type: [String, Number, Function], required: false },
|
|
31
|
+
subtitle: { type: [String, Number, Function], required: false },
|
|
32
|
+
size: { type: String, required: false },
|
|
33
|
+
rows: { type: String, required: false },
|
|
34
|
+
card: { type: Boolean, required: false },
|
|
35
|
+
activation: { type: String, required: false },
|
|
36
|
+
empty: { type: Object, required: false },
|
|
37
|
+
menu: { type: [Boolean, Array, Function], required: false },
|
|
38
|
+
actions: { type: Array, required: false },
|
|
39
|
+
freshness: { type: Boolean, required: false },
|
|
40
|
+
source: { type: Object, required: true },
|
|
41
|
+
label: { type: Function, required: true },
|
|
42
|
+
value: { type: Function, required: true },
|
|
43
|
+
text: { type: Function, required: false },
|
|
44
|
+
color: { type: Function, required: false },
|
|
45
|
+
legendColumns: { type: Number, required: false },
|
|
46
|
+
onSelect: { type: Function, required: false },
|
|
47
|
+
ui: { type: Object, required: false }
|
|
48
|
+
});
|
|
49
|
+
defineSlots();
|
|
50
|
+
const { t } = useUiToolsLocale();
|
|
51
|
+
const formats = useDashboardFormat();
|
|
52
|
+
const appUi = useDashboardUi();
|
|
53
|
+
const classes = computed(
|
|
54
|
+
() => resolveDashboardClasses(
|
|
55
|
+
{
|
|
56
|
+
item: "flex min-w-0 items-center gap-2",
|
|
57
|
+
legend: [
|
|
58
|
+
"grid grid-cols-1 gap-x-[18px] gap-y-2 text-[13px]",
|
|
59
|
+
legendColumns === 2 && "sm:grid-cols-2"
|
|
60
|
+
].filter(Boolean).join(" "),
|
|
61
|
+
track: "mt-1.5 mb-4 flex h-3.5 gap-0.5 overflow-hidden rounded-full"
|
|
62
|
+
},
|
|
63
|
+
appUi.value.stackBar,
|
|
64
|
+
ui
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
const parts = computed(() => {
|
|
68
|
+
const data = source.data ?? [];
|
|
69
|
+
const values = data.map((row) => value(row));
|
|
70
|
+
const total = values.reduce((sum, amount) => sum + amount, 0);
|
|
71
|
+
return data.map((row, index) => {
|
|
72
|
+
const amount = values[index] ?? 0;
|
|
73
|
+
const share = total > 0 ? amount / total * 100 : 0;
|
|
74
|
+
return {
|
|
75
|
+
amount,
|
|
76
|
+
color: resolveDashboardColor(color?.(row, index), index),
|
|
77
|
+
index,
|
|
78
|
+
label: resolveTextValue(label(row)),
|
|
79
|
+
row,
|
|
80
|
+
share,
|
|
81
|
+
text: text ? resolveTextValue(text(row, share)) : formats.percent.value(share),
|
|
82
|
+
width: `${share}%`
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
function tabulate() {
|
|
87
|
+
return {
|
|
88
|
+
columns: [
|
|
89
|
+
{ key: "label", label: t("dashboard.table.label"), numeric: false },
|
|
90
|
+
{ key: "value", label: t("dashboard.table.value"), numeric: true },
|
|
91
|
+
{ key: "share", label: t("dashboard.table.share"), numeric: true }
|
|
92
|
+
],
|
|
93
|
+
rows: parts.value.map((part) => [
|
|
94
|
+
toDashboardCell(part.label),
|
|
95
|
+
toDashboardCell(part.amount, formats.number.value(part.amount)),
|
|
96
|
+
toDashboardCell(Math.round(part.share * 10) / 10, formats.percent.value(part.share))
|
|
97
|
+
])
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<template>
|
|
103
|
+
<DashboardCard
|
|
104
|
+
v-bind="block"
|
|
105
|
+
:card
|
|
106
|
+
:menu
|
|
107
|
+
:freshness
|
|
108
|
+
:ui
|
|
109
|
+
:source
|
|
110
|
+
:is-empty="parts.length === 0"
|
|
111
|
+
:tabulate
|
|
112
|
+
>
|
|
113
|
+
<template #skeleton>
|
|
114
|
+
<DashboardSkeleton kind="stack" />
|
|
115
|
+
</template>
|
|
116
|
+
<template v-if="$slots['header-right']" #header-right>
|
|
117
|
+
<slot name="header-right" />
|
|
118
|
+
</template>
|
|
119
|
+
<template v-if="$slots.toolbar" #toolbar>
|
|
120
|
+
<slot name="toolbar" />
|
|
121
|
+
</template>
|
|
122
|
+
<template v-if="$slots.footer" #footer>
|
|
123
|
+
<slot name="footer" />
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<div :class="classes.track">
|
|
127
|
+
<i
|
|
128
|
+
v-for="part in parts"
|
|
129
|
+
:key="part.index"
|
|
130
|
+
class="block h-full transition-[width] duration-500 ease-out"
|
|
131
|
+
:class="onSelect && 'cursor-pointer'"
|
|
132
|
+
:style="{ background: part.color, width: part.width }"
|
|
133
|
+
:title="`${part.label} \xB7 ${part.text}`"
|
|
134
|
+
@click="onSelect?.({ index: part.index, row: part.row })"
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
<ul :class="classes.legend">
|
|
138
|
+
<li
|
|
139
|
+
v-for="part in parts"
|
|
140
|
+
:key="part.index"
|
|
141
|
+
:class="[classes.item, onSelect && DASHBOARD_SELECTABLE_ROW]"
|
|
142
|
+
>
|
|
143
|
+
<span
|
|
144
|
+
aria-hidden="true"
|
|
145
|
+
class="size-[9px] shrink-0 rounded-[3px]"
|
|
146
|
+
:style="{ background: part.color }"
|
|
147
|
+
/>
|
|
148
|
+
<span class="min-w-0 flex-1 truncate text-muted">{{ part.label }}</span>
|
|
149
|
+
<b class="shrink-0 font-semibold whitespace-nowrap text-highlighted tabular-nums">
|
|
150
|
+
{{ part.text }}
|
|
151
|
+
</b>
|
|
152
|
+
<button
|
|
153
|
+
v-if="onSelect"
|
|
154
|
+
type="button"
|
|
155
|
+
:class="DASHBOARD_ROW_BUTTON"
|
|
156
|
+
:aria-label="part.label"
|
|
157
|
+
@click="onSelect({ index: part.index, row: part.row })"
|
|
158
|
+
/>
|
|
159
|
+
</li>
|
|
160
|
+
</ul>
|
|
161
|
+
</DashboardCard>
|
|
162
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LazyTextValue } from '#ui-tools/shared/types/utils';
|
|
2
|
+
import type { DashboardBlockBaseProps, DashboardBlockUi, DashboardSelectEvent, DashboardSeriesColor, DashboardSourceLike, DashboardStackBarUi } from '../types/index.js';
|
|
3
|
+
declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<Omit<DashboardBlockBaseProps, "ui"> & {
|
|
5
|
+
source: DashboardSourceLike<readonly TRow[] | undefined>;
|
|
6
|
+
label: (row: TRow) => LazyTextValue;
|
|
7
|
+
value: (row: TRow) => number;
|
|
8
|
+
/** Legend value text. Defaults to the share in percent. */
|
|
9
|
+
text?: (row: TRow, share: number) => LazyTextValue;
|
|
10
|
+
color?: (row: TRow, index: number) => DashboardSeriesColor | undefined;
|
|
11
|
+
/** Legend columns from the `sm` breakpoint (one column below). */
|
|
12
|
+
legendColumns?: 1 | 2;
|
|
13
|
+
/** Makes each segment and legend entry selectable. */
|
|
14
|
+
onSelect?: (event: DashboardSelectEvent<TRow>) => void;
|
|
15
|
+
ui?: DashboardBlockUi & DashboardStackBarUi;
|
|
16
|
+
}> & (typeof globalThis extends {
|
|
17
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
18
|
+
} ? P : {});
|
|
19
|
+
expose: (exposed: {}) => void;
|
|
20
|
+
attrs: any;
|
|
21
|
+
slots: {
|
|
22
|
+
'header-right'?: () => unknown;
|
|
23
|
+
toolbar?: () => unknown;
|
|
24
|
+
footer?: () => unknown;
|
|
25
|
+
};
|
|
26
|
+
emit: {};
|
|
27
|
+
}>) => import("vue").VNode & {
|
|
28
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
29
|
+
};
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
32
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
33
|
+
[K in keyof T]: T[K];
|
|
34
|
+
} : {
|
|
35
|
+
[K in keyof T as K]: T[K];
|
|
36
|
+
}) & {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { LazyTextValue } from '#ui-tools/shared/types/utils';
|
|
2
|
+
import type { DashboardBlockBaseProps, DashboardBlockUi, DashboardSeriesColor, DashboardSourceLike, DashboardStatUi, DashboardStatus, DashboardValueFormat } from '../types/index.js';
|
|
3
|
+
declare const __VLS_export: <TData>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<Omit<DashboardBlockBaseProps, "ui" | "title" | "subtitle"> & {
|
|
5
|
+
source: DashboardSourceLike<TData>;
|
|
6
|
+
/** KPI label, shown above the value. */
|
|
7
|
+
label: LazyTextValue;
|
|
8
|
+
/** Main value. Numbers go through `format` (locale number format by default). */
|
|
9
|
+
value: (data: TData & ({} | null)) => LazyTextValue;
|
|
10
|
+
format?: DashboardValueFormat;
|
|
11
|
+
/**
|
|
12
|
+
* Change indicator, in percent by default. `null` hides it. Defaults to the change from
|
|
13
|
+
* `compare` when that is set.
|
|
14
|
+
*/
|
|
15
|
+
delta?: (data: TData & ({} | null)) => number | null | undefined;
|
|
16
|
+
deltaFormat?: DashboardValueFormat;
|
|
17
|
+
/** A decrease is good news (e.g. a failure rate): colors the delta accordingly. */
|
|
18
|
+
invertDelta?: boolean;
|
|
19
|
+
/** Secondary text after the delta. Wraps under it when space runs out. */
|
|
20
|
+
caption?: string | ((data: TData & ({} | null)) => LazyTextValue | undefined);
|
|
21
|
+
icon?: string;
|
|
22
|
+
/** Recent values, oldest first, drawn as a sparkline under the value. `null` leaves a gap. */
|
|
23
|
+
trend?: (data: TData & ({} | null)) => readonly (number | null | undefined)[] | undefined;
|
|
24
|
+
/** How `trend` is drawn: a filled line (default), a bare line, or mini bars. */
|
|
25
|
+
trendType?: "area" | "line" | "bars";
|
|
26
|
+
trendColor?: DashboardSeriesColor;
|
|
27
|
+
/**
|
|
28
|
+
* The same measure over the comparison period (previous period, previous year). Gives the
|
|
29
|
+
* default `delta`, and the default caption ("vs 1,204 previous period").
|
|
30
|
+
*/
|
|
31
|
+
compare?: (data: TData & ({} | null)) => number | null | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Caption shown with `compare`, as text or built from the formatted previous value. Defaults to
|
|
34
|
+
* "vs <value> previous period".
|
|
35
|
+
*/
|
|
36
|
+
compareLabel?: LazyTextValue | ((previous: string) => LazyTextValue);
|
|
37
|
+
/**
|
|
38
|
+
* Target of a numeric `value`: draws a progress bar with the goal and the completion. `null`
|
|
39
|
+
* hides it.
|
|
40
|
+
*/
|
|
41
|
+
goal?: (data: TData & ({} | null)) => number | null | undefined;
|
|
42
|
+
/** Status on the title row (a colored dot and label). `null` hides it. */
|
|
43
|
+
status?: (data: TData & ({} | null)) => DashboardStatus | null | undefined;
|
|
44
|
+
ui?: DashboardBlockUi & DashboardStatUi;
|
|
45
|
+
}> & (typeof globalThis extends {
|
|
46
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
47
|
+
} ? P : {});
|
|
48
|
+
expose: (exposed: {}) => void;
|
|
49
|
+
attrs: any;
|
|
50
|
+
slots: {
|
|
51
|
+
value?: (props: {
|
|
52
|
+
data: TData & ({} | null);
|
|
53
|
+
value: string;
|
|
54
|
+
}) => unknown;
|
|
55
|
+
caption?: (props: {
|
|
56
|
+
data: TData & ({} | null);
|
|
57
|
+
}) => unknown;
|
|
58
|
+
};
|
|
59
|
+
emit: {};
|
|
60
|
+
}>) => import("vue").VNode & {
|
|
61
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
62
|
+
};
|
|
63
|
+
declare const _default: typeof __VLS_export;
|
|
64
|
+
export default _default;
|
|
65
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
66
|
+
[K in keyof T]: T[K];
|
|
67
|
+
} : {
|
|
68
|
+
[K in keyof T as K]: T[K];
|
|
69
|
+
}) & {};
|