@vc-shell/framework 1.0.147 → 1.0.149
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 +21 -0
- package/core/composables/index.ts +1 -1
- package/core/composables/useLanguages/index.ts +52 -0
- package/core/plugins/i18n/index.ts +1 -1
- package/core/plugins/modularity/index.ts +10 -1
- package/core/plugins/validation/index.ts +0 -11
- package/core/plugins/validation/rules.ts +7 -6
- package/dist/core/composables/index.d.ts +1 -1
- package/dist/core/composables/index.d.ts.map +1 -1
- package/dist/core/composables/useLanguages/index.d.ts +12 -0
- package/dist/core/composables/useLanguages/index.d.ts.map +1 -0
- package/dist/core/plugins/modularity/index.d.ts.map +1 -1
- package/dist/core/plugins/validation/index.d.ts +0 -3
- package/dist/core/plugins/validation/index.d.ts.map +1 -1
- package/dist/core/plugins/validation/rules.d.ts +1 -1
- package/dist/core/plugins/validation/rules.d.ts.map +1 -1
- package/dist/framework.js +11732 -10993
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/shared/components/app-switcher/composables/useAppSwitcher/index.d.ts.map +1 -1
- 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/components/vc-blade-view/vc-blade-view.d.ts +0 -12
- package/dist/shared/components/blade-navigation/components/vc-blade-view/vc-blade-view.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts +6 -3
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/plugin.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/types/index.d.ts +6 -8
- package/dist/shared/components/blade-navigation/types/index.d.ts.map +1 -1
- package/dist/shared/components/language-selector/language-selector.vue.d.ts.map +1 -1
- package/dist/shared/components/user-dropdown-button/user-dropdown-button.vue.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/components/SchemaRender.d.ts +3 -3
- package/dist/shared/modules/dynamic/components/fields/Button.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/Card.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/Checkbox.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/ContentField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/DynamicProperty.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/EditorField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/Fieldset.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/GalleryField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/ImageField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/InputCurrency.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/InputField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/MultivalueField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/SelectField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/StatusField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/TextareaField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/VideoField.d.ts +1 -1
- package/dist/shared/modules/dynamic/components/fields/props.d.ts +1 -1
- package/dist/shared/modules/dynamic/factories/types/index.d.ts +1 -1
- package/dist/shared/modules/dynamic/factories/types/index.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/helpers/nodeBuilder.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/helpers/override.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/index.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts +3 -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 +2 -0
- package/dist/shared/modules/dynamic/pages/dynamic-blade-list.vue.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/types/index.d.ts +13 -4
- package/dist/shared/modules/dynamic/types/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
- package/package.json +6 -5
- package/shared/components/app-switcher/composables/useAppSwitcher/index.ts +2 -1
- package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +12 -26
- package/shared/components/blade-navigation/components/vc-blade-view/vc-blade-view.ts +18 -11
- package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +231 -337
- package/shared/components/blade-navigation/plugin.ts +2 -1
- package/shared/components/blade-navigation/types/index.ts +5 -11
- package/shared/components/language-selector/language-selector.vue +12 -10
- package/shared/components/notification-dropdown/notification-dropdown.vue +1 -1
- package/shared/components/user-dropdown-button/user-dropdown-button.vue +55 -40
- package/shared/modules/dynamic/factories/types/index.ts +1 -1
- package/shared/modules/dynamic/helpers/nodeBuilder.ts +6 -3
- package/shared/modules/dynamic/helpers/override.ts +29 -11
- package/shared/modules/dynamic/index.ts +1 -0
- package/shared/modules/dynamic/pages/dynamic-blade-form.vue +47 -17
- package/shared/modules/dynamic/pages/dynamic-blade-list.vue +11 -1
- package/shared/modules/dynamic/types/index.ts +13 -4
- package/ui/components/atoms/vc-label/vc-label.vue +18 -19
- package/ui/components/molecules/vc-multivalue/vc-multivalue.vue +1 -0
- package/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +5 -19
- package/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +1 -1
- package/ui/components/organisms/vc-app/vc-app.vue +2 -8
- package/core/composables/useI18n/index.ts +0 -7
- package/dist/core/composables/useI18n/index.d.ts +0 -3
- package/dist/core/composables/useI18n/index.d.ts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Router } from "vue-router";
|
|
2
|
-
import { App, inject } from "vue";
|
|
2
|
+
import { App, inject, ref } from "vue";
|
|
3
3
|
import * as components from "./components";
|
|
4
4
|
import { BladeNavigationPlugin, BladeRoutesRecord } from "./types";
|
|
5
5
|
|
|
@@ -25,6 +25,7 @@ export const VcBladeNavigationComponent = {
|
|
|
25
25
|
const bladeNavigationPlugin: BladeNavigationPlugin = {
|
|
26
26
|
router: args.router,
|
|
27
27
|
internalRoutes,
|
|
28
|
+
blades: ref([]),
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
app.config.globalProperties.$bladeNavigationPlugin = bladeNavigationPlugin;
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
VNode,
|
|
9
9
|
ComponentInternalInstance,
|
|
10
10
|
VNodeTypes,
|
|
11
|
-
|
|
11
|
+
Ref,
|
|
12
12
|
} from "vue";
|
|
13
13
|
import { ComponentPublicInstanceConstructor } from "../../../utilities/vueUtils";
|
|
14
14
|
import { MenuItemConfig } from "../../../../core/types";
|
|
@@ -27,6 +27,7 @@ export type CoreDynamicBladeComponentProps = {
|
|
|
27
27
|
|
|
28
28
|
export type CoreBladeAdditionalSettings = {
|
|
29
29
|
url?: `/${string}`;
|
|
30
|
+
routable?: boolean;
|
|
30
31
|
permissions?: string | string[];
|
|
31
32
|
isWorkspace?: boolean;
|
|
32
33
|
name?: string;
|
|
@@ -75,6 +76,7 @@ export interface IBladeEvent<T extends Component = Component> {
|
|
|
75
76
|
export interface BladeNavigationPlugin {
|
|
76
77
|
router: Router;
|
|
77
78
|
internalRoutes: BladeRoutesRecord[];
|
|
79
|
+
blades: Ref<BladeVNode[]>;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
export interface BladeRoutesRecord {
|
|
@@ -90,10 +92,10 @@ export interface BladeVNode extends VNode {
|
|
|
90
92
|
navigation: {
|
|
91
93
|
onOpen?: () => void;
|
|
92
94
|
onClose?: () => void;
|
|
95
|
+
onBeforeClose?: () => Promise<boolean | undefined>;
|
|
96
|
+
instance: Ref<CoreBladeExposed | undefined | null>;
|
|
93
97
|
fullPath: string;
|
|
94
|
-
bladePath?: string;
|
|
95
98
|
idx: number;
|
|
96
|
-
uniqueRouteKey: string;
|
|
97
99
|
};
|
|
98
100
|
onVnodeUnmounted?: VNodeMountHook | VNodeMountHook[];
|
|
99
101
|
onVnodeMounted?: VNodeMountHook | VNodeMountHook[];
|
|
@@ -101,11 +103,3 @@ export interface BladeVNode extends VNode {
|
|
|
101
103
|
CoreBladeComponentProps;
|
|
102
104
|
type: VNodeTypes & BladeInstanceConstructor;
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
export interface BladeRouteRecordLocationNormalized extends RouteRecordNormalized {
|
|
106
|
-
components: Record<string, BladeVNode>;
|
|
107
|
-
instances: Record<
|
|
108
|
-
string,
|
|
109
|
-
ComponentPublicInstance<CoreBladeExposed, any, CoreBladeExposed, any, CoreBladeExposed, any, any, any, any, any>
|
|
110
|
-
>;
|
|
111
|
-
}
|
|
@@ -44,17 +44,19 @@ import { VcIcon } from "./../../../ui/components";
|
|
|
44
44
|
import { ref } from "vue";
|
|
45
45
|
import { vOnClickOutside } from "@vueuse/components";
|
|
46
46
|
import { useI18n } from "vue-i18n";
|
|
47
|
+
import { useLanguages } from "../../../core/composables";
|
|
47
48
|
|
|
48
|
-
const {
|
|
49
|
-
|
|
49
|
+
const { availableLocales, getLocaleMessage } = useI18n({ useScope: "global" });
|
|
50
|
+
const { setLocale } = useLanguages();
|
|
50
51
|
const isDropActive = ref(false);
|
|
51
52
|
|
|
52
|
-
const languageItems = availableLocales
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}))
|
|
53
|
+
const languageItems = availableLocales
|
|
54
|
+
.map((locale: string) => ({
|
|
55
|
+
lang: locale,
|
|
56
|
+
title: (getLocaleMessage(locale) as { language_name: string }).language_name,
|
|
57
|
+
clickHandler(lang: string) {
|
|
58
|
+
setLocale(lang);
|
|
59
|
+
},
|
|
60
|
+
}))
|
|
61
|
+
.filter((item) => item.title);
|
|
60
62
|
</script>
|
|
@@ -4,40 +4,42 @@
|
|
|
4
4
|
class="user-dropdown-button"
|
|
5
5
|
:class="{
|
|
6
6
|
'user-dropdown-button_active': accountMenuVisible,
|
|
7
|
-
'user-dropdown-button_no-pointer': $isMobile.value,
|
|
8
7
|
}"
|
|
9
8
|
@click.stop="toggleAccountMenuVisible"
|
|
10
9
|
>
|
|
11
|
-
<div
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<div class="
|
|
24
|
-
|
|
10
|
+
<div class="user-dropdown-button__wrap tw-flex tw-justify-between tw-items-center tw-flex-auto">
|
|
11
|
+
<div
|
|
12
|
+
v-if="avatarUrl"
|
|
13
|
+
class="user-dropdown-button__avatar"
|
|
14
|
+
:style="imageHandler"
|
|
15
|
+
></div>
|
|
16
|
+
<VcIcon
|
|
17
|
+
v-else
|
|
18
|
+
icon="fas fa-user-circle"
|
|
19
|
+
size="xxl"
|
|
20
|
+
class="tw-text-[color:var(--app-bar-button-color)]"
|
|
21
|
+
/>
|
|
22
|
+
<div class="tw-grow tw-basis-0 tw-ml-3 tw-overflow-hidden">
|
|
23
|
+
<div class="user-dropdown-button__name tw-truncate">
|
|
24
|
+
{{ name || user?.userName }}
|
|
25
|
+
</div>
|
|
26
|
+
<div class="user-dropdown-button__role">
|
|
27
|
+
{{
|
|
28
|
+
(role && $t(`SHELL.USER.ROLE.${role}`)) ||
|
|
29
|
+
(user?.isAdministrator ? $t("SHELL.USER.ROLE.ADMINISTRATOR") : "")
|
|
30
|
+
}}
|
|
31
|
+
</div>
|
|
25
32
|
</div>
|
|
26
|
-
<div
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
<div
|
|
34
|
+
v-if="menu && menu.length"
|
|
35
|
+
class="user-dropdown-button__chevron"
|
|
36
|
+
>
|
|
37
|
+
<VcIcon
|
|
38
|
+
icon="fas fa-chevron-down"
|
|
39
|
+
size="xl"
|
|
40
|
+
></VcIcon>
|
|
30
41
|
</div>
|
|
31
42
|
</div>
|
|
32
|
-
<div
|
|
33
|
-
v-if="menu && menu.length && !$isMobile.value"
|
|
34
|
-
class="user-dropdown-button__chevron"
|
|
35
|
-
>
|
|
36
|
-
<VcIcon
|
|
37
|
-
icon="fas fa-chevron-down"
|
|
38
|
-
size="xl"
|
|
39
|
-
></VcIcon>
|
|
40
|
-
</div>
|
|
41
43
|
<div
|
|
42
44
|
v-if="menu && accountMenuVisible"
|
|
43
45
|
class="user-dropdown-button__menu"
|
|
@@ -56,7 +58,7 @@
|
|
|
56
58
|
</template>
|
|
57
59
|
|
|
58
60
|
<script lang="ts" setup>
|
|
59
|
-
import {
|
|
61
|
+
import { computed, ref } from "vue";
|
|
60
62
|
import { vOnClickOutside } from "@vueuse/components";
|
|
61
63
|
import { useUser } from "../../../core/composables";
|
|
62
64
|
import { useRouter } from "vue-router";
|
|
@@ -65,6 +67,7 @@ import { VcIcon } from "../../../ui/components";
|
|
|
65
67
|
import { BladeMenu } from "../../../core/types";
|
|
66
68
|
import { usePopup } from "../popup-handler/composables/usePopup";
|
|
67
69
|
import { ChangePassword } from "../change-password";
|
|
70
|
+
import { useBladeNavigation } from "..";
|
|
68
71
|
|
|
69
72
|
export interface Props {
|
|
70
73
|
avatarUrl?: string | undefined;
|
|
@@ -76,8 +79,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
76
79
|
menuItems: () => [],
|
|
77
80
|
});
|
|
78
81
|
|
|
79
|
-
const isMobile = inject("isMobile") as Ref<boolean>;
|
|
80
|
-
|
|
81
82
|
const { user, signOut } = useUser();
|
|
82
83
|
const router = useRouter();
|
|
83
84
|
const { t } = useI18n({ useScope: "global" });
|
|
@@ -85,7 +86,7 @@ const { t } = useI18n({ useScope: "global" });
|
|
|
85
86
|
const { open } = usePopup({
|
|
86
87
|
component: ChangePassword,
|
|
87
88
|
});
|
|
88
|
-
|
|
89
|
+
const { closeBlade } = useBladeNavigation();
|
|
89
90
|
const accountMenuVisible = ref(false);
|
|
90
91
|
const menu = computed(() => [
|
|
91
92
|
...props.menuItems,
|
|
@@ -98,14 +99,18 @@ const menu = computed(() => [
|
|
|
98
99
|
{
|
|
99
100
|
title: t("SHELL.ACCOUNT.LOGOUT"),
|
|
100
101
|
async clickHandler() {
|
|
101
|
-
await
|
|
102
|
-
|
|
102
|
+
const isPrevented = await closeBlade(0);
|
|
103
|
+
|
|
104
|
+
if (!isPrevented) {
|
|
105
|
+
await signOut();
|
|
106
|
+
router.push({ name: "Login" });
|
|
107
|
+
}
|
|
103
108
|
},
|
|
104
109
|
},
|
|
105
110
|
]);
|
|
106
111
|
|
|
107
112
|
const toggleAccountMenuVisible = () => {
|
|
108
|
-
if (menu.value && menu.value.length
|
|
113
|
+
if (menu.value && menu.value.length) {
|
|
109
114
|
accountMenuVisible.value = !accountMenuVisible.value;
|
|
110
115
|
}
|
|
111
116
|
};
|
|
@@ -125,11 +130,7 @@ const imageHandler = computed(() => {
|
|
|
125
130
|
<style lang="scss">
|
|
126
131
|
.user-dropdown-button {
|
|
127
132
|
@apply tw-w-[240px] tw-border-l tw-border-solid tw-border-l-[color:var(--app-bar-divider-color)] tw-px-4 tw-cursor-pointer
|
|
128
|
-
tw-relative tw-flex tw-
|
|
129
|
-
|
|
130
|
-
&_no-pointer {
|
|
131
|
-
@apply tw-cursor-default;
|
|
132
|
-
}
|
|
133
|
+
tw-relative tw-flex tw-h-full tw-flex-col tw-select-none;
|
|
133
134
|
|
|
134
135
|
&:hover,
|
|
135
136
|
&_active {
|
|
@@ -168,5 +169,19 @@ const imageHandler = computed(() => {
|
|
|
168
169
|
@apply tw-p-3 tw-text-lg tw-text-black tw-border-l tw-border-solid tw-border-l-[#eef0f2] tw-border-b tw-border-b-[#eef0f2] tw-bg-white hover:tw-bg-[#eff7fc];
|
|
169
170
|
}
|
|
170
171
|
}
|
|
172
|
+
|
|
173
|
+
.vc-app_mobile & {
|
|
174
|
+
&__wrap {
|
|
175
|
+
height: var(--app-bar-height);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
&__menu {
|
|
179
|
+
@apply tw-static tw-shadow-none #{!important};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&__menu-item {
|
|
183
|
+
@apply tw-border-none #{!important};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
171
186
|
}
|
|
172
187
|
</style>
|
|
@@ -79,7 +79,7 @@ export interface DetailsBaseBladeScope extends BaseBladeScope {
|
|
|
79
79
|
currentLocale: Ref<string>;
|
|
80
80
|
languages: Ref<string[]>;
|
|
81
81
|
setLocale: (locale: string) => void;
|
|
82
|
-
localesOptions: Ref<{ label: string; value: string }[]>;
|
|
82
|
+
localesOptions: Ref<{ label: string | undefined; value: string }[]>;
|
|
83
83
|
getLanguages: AsyncAction<void, void>;
|
|
84
84
|
};
|
|
85
85
|
dynamicProperties?: {
|
|
@@ -7,6 +7,7 @@ import { setModel } from "./setters";
|
|
|
7
7
|
import { unwrapInterpolation } from "./unwrapInterpolation";
|
|
8
8
|
import { DetailsBladeContext } from "../factories";
|
|
9
9
|
import { safeIn } from "./safeIn";
|
|
10
|
+
import { i18n } from "./../../../../core/plugins/i18n";
|
|
10
11
|
|
|
11
12
|
function disabledHandler(
|
|
12
13
|
disabled: { method?: string } | boolean,
|
|
@@ -41,6 +42,8 @@ function nodeBuilder<
|
|
|
41
42
|
}): VNode {
|
|
42
43
|
if (!controlSchema) throw new Error("There is no controlSchema provided");
|
|
43
44
|
|
|
45
|
+
const { t } = i18n.global;
|
|
46
|
+
|
|
44
47
|
const name = controlSchema.id;
|
|
45
48
|
const rules = (safeIn("rules", controlSchema) && controlSchema.rules) || undefined;
|
|
46
49
|
const placeholder = (safeIn("placeholder", controlSchema) && controlSchema.placeholder) || undefined;
|
|
@@ -99,15 +102,15 @@ function nodeBuilder<
|
|
|
99
102
|
|
|
100
103
|
const baseProps: IControlBaseProps = reactive({
|
|
101
104
|
key: `${parentId}`,
|
|
102
|
-
label,
|
|
105
|
+
label: unref(computed(() => (label ? t(label) : undefined))),
|
|
103
106
|
disabled,
|
|
104
107
|
name,
|
|
105
108
|
rules,
|
|
106
|
-
placeholder,
|
|
109
|
+
placeholder: unref(computed(() => (placeholder ? t(placeholder) : undefined))),
|
|
107
110
|
required,
|
|
108
111
|
modelValue,
|
|
109
112
|
"onUpdate:modelValue": onUpdateModelValue,
|
|
110
|
-
tooltip,
|
|
113
|
+
tooltip: unref(computed(() => (tooltip ? t(tooltip) : undefined))),
|
|
111
114
|
multilanguage,
|
|
112
115
|
});
|
|
113
116
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _ from "lodash-es";
|
|
2
|
-
import { DynamicSchema, OverridesSchema } from "../types";
|
|
2
|
+
import { DynamicSchema, OverridesRemove, OverridesSchema } from "../types";
|
|
3
3
|
import "core-js/actual/array/to-spliced";
|
|
4
4
|
|
|
5
5
|
export const handleOverrides = (overrides: OverridesSchema, schemaCopy: { [key: string]: DynamicSchema }) => {
|
|
@@ -43,22 +43,40 @@ const upsertHelper = (overrides: OverridesSchema, schemaCopy: { [key: string]: D
|
|
|
43
43
|
);
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
const removeHelper = (overrides: OverridesSchema, schemaCopy:
|
|
46
|
+
const removeHelper = (overrides: OverridesSchema, schemaCopy: Record<string, DynamicSchema>) => {
|
|
47
47
|
return Object.entries(schemaCopy).reduce(
|
|
48
48
|
(obj, [name, schema]) => {
|
|
49
49
|
const clonedSchema = _.cloneDeep(schema);
|
|
50
|
-
overrides.remove
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
_.unset(clonedSchema, path);
|
|
56
|
-
_.update(clonedSchema, parentPath, _.compact);
|
|
57
|
-
}
|
|
58
|
-
}, {});
|
|
50
|
+
sortByMaxIndexPath(overrides.remove?.filter((x) => schema.settings.id === x.id)).forEach(({ path }) => {
|
|
51
|
+
if (path) {
|
|
52
|
+
removePath(clonedSchema, path);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
59
55
|
obj[name] = clonedSchema;
|
|
60
56
|
return obj;
|
|
61
57
|
},
|
|
62
58
|
{} as Record<string, DynamicSchema>,
|
|
63
59
|
);
|
|
64
60
|
};
|
|
61
|
+
|
|
62
|
+
function removePath(obj: DynamicSchema, path: string) {
|
|
63
|
+
const parentPath = path.slice(0, path.lastIndexOf("["));
|
|
64
|
+
_.unset(obj, path);
|
|
65
|
+
_.update(obj, parentPath, _.compact);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// this part sorts paths with indexes in descending order to avoid deleting items with already changed indexes
|
|
69
|
+
function sortByMaxIndexPath(items: { path: string }[] | undefined) {
|
|
70
|
+
return (items || []).sort((a, b) => getMaxIndexFromPath(b.path) - getMaxIndexFromPath(a.path));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getMaxIndexFromPath(path: string): number {
|
|
74
|
+
const matches = path.match(/\[(\d+)\]/g);
|
|
75
|
+
|
|
76
|
+
if (matches) {
|
|
77
|
+
const indexes = matches.map((match) => parseInt(match.slice(1, -1), 10));
|
|
78
|
+
return Math.max(...indexes);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return Infinity;
|
|
82
|
+
}
|
|
@@ -72,6 +72,7 @@ const register = (
|
|
|
72
72
|
name: bladeName,
|
|
73
73
|
isWorkspace: "isWorkspace" in json.settings && json.settings.isWorkspace,
|
|
74
74
|
menuItem: ("menuItem" in json.settings && json.settings.menuItem) ?? undefined,
|
|
75
|
+
routable: json.settings.routable ?? true,
|
|
75
76
|
setup: (props: ComponentProps<typeof bladeComponent>, ctx) =>
|
|
76
77
|
(bladeComponent?.setup &&
|
|
77
78
|
bladeComponent.setup(
|
|
@@ -50,7 +50,9 @@
|
|
|
50
50
|
>
|
|
51
51
|
<component
|
|
52
52
|
:is="item"
|
|
53
|
+
:ref="(el: HTMLElement) => widgetsRefs.set({ component: item, el })"
|
|
53
54
|
v-model="bladeContext"
|
|
55
|
+
@click="setActiveWidget(item)"
|
|
54
56
|
></component>
|
|
55
57
|
</div>
|
|
56
58
|
</div>
|
|
@@ -75,9 +77,10 @@ import {
|
|
|
75
77
|
onBeforeMount,
|
|
76
78
|
ComputedRef,
|
|
77
79
|
type Component,
|
|
80
|
+
ConcreteComponent,
|
|
78
81
|
} from "vue";
|
|
79
82
|
import { DynamicDetailsSchema, FormContentSchema, SettingsSchema } from "../types";
|
|
80
|
-
import { reactiveComputed, useMounted } from "@vueuse/core";
|
|
83
|
+
import { reactiveComputed, useMounted, useTemplateRefsList } from "@vueuse/core";
|
|
81
84
|
import {
|
|
82
85
|
DetailsBladeContext,
|
|
83
86
|
DetailsBaseBladeScope,
|
|
@@ -85,11 +88,11 @@ import {
|
|
|
85
88
|
UseDetails,
|
|
86
89
|
usePopup,
|
|
87
90
|
useBladeNavigation,
|
|
91
|
+
CoreBladeExposed,
|
|
88
92
|
} from "../../../index";
|
|
89
93
|
import SchemaRender from "../components/SchemaRender";
|
|
90
94
|
import { VcSelect } from "../../../../ui/components";
|
|
91
95
|
import { toolbarReducer } from "../helpers/toolbarReducer";
|
|
92
|
-
import { onBeforeRouteLeave } from "vue-router";
|
|
93
96
|
import { useBeforeUnload } from "../../../../core/composables/useBeforeUnload";
|
|
94
97
|
import * as _ from "lodash-es";
|
|
95
98
|
import { IBladeToolbar } from "../../../../core/types";
|
|
@@ -123,7 +126,9 @@ const { t } = useI18n({ useScope: "global" });
|
|
|
123
126
|
|
|
124
127
|
const { showConfirmation } = usePopup();
|
|
125
128
|
|
|
126
|
-
const {
|
|
129
|
+
const { onBeforeClose } = useBladeNavigation();
|
|
130
|
+
|
|
131
|
+
const widgetsRefs = useTemplateRefsList<{ el: HTMLDivElement; component: ConcreteComponent }>();
|
|
127
132
|
|
|
128
133
|
const { loading, item, validationState, scope, load, remove, saveChanges, bladeTitle } = props.composables
|
|
129
134
|
? (props.composables?.[props.model?.settings?.composable ?? ""]({ emit, props, mounted: useMounted() }) as UseDetails<
|
|
@@ -143,6 +148,7 @@ const { loading, item, validationState, scope, load, remove, saveChanges, bladeT
|
|
|
143
148
|
|
|
144
149
|
const title = ref();
|
|
145
150
|
const isReady = ref(false);
|
|
151
|
+
const activeWidgetExposed = ref<CoreBladeExposed>();
|
|
146
152
|
|
|
147
153
|
watch(
|
|
148
154
|
() => bladeTitle?.value,
|
|
@@ -245,6 +251,11 @@ const toolbarComputed =
|
|
|
245
251
|
emit("parent:call", {
|
|
246
252
|
method: "reload",
|
|
247
253
|
});
|
|
254
|
+
|
|
255
|
+
emit("parent:call", {
|
|
256
|
+
method: "updateActiveWidgetCount",
|
|
257
|
+
});
|
|
258
|
+
|
|
248
259
|
if (!props.param) {
|
|
249
260
|
emit("close:blade");
|
|
250
261
|
}
|
|
@@ -264,6 +275,10 @@ const toolbarComputed =
|
|
|
264
275
|
emit("parent:call", {
|
|
265
276
|
method: "reload",
|
|
266
277
|
});
|
|
278
|
+
emit("parent:call", {
|
|
279
|
+
method: "updateActiveWidgetCount",
|
|
280
|
+
});
|
|
281
|
+
|
|
267
282
|
emit("close:blade");
|
|
268
283
|
}
|
|
269
284
|
}
|
|
@@ -275,24 +290,24 @@ const toolbarComputed =
|
|
|
275
290
|
context: bladeContext.value,
|
|
276
291
|
});
|
|
277
292
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
293
|
+
async function setActiveWidget(widget: string | ConcreteComponent) {
|
|
294
|
+
const component = typeof widget === "string" ? resolveComponent(widget) : widget;
|
|
295
|
+
|
|
296
|
+
if (typeof component !== "string") {
|
|
297
|
+
await nextTick(
|
|
298
|
+
() => (activeWidgetExposed.value = widgetsRefs.value.find((x) => _.isEqual(x.component, component))?.el),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
281
302
|
|
|
282
|
-
|
|
303
|
+
async function updateActiveWidgetCount() {
|
|
283
304
|
if (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
: true) &&
|
|
287
|
-
unref(validated)
|
|
305
|
+
activeWidgetExposed.value?.updateActiveWidgetCount &&
|
|
306
|
+
typeof activeWidgetExposed.value?.updateActiveWidgetCount === "function"
|
|
288
307
|
) {
|
|
289
|
-
|
|
290
|
-
unref(
|
|
291
|
-
computed(() => t(`${settings.value?.localizationPrefix.trim().toUpperCase()}.PAGES.ALERTS.CLOSE_CONFIRMATION`)),
|
|
292
|
-
),
|
|
293
|
-
);
|
|
308
|
+
await activeWidgetExposed.value.updateActiveWidgetCount();
|
|
294
309
|
}
|
|
295
|
-
}
|
|
310
|
+
}
|
|
296
311
|
|
|
297
312
|
async function init() {
|
|
298
313
|
if (props.param) {
|
|
@@ -304,8 +319,23 @@ async function init() {
|
|
|
304
319
|
});
|
|
305
320
|
}
|
|
306
321
|
|
|
322
|
+
onBeforeMount(async () => {
|
|
323
|
+
if (props.composables) await init();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
onBeforeClose(async () => {
|
|
327
|
+
if (unref(validated)) {
|
|
328
|
+
return await showConfirmation(
|
|
329
|
+
unref(
|
|
330
|
+
computed(() => t(`${settings.value?.localizationPrefix.trim().toUpperCase()}.PAGES.ALERTS.CLOSE_CONFIRMATION`)),
|
|
331
|
+
),
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
|
|
307
336
|
defineExpose({
|
|
308
337
|
title: bladeTitle ?? "",
|
|
338
|
+
updateActiveWidgetCount,
|
|
309
339
|
...scope?.value,
|
|
310
340
|
});
|
|
311
341
|
</script>
|
|
@@ -345,7 +345,7 @@ const toolbarComputed =
|
|
|
345
345
|
},
|
|
346
346
|
removeItems: {
|
|
347
347
|
async clickHandler() {
|
|
348
|
-
removeItems();
|
|
348
|
+
await removeItems();
|
|
349
349
|
},
|
|
350
350
|
disabled: computed(() => !selectedIds.value?.length),
|
|
351
351
|
isVisible: isDesktop.value,
|
|
@@ -472,6 +472,9 @@ async function removeItems() {
|
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
|
+
emit("parent:call", {
|
|
476
|
+
method: "updateActiveWidgetCount",
|
|
477
|
+
});
|
|
475
478
|
await reload();
|
|
476
479
|
}
|
|
477
480
|
}
|
|
@@ -590,9 +593,16 @@ function sortRows(event: { dragIndex: number; dropIndex: number; value: any[] })
|
|
|
590
593
|
}
|
|
591
594
|
}
|
|
592
595
|
|
|
596
|
+
function updateActiveWidgetCount() {
|
|
597
|
+
emit("parent:call", {
|
|
598
|
+
method: "updateActiveWidgetCount",
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
593
602
|
defineExpose({
|
|
594
603
|
reload,
|
|
595
604
|
title,
|
|
605
|
+
updateActiveWidgetCount,
|
|
596
606
|
...scope?.value,
|
|
597
607
|
});
|
|
598
608
|
</script>
|
|
@@ -42,6 +42,10 @@ export type SettingsSchema = SettingsGrid | SettingsDetails;
|
|
|
42
42
|
|
|
43
43
|
export interface SettingsGrid extends SettingsBase {
|
|
44
44
|
component: "DynamicBladeList";
|
|
45
|
+
/**
|
|
46
|
+
* Blade default header title
|
|
47
|
+
*/
|
|
48
|
+
titleTemplate: string;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export interface SettingsDetails extends SettingsBase {
|
|
@@ -58,6 +62,15 @@ export interface SettingsBase {
|
|
|
58
62
|
* Blade url
|
|
59
63
|
*/
|
|
60
64
|
url?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Determines whether you can navigate to the blade directly
|
|
67
|
+
* without parameters or options.
|
|
68
|
+
*
|
|
69
|
+
* @example Blade is not workspace and use context (passed `options` or `params` in openBlade method) to load data - then set `routable` to `false`
|
|
70
|
+
*
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
routable?: boolean;
|
|
61
74
|
/**
|
|
62
75
|
* Locale key for VueI18n locale files
|
|
63
76
|
*/
|
|
@@ -66,10 +79,6 @@ export interface SettingsBase {
|
|
|
66
79
|
* Required component id
|
|
67
80
|
*/
|
|
68
81
|
id: string;
|
|
69
|
-
/**
|
|
70
|
-
* Blade default header title
|
|
71
|
-
*/
|
|
72
|
-
titleTemplate: string;
|
|
73
82
|
/**
|
|
74
83
|
* Composable to use at {@link SettingsBase.model } blade component view
|
|
75
84
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="tw-flex tw-flex-row tw-justify-between tw-items-center">
|
|
3
|
-
<div class="tw-flex-nowrap tw-font-bold tw-
|
|
2
|
+
<div class="tw-flex tw-flex-row tw-justify-between tw-items-center tw-relative">
|
|
3
|
+
<div class="tw-flex-nowrap tw-font-bold tw-truncate">
|
|
4
4
|
<span class="tw-truncate">
|
|
5
5
|
<slot></slot>
|
|
6
6
|
</span>
|
|
@@ -9,26 +9,25 @@
|
|
|
9
9
|
class="tw-text-[color:var(--label-required-color)] tw-ml-1"
|
|
10
10
|
>*</span
|
|
11
11
|
>
|
|
12
|
-
|
|
12
|
+
</div>
|
|
13
|
+
<span
|
|
14
|
+
v-if="$slots['tooltip']"
|
|
15
|
+
class="tw-grow tw-basis-0 tw-ml-1"
|
|
16
|
+
>
|
|
17
|
+
<VcIcon
|
|
18
|
+
class="tw-text-[color:var(--label-tooltip-color)]"
|
|
19
|
+
:icon="tooltipIcon"
|
|
20
|
+
size="s"
|
|
21
|
+
@mouseenter="tooltipVisible = true"
|
|
22
|
+
@mouseleave="tooltipVisible = false"
|
|
23
|
+
></VcIcon>
|
|
13
24
|
<span
|
|
14
|
-
v-if="
|
|
15
|
-
class="tw-
|
|
25
|
+
v-if="tooltipVisible"
|
|
26
|
+
class="tw-absolute tw-z-10 tw-bg-white tw-border tw-border-solid tw-border-[color:#eef0f2] tw-shadow-[1px_1px_8px_rgba(126,142,157,0.25)] tw-rounded-[3px] tw-text-[color:#8e9daa] tw-font-normal tw-py-1 tw-px-2 tw-ml-4"
|
|
16
27
|
>
|
|
17
|
-
<
|
|
18
|
-
class="tw-text-[color:var(--label-tooltip-color)]"
|
|
19
|
-
:icon="tooltipIcon"
|
|
20
|
-
size="s"
|
|
21
|
-
@mouseenter="tooltipVisible = true"
|
|
22
|
-
@mouseleave="tooltipVisible = false"
|
|
23
|
-
></VcIcon>
|
|
24
|
-
<span
|
|
25
|
-
v-if="tooltipVisible"
|
|
26
|
-
class="tw-absolute tw-z-10 tw-bg-white tw-border tw-border-solid tw-border-[color:#eef0f2] tw-shadow-[1px_1px_8px_rgba(126,142,157,0.25)] tw-rounded-[3px] tw-text-[color:#8e9daa] tw-font-normal tw-py-1 tw-px-2 tw-ml-4"
|
|
27
|
-
>
|
|
28
|
-
<slot name="tooltip"></slot>
|
|
29
|
-
</span>
|
|
28
|
+
<slot name="tooltip"></slot>
|
|
30
29
|
</span>
|
|
31
|
-
</
|
|
30
|
+
</span>
|
|
32
31
|
<div
|
|
33
32
|
v-if="multilanguage"
|
|
34
33
|
class="tw-text-[color:var(--app-menu-item-icon-color)] tw-shrink-0"
|