summaryrefslogtreecommitdiff
path: root/packages/frontend/src/widgets/widget.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/widgets/widget.ts')
-rw-r--r--packages/frontend/src/widgets/widget.ts69
1 files changed, 50 insertions, 19 deletions
diff --git a/packages/frontend/src/widgets/widget.ts b/packages/frontend/src/widgets/widget.ts
index c5ca7ac26c..bfb724ff72 100644
--- a/packages/frontend/src/widgets/widget.ts
+++ b/packages/frontend/src/widgets/widget.ts
@@ -3,12 +3,14 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { reactive, watch } from 'vue';
-import type { Reactive } from 'vue';
+import { defineAsyncComponent, reactive, watch } from 'vue';
import { throttle } from 'throttle-debounce';
+import type { Reactive } from 'vue';
import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
+import { getDefaultFormValues } from '@/utility/form.js';
import * as os from '@/os.js';
import { deepClone } from '@/utility/clone.js';
+import type { WidgetName } from './index.js';
export type Widget<P extends Record<string, unknown>> = {
id: string;
@@ -20,7 +22,7 @@ export type WidgetComponentProps<P extends Record<string, unknown>> = {
};
export type WidgetComponentEmits<P extends Record<string, unknown>> = {
- (ev: 'updateProps', props: P);
+ (ev: 'updateProps', props: P): void;
};
export type WidgetComponentExpose = {
@@ -30,7 +32,7 @@ export type WidgetComponentExpose = {
};
export const useWidgetPropsManager = <F extends FormWithDefault>(
- name: string,
+ name: WidgetName,
propsDef: F,
props: Readonly<WidgetComponentProps<GetFormResultType<F>>>,
emit: WidgetComponentEmits<GetFormResultType<F>>,
@@ -39,19 +41,23 @@ export const useWidgetPropsManager = <F extends FormWithDefault>(
save: () => void;
configure: () => void;
} => {
- const widgetProps = reactive<GetFormResultType<F>>((props.widget ? deepClone(props.widget.data) : {}) as GetFormResultType<F>);
-
- const mergeProps = () => {
- for (const prop of Object.keys(propsDef)) {
- if (typeof widgetProps[prop] === 'undefined') {
- widgetProps[prop] = propsDef[prop].default;
+ const widgetProps = reactive((() => {
+ const np = getDefaultFormValues(propsDef);
+ if (props.widget?.data != null) {
+ for (const key of Object.keys(props.widget.data) as (keyof F)[]) {
+ np[key] = props.widget.data[key] as GetFormResultType<F>[typeof key];
}
}
- };
+ return np;
+ })());
- watch(widgetProps, () => {
- mergeProps();
- }, { deep: true, immediate: true });
+ watch(() => props.widget?.data, (to) => {
+ if (to != null) {
+ for (const key of Object.keys(propsDef)) {
+ (widgetProps as any)[key] = to[key];
+ }
+ }
+ }, { deep: true });
const save = throttle(3000, () => {
emit('updateProps', widgetProps as GetFormResultType<F>);
@@ -60,13 +66,38 @@ export const useWidgetPropsManager = <F extends FormWithDefault>(
const configure = async () => {
const form = deepClone(propsDef);
for (const item of Object.keys(form)) {
- form[item].default = widgetProps[item];
+ form[item].default = (widgetProps as any)[item];
+ }
+
+ const res = await new Promise<{
+ canceled: false;
+ result: GetFormResultType<F>;
+ } | {
+ canceled: true;
+ }>((resolve) => {
+ const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkWidgetSettingsDialog.vue')), {
+ widgetName: name,
+ form: form,
+ currentSettings: widgetProps,
+ }, {
+ saved: (newProps) => {
+ resolve({ canceled: false, result: newProps as GetFormResultType<F> });
+ },
+ canceled: () => {
+ resolve({ canceled: true });
+ },
+ closed: () => {
+ dispose();
+ },
+ });
+ });
+
+ if (res.canceled) {
+ return;
}
- const { canceled, result } = await os.form(name, form);
- if (canceled) return;
- for (const key of Object.keys(result)) {
- widgetProps[key] = result[key];
+ for (const key of Object.keys(res.result)) {
+ (widgetProps as any)[key] = res.result[key];
}
save();