@dou-ui/dashboard 0.1.0-alpha.3 → 0.1.0-alpha.5
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/chart/chart-settings.js.map +1 -1
- package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js +10 -8
- package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/chart/chart.js.map +1 -1
- package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js +19 -15
- package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/chart/read-props.js +26 -0
- package/dist/chart/read-props.js.map +1 -0
- package/dist/core/document.js +10 -1
- package/dist/core/document.js.map +1 -1
- package/dist/core/history.js +23 -0
- package/dist/core/history.js.map +1 -1
- package/dist/core/transaction.js +8 -2
- package/dist/core/transaction.js.map +1 -1
- package/dist/dashboard/comment-button.js +6 -0
- package/dist/dashboard/comment-button.js.map +1 -0
- package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js +59 -0
- package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/comment-card.js +6 -0
- package/dist/dashboard/comment-card.js.map +1 -0
- package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js +128 -0
- package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/comments.js +144 -0
- package/dist/dashboard/comments.js.map +1 -0
- package/dist/dashboard/dashboard.js.map +1 -1
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +132 -20
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/dashboard/error-boundary.js +64 -0
- package/dist/dashboard/error-boundary.js.map +1 -0
- package/dist/dashboard/frame-context.js.map +1 -1
- package/dist/dashboard/widget-body.js.map +1 -1
- package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js +53 -12
- package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/dashboard/widget-frame.js.map +1 -1
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +14 -2
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/dashboard/widget-settings.js.map +1 -1
- package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js +31 -5
- package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/locale.js +12 -0
- package/dist/locale.js.map +1 -1
- package/dist/pivot/pivot-settings.js.map +1 -1
- package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js +6 -4
- package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/pivot/pivot.js.map +1 -1
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/pivot/read-props.js +44 -0
- package/dist/pivot/read-props.js.map +1 -0
- package/dist/style.css +1 -1
- package/dist/style.js +2 -3
- package/dist/types/chart/read-props.d.ts +3 -0
- package/dist/types/core/document.d.ts +3 -2
- package/dist/types/core/history.d.ts +7 -1
- package/dist/types/core/transaction.d.ts +10 -1
- package/dist/types/core/types.d.ts +5 -0
- package/dist/types/dashboard/comment-button.vue.d.ts +15 -0
- package/dist/types/dashboard/comment-card.vue.d.ts +13 -0
- package/dist/types/dashboard/comments.d.ts +44 -0
- package/dist/types/dashboard/dashboard.vue.d.ts +12 -0
- package/dist/types/dashboard/error-boundary.d.ts +12 -0
- package/dist/types/dashboard/frame-context.d.ts +4 -0
- package/dist/types/dashboard/types.d.ts +47 -0
- package/dist/types/dashboard/widget-body.vue.d.ts +2 -0
- package/dist/types/dashboard/widget-settings.vue.d.ts +4 -0
- package/dist/types/index.d.ts +22 -1
- package/dist/types/locale.d.ts +8 -0
- package/dist/types/pivot/read-props.d.ts +3 -0
- package/dist/types/widgets/index.d.ts +1 -1
- package/dist/types/widgets/read-props.d.ts +4 -0
- package/dist/types/widgets/shared.d.ts +20 -4
- package/dist/widgets/index.js +2 -2
- package/dist/widgets/index.js.map +1 -1
- package/dist/widgets/read-props.js +52 -0
- package/dist/widgets/read-props.js.map +1 -0
- package/dist/widgets/shared.js +27 -5
- package/dist/widgets/shared.js.map +1 -1
- package/dist/widgets/stat-settings.js.map +1 -1
- package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js +12 -10
- package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/widgets/stat.js.map +1 -1
- package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js +10 -13
- package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/widgets/table-settings.js.map +1 -1
- package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js +6 -4
- package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/widgets/table.js.map +1 -1
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/widgets/text-settings.js.map +1 -1
- package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js +5 -3
- package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/widgets/text.js.map +1 -1
- package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js +5 -3
- package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/package.json +8 -8
|
@@ -15,19 +15,31 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, Das
|
|
|
15
15
|
breakpointChange: (breakpoint: string) => any;
|
|
16
16
|
"update:filters": (value: DashboardFilters) => any;
|
|
17
17
|
exportError: (event: DashboardExportErrorEvent) => any;
|
|
18
|
+
widgetError: (event: import("./types").DashboardWidgetErrorEvent) => any;
|
|
19
|
+
"update:comments": (threads: import("dou-ui").CommentThread[]) => any;
|
|
20
|
+
"update:activeComment": (id: string | null) => any;
|
|
21
|
+
commentAction: (action: import("dou-ui").CommentAction) => any;
|
|
18
22
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
23
|
onChange?: ((transaction: DashboardTransaction) => any) | undefined;
|
|
20
24
|
"onUpdate:modelValue"?: ((value: DashboardDocument) => any) | undefined;
|
|
21
25
|
onBreakpointChange?: ((breakpoint: string) => any) | undefined;
|
|
22
26
|
"onUpdate:filters"?: ((value: DashboardFilters) => any) | undefined;
|
|
23
27
|
onExportError?: ((event: DashboardExportErrorEvent) => any) | undefined;
|
|
28
|
+
onWidgetError?: ((event: import("./types").DashboardWidgetErrorEvent) => any) | undefined;
|
|
29
|
+
"onUpdate:comments"?: ((threads: import("dou-ui").CommentThread[]) => any) | undefined;
|
|
30
|
+
"onUpdate:activeComment"?: ((id: string | null) => any) | undefined;
|
|
31
|
+
onCommentAction?: ((action: import("dou-ui").CommentAction) => any) | undefined;
|
|
24
32
|
}>, {
|
|
33
|
+
comments: import("dou-ui").CommentThread[];
|
|
25
34
|
columns: number | Record<string, number>;
|
|
26
35
|
breakpoints: Record<string, number>;
|
|
27
36
|
rowHeight: number;
|
|
28
37
|
gap: number | [number, number];
|
|
29
38
|
compact: import("..").GridCompact;
|
|
30
39
|
widgets: DashboardWidgetType<any>[];
|
|
40
|
+
author: import("dou-ui").CommentAuthor;
|
|
41
|
+
activeComment: string | null;
|
|
42
|
+
commentable: boolean;
|
|
31
43
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
32
44
|
declare const _default: typeof __VLS_export;
|
|
33
45
|
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Whether an error broke what a component shows. Errors in event handlers,
|
|
4
|
+
* watchers and the like leave it showing: they go on to the app as usual.
|
|
5
|
+
*/
|
|
6
|
+
export declare function breaksView(info: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Keeps an error that breaks a widget's content or settings in that part:
|
|
9
|
+
* `failed` turns on, `report` is told, and the error goes no further. The
|
|
10
|
+
* caller shows the error state and turns `failed` off to try again.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useErrorBoundary(label: () => string, report: (error: unknown) => void): Ref<boolean>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SheetWorkbook } from '@dou-ui/sheet/core';
|
|
2
2
|
import type { Component, InjectionKey } from 'vue';
|
|
3
3
|
import type { DashboardPeer } from '../core/collaboration';
|
|
4
|
+
import type { DashboardComments } from './comments';
|
|
4
5
|
import type { DashboardWidget } from '../core/types';
|
|
5
6
|
import type { DashboardLinkedFilter } from '../data/types';
|
|
6
7
|
import type { DashboardMessages } from '../locale';
|
|
@@ -18,6 +19,7 @@ export interface FrameExporter {
|
|
|
18
19
|
* that widget's frame again, not every frame on the grid.
|
|
19
20
|
*/
|
|
20
21
|
export interface FrameContext {
|
|
22
|
+
comments: DashboardComments;
|
|
21
23
|
widget: (id: string) => DashboardWidget | undefined;
|
|
22
24
|
type: (widget: DashboardWidget) => DashboardWidgetType<any> | undefined;
|
|
23
25
|
title: (widget: DashboardWidget) => string;
|
|
@@ -50,5 +52,7 @@ export interface FrameContext {
|
|
|
50
52
|
/** Why the last export from a widget's menu failed. */
|
|
51
53
|
exportError: (id: string) => string | undefined;
|
|
52
54
|
clearExportError: (id: string) => void;
|
|
55
|
+
/** A widget's content broke, for `widgetError`. */
|
|
56
|
+
reportError: (id: string, error: unknown) => void;
|
|
53
57
|
}
|
|
54
58
|
export declare const frameContextKey: InjectionKey<FrameContext>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommentAction, CommentAuthor, CommentThread } from 'dou-ui';
|
|
1
2
|
import type { SheetExporterOptionsOf } from '@dou-ui/sheet';
|
|
2
3
|
import type { SheetExporter } from '@dou-ui/sheet/core';
|
|
3
4
|
import type { DashboardCollaboration } from '../core/collaboration';
|
|
@@ -8,6 +9,10 @@ import type { GridCompact } from '../layout/types';
|
|
|
8
9
|
import type { DashboardMessagesOverride } from '../locale';
|
|
9
10
|
import type { DashboardWidgetType } from '../widget/define';
|
|
10
11
|
import type { DashboardImageOptions } from './export';
|
|
12
|
+
/** What a comment thread is about: a widget. */
|
|
13
|
+
export interface DashboardCommentAnchor {
|
|
14
|
+
widget: string;
|
|
15
|
+
}
|
|
11
16
|
export interface DashboardProps {
|
|
12
17
|
/** The dashboard, bound with `v-model`; a new document object after every change. */
|
|
13
18
|
modelValue?: DashboardDocument;
|
|
@@ -58,6 +63,18 @@ export interface DashboardProps {
|
|
|
58
63
|
* such as PNG, are left out.
|
|
59
64
|
*/
|
|
60
65
|
exporters?: readonly SheetExporter[];
|
|
66
|
+
/**
|
|
67
|
+
* The comment threads, bound with `v-model:comments`. The widget a thread
|
|
68
|
+
* is about keeps the thread's id in its `comments`. Left out, there are
|
|
69
|
+
* no comments.
|
|
70
|
+
*/
|
|
71
|
+
comments?: CommentThread[];
|
|
72
|
+
/** Who is commenting. Without it comments can be read but not written. */
|
|
73
|
+
author?: CommentAuthor;
|
|
74
|
+
/** The thread open now, bound with `v-model:activeComment`. */
|
|
75
|
+
activeComment?: string | null;
|
|
76
|
+
/** Threads can be started and replied to; also while not `editable`. On by default. */
|
|
77
|
+
commentable?: boolean;
|
|
61
78
|
}
|
|
62
79
|
/** Options of a dashboard's `exportWidget`. */
|
|
63
80
|
export interface DashboardExportOptions<Options = any> {
|
|
@@ -71,6 +88,17 @@ export interface DashboardSaveOptions<Options = any> extends DashboardExportOpti
|
|
|
71
88
|
/** The file's name, with its extension; the widget's title by default. */
|
|
72
89
|
fileName?: string;
|
|
73
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* A widget's component threw while setting up or drawing its content or
|
|
93
|
+
* settings form; that part shows an error with a retry button instead.
|
|
94
|
+
*/
|
|
95
|
+
export interface DashboardWidgetErrorEvent {
|
|
96
|
+
/** The widget's id. */
|
|
97
|
+
widget: string;
|
|
98
|
+
/** Which part broke: what the widget shows, or its settings form. */
|
|
99
|
+
part: 'content' | 'settings';
|
|
100
|
+
error: unknown;
|
|
101
|
+
}
|
|
74
102
|
/** A widget's export from its menu failed. */
|
|
75
103
|
export interface DashboardExportErrorEvent {
|
|
76
104
|
/** The widget's id. */
|
|
@@ -92,6 +120,16 @@ export interface DashboardEmits {
|
|
|
92
120
|
breakpointChange: [breakpoint: string];
|
|
93
121
|
/** Exporting a widget from its menu or `saveWidget` failed; the widget tells of it unless prevented. */
|
|
94
122
|
exportError: [event: DashboardExportErrorEvent];
|
|
123
|
+
/**
|
|
124
|
+
* A widget's content or settings form threw while it set up or drew; it
|
|
125
|
+
* shows an error in its place, and the error goes no further. To report
|
|
126
|
+
* to error tracking.
|
|
127
|
+
*/
|
|
128
|
+
widgetError: [event: DashboardWidgetErrorEvent];
|
|
129
|
+
'update:comments': [threads: CommentThread[]];
|
|
130
|
+
'update:activeComment': [id: string | null];
|
|
131
|
+
/** A change to the comments made here: to send to a server, notify people, keep a log. */
|
|
132
|
+
commentAction: [action: CommentAction];
|
|
95
133
|
}
|
|
96
134
|
export interface DashboardAddOptions {
|
|
97
135
|
/** Where on the widest breakpoint; defaults to the first spot it fits. */
|
|
@@ -114,6 +152,15 @@ export interface DashboardExpose {
|
|
|
114
152
|
/** Adds a widget of a registered type; returns its id, or `undefined` for an unknown type. */
|
|
115
153
|
addWidget: (type: string, options?: DashboardAddOptions) => string | undefined;
|
|
116
154
|
removeWidget: (id: string) => void;
|
|
155
|
+
/**
|
|
156
|
+
* Opens the open threads on a widget (the one holding the focus when
|
|
157
|
+
* left out), ready to reply, or starts one there; `false` when there is
|
|
158
|
+
* no such widget, comments are off, or there is nothing to open and
|
|
159
|
+
* comments can't be written.
|
|
160
|
+
*/
|
|
161
|
+
comment: (id?: string) => boolean;
|
|
162
|
+
/** The widget each thread is about; `null` when it is gone. Not reactive. */
|
|
163
|
+
getCommentAnchors: () => Record<string, DashboardCommentAnchor | null>;
|
|
117
164
|
/** Adds a copy of a widget next to it; returns the copy's id. */
|
|
118
165
|
duplicateWidget: (id: string) => string | undefined;
|
|
119
166
|
focusWidget: (id: string) => void;
|
|
@@ -13,6 +13,8 @@ type __VLS_Props = {
|
|
|
13
13
|
}) => void;
|
|
14
14
|
/** Where the widget's workbook goes, for its export menu; the full-screen copy has none. */
|
|
15
15
|
setWorkbook?: (id: string, get: () => SheetWorkbook | undefined) => () => void;
|
|
16
|
+
/** Told when the widget's content breaks, for the dashboard's `widgetError`. */
|
|
17
|
+
reportError?: (id: string, error: unknown) => void;
|
|
16
18
|
};
|
|
17
19
|
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>;
|
|
18
20
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { DashboardWidget } from '../core/types';
|
|
2
|
+
import type { DashboardMessages } from '../locale';
|
|
2
3
|
import type { DashboardWidgetType } from '../widget/define';
|
|
3
4
|
type __VLS_Props = {
|
|
4
5
|
widget: DashboardWidget;
|
|
5
6
|
type: DashboardWidgetType<any>;
|
|
7
|
+
messages: DashboardMessages;
|
|
6
8
|
setProps: (id: string, patch: Record<string, unknown>, options?: {
|
|
7
9
|
group?: string;
|
|
8
10
|
}) => void;
|
|
11
|
+
/** Told when the settings form breaks, for the dashboard's `widgetError`. */
|
|
12
|
+
reportError?: (id: string, error: unknown) => void;
|
|
9
13
|
};
|
|
10
14
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
15
|
"update:props": (props: Record<string, unknown>) => any;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -154,6 +154,7 @@ export declare const DouGridLayoutHandle: import("dou-ui").WithInstall<{
|
|
|
154
154
|
};
|
|
155
155
|
}), import("vue").HTMLAttributes>;
|
|
156
156
|
export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").DefineComponent<{
|
|
157
|
+
comments?: import("dou-ui").CommentThread[] | undefined;
|
|
157
158
|
columns?: (number | Record<string, number>) | undefined;
|
|
158
159
|
editable?: boolean | undefined;
|
|
159
160
|
label?: string | undefined;
|
|
@@ -167,6 +168,9 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
167
168
|
createId?: ((type: string) => string) | undefined;
|
|
168
169
|
collaboration?: import("./index.js").DashboardCollaboration | undefined;
|
|
169
170
|
exporters?: readonly import("@dou-ui/sheet").SheetExporter[] | undefined;
|
|
171
|
+
author?: import("dou-ui").CommentAuthor | undefined;
|
|
172
|
+
activeComment?: string | null | undefined;
|
|
173
|
+
commentable?: boolean | undefined;
|
|
170
174
|
} & {
|
|
171
175
|
modelValue?: import("./index.js").DashboardDocument;
|
|
172
176
|
filters?: import("./index.js").DashboardFilters;
|
|
@@ -176,7 +180,12 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
176
180
|
breakpointChange: (breakpoint: string) => any;
|
|
177
181
|
"update:filters": (value: import("./index.js").DashboardFilters) => any;
|
|
178
182
|
exportError: (event: import("./index.js").DashboardExportErrorEvent) => any;
|
|
183
|
+
widgetError: (event: import("./index.js").DashboardWidgetErrorEvent) => any;
|
|
184
|
+
"update:comments": (threads: import("dou-ui").CommentThread[]) => any;
|
|
185
|
+
"update:activeComment": (id: string | null) => any;
|
|
186
|
+
commentAction: (action: import("dou-ui").CommentAction) => any;
|
|
179
187
|
}, string, import("vue").PublicProps, Readonly<{
|
|
188
|
+
comments?: import("dou-ui").CommentThread[] | undefined;
|
|
180
189
|
columns?: (number | Record<string, number>) | undefined;
|
|
181
190
|
editable?: boolean | undefined;
|
|
182
191
|
label?: string | undefined;
|
|
@@ -190,6 +199,9 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
190
199
|
createId?: ((type: string) => string) | undefined;
|
|
191
200
|
collaboration?: import("./index.js").DashboardCollaboration | undefined;
|
|
192
201
|
exporters?: readonly import("@dou-ui/sheet").SheetExporter[] | undefined;
|
|
202
|
+
author?: import("dou-ui").CommentAuthor | undefined;
|
|
203
|
+
activeComment?: string | null | undefined;
|
|
204
|
+
commentable?: boolean | undefined;
|
|
193
205
|
} & {
|
|
194
206
|
modelValue?: import("./index.js").DashboardDocument;
|
|
195
207
|
filters?: import("./index.js").DashboardFilters;
|
|
@@ -199,13 +211,21 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
199
211
|
onBreakpointChange?: ((breakpoint: string) => any) | undefined;
|
|
200
212
|
"onUpdate:filters"?: ((value: import("./index.js").DashboardFilters) => any) | undefined;
|
|
201
213
|
onExportError?: ((event: import("./index.js").DashboardExportErrorEvent) => any) | undefined;
|
|
214
|
+
onWidgetError?: ((event: import("./index.js").DashboardWidgetErrorEvent) => any) | undefined;
|
|
215
|
+
"onUpdate:comments"?: ((threads: import("dou-ui").CommentThread[]) => any) | undefined;
|
|
216
|
+
"onUpdate:activeComment"?: ((id: string | null) => any) | undefined;
|
|
217
|
+
onCommentAction?: ((action: import("dou-ui").CommentAction) => any) | undefined;
|
|
202
218
|
}>, {
|
|
219
|
+
comments: import("dou-ui").CommentThread[];
|
|
203
220
|
columns: number | Record<string, number>;
|
|
204
221
|
breakpoints: Record<string, number>;
|
|
205
222
|
rowHeight: number;
|
|
206
223
|
gap: number | [number, number];
|
|
207
224
|
compact: import("./layout").GridCompact;
|
|
208
225
|
widgets: import("./index.js").DashboardWidgetType<any>[];
|
|
226
|
+
author: import("dou-ui").CommentAuthor;
|
|
227
|
+
activeComment: string | null;
|
|
228
|
+
commentable: boolean;
|
|
209
229
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, import("vue").HTMLAttributes>;
|
|
210
230
|
export declare const DouDashboardPalette: import("dou-ui").WithInstall<{
|
|
211
231
|
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<Readonly<import("./index.js").DashboardPaletteProps> & Readonly<{}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, import("vue").PublicProps, {
|
|
@@ -264,11 +284,12 @@ export declare const DouDashboardFilterBar: import("dou-ui").WithInstall<{
|
|
|
264
284
|
default?: () => unknown;
|
|
265
285
|
};
|
|
266
286
|
}), import("vue").HTMLAttributes>;
|
|
267
|
-
export type { DashboardAddOptions, DashboardEmits, DashboardExportErrorEvent, DashboardExportOptions, DashboardSaveOptions, DashboardExpose, DashboardFilterBarProps, DashboardPaletteProps, DashboardProps, } from './dashboard/types';
|
|
287
|
+
export type { DashboardAddOptions, DashboardEmits, DashboardExportErrorEvent, DashboardWidgetErrorEvent, DashboardExportOptions, DashboardSaveOptions, DashboardCommentAnchor, DashboardExpose, DashboardFilterBarProps, DashboardPaletteProps, DashboardProps, } from './dashboard/types';
|
|
268
288
|
export type { DashboardDocument, DashboardPlace, DashboardWidget } from './core/types';
|
|
269
289
|
export { checkDocument, emptyDocument, isDashboardPlace, migrateDocument } from './core/document';
|
|
270
290
|
export type { CheckDocumentOptions, DocumentProblem } from './core/document';
|
|
271
291
|
export { applySteps, DashboardTransaction, replaceWidgets, sameValue } from './core/transaction';
|
|
292
|
+
export type { ReplaceWidgetsOptions } from './core/transaction';
|
|
272
293
|
export type { DashboardCollaboration, DashboardCollaborationHost, DashboardPeer, DashboardPresence, DashboardPresenceAction, } from './core/collaboration';
|
|
273
294
|
export type { DashboardStep, DashboardTransactionMeta, DashboardWidgetPatch, } from './core/transaction';
|
|
274
295
|
export { DashboardHistory } from './core/history';
|
package/dist/types/locale.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export interface DashboardMessages {
|
|
|
37
37
|
nothingToExport: string;
|
|
38
38
|
duplicate: string;
|
|
39
39
|
remove: string;
|
|
40
|
+
/** The comment button and the card of a widget's discussions. */
|
|
41
|
+
comment: string;
|
|
42
|
+
/** The comment button of a widget with discussions; `{count}` is how many are open. */
|
|
43
|
+
comments: string;
|
|
40
44
|
/** The settings drawer's title: `{title}`. */
|
|
41
45
|
settingsTitle: string;
|
|
42
46
|
/** The title field in the settings drawer. */
|
|
@@ -49,6 +53,10 @@ export interface DashboardMessages {
|
|
|
49
53
|
/** A widget's status. */
|
|
50
54
|
loading: string;
|
|
51
55
|
error: string;
|
|
56
|
+
/** A widget that failed to show, e.g. for props it can't use. */
|
|
57
|
+
renderError: string;
|
|
58
|
+
/** A widget's settings form that failed to show. */
|
|
59
|
+
settingsError: string;
|
|
52
60
|
empty: string;
|
|
53
61
|
retry: string;
|
|
54
62
|
/** A dashboard without widgets, while editing. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { DashboardWidgetType } from '../widget/define';
|
|
2
2
|
import type { StatWidgetProps, TableWidgetProps, TextWidgetProps } from './types';
|
|
3
3
|
export type { StatWidgetProps, TableWidgetColumn, TableWidgetProps, TextWidgetProps } from './types';
|
|
4
|
-
export { fieldsOf, filterValueOf, numberFieldsOf, rowsOf, valueAt } from './shared';
|
|
4
|
+
export { fieldsOf, filterValueOf, flagOf, numberFieldsOf, numberOf, recordOf, rowsOf, textOf, textsOf, valueAt, } from './shared';
|
|
5
5
|
/** What a built-in widget's definition can change: its type, label, icon, size and more. */
|
|
6
6
|
export type WidgetOverrides<P extends object> = Partial<Omit<DashboardWidgetType<P>, 'component'>>;
|
|
7
7
|
/**
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StatWidgetProps, TableWidgetProps, TextWidgetProps } from './types';
|
|
2
|
+
export declare function statPropsOf(props: Record<string, unknown>): StatWidgetProps;
|
|
3
|
+
export declare function textPropsOf(props: Record<string, unknown>): TextWidgetProps;
|
|
4
|
+
export declare function tablePropsOf(props: Record<string, unknown>): TableWidgetProps;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import type { SheetWorkbook } from '@dou-ui/sheet/core';
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The value at a dotted path, e.g. `total.amount`; the data itself for an
|
|
4
|
+
* empty path. A path that isn't text, e.g. a number in JSON written by hand
|
|
5
|
+
* or by a program, finds nothing.
|
|
6
|
+
*/
|
|
7
|
+
export declare function valueAt(data: unknown, path: unknown): unknown;
|
|
8
|
+
/** The rows of a source's data: the data when it is a list, or the list at `path`. Items that aren't objects are left out. */
|
|
9
|
+
export declare function rowsOf(data: unknown, path?: unknown): Record<string, unknown>[];
|
|
10
|
+
/** Text, or not set. */
|
|
11
|
+
export declare const textOf: (value: unknown) => string | undefined;
|
|
12
|
+
/** A list of texts: the texts in it, or none. */
|
|
13
|
+
export declare const textsOf: (value: unknown) => string[];
|
|
14
|
+
/** A finite number, or text that is one (`'12'`, as a number read from data); otherwise not set. */
|
|
15
|
+
export declare function numberOf(value: unknown): number | undefined;
|
|
16
|
+
/** On only for `true`: `'no'` or `1` don't turn a switch on. */
|
|
17
|
+
export declare const flagOf: (value: unknown) => boolean;
|
|
18
|
+
/** A plain object, not a list; otherwise not set. */
|
|
19
|
+
export declare const recordOf: (value: unknown) => Record<string, unknown> | undefined;
|
|
20
|
+
/** One of the values listed, or not set. */
|
|
21
|
+
export declare const oneOf: <T extends string>(value: unknown, values: readonly T[]) => T | undefined;
|
|
6
22
|
/** The keys of the first row of a list, or of an object: the fields to pick from in settings. */
|
|
7
23
|
export declare function fieldsOf(data: unknown): string[];
|
|
8
24
|
/** The keys whose value in the first row is a number. */
|
package/dist/widgets/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineDashboardWidget } from "../widget/define.js";
|
|
2
|
-
import { fieldsOf, filterValueOf, numberFieldsOf, rowsOf, valueAt } from "./shared.js";
|
|
2
|
+
import { fieldsOf, filterValueOf, flagOf, numberFieldsOf, numberOf, recordOf, rowsOf, textOf, textsOf, valueAt } from "./shared.js";
|
|
3
3
|
import stat_default from "./stat.js";
|
|
4
4
|
import stat_settings_default from "./stat-settings.js";
|
|
5
5
|
import table_default from "./table.js";
|
|
@@ -69,6 +69,6 @@ function tableWidget(overrides = {}) {
|
|
|
69
69
|
...overrides
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
export { fieldsOf, filterValueOf, numberFieldsOf, rowsOf, statWidget, tableWidget, textWidget, valueAt };
|
|
72
|
+
export { fieldsOf, filterValueOf, flagOf, numberFieldsOf, numberOf, recordOf, rowsOf, statWidget, tableWidget, textOf, textWidget, textsOf, valueAt };
|
|
73
73
|
|
|
74
74
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Stat","StatSettings","Text","TextSettings","Table","TableSettings"],"sources":["../../src/widgets/index.ts"],"sourcesContent":["import { HashIcon, TableIcon, TypeIcon } from '@dou-ui/icons'\nimport { defineDashboardWidget } from '../widget/define'\nimport type { DashboardWidgetType } from '../widget/define'\nimport Stat from './stat.vue'\nimport StatSettings from './stat-settings.vue'\nimport Table from './table.vue'\nimport TableSettings from './table-settings.vue'\nimport Text from './text.vue'\nimport TextSettings from './text-settings.vue'\nimport type { StatWidgetProps, TableWidgetProps, TextWidgetProps } from './types'\n\nexport type { StatWidgetProps, TableWidgetColumn, TableWidgetProps, TextWidgetProps } from './types'\nexport {
|
|
1
|
+
{"version":3,"file":"index.js","names":["Stat","StatSettings","Text","TextSettings","Table","TableSettings"],"sources":["../../src/widgets/index.ts"],"sourcesContent":["import { HashIcon, TableIcon, TypeIcon } from '@dou-ui/icons'\nimport { defineDashboardWidget } from '../widget/define'\nimport type { DashboardWidgetType } from '../widget/define'\nimport Stat from './stat.vue'\nimport StatSettings from './stat-settings.vue'\nimport Table from './table.vue'\nimport TableSettings from './table-settings.vue'\nimport Text from './text.vue'\nimport TextSettings from './text-settings.vue'\nimport type { StatWidgetProps, TableWidgetProps, TextWidgetProps } from './types'\n\nexport type { StatWidgetProps, TableWidgetColumn, TableWidgetProps, TextWidgetProps } from './types'\nexport {\n fieldsOf,\n filterValueOf,\n flagOf,\n numberFieldsOf,\n numberOf,\n recordOf,\n rowsOf,\n textOf,\n textsOf,\n valueAt,\n} from './shared'\n\n/** What a built-in widget's definition can change: its type, label, icon, size and more. */\nexport type WidgetOverrides<P extends object> = Partial<Omit<DashboardWidgetType<P>, 'component'>>\n\n/**\n * A number, read from a source or given, with its change since the last\n * period and a sparkline under it.\n */\nexport function statWidget(overrides: WidgetOverrides<StatWidgetProps> = {}) {\n return defineDashboardWidget<StatWidgetProps>({\n type: 'stat',\n label: '统计数字',\n icon: HashIcon,\n size: { w: 3, h: 2, minW: 2, minH: 2 },\n defaultProps: { value: 0 },\n component: Stat,\n settings: StatSettings,\n fullscreen: false,\n ...overrides,\n })\n}\n\n/** A note: plain text in three sizes, its line breaks kept. */\nexport function textWidget(overrides: WidgetOverrides<TextWidgetProps> = {}) {\n return defineDashboardWidget<TextWidgetProps>({\n type: 'text',\n label: '文字',\n icon: TypeIcon,\n size: { w: 4, h: 2, minW: 2, minH: 1 },\n defaultProps: { text: '', size: 'md' },\n component: Text,\n settings: TextSettings,\n fullscreen: false,\n ...overrides,\n })\n}\n\n/** A source's rows in a table, with the columns picked in its settings. */\nexport function tableWidget(overrides: WidgetOverrides<TableWidgetProps> = {}) {\n return defineDashboardWidget<TableWidgetProps>({\n type: 'table',\n label: '表格',\n icon: TableIcon,\n size: { w: 6, h: 4, minW: 3, minH: 3 },\n component: Table,\n settings: TableSettings,\n ...overrides,\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAgCA,SAAgB,WAAW,YAA8C,CAAC,GAAG;CAC3E,OAAO,sBAAuC;EAC5C,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;GAAE,GAAG;GAAG,GAAG;GAAG,MAAM;GAAG,MAAM;EAAE;EACrC,cAAc,EAAE,OAAO,EAAE;EACzB,WAAWA;EACX,UAAUC;EACV,YAAY;EACZ,GAAG;CACL,CAAC;AACH;;AAGA,SAAgB,WAAW,YAA8C,CAAC,GAAG;CAC3E,OAAO,sBAAuC;EAC5C,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;GAAE,GAAG;GAAG,GAAG;GAAG,MAAM;GAAG,MAAM;EAAE;EACrC,cAAc;GAAE,MAAM;GAAI,MAAM;EAAK;EACrC,WAAWC;EACX,UAAUC;EACV,YAAY;EACZ,GAAG;CACL,CAAC;AACH;;AAGA,SAAgB,YAAY,YAA+C,CAAC,GAAG;CAC7E,OAAO,sBAAwC;EAC7C,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;GAAE,GAAG;GAAG,GAAG;GAAG,MAAM;GAAG,MAAM;EAAE;EACrC,WAAWC;EACX,UAAUC;EACV,GAAG;CACL,CAAC;AACH"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { numberOf, oneOf, recordOf, textOf } from "./shared.js";
|
|
2
|
+
// src/widgets/read-props.ts
|
|
3
|
+
function statPropsOf(props) {
|
|
4
|
+
const precision = numberOf(props.precision);
|
|
5
|
+
return {
|
|
6
|
+
source: textOf(props.source),
|
|
7
|
+
field: textOf(props.field),
|
|
8
|
+
value: numberOf(props.value),
|
|
9
|
+
prefix: textOf(props.prefix),
|
|
10
|
+
suffix: textOf(props.suffix),
|
|
11
|
+
precision: precision !== void 0 && Number.isInteger(precision) && precision >= 0 && precision <= 20 ? precision : void 0,
|
|
12
|
+
trend: textOf(props.trend),
|
|
13
|
+
delta: textOf(props.delta)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function textPropsOf(props) {
|
|
17
|
+
const text = props.text;
|
|
18
|
+
return {
|
|
19
|
+
text: typeof text === "number" ? String(text) : textOf(text),
|
|
20
|
+
size: oneOf(props.size, [
|
|
21
|
+
"sm",
|
|
22
|
+
"md",
|
|
23
|
+
"lg"
|
|
24
|
+
])
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** The columns given, those with a text `key`; not set when not a list. */
|
|
28
|
+
function columnsOf(value) {
|
|
29
|
+
if (!Array.isArray(value)) return void 0;
|
|
30
|
+
const columns = [];
|
|
31
|
+
for (const item of value) {
|
|
32
|
+
const column = recordOf(item);
|
|
33
|
+
if (typeof column?.key !== "string") continue;
|
|
34
|
+
const title = textOf(column.title);
|
|
35
|
+
columns.push(title === void 0 ? { key: column.key } : {
|
|
36
|
+
key: column.key,
|
|
37
|
+
title
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return columns;
|
|
41
|
+
}
|
|
42
|
+
function tablePropsOf(props) {
|
|
43
|
+
return {
|
|
44
|
+
source: textOf(props.source),
|
|
45
|
+
path: textOf(props.path),
|
|
46
|
+
columns: columnsOf(props.columns),
|
|
47
|
+
rowKey: textOf(props.rowKey)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export { statPropsOf, tablePropsOf, textPropsOf };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=read-props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-props.js","names":[],"sources":["../../src/widgets/read-props.ts"],"sourcesContent":["import { numberOf, oneOf, recordOf, textOf } from './shared'\nimport type { StatWidgetProps, TableWidgetColumn, TableWidgetProps, TextWidgetProps } from './types'\n\n/*\n * The props of the built-in widgets as their types say, from whatever JSON\n * was saved: what isn't the right type counts as not set. The widgets and\n * their settings both read through these.\n */\n\nexport function statPropsOf(props: Record<string, unknown>): StatWidgetProps {\n const precision = numberOf(props.precision)\n return {\n source: textOf(props.source),\n field: textOf(props.field),\n value: numberOf(props.value),\n prefix: textOf(props.prefix),\n suffix: textOf(props.suffix),\n precision:\n precision !== undefined && Number.isInteger(precision) && precision >= 0 && precision <= 20\n ? precision\n : undefined,\n trend: textOf(props.trend),\n delta: textOf(props.delta),\n }\n}\n\nexport function textPropsOf(props: Record<string, unknown>): TextWidgetProps {\n const text = props.text\n return {\n text: typeof text === 'number' ? String(text) : textOf(text),\n size: oneOf(props.size, ['sm', 'md', 'lg'] as const),\n }\n}\n\n/** The columns given, those with a text `key`; not set when not a list. */\nfunction columnsOf(value: unknown): TableWidgetColumn[] | undefined {\n if (!Array.isArray(value)) return undefined\n const columns: TableWidgetColumn[] = []\n for (const item of value) {\n const column = recordOf(item)\n if (typeof column?.key !== 'string') continue\n const title = textOf(column.title)\n columns.push(title === undefined ? { key: column.key } : { key: column.key, title })\n }\n return columns\n}\n\nexport function tablePropsOf(props: Record<string, unknown>): TableWidgetProps {\n return {\n source: textOf(props.source),\n path: textOf(props.path),\n columns: columnsOf(props.columns),\n rowKey: textOf(props.rowKey),\n }\n}\n"],"mappings":";;AASA,SAAgB,YAAY,OAAiD;CAC3E,MAAM,YAAY,SAAS,MAAM,SAAS;CAC1C,OAAO;EACL,QAAQ,OAAO,MAAM,MAAM;EAC3B,OAAO,OAAO,MAAM,KAAK;EACzB,OAAO,SAAS,MAAM,KAAK;EAC3B,QAAQ,OAAO,MAAM,MAAM;EAC3B,QAAQ,OAAO,MAAM,MAAM;EAC3B,WACE,cAAc,KAAA,KAAa,OAAO,UAAU,SAAS,KAAK,aAAa,KAAK,aAAa,KACrF,YACA,KAAA;EACN,OAAO,OAAO,MAAM,KAAK;EACzB,OAAO,OAAO,MAAM,KAAK;CAC3B;AACF;AAEA,SAAgB,YAAY,OAAiD;CAC3E,MAAM,OAAO,MAAM;CACnB,OAAO;EACL,MAAM,OAAO,SAAS,WAAW,OAAO,IAAI,IAAI,OAAO,IAAI;EAC3D,MAAM,MAAM,MAAM,MAAM;GAAC;GAAM;GAAM;EAAI,CAAU;CACrD;AACF;;AAGA,SAAS,UAAU,OAAiD;CAClE,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;CAClC,MAAM,UAA+B,CAAC;CACtC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,SAAS,IAAI;EAC5B,IAAI,OAAO,QAAQ,QAAQ,UAAU;EACrC,MAAM,QAAQ,OAAO,OAAO,KAAK;EACjC,QAAQ,KAAK,UAAU,KAAA,IAAY,EAAE,KAAK,OAAO,IAAI,IAAI;GAAE,KAAK,OAAO;GAAK;EAAM,CAAC;CACrF;CACA,OAAO;AACT;AAEA,SAAgB,aAAa,OAAkD;CAC7E,OAAO;EACL,QAAQ,OAAO,MAAM,MAAM;EAC3B,MAAM,OAAO,MAAM,IAAI;EACvB,SAAS,UAAU,MAAM,OAAO;EAChC,QAAQ,OAAO,MAAM,MAAM;CAC7B;AACF"}
|
package/dist/widgets/shared.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// src/widgets/shared.ts
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The value at a dotted path, e.g. `total.amount`; the data itself for an
|
|
4
|
+
* empty path. A path that isn't text, e.g. a number in JSON written by hand
|
|
5
|
+
* or by a program, finds nothing.
|
|
6
|
+
*/
|
|
3
7
|
function valueAt(data, path) {
|
|
4
|
-
if (
|
|
8
|
+
if (path === void 0 || path === null || path === "") return data;
|
|
9
|
+
if (typeof path !== "string") return void 0;
|
|
5
10
|
let value = data;
|
|
6
11
|
for (const key of path.split(".")) {
|
|
7
12
|
if (value == null || typeof value !== "object") return void 0;
|
|
@@ -9,11 +14,28 @@ function valueAt(data, path) {
|
|
|
9
14
|
}
|
|
10
15
|
return value;
|
|
11
16
|
}
|
|
12
|
-
/** The rows of a source's data: the data when it is a list, or the list at `path`. */
|
|
17
|
+
/** The rows of a source's data: the data when it is a list, or the list at `path`. Items that aren't objects are left out. */
|
|
13
18
|
function rowsOf(data, path) {
|
|
14
19
|
const value = valueAt(data, path);
|
|
15
|
-
|
|
20
|
+
if (!Array.isArray(value)) return [];
|
|
21
|
+
return value.every(isRecord) ? value : value.filter(isRecord);
|
|
22
|
+
}
|
|
23
|
+
var isRecord = (value) => value !== null && typeof value === "object";
|
|
24
|
+
/** Text, or not set. */
|
|
25
|
+
var textOf = (value) => typeof value === "string" ? value : void 0;
|
|
26
|
+
/** A list of texts: the texts in it, or none. */
|
|
27
|
+
var textsOf = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
28
|
+
/** A finite number, or text that is one (`'12'`, as a number read from data); otherwise not set. */
|
|
29
|
+
function numberOf(value) {
|
|
30
|
+
const n = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
|
|
31
|
+
return Number.isFinite(n) ? n : void 0;
|
|
16
32
|
}
|
|
33
|
+
/** On only for `true`: `'no'` or `1` don't turn a switch on. */
|
|
34
|
+
var flagOf = (value) => value === true;
|
|
35
|
+
/** A plain object, not a list; otherwise not set. */
|
|
36
|
+
var recordOf = (value) => isRecord(value) && !Array.isArray(value) ? value : void 0;
|
|
37
|
+
/** One of the values listed, or not set. */
|
|
38
|
+
var oneOf = (value, values) => values.includes(value) ? value : void 0;
|
|
17
39
|
/** The keys of the first row of a list, or of an object: the fields to pick from in settings. */
|
|
18
40
|
function fieldsOf(data) {
|
|
19
41
|
const first = Array.isArray(data) ? data[0] : data;
|
|
@@ -63,6 +85,6 @@ function rowsToWorkbook(name, columns, rows) {
|
|
|
63
85
|
styles: { head: { bold: true } }
|
|
64
86
|
};
|
|
65
87
|
}
|
|
66
|
-
export { fieldsOf, filterValueOf, numberFieldsOf, rowsOf, rowsToWorkbook, valueAt };
|
|
88
|
+
export { fieldsOf, filterValueOf, flagOf, numberFieldsOf, numberOf, oneOf, recordOf, rowsOf, rowsToWorkbook, textOf, textsOf, valueAt };
|
|
67
89
|
|
|
68
90
|
//# sourceMappingURL=shared.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","names":[],"sources":["../../src/widgets/shared.ts"],"sourcesContent":["import type { SheetValue, SheetWorkbook } from '@dou-ui/sheet/core'\n\n
|
|
1
|
+
{"version":3,"file":"shared.js","names":[],"sources":["../../src/widgets/shared.ts"],"sourcesContent":["import type { SheetValue, SheetWorkbook } from '@dou-ui/sheet/core'\n\n/**\n * The value at a dotted path, e.g. `total.amount`; the data itself for an\n * empty path. A path that isn't text, e.g. a number in JSON written by hand\n * or by a program, finds nothing.\n */\nexport function valueAt(data: unknown, path: unknown): unknown {\n if (path === undefined || path === null || path === '') return data\n if (typeof path !== 'string') return undefined\n let value = data\n for (const key of path.split('.')) {\n if (value == null || typeof value !== 'object') return undefined\n value = (value as Record<string, unknown>)[key]\n }\n return value\n}\n\n/** The rows of a source's data: the data when it is a list, or the list at `path`. Items that aren't objects are left out. */\nexport function rowsOf(data: unknown, path?: unknown): Record<string, unknown>[] {\n const value = valueAt(data, path)\n if (!Array.isArray(value)) return []\n return value.every(isRecord) ? value : value.filter(isRecord)\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n value !== null && typeof value === 'object'\n\n/*\n * A widget's props come from JSON that types don't check, often written by a\n * program or an AI. These read one prop as the type it is meant to be; any\n * other value counts as not set, so a widget never throws on it.\n */\n\n/** Text, or not set. */\nexport const textOf = (value: unknown): string | undefined =>\n typeof value === 'string' ? value : undefined\n\n/** A list of texts: the texts in it, or none. */\nexport const textsOf = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []\n\n/** A finite number, or text that is one (`'12'`, as a number read from data); otherwise not set. */\nexport function numberOf(value: unknown): number | undefined {\n const n =\n typeof value === 'number'\n ? value\n : typeof value === 'string' && value.trim()\n ? Number(value)\n : Number.NaN\n return Number.isFinite(n) ? n : undefined\n}\n\n/** On only for `true`: `'no'` or `1` don't turn a switch on. */\nexport const flagOf = (value: unknown): boolean => value === true\n\n/** A plain object, not a list; otherwise not set. */\nexport const recordOf = (value: unknown): Record<string, unknown> | undefined =>\n isRecord(value) && !Array.isArray(value) ? value : undefined\n\n/** One of the values listed, or not set. */\nexport const oneOf = <T extends string>(value: unknown, values: readonly T[]): T | undefined =>\n values.includes(value as T) ? (value as T) : undefined\n\n/** The keys of the first row of a list, or of an object: the fields to pick from in settings. */\nexport function fieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return first && typeof first === 'object' && !Array.isArray(first) ? Object.keys(first) : []\n}\n\n/** The keys whose value in the first row is a number. */\nexport function numberFieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return fieldsOf(data).filter((key) => typeof (first as Record<string, unknown>)[key] === 'number')\n}\n\n/** A filter value from a value of the data: dates as `YYYY-MM-DD`, so the filters stay JSON. */\nconst pad = (n: number) => String(n).padStart(2, '0')\n\nexport function filterValueOf(value: unknown): unknown {\n if (!(value instanceof Date)) return value\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`\n}\n\n/** A value of the data as a sheet cell's: dates as `YYYY-MM-DD`, text starting with `=` kept as text. */\nfunction sheetValueOf(value: unknown): SheetValue {\n if (value == null) return null\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'boolean') return value\n const text = value instanceof Date ? (filterValueOf(value) as string) : String(value)\n return text.startsWith('=') ? `'${text}` : text\n}\n\n/**\n * Rows of data as a workbook, for the dashboard's export menu: one sheet,\n * a bold head row with the columns' titles, a row per row of data. An\n * empty `name` takes the widget's title.\n */\nexport function rowsToWorkbook(\n name: string,\n columns: readonly { key: string; title: string; width?: number }[],\n rows: readonly Record<string, unknown>[],\n): SheetWorkbook {\n const colSizes: Record<number, number> = {}\n columns.forEach((column, i) => column.width && (colSizes[i] = Math.round(column.width)))\n return {\n version: 1,\n sheets: [\n {\n name,\n cells: [\n columns.map((column) => ({ value: sheetValueOf(column.title), style: 'head' })),\n ...rows.map((row) => columns.map((column) => sheetValueOf(row[column.key]))),\n ],\n freeze: { rows: 1, cols: 0 },\n colSizes,\n },\n ],\n styles: { head: { bold: true } },\n }\n}\n"],"mappings":";;;;;;AAOA,SAAgB,QAAQ,MAAe,MAAwB;CAC7D,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,SAAS,IAAI,OAAO;CAC/D,IAAI,OAAO,SAAS,UAAU,OAAO,KAAA;CACrC,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG;EACjC,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO,KAAA;EACvD,QAAS,MAAkC;CAC7C;CACA,OAAO;AACT;;AAGA,SAAgB,OAAO,MAAe,MAA2C;CAC/E,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;CACnC,OAAO,MAAM,MAAM,QAAQ,IAAI,QAAQ,MAAM,OAAO,QAAQ;AAC9D;AAEA,IAAM,YAAY,UAChB,UAAU,QAAQ,OAAO,UAAU;;AASrC,IAAa,UAAU,UACrB,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAGtC,IAAa,WAAW,UACtB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;;AAG7F,SAAgB,SAAS,OAAoC;CAC3D,MAAM,IACJ,OAAO,UAAU,WACb,QACA,OAAO,UAAU,YAAY,MAAM,KAAK,IACtC,OAAO,KAAK,IACZ;CACR,OAAO,OAAO,SAAS,CAAC,IAAI,IAAI,KAAA;AAClC;;AAGA,IAAa,UAAU,UAA4B,UAAU;;AAG7D,IAAa,YAAY,UACvB,SAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAA;;AAGrD,IAAa,SAA2B,OAAgB,WACtD,OAAO,SAAS,KAAU,IAAK,QAAc,KAAA;;AAG/C,SAAgB,SAAS,MAAyB;CAChD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC;AAC7F;;AAGA,SAAgB,eAAe,MAAyB;CACtD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,IAAI,CAAC,CAAC,QAAQ,QAAQ,OAAQ,MAAkC,SAAS,QAAQ;AACnG;;AAGA,IAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;AAEpD,SAAgB,cAAc,OAAyB;CACrD,IAAI,EAAE,iBAAiB,OAAO,OAAO;CACrC,OAAO,GAAG,MAAM,YAAY,EAAE,GAAG,IAAI,MAAM,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,MAAM,QAAQ,CAAC;AACnF;;AAGA,SAAS,aAAa,OAA4B;CAChD,IAAI,SAAS,MAAM,OAAO;CAC1B,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;CACvE,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,MAAM,OAAO,iBAAiB,OAAQ,cAAc,KAAK,IAAe,OAAO,KAAK;CACpF,OAAO,KAAK,WAAW,GAAG,IAAI,IAAI,SAAS;AAC7C;;;;;;AAOA,SAAgB,eACd,MACA,SACA,MACe;CACf,MAAM,WAAmC,CAAC;CAC1C,QAAQ,SAAS,QAAQ,MAAM,OAAO,UAAU,SAAS,KAAK,KAAK,MAAM,OAAO,KAAK,EAAE;CACvF,OAAO;EACL,SAAS;EACT,QAAQ,CACN;GACE;GACA,OAAO,CACL,QAAQ,KAAK,YAAY;IAAE,OAAO,aAAa,OAAO,KAAK;IAAG,OAAO;GAAO,EAAE,GAC9E,GAAG,KAAK,KAAK,QAAQ,QAAQ,KAAK,WAAW,aAAa,IAAI,OAAO,IAAI,CAAC,CAAC,CAC7E;GACA,QAAQ;IAAE,MAAM;IAAG,MAAM;GAAE;GAC3B;EACF,CACF;EACA,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE;CACjC;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"
|
|
1
|
+
{"version":3,"file":"stat-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\nimport { statPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => statPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"view.source\"\n optional\n @update:model-value=\"(source) => set({ source })\"\n />\n <FieldSelect\n v-if=\"view.source\"\n :model-value=\"view.field\"\n :label=\"messages.value\"\n :fields=\"fields\"\n @update:model-value=\"(field) => set({ field: field as string | undefined })\"\n />\n <SettingsField v-else :label=\"messages.value\">\n <DouInputNumber\n :model-value=\"view.value ?? null\"\n :aria-label=\"messages.value\"\n @update:model-value=\"(value) => set({ value: value ?? undefined })\"\n />\n </SettingsField>\n <div class=\"dou-dashboard__field-row\">\n <SettingsField :label=\"messages.prefix\">\n <DouInput\n :model-value=\"view.prefix ?? ''\"\n :aria-label=\"messages.prefix\"\n @update:model-value=\"(prefix) => set({ prefix: prefix || undefined })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.suffix\">\n <DouInput\n :model-value=\"view.suffix ?? ''\"\n :aria-label=\"messages.suffix\"\n @update:model-value=\"(suffix) => set({ suffix: suffix || undefined })\"\n />\n </SettingsField>\n </div>\n <SettingsField :label=\"messages.precision\">\n <DouInputNumber\n :model-value=\"view.precision ?? null\"\n :min=\"0\"\n :max=\"6\"\n :aria-label=\"messages.precision\"\n @update:model-value=\"(precision) => set({ precision: precision ?? undefined })\"\n />\n </SettingsField>\n <template v-if=\"view.source\">\n <FieldSelect\n :model-value=\"view.trend\"\n :label=\"messages.trend\"\n :fields=\"fields\"\n @update:model-value=\"(trend) => set({ trend: trend as string | undefined })\"\n />\n <FieldSelect\n :model-value=\"view.delta\"\n :label=\"messages.delta\"\n :fields=\"fields\"\n @update:model-value=\"(delta) => set({ delta: delta as string | undefined })\"\n />\n </template>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useDashboardMessages } from "../locale.js";
|
|
2
2
|
import { useDashboardWidget } from "../widget/context.js";
|
|
3
3
|
import { fieldsOf } from "./shared.js";
|
|
4
|
+
import { statPropsOf } from "./read-props.js";
|
|
4
5
|
import settings_field_default from "./settings-field.js";
|
|
5
6
|
import field_select_default from "./field-select.js";
|
|
6
7
|
import source_field_default from "./source-field.js";
|
|
@@ -19,6 +20,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
19
20
|
emits: ["update:modelValue"],
|
|
20
21
|
setup(__props) {
|
|
21
22
|
const model = useModel(__props, "modelValue");
|
|
23
|
+
const view = computed(() => statPropsOf(model.value));
|
|
22
24
|
const messages = useDashboardMessages();
|
|
23
25
|
const { data } = useDashboardWidget();
|
|
24
26
|
const fields = computed(() => fieldsOf(data.value));
|
|
@@ -29,13 +31,13 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
29
31
|
return (_ctx, _cache) => {
|
|
30
32
|
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
31
33
|
createVNode(source_field_default, {
|
|
32
|
-
"model-value":
|
|
34
|
+
"model-value": view.value.source,
|
|
33
35
|
optional: "",
|
|
34
36
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = (source) => set({ source }))
|
|
35
37
|
}, null, 8, ["model-value"]),
|
|
36
|
-
|
|
38
|
+
view.value.source ? (openBlock(), createBlock(field_select_default, {
|
|
37
39
|
key: 0,
|
|
38
|
-
"model-value":
|
|
40
|
+
"model-value": view.value.field,
|
|
39
41
|
label: unref(messages).value,
|
|
40
42
|
fields: fields.value,
|
|
41
43
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = (field) => set({ field }))
|
|
@@ -48,7 +50,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
48
50
|
label: unref(messages).value
|
|
49
51
|
}, {
|
|
50
52
|
default: withCtx(() => [createVNode(unref(DouInputNumber), {
|
|
51
|
-
"model-value":
|
|
53
|
+
"model-value": view.value.value ?? null,
|
|
52
54
|
"aria-label": unref(messages).value,
|
|
53
55
|
"onUpdate:modelValue": _cache[2] || (_cache[2] = (value) => set({ value: value ?? void 0 }))
|
|
54
56
|
}, null, 8, ["model-value", "aria-label"])]),
|
|
@@ -56,14 +58,14 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
56
58
|
}, 8, ["label"])),
|
|
57
59
|
createElementVNode("div", _hoisted_2, [createVNode(settings_field_default, { label: unref(messages).prefix }, {
|
|
58
60
|
default: withCtx(() => [createVNode(unref(DouInput), {
|
|
59
|
-
"model-value":
|
|
61
|
+
"model-value": view.value.prefix ?? "",
|
|
60
62
|
"aria-label": unref(messages).prefix,
|
|
61
63
|
"onUpdate:modelValue": _cache[3] || (_cache[3] = (prefix) => set({ prefix: prefix || void 0 }))
|
|
62
64
|
}, null, 8, ["model-value", "aria-label"])]),
|
|
63
65
|
_: 1
|
|
64
66
|
}, 8, ["label"]), createVNode(settings_field_default, { label: unref(messages).suffix }, {
|
|
65
67
|
default: withCtx(() => [createVNode(unref(DouInput), {
|
|
66
|
-
"model-value":
|
|
68
|
+
"model-value": view.value.suffix ?? "",
|
|
67
69
|
"aria-label": unref(messages).suffix,
|
|
68
70
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = (suffix) => set({ suffix: suffix || void 0 }))
|
|
69
71
|
}, null, 8, ["model-value", "aria-label"])]),
|
|
@@ -71,7 +73,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
71
73
|
}, 8, ["label"])]),
|
|
72
74
|
createVNode(settings_field_default, { label: unref(messages).precision }, {
|
|
73
75
|
default: withCtx(() => [createVNode(unref(DouInputNumber), {
|
|
74
|
-
"model-value":
|
|
76
|
+
"model-value": view.value.precision ?? null,
|
|
75
77
|
min: 0,
|
|
76
78
|
max: 6,
|
|
77
79
|
"aria-label": unref(messages).precision,
|
|
@@ -79,8 +81,8 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
79
81
|
}, null, 8, ["model-value", "aria-label"])]),
|
|
80
82
|
_: 1
|
|
81
83
|
}, 8, ["label"]),
|
|
82
|
-
|
|
83
|
-
"model-value":
|
|
84
|
+
view.value.source ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createVNode(field_select_default, {
|
|
85
|
+
"model-value": view.value.trend,
|
|
84
86
|
label: unref(messages).trend,
|
|
85
87
|
fields: fields.value,
|
|
86
88
|
"onUpdate:modelValue": _cache[6] || (_cache[6] = (trend) => set({ trend }))
|
|
@@ -89,7 +91,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
89
91
|
"label",
|
|
90
92
|
"fields"
|
|
91
93
|
]), createVNode(field_select_default, {
|
|
92
|
-
"model-value":
|
|
94
|
+
"model-value": view.value.delta,
|
|
93
95
|
label: unref(messages).delta,
|
|
94
96
|
fields: fields.value,
|
|
95
97
|
"onUpdate:modelValue": _cache[7] || (_cache[7] = (delta) => set({ delta }))
|