@vc-shell/framework 1.0.213 → 1.0.215
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/CHANGELOG.md +18 -0
- package/dist/framework.js +2392 -2368
- package/dist/index.css +1 -1
- package/dist/locales/en.json +1 -0
- package/dist/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/types/index.d.ts +2 -0
- package/dist/shared/components/blade-navigation/types/index.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/factories/types/index.d.ts +1 -0
- package/dist/shared/modules/dynamic/factories/types/index.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts +1 -1
- package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts +3 -2
- package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.stories.d.ts +12 -0
- package/dist/ui/components/organisms/vc-blade/vc-blade.stories.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts +1 -0
- package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
- package/package.json +4 -4
- package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +71 -42
- package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +9 -3
- package/shared/components/blade-navigation/types/index.ts +2 -0
- package/shared/modules/dynamic/factories/base/useDetailsFactory.ts +1 -1
- package/shared/modules/dynamic/factories/types/index.ts +1 -0
- package/shared/modules/dynamic/pages/dynamic-blade-form.vue +2 -1
- package/shared/modules/dynamic/pages/dynamic-blade-list.vue +14 -24
- package/ui/components/atoms/vc-switch/vc-switch.vue +6 -12
- package/ui/components/organisms/vc-blade/vc-blade.vue +16 -0
- package/ui/components/organisms/vc-table/vc-table.vue +1 -1
|
@@ -32,6 +32,9 @@ declare const _default: {
|
|
|
32
32
|
type: import("vue").PropType<import("../../../..").IBladeToolbar[]>;
|
|
33
33
|
default: () => never[];
|
|
34
34
|
};
|
|
35
|
+
hasUnsavedChanges: {
|
|
36
|
+
type: import("vue").PropType<boolean>;
|
|
37
|
+
};
|
|
35
38
|
}>> & {
|
|
36
39
|
onClose?: (() => any) | undefined;
|
|
37
40
|
onExpand?: (() => any) | undefined;
|
|
@@ -69,6 +72,9 @@ declare const _default: {
|
|
|
69
72
|
type: import("vue").PropType<import("../../../..").IBladeToolbar[]>;
|
|
70
73
|
default: () => never[];
|
|
71
74
|
};
|
|
75
|
+
hasUnsavedChanges: {
|
|
76
|
+
type: import("vue").PropType<boolean>;
|
|
77
|
+
};
|
|
72
78
|
}>> & {
|
|
73
79
|
onClose?: (() => any) | undefined;
|
|
74
80
|
onExpand?: (() => any) | undefined;
|
|
@@ -114,6 +120,9 @@ declare const _default: {
|
|
|
114
120
|
type: import("vue").PropType<import("../../../..").IBladeToolbar[]>;
|
|
115
121
|
default: () => never[];
|
|
116
122
|
};
|
|
123
|
+
hasUnsavedChanges: {
|
|
124
|
+
type: import("vue").PropType<boolean>;
|
|
125
|
+
};
|
|
117
126
|
}>> & {
|
|
118
127
|
onClose?: (() => any) | undefined;
|
|
119
128
|
onExpand?: (() => any) | undefined;
|
|
@@ -156,6 +165,9 @@ declare const _default: {
|
|
|
156
165
|
type: import("vue").PropType<import("../../../..").IBladeToolbar[]>;
|
|
157
166
|
default: () => never[];
|
|
158
167
|
};
|
|
168
|
+
hasUnsavedChanges: {
|
|
169
|
+
type: import("vue").PropType<boolean>;
|
|
170
|
+
};
|
|
159
171
|
}>> & {
|
|
160
172
|
onClose?: (() => any) | undefined;
|
|
161
173
|
onExpand?: (() => any) | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vc-blade.stories.d.ts","sourceRoot":"","sources":["../../../../../ui/components/organisms/vc-blade/vc-blade.stories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC
|
|
1
|
+
{"version":3,"file":"vc-blade.stories.d.ts","sourceRoot":"","sources":["../../../../../ui/components/organisms/vc-blade/vc-blade.stories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG7B,wBAuBiC;AAEjC,eAAO,MAAM,OAAO,EAAE,OAAO,CAAC,OAAO,OAAO,CAM1C,CAAC;AAEH,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,OAAO,OAAO,CAOjD,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,OAAO,CAAC,OAAO,OAAO,CAMnD,CAAC;AAEH,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,OAAO,OAAO,CAShD,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,OAAO,OAAO,CASlD,CAAC;AAEH,eAAO,MAAM,mBAAmB,EAAE,OAAO,CAAC,OAAO,OAAO,CAMtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vc-blade.vue.d.ts","sourceRoot":"","sources":["../../../../../ui/components/organisms/vc-blade/vc-blade.vue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQvD,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"vc-blade.vue.d.ts","sourceRoot":"","sources":["../../../../../ui/components/organisms/vc-blade/vc-blade.vue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAQvD,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,KAAK;IACpB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4RD,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vc-shell/framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.215",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/framework.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/dompurify": "^3.0.5",
|
|
61
61
|
"@types/quill": "^2.0.14",
|
|
62
|
-
"@vc-shell/api-client-generator": "^1.0.
|
|
63
|
-
"@vc-shell/config-generator": "^1.0.
|
|
64
|
-
"@vc-shell/ts-config": "^1.0.
|
|
62
|
+
"@vc-shell/api-client-generator": "^1.0.215",
|
|
63
|
+
"@vc-shell/config-generator": "^1.0.215",
|
|
64
|
+
"@vc-shell/ts-config": "^1.0.215",
|
|
65
65
|
"@vitejs/plugin-vue": "^5.0.3",
|
|
66
66
|
"sass": "^1.69.6",
|
|
67
67
|
"shx": "^0.3.4",
|
package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
20
|
<script lang="ts" setup>
|
|
21
|
-
import { Ref, computed, inject, withDirectives, h, vShow, toRef } from "vue";
|
|
21
|
+
import { Ref, computed, inject, withDirectives, h, vShow, toRef, VNode, nextTick } from "vue";
|
|
22
22
|
import { RouterView } from "vue-router";
|
|
23
23
|
import { BladeVNode, IParentCallArgs, useBladeNavigation } from "./../../../../../shared";
|
|
24
24
|
import { ErrorInterceptor } from "./../../../error-interceptor";
|
|
@@ -31,7 +31,10 @@ const { blades, closeBlade, onParentCall } = useBladeNavigation();
|
|
|
31
31
|
const { breadcrumbs, push, remove } = useBreadcrumbs();
|
|
32
32
|
|
|
33
33
|
const quantity = computed(() => {
|
|
34
|
-
return
|
|
34
|
+
return (
|
|
35
|
+
blades.value.filter((x) => x.props.navigation.isVisible || typeof x.props.navigation.isVisible === "undefined")
|
|
36
|
+
.length || 0
|
|
37
|
+
);
|
|
35
38
|
});
|
|
36
39
|
|
|
37
40
|
const isMobile = inject("isMobile") as Ref<boolean>;
|
|
@@ -46,6 +49,9 @@ watchDebounced(
|
|
|
46
49
|
id: blade.props.navigation.idx.toString(),
|
|
47
50
|
title: toRef(blade.props.navigation.instance ?? { title: "" }, "title"),
|
|
48
51
|
clickHandler: async (id) => {
|
|
52
|
+
if (blade.props.navigation.isVisible === false) {
|
|
53
|
+
blade.props.navigation.isVisible = true;
|
|
54
|
+
}
|
|
49
55
|
const isPrevented = await closeBlade(parseInt(id) + 1);
|
|
50
56
|
return !isPrevented;
|
|
51
57
|
},
|
|
@@ -64,49 +70,72 @@ const render = () => {
|
|
|
64
70
|
if (!blades.value.length) {
|
|
65
71
|
return h(RouterView);
|
|
66
72
|
}
|
|
73
|
+
|
|
67
74
|
return h("div", { class: "tw-w-full tw-overflow-hidden tw-flex tw-grow tw-basis-0 tw-relative" }, [
|
|
68
|
-
blades.value.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
75
|
+
blades.value.reduce(
|
|
76
|
+
(arr, bladeVNode, index) => {
|
|
77
|
+
if (bladeVNode.type.isBlade) {
|
|
78
|
+
const hiddenQuantity = blades.value.filter(
|
|
79
|
+
(x) => x.props.navigation.isVisible === false && x.props.navigation.idx < index,
|
|
80
|
+
).length;
|
|
81
|
+
|
|
82
|
+
arr.push(
|
|
83
|
+
h(
|
|
84
|
+
ErrorInterceptor,
|
|
85
|
+
{
|
|
86
|
+
key: index,
|
|
87
|
+
capture: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
default: ({
|
|
91
|
+
error,
|
|
92
|
+
reset,
|
|
93
|
+
}: Parameters<InstanceType<typeof ErrorInterceptor>["$slots"]["default"]>["0"]) => {
|
|
94
|
+
return withDirectives(
|
|
95
|
+
h(
|
|
96
|
+
VcBladeView,
|
|
97
|
+
{ key: `${bladeVNode.type?.name}_${index}` || `blade_${index}`, blade: bladeVNode },
|
|
98
|
+
{
|
|
99
|
+
default: ({ Component }: { Component: BladeVNode }) => {
|
|
100
|
+
return h(Component, {
|
|
101
|
+
error,
|
|
102
|
+
closable: index >= 1,
|
|
103
|
+
expandable: quantity.value > 1,
|
|
104
|
+
expanded: index - hiddenQuantity === quantity.value - 1,
|
|
105
|
+
"onClose:blade": () => {
|
|
106
|
+
closeBlade(index);
|
|
107
|
+
},
|
|
108
|
+
"onParent:call": async (args: IParentCallArgs) => {
|
|
109
|
+
await nextTick(() => {
|
|
110
|
+
const instance = blades.value?.[index - 1]?.props?.navigation?.instance;
|
|
111
|
+
if (instance) onParentCall(instance, args);
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
onVnodeUnmounted: reset,
|
|
115
|
+
});
|
|
96
116
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
},
|
|
118
|
+
),
|
|
119
|
+
|
|
120
|
+
[
|
|
121
|
+
[
|
|
122
|
+
vShow,
|
|
123
|
+
(bladeVNode.props.navigation.isVisible ||
|
|
124
|
+
typeof bladeVNode.props.navigation.isVisible === "undefined") &&
|
|
125
|
+
index >= quantity.value - (isMobile.value ? 1 : 2),
|
|
126
|
+
],
|
|
127
|
+
],
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
102
134
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}),
|
|
135
|
+
return arr;
|
|
136
|
+
},
|
|
137
|
+
[] as unknown as VNode[],
|
|
138
|
+
),
|
|
110
139
|
]);
|
|
111
140
|
};
|
|
112
141
|
</script>
|
|
@@ -45,7 +45,7 @@ interface IUseBladeNavigation {
|
|
|
45
45
|
readonly blades: ComputedRef<BladeVNode[]>;
|
|
46
46
|
readonly currentBladeNavigationData: ComputedRef<BladeVNode["props"]["navigation"]>;
|
|
47
47
|
openBlade: <Blade extends Component>(
|
|
48
|
-
{ blade, param, options, onOpen, onClose }: IBladeEvent<Blade>,
|
|
48
|
+
{ blade, param, options, onOpen, onClose, replaceCurrentBlade }: IBladeEvent<Blade>,
|
|
49
49
|
isWorkspace?: boolean,
|
|
50
50
|
) => Promise<void | NavigationFailure>;
|
|
51
51
|
closeBlade: (index: number) => Promise<boolean>;
|
|
@@ -255,6 +255,9 @@ const useBladeNavigationSingleton = createSharedComposable(() => {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
if (!isPrevented) {
|
|
258
|
+
if (navigationInstance.blades.value[index - 1]?.props?.navigation?.isVisible === false) {
|
|
259
|
+
navigationInstance.blades.value[index - 1].props.navigation.isVisible = true;
|
|
260
|
+
}
|
|
258
261
|
navigationInstance.blades.value.splice(index);
|
|
259
262
|
}
|
|
260
263
|
|
|
@@ -338,7 +341,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
|
|
|
338
341
|
}
|
|
339
342
|
|
|
340
343
|
async function openBlade<Blade extends Component>(
|
|
341
|
-
{ blade, param, options, onOpen, onClose }: IBladeEvent<Blade>,
|
|
344
|
+
{ blade, param, options, onOpen, onClose, replaceCurrentBlade = false }: IBladeEvent<Blade>,
|
|
342
345
|
isWorkspace = false,
|
|
343
346
|
) {
|
|
344
347
|
if (!blade) {
|
|
@@ -372,6 +375,9 @@ export function useBladeNavigation(): IUseBladeNavigation {
|
|
|
372
375
|
|
|
373
376
|
if (!isPrevented) {
|
|
374
377
|
if (hasAccess(blade.permissions)) {
|
|
378
|
+
if (replaceCurrentBlade) {
|
|
379
|
+
navigationInstance.blades.value[currentBladeIdx].props.navigation.isVisible = false;
|
|
380
|
+
}
|
|
375
381
|
navigationInstance.blades.value.push(bladeNode);
|
|
376
382
|
} else {
|
|
377
383
|
notification.error(i18n.global.t("PERMISSION_MESSAGES.ACCESS_RESTRICTED"), { timeout: 3000 });
|
|
@@ -491,7 +497,7 @@ export function useBladeNavigation(): IUseBladeNavigation {
|
|
|
491
497
|
const registeredWorkspaceComponent = routes.find((route) => route.route === `/${workspace}`)?.component;
|
|
492
498
|
const registeredRouteComponent = routes.find((route) => route.route === `/${blade}`)?.component;
|
|
493
499
|
|
|
494
|
-
if (!registeredWorkspaceComponent) {
|
|
500
|
+
if (!hasAccess(registeredWorkspaceComponent?.type.permissions) || !registeredWorkspaceComponent) {
|
|
495
501
|
return goToRoot();
|
|
496
502
|
}
|
|
497
503
|
|
|
@@ -72,6 +72,7 @@ export interface IBladeEvent<T extends Component = Component> {
|
|
|
72
72
|
param?: string;
|
|
73
73
|
onOpen?: () => void;
|
|
74
74
|
onClose?: () => void;
|
|
75
|
+
replaceCurrentBlade?: boolean;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export interface BladeNavigationPlugin {
|
|
@@ -96,6 +97,7 @@ export interface BladeVNode extends VNode {
|
|
|
96
97
|
onBeforeClose?: () => Promise<boolean | undefined>;
|
|
97
98
|
instance: CoreBladeExposed | undefined | null;
|
|
98
99
|
idx: number;
|
|
100
|
+
isVisible?: boolean;
|
|
99
101
|
};
|
|
100
102
|
onVnodeUnmounted?: VNodeMountHook | VNodeMountHook[];
|
|
101
103
|
onVnodeMounted?: VNodeMountHook | VNodeMountHook[];
|
|
@@ -38,7 +38,7 @@ export const useDetailsFactory = <Item>(factoryParams: UseDetailsFactoryParams<I
|
|
|
38
38
|
} else throw new Error("Form is not valid");
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
const { loading: removeLoading, action: remove } = useAsync<ItemId>(async (args) => {
|
|
41
|
+
const { loading: removeLoading, action: remove } = useAsync<ItemId | Item>(async (args) => {
|
|
42
42
|
await factoryParams.remove?.(args as ItemId);
|
|
43
43
|
});
|
|
44
44
|
|
|
@@ -84,6 +84,7 @@ export interface ListBaseBladeScope<Item = Record<string, any>, Query = Record<s
|
|
|
84
84
|
) => void;
|
|
85
85
|
onPaginationClick?: (query: Query) => void;
|
|
86
86
|
breadcrumbs?: ComputedRef<Breadcrumbs[]>;
|
|
87
|
+
modified?: ComputedRef<boolean> | Ref<boolean> | boolean;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
export type TOpenBladeArgs = Omit<Parameters<ReturnType<typeof useBladeNavigation>["openBlade"]>["0"], "blade">;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
:width="settings?.width || '50%'"
|
|
8
8
|
:toolbar-items="toolbarComputed"
|
|
9
9
|
:title="title"
|
|
10
|
+
:has-unsaved-changes="isFormModified"
|
|
10
11
|
@close="$emit('close:blade')"
|
|
11
12
|
@expand="$emit('expand:blade')"
|
|
12
13
|
@collapse="$emit('collapse:blade')"
|
|
@@ -104,7 +105,7 @@ import { notification } from "../../../components";
|
|
|
104
105
|
interface Props {
|
|
105
106
|
expanded?: boolean;
|
|
106
107
|
closable?: boolean;
|
|
107
|
-
param?: string;
|
|
108
|
+
param?: string | any;
|
|
108
109
|
model?: DynamicDetailsSchema;
|
|
109
110
|
options?: {
|
|
110
111
|
[x: string]: unknown;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
:class="{
|
|
11
11
|
'tw-flex tw-flex-auto': isWidgetView,
|
|
12
12
|
}"
|
|
13
|
+
:has-unsaved-changes="unref(scope)?.modified"
|
|
13
14
|
@close="$emit('close:blade')"
|
|
14
15
|
@expand="$emit('expand:blade')"
|
|
15
16
|
@collapse="$emit('collapse:blade')"
|
|
@@ -39,20 +40,20 @@
|
|
|
39
40
|
class="tw-grow tw-basis-0"
|
|
40
41
|
:loading="loading"
|
|
41
42
|
:expanded="expanded"
|
|
42
|
-
:columns="
|
|
43
|
+
:columns="tableColsWithLocales ?? []"
|
|
43
44
|
:state-key="stateKey ?? ''"
|
|
44
|
-
:items="itemsProxy
|
|
45
|
+
:items="itemsProxy ?? []"
|
|
45
46
|
:multiselect="isWidgetView ? false : tableData?.multiselect"
|
|
46
47
|
:header="isWidgetView ? false : tableData?.header"
|
|
47
48
|
:item-action-builder="actionBuilder"
|
|
48
49
|
:enable-item-actions="!!tableData?.actions && !isWidgetView"
|
|
49
|
-
:footer="
|
|
50
|
+
:footer="isWidgetView ? false : tableData?.footer"
|
|
50
51
|
:sort="sort"
|
|
51
52
|
:pages="pagination?.pages"
|
|
52
53
|
:current-page="pagination?.currentPage"
|
|
53
54
|
:search-value="searchValue"
|
|
54
55
|
:selected-item-id="selectedItemId"
|
|
55
|
-
:total-label="$t(`${
|
|
56
|
+
:total-label="$t(`${localizationPrefix}.PAGES.LIST.TABLE.TOTALS`)"
|
|
56
57
|
:total-count="pagination?.totalCount"
|
|
57
58
|
:active-filter-count="activeFilterCount"
|
|
58
59
|
:reorderable-rows="isWidgetView ? false : tableData?.reorderableRows"
|
|
@@ -87,12 +88,12 @@
|
|
|
87
88
|
<template v-else>
|
|
88
89
|
<div class="tw-w-full tw-h-full tw-box-border tw-flex tw-flex-col tw-items-center tw-justify-center">
|
|
89
90
|
<div class="tw-m-4 tw-text-xl tw-font-medium">
|
|
90
|
-
{{ $t(`${
|
|
91
|
+
{{ $t(`${localizationPrefix}.PAGES.LIST.NOT_FOUND.EMPTY`) }}
|
|
91
92
|
</div>
|
|
92
93
|
<VcButton
|
|
93
94
|
v-if="isFilterVisible"
|
|
94
95
|
@click="resetSearch"
|
|
95
|
-
>{{ $t(`${
|
|
96
|
+
>{{ $t(`${localizationPrefix}.PAGES.LIST.NOT_FOUND.RESET`) }}</VcButton
|
|
96
97
|
>
|
|
97
98
|
</div>
|
|
98
99
|
</template>
|
|
@@ -113,7 +114,7 @@
|
|
|
113
114
|
<template v-else>
|
|
114
115
|
<div class="tw-w-full tw-h-full tw-box-border tw-flex tw-flex-col tw-items-center tw-justify-center">
|
|
115
116
|
<div class="tw-m-4 tw-text-xl tw-font-medium">
|
|
116
|
-
{{ $t(`${
|
|
117
|
+
{{ $t(`${localizationPrefix}.PAGES.LIST.EMPTY.NO_ITEMS`) }}
|
|
117
118
|
</div>
|
|
118
119
|
</div>
|
|
119
120
|
</template>
|
|
@@ -180,7 +181,7 @@ import { safeIn } from "../helpers/safeIn";
|
|
|
180
181
|
export interface Props {
|
|
181
182
|
expanded?: boolean;
|
|
182
183
|
closable?: boolean;
|
|
183
|
-
param?: string;
|
|
184
|
+
param?: string | any;
|
|
184
185
|
options?: unknown;
|
|
185
186
|
model?: DynamicGridSchema;
|
|
186
187
|
composables?: Record<string, (...args: any[]) => Record<string, any>>;
|
|
@@ -210,6 +211,7 @@ const { debounce } = useFunctions();
|
|
|
210
211
|
const emit = defineEmits<Emits>();
|
|
211
212
|
|
|
212
213
|
const settings = computed(() => props.model?.settings);
|
|
214
|
+
const localizationPrefix = computed(() => settings.value?.localizationPrefix.trim().toUpperCase());
|
|
213
215
|
const title = computed(() => t(settings.value?.titleTemplate as string));
|
|
214
216
|
const allSelected = ref(false);
|
|
215
217
|
const searchValue = ref();
|
|
@@ -217,7 +219,6 @@ const selectedItemId = shallowRef();
|
|
|
217
219
|
const sort = shallowRef("createdDate:DESC");
|
|
218
220
|
const selectedIds = shallowRef<string[]>([]);
|
|
219
221
|
const itemsProxy = ref<Record<string, any>[]>();
|
|
220
|
-
const modified = shallowRef(false);
|
|
221
222
|
|
|
222
223
|
const { moduleNotifications, markAsRead } = useNotifications(settings.value?.pushNotificationType);
|
|
223
224
|
const { setNavigationQuery, getNavigationQuery } = useBladeNavigation();
|
|
@@ -242,7 +243,10 @@ const tableData =
|
|
|
242
243
|
props.composables &&
|
|
243
244
|
computed(() => props.model?.content.find((type: ListContentSchema) => type.component === "vc-table"));
|
|
244
245
|
|
|
245
|
-
const tableColsWithLocales = tableData?.value?.columns?.map((col) => ({
|
|
246
|
+
const tableColsWithLocales = tableData?.value?.columns?.map((col) => ({
|
|
247
|
+
...col,
|
|
248
|
+
title: computed(() => t(col.title)),
|
|
249
|
+
})) as ITableColumns[];
|
|
246
250
|
|
|
247
251
|
const stateKey =
|
|
248
252
|
props.composables &&
|
|
@@ -348,12 +352,6 @@ const toolbarComputed =
|
|
|
348
352
|
useToolbarReducer({
|
|
349
353
|
defaultToolbarSchema: settings.value?.toolbar ?? [],
|
|
350
354
|
defaultToolbarBindings: {
|
|
351
|
-
save: {
|
|
352
|
-
clickHandler() {
|
|
353
|
-
emit("close:blade");
|
|
354
|
-
},
|
|
355
|
-
disabled: computed(() => !modified.value),
|
|
356
|
-
},
|
|
357
355
|
openAddBlade: {
|
|
358
356
|
async clickHandler() {
|
|
359
357
|
if (
|
|
@@ -398,14 +396,6 @@ watch(
|
|
|
398
396
|
{ immediate: true },
|
|
399
397
|
);
|
|
400
398
|
|
|
401
|
-
watch(
|
|
402
|
-
() => itemsProxy.value,
|
|
403
|
-
(newVal) => {
|
|
404
|
-
modified.value = !_.isEqual(newVal, items.value);
|
|
405
|
-
},
|
|
406
|
-
{ deep: true },
|
|
407
|
-
);
|
|
408
|
-
|
|
409
399
|
watch(sort, async (value) => {
|
|
410
400
|
await load({ ...query.value, sort: value });
|
|
411
401
|
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
>
|
|
9
9
|
<span>{{ label }}</span>
|
|
10
10
|
</VcLabel>
|
|
11
|
-
<div class="tw-relative tw-inline-block tw-w-[
|
|
11
|
+
<div class="tw-relative tw-inline-block tw-w-[32px] tw-h-[18px]">
|
|
12
12
|
<label>
|
|
13
13
|
<input
|
|
14
14
|
type="checkbox"
|
|
@@ -63,11 +63,9 @@ function onInput(e: Event) {
|
|
|
63
63
|
<style lang="scss">
|
|
64
64
|
:root {
|
|
65
65
|
--switch-main-color: #43b0e6;
|
|
66
|
-
--switch-secondary-color: #
|
|
66
|
+
--switch-secondary-color: #d2d4d7;
|
|
67
67
|
--switch-transition: all 0.2s ease-in-out;
|
|
68
68
|
--switch-icon-transition: opacity 0.3s ease-in-out;
|
|
69
|
-
--switch-active-icon: url("data:image/svg+xml;utf8,<svg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M3.73609 7.34288L0.161085 3.85628C-0.0536949 3.64681 -0.0536949 3.30718 0.161085 3.09769L0.938884 2.3391C1.15366 2.12961 1.50193 2.12961 1.71671 2.3391L4.125 4.68782L8.28329 0.657101C8.49807 0.447633 8.84634 0.447633 9.06112 0.657101L9.83892 1.41569C10.0537 1.62516 10.0537 1.96479 9.83892 2.17428L4.51391 7.3429C4.29911 7.55237 3.95087 7.55237 3.73609 7.34288Z' fill='white'/></svg>");
|
|
70
|
-
--switch-disabled-icon: url("data:image/svg+xml;utf8,<svg width='8' height='8' viewBox='0 0 8 8' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M5.51636 4L7.79068 1.72568C8.06977 1.44659 8.06977 0.994091 7.79068 0.714773L7.28523 0.209318C7.00614 -0.0697727 6.55364 -0.0697727 6.27432 0.209318L4 2.48364L1.72568 0.209318C1.44659 -0.0697727 0.994091 -0.0697727 0.714773 0.209318L0.209318 0.714773C-0.0697727 0.993864 -0.0697727 1.44636 0.209318 1.72568L2.48364 4L0.209318 6.27432C-0.0697727 6.55341 -0.0697727 7.00591 0.209318 7.28523L0.714773 7.79068C0.993864 8.06977 1.44659 8.06977 1.72568 7.79068L4 5.51636L6.27432 7.79068C6.55341 8.06977 7.00614 8.06977 7.28523 7.79068L7.79068 7.28523C8.06977 7.00614 8.06977 6.55364 7.79068 6.27432L5.51636 4Z' fill='white'/></svg>");
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
.vc-switch {
|
|
@@ -75,11 +73,11 @@ function onInput(e: Event) {
|
|
|
75
73
|
@apply tw-w-0 tw-h-0 tw-opacity-0;
|
|
76
74
|
|
|
77
75
|
&:checked + .vc-switch__slider:before {
|
|
78
|
-
@apply tw-translate-x-[
|
|
76
|
+
@apply tw-translate-x-[14px];
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
&:checked + .vc-switch__slider {
|
|
82
|
-
@apply tw-bg-[color:var(--switch-main-color)] after:tw-bg-[
|
|
80
|
+
@apply tw-bg-[color:var(--switch-main-color)] after:tw-bg-[position:10px] after:tw-bg-[length:10px_7px];
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
&:disabled + .vc-switch__slider {
|
|
@@ -88,14 +86,10 @@ function onInput(e: Event) {
|
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
&__slider {
|
|
91
|
-
@apply tw-absolute tw-top-0 tw-right-0 tw-bottom-0 tw-left-0 tw-bg-[color:var(--switch-secondary-color)] tw-rounded-[
|
|
92
|
-
|
|
93
|
-
&:after {
|
|
94
|
-
@apply tw-inline-block tw-w-full tw-h-full tw-bg-[image:var(--switch-disabled-icon)] tw-bg-[position:calc(100%-11px)] tw-bg-no-repeat tw-bg-[length:8px_8px] tw-content-[""];
|
|
95
|
-
}
|
|
89
|
+
@apply tw-absolute tw-top-0 tw-right-0 tw-bottom-0 tw-left-0 tw-bg-[color:var(--switch-secondary-color)] tw-rounded-[9999px] tw-cursor-pointer tw-transition tw-duration-200 tw-shadow-[inset_0px_2px_4px_rgba(0,0,0,0.1)];
|
|
96
90
|
|
|
97
91
|
&:before {
|
|
98
|
-
@apply tw-absolute tw-bottom-px tw-left-px tw-flex tw-justify-center tw-items-center tw-w-[
|
|
92
|
+
@apply tw-absolute tw-bottom-px tw-left-px tw-flex tw-justify-center tw-items-center tw-w-[16px] tw-h-[16px] tw-bg-white tw-rounded-[9999px] tw-text-[color:#d2d2d2] tw-text-[10px] tw-transition tw-shadow-[0_2px_4px_rgba(0,0,0,0.1)] tw-duration-200 tw-content-[""];
|
|
99
93
|
}
|
|
100
94
|
}
|
|
101
95
|
}
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
</template>
|
|
35
35
|
</VcBladeHeader>
|
|
36
36
|
|
|
37
|
+
<!-- Show error message -->
|
|
37
38
|
<template v-if="error">
|
|
38
39
|
<div class="tw-text-white tw-p-2 tw-flex tw-flex-row tw-items-center tw-bg-[color:var(--blade-color-error)]">
|
|
39
40
|
<VcIcon
|
|
@@ -50,6 +51,19 @@
|
|
|
50
51
|
</div>
|
|
51
52
|
</template>
|
|
52
53
|
|
|
54
|
+
<!-- Unsaved changes -->
|
|
55
|
+
<template v-if="hasUnsavedChanges">
|
|
56
|
+
<div
|
|
57
|
+
class="tw-text-white tw-px-2 tw-py-1 tw-flex tw-flex-row tw-items-center tw-bg-[color:var(--blade-color-unsaved-changes)]"
|
|
58
|
+
>
|
|
59
|
+
<VcIcon
|
|
60
|
+
size="s"
|
|
61
|
+
icon="fas fa-info-circle"
|
|
62
|
+
/>
|
|
63
|
+
<div class="tw-line-clamp-1 tw-w-full tw-ml-2">{{ t("COMPONENTS.ORGANISMS.VC_BLADE.UNSAVED_CHANGES") }}</div>
|
|
64
|
+
</div>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
53
67
|
<!-- Set up blade toolbar -->
|
|
54
68
|
<VcBladeToolbar
|
|
55
69
|
class="tw-shrink-0"
|
|
@@ -78,6 +92,7 @@ export interface Props {
|
|
|
78
92
|
expandable?: boolean;
|
|
79
93
|
closable?: boolean;
|
|
80
94
|
toolbarItems?: IBladeToolbar[];
|
|
95
|
+
hasUnsavedChanges?: boolean;
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
export interface Emits {
|
|
@@ -123,6 +138,7 @@ const { open } = usePopup({
|
|
|
123
138
|
--blade-background-color: #ffffff;
|
|
124
139
|
--blade-border-radius: 6px;
|
|
125
140
|
--blade-color-error: #f14e4e;
|
|
141
|
+
--blade-color-unsaved-changes: #82a6bd;
|
|
126
142
|
}
|
|
127
143
|
|
|
128
144
|
.vc-app_mobile .vc-blade {
|
|
@@ -629,7 +629,7 @@ const mobileTemplateRenderer = ({ item }: { item: TableItem }) => {
|
|
|
629
629
|
{ class: "tw-border-b tw-border-solid tw-border-b-[#e3e7ec] tw-p-3 tw-gap-2 tw-flex tw-flex-wrap" },
|
|
630
630
|
props.columns.map((x) => {
|
|
631
631
|
return h("div", { class: "tw-grow tw-w-[33%] tw-ml-3 tw-truncate" }, [
|
|
632
|
-
h(VcHint, { class: "tw-mb-1 tw-truncate" }, toValue(x.title)),
|
|
632
|
+
h(VcHint, { class: "tw-mb-1 tw-truncate" }, () => toValue(x.title)),
|
|
633
633
|
h(VcTableCell, { cell: { ...x, class: "!tw-justify-start" }, item, class: "" }),
|
|
634
634
|
]);
|
|
635
635
|
}),
|