@vc-shell/framework 1.0.293 → 1.0.294
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 +17 -0
- package/core/composables/useLanguages/index.ts +30 -0
- package/core/composables/useMenuService/index.ts +1 -1
- package/core/composables/useSettings/index.ts +2 -3
- package/core/composables/useTheme/index.ts +2 -1
- package/core/composables/useUser/index.ts +4 -76
- package/core/constants/index.ts +1 -0
- package/core/constants/locale.ts +78 -0
- package/core/interceptors/index.ts +3 -0
- package/core/plugins/modularity/index.ts +106 -16
- package/dist/core/composables/useLanguages/index.d.ts +5 -0
- package/dist/core/composables/useLanguages/index.d.ts.map +1 -1
- package/dist/core/composables/useSettings/index.d.ts.map +1 -1
- package/dist/core/composables/useTheme/index.d.ts.map +1 -1
- package/dist/core/composables/useUser/index.d.ts +1 -3
- package/dist/core/composables/useUser/index.d.ts.map +1 -1
- package/dist/core/constants/index.d.ts +2 -0
- package/dist/core/constants/index.d.ts.map +1 -0
- package/dist/core/constants/locale.d.ts +7 -0
- package/dist/core/constants/locale.d.ts.map +1 -0
- package/dist/core/interceptors/index.d.ts.map +1 -1
- package/dist/core/plugins/modularity/index.d.ts.map +1 -1
- package/dist/framework.js +21278 -20967
- package/dist/index.css +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/locales/en.json +2 -1
- package/dist/shared/components/app-switcher/components/vc-app-switcher/vc-app-switcher.vue.d.ts.map +1 -1
- package/dist/shared/components/index.d.ts +1 -0
- package/dist/shared/components/index.d.ts.map +1 -1
- package/dist/shared/components/language-selector/language-selector.vue.d.ts.map +1 -1
- package/dist/shared/components/sidebar/sidebar.vue.d.ts +1 -1
- package/dist/shared/components/sidebar/sidebar.vue.d.ts.map +1 -1
- package/dist/shared/components/sign-in/azuread.vue.d.ts +17 -0
- package/dist/shared/components/sign-in/azuread.vue.d.ts.map +1 -0
- package/dist/shared/components/sign-in/external-provider.vue.d.ts +23 -0
- package/dist/shared/components/sign-in/external-provider.vue.d.ts.map +1 -0
- package/dist/shared/components/sign-in/external-providers.vue.d.ts +16 -0
- package/dist/shared/components/sign-in/external-providers.vue.d.ts.map +1 -0
- package/dist/shared/components/sign-in/index.d.ts +2 -0
- package/dist/shared/components/sign-in/index.d.ts.map +1 -0
- package/dist/shared/components/sign-in/useExternalProvider.d.ts +12 -0
- package/dist/shared/components/sign-in/useExternalProvider.d.ts.map +1 -0
- package/dist/shared/components/theme-selector/theme-selector.vue.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/index.d.ts +13 -10
- package/dist/shared/modules/dynamic/index.d.ts.map +1 -1
- package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts +1 -0
- package/dist/shared/modules/dynamic/pages/dynamic-blade-form.vue.d.ts.map +1 -1
- package/dist/shared/pages/LoginPage/components/login/Login.vue.d.ts.map +1 -1
- package/dist/tailwind.config.d.ts +1 -1
- package/dist/tailwind.config.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/vc-image/index.d.ts +1 -68
- package/dist/ui/components/atoms/vc-image/index.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-image/vc-image.stories.d.ts +3 -3
- package/dist/ui/components/atoms/vc-image/vc-image.vue.d.ts +2 -2
- package/dist/ui/components/atoms/vc-image/vc-image.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue.d.ts +2 -2
- package/dist/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue.d.ts +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/vc-table.stories.d.ts +30 -30
- package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts +9 -6
- package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
- package/package.json +5 -5
- package/shared/components/app-switcher/components/vc-app-switcher/vc-app-switcher.vue +1 -2
- package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +1 -1
- package/shared/components/index.ts +1 -0
- package/shared/components/language-selector/language-selector.vue +59 -6
- package/shared/components/sidebar/sidebar.vue +1 -1
- package/shared/components/sign-in/azuread.vue +24 -0
- package/shared/components/sign-in/external-provider.vue +38 -0
- package/shared/components/sign-in/external-providers.vue +39 -0
- package/shared/components/sign-in/index.ts +1 -0
- package/shared/components/sign-in/useExternalProvider.ts +102 -0
- package/shared/components/theme-selector/theme-selector.vue +7 -8
- package/shared/modules/dynamic/helpers/nodeBuilder.ts +2 -2
- package/shared/modules/dynamic/helpers/override.ts +1 -1
- package/shared/modules/dynamic/index.ts +166 -63
- package/shared/modules/dynamic/pages/dynamic-blade-form.vue +99 -20
- package/shared/modules/dynamic/pages/dynamic-blade-list.vue +1 -1
- package/shared/pages/LoginPage/components/login/Login.vue +8 -40
- package/tailwind.config.ts +6 -198
- package/ui/components/atoms/vc-image/index.ts +1 -3
- package/ui/components/atoms/vc-image/vc-image.vue +3 -2
- package/ui/components/atoms/vc-tooltip/vc-tooltip.vue +1 -1
- package/ui/components/molecules/vc-field/_internal/vc-field-type/vc-field-type.vue +1 -1
- package/ui/components/molecules/vc-input/vc-input.vue +38 -0
- package/ui/components/molecules/vc-input-currency/vc-input-currency.vue +1 -1
- package/ui/components/molecules/vc-select/vc-select.vue +15 -5
- package/ui/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +2 -24
- package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +12 -3
- package/ui/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue +1 -1
- package/ui/components/organisms/vc-table/vc-table.vue +124 -65
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import * as pages from "./pages";
|
|
3
|
-
import { App, Component, defineComponent } from "vue";
|
|
3
|
+
import { App, Component, SetupContext, defineComponent } from "vue";
|
|
4
4
|
import { DynamicSchema, OverridesSchema } from "./types";
|
|
5
5
|
import * as _ from "lodash-es";
|
|
6
6
|
import { handleOverrides } from "./helpers/override";
|
|
@@ -15,12 +15,17 @@ interface Registered {
|
|
|
15
15
|
component: BladeInstanceConstructor;
|
|
16
16
|
name: string;
|
|
17
17
|
model: DynamicSchema;
|
|
18
|
+
composables: { [key: string]: (...args: any[]) => any };
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
const registeredModules: { [key: string]: Registered } = {};
|
|
22
|
+
const installedBladeIds = new Set<string>();
|
|
23
|
+
const registeredSchemas: { [key: string]: DynamicSchema } = {};
|
|
24
|
+
|
|
20
25
|
const createAppModuleWrapper = (args: {
|
|
21
26
|
bladeName: string;
|
|
22
27
|
bladeComponent: BladeInstanceConstructor;
|
|
23
|
-
appModuleContent
|
|
28
|
+
appModuleContent?:
|
|
24
29
|
| {
|
|
25
30
|
locales?: { [key: string]: object };
|
|
26
31
|
notificationTemplates?: { [key: string]: Component };
|
|
@@ -37,31 +42,19 @@ const createAppModuleWrapper = (args: {
|
|
|
37
42
|
);
|
|
38
43
|
};
|
|
39
44
|
|
|
40
|
-
const
|
|
45
|
+
const createBladeInstanceConstructor = (
|
|
46
|
+
bladeComponent: any,
|
|
47
|
+
bladeName: string,
|
|
48
|
+
json: DynamicSchema,
|
|
41
49
|
args: {
|
|
42
|
-
app: App;
|
|
43
|
-
component: BladeInstanceConstructor;
|
|
44
|
-
composables: { [key: string]: (...args: any[]) => any };
|
|
45
|
-
json: DynamicSchema;
|
|
46
|
-
options?: { router: any };
|
|
47
50
|
moduleUid: string;
|
|
51
|
+
composables?: { [key: string]: (...args: any[]) => any };
|
|
52
|
+
mixin?: ((...args: any[]) => any)[];
|
|
48
53
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
locales?: { [key: string]: object };
|
|
52
|
-
notificationTemplates?: { [key: string]: Component };
|
|
53
|
-
moduleComponents?: { [key: string]: Component };
|
|
54
|
-
}
|
|
55
|
-
| undefined,
|
|
56
|
-
): Registered => {
|
|
57
|
-
const { app, component, json, options } = args;
|
|
58
|
-
const bladeComponent = _.cloneDeep(component);
|
|
59
|
-
let rawUrl: `/${string}`;
|
|
60
|
-
|
|
61
|
-
const bladeName = kebabToPascal(json.settings.id);
|
|
62
|
-
|
|
54
|
+
existingComposables?: { [key: string]: (...args: any[]) => any },
|
|
55
|
+
) => {
|
|
63
56
|
if (json.settings.url) {
|
|
64
|
-
rawUrl = json.settings.url as `/${string}`;
|
|
57
|
+
const rawUrl = json.settings.url as `/${string}`;
|
|
65
58
|
bladeComponent.url = rawUrl;
|
|
66
59
|
}
|
|
67
60
|
|
|
@@ -69,76 +62,180 @@ const register = (
|
|
|
69
62
|
bladeComponent.permissions = json.settings.permissions;
|
|
70
63
|
}
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
return defineComponent({
|
|
73
66
|
...bladeComponent,
|
|
74
67
|
name: bladeName,
|
|
75
68
|
isWorkspace: "isWorkspace" in json.settings && json.settings.isWorkspace,
|
|
76
69
|
menuItem: ("menuItem" in json.settings && json.settings.menuItem) ?? undefined,
|
|
77
70
|
moduleUid: args.moduleUid,
|
|
78
71
|
routable: json.settings.routable ?? true,
|
|
79
|
-
composables: args.composables,
|
|
80
|
-
setup: (props: ComponentProps<typeof bladeComponent>, ctx) =>
|
|
72
|
+
composables: existingComposables ? { ...existingComposables, ...args.composables } : args.composables,
|
|
73
|
+
setup: (props: ComponentProps<typeof bladeComponent>, ctx: SetupContext) =>
|
|
81
74
|
(bladeComponent?.setup &&
|
|
82
75
|
bladeComponent.setup(
|
|
83
76
|
reactiveComputed(() =>
|
|
84
77
|
Object.assign({}, props, {
|
|
85
78
|
model: json,
|
|
86
|
-
composables: args.composables,
|
|
79
|
+
composables: existingComposables ? { ...existingComposables, ...args.composables } : args.composables,
|
|
80
|
+
mixinFn: args.mixin?.length ? args.mixin : undefined,
|
|
87
81
|
} as any),
|
|
88
82
|
),
|
|
89
83
|
ctx,
|
|
90
84
|
)) ??
|
|
91
85
|
{},
|
|
92
86
|
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const register = (
|
|
90
|
+
args: {
|
|
91
|
+
app: App;
|
|
92
|
+
component: BladeInstanceConstructor;
|
|
93
|
+
composables: { [key: string]: (...args: any[]) => any };
|
|
94
|
+
mixin?: ((...args: any[]) => any)[];
|
|
95
|
+
json: DynamicSchema;
|
|
96
|
+
options?: { router: Router };
|
|
97
|
+
moduleUid: string;
|
|
98
|
+
},
|
|
99
|
+
appModuleContent?:
|
|
100
|
+
| {
|
|
101
|
+
locales?: { [key: string]: object };
|
|
102
|
+
notificationTemplates?: { [key: string]: Component };
|
|
103
|
+
moduleComponents?: { [key: string]: Component };
|
|
104
|
+
}
|
|
105
|
+
| undefined,
|
|
106
|
+
): Registered => {
|
|
107
|
+
const { app, component, json, options } = args;
|
|
108
|
+
const bladeId = json.settings.id;
|
|
109
|
+
const bladeName = kebabToPascal(bladeId);
|
|
110
|
+
|
|
111
|
+
if (registeredModules[bladeName]) {
|
|
112
|
+
// Module already registered, updating it
|
|
113
|
+
updateBlade(bladeName, json, args, appModuleContent);
|
|
114
|
+
return registeredModules[bladeName];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const bladeComponent = _.cloneDeep(component);
|
|
118
|
+
const BladeInstanceConstructor = createBladeInstanceConstructor(bladeComponent, bladeName, json, args);
|
|
93
119
|
|
|
94
120
|
const module = createAppModuleWrapper({
|
|
95
121
|
bladeName,
|
|
96
|
-
bladeComponent: BladeInstanceConstructor,
|
|
122
|
+
bladeComponent: BladeInstanceConstructor as BladeInstanceConstructor,
|
|
97
123
|
appModuleContent,
|
|
98
124
|
});
|
|
99
125
|
|
|
100
126
|
module.install(app, options);
|
|
101
127
|
|
|
102
|
-
|
|
103
|
-
component: BladeInstanceConstructor,
|
|
128
|
+
const newModule: Registered = {
|
|
129
|
+
component: BladeInstanceConstructor as BladeInstanceConstructor,
|
|
104
130
|
name: bladeName,
|
|
105
131
|
model: json,
|
|
132
|
+
composables: args.composables,
|
|
106
133
|
};
|
|
134
|
+
|
|
135
|
+
registeredModules[bladeName] = newModule;
|
|
136
|
+
|
|
137
|
+
return newModule;
|
|
107
138
|
};
|
|
108
139
|
|
|
109
|
-
const handleError = (errorKey: string,
|
|
140
|
+
const handleError = (errorKey: string, schemas: { [key: string]: DynamicSchema }, text?: string) => {
|
|
110
141
|
return console.error(
|
|
111
|
-
`Module initialization aborted. '${errorKey}'
|
|
142
|
+
`Module initialization aborted. Key '${errorKey}' not found in schemas: ${Object.keys(schemas).join(
|
|
112
143
|
", ",
|
|
113
|
-
)}. '${errorKey}'
|
|
144
|
+
)}. Key '${errorKey}' ${text}`,
|
|
114
145
|
);
|
|
115
146
|
};
|
|
116
147
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
148
|
+
const updateBlade = (
|
|
149
|
+
moduleName: string,
|
|
150
|
+
newSchema: DynamicSchema,
|
|
151
|
+
args: {
|
|
152
|
+
app: App;
|
|
153
|
+
component: BladeInstanceConstructor;
|
|
154
|
+
composables?: { [key: string]: (...args: any[]) => any };
|
|
155
|
+
mixin?: ((...args: any[]) => any)[];
|
|
156
|
+
json: DynamicSchema;
|
|
157
|
+
options?: { router: Router };
|
|
158
|
+
moduleUid: string;
|
|
159
|
+
},
|
|
160
|
+
appModuleContent?:
|
|
161
|
+
| {
|
|
162
|
+
locales?: { [key: string]: object };
|
|
163
|
+
notificationTemplates?: { [key: string]: Component };
|
|
164
|
+
moduleComponents?: { [key: string]: Component };
|
|
165
|
+
}
|
|
166
|
+
| undefined,
|
|
167
|
+
) => {
|
|
168
|
+
const existingModule = registeredModules[moduleName];
|
|
169
|
+
|
|
170
|
+
if (existingModule) {
|
|
171
|
+
// Updating blade model
|
|
172
|
+
existingModule.model = newSchema;
|
|
173
|
+
|
|
174
|
+
// Updating blade component
|
|
175
|
+
const bladeComponent = _.cloneDeep(args.component);
|
|
176
|
+
const BladeInstanceConstructor = createBladeInstanceConstructor(
|
|
177
|
+
bladeComponent,
|
|
178
|
+
moduleName,
|
|
179
|
+
newSchema,
|
|
180
|
+
args,
|
|
181
|
+
existingModule.composables,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// Reinstall the blade with the updated component
|
|
185
|
+
const module = createAppModuleWrapper({
|
|
186
|
+
bladeName: moduleName,
|
|
187
|
+
bladeComponent: BladeInstanceConstructor as BladeInstanceConstructor,
|
|
188
|
+
appModuleContent,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
module.install(args.app, args.options);
|
|
192
|
+
|
|
193
|
+
// Update registered blade with the new component
|
|
194
|
+
existingModule.component = BladeInstanceConstructor as BladeInstanceConstructor;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export function createDynamicAppModule(args: {
|
|
199
|
+
schema?: { [key: string]: DynamicSchema };
|
|
200
|
+
composables?: { [key: string]: (...args: any[]) => any };
|
|
201
|
+
mixin?: { [x: string]: ((...args: any[]) => any)[] };
|
|
120
202
|
overrides?: OverridesSchema;
|
|
121
203
|
moduleComponents?: { [key: string]: Component };
|
|
122
204
|
locales?: { [key: string]: object };
|
|
123
205
|
notificationTemplates?: { [key: string]: Component };
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
206
|
+
}): {
|
|
207
|
+
install(
|
|
208
|
+
app: App<any>,
|
|
209
|
+
options?:
|
|
210
|
+
| {
|
|
211
|
+
router: Router;
|
|
212
|
+
}
|
|
213
|
+
| undefined,
|
|
214
|
+
): void;
|
|
215
|
+
} {
|
|
216
|
+
let schemaCopy: { [key: string]: DynamicSchema } = {};
|
|
135
217
|
|
|
136
|
-
|
|
218
|
+
if (args.schema && Object.keys(args.schema).length > 0) {
|
|
219
|
+
schemaCopy = _.cloneDeep({ ...args.schema });
|
|
220
|
+
// Save schemas in the global registry
|
|
221
|
+
Object.assign(registeredSchemas, schemaCopy);
|
|
222
|
+
} else {
|
|
223
|
+
// Use registered schemas if new ones are not provided
|
|
224
|
+
schemaCopy = _.cloneDeep({ ...registeredSchemas });
|
|
225
|
+
}
|
|
137
226
|
|
|
138
227
|
if (args.overrides) {
|
|
139
228
|
schemaCopy = handleOverrides(args.overrides, schemaCopy);
|
|
140
229
|
}
|
|
141
230
|
|
|
231
|
+
// Validation
|
|
232
|
+
const moduleInitializer = _.findKey(schemaCopy, (o) => o.settings.isWorkspace);
|
|
233
|
+
const everyHasTemplate = _.every(Object.values(schemaCopy), (o) => o?.settings?.component);
|
|
234
|
+
|
|
235
|
+
if (!everyHasTemplate) handleError("component", schemaCopy, "must be included in 'settings' of each file");
|
|
236
|
+
if (!moduleInitializer)
|
|
237
|
+
handleError("isWorkspace", schemaCopy, "must be included in one of the files to initialize the module workspace");
|
|
238
|
+
|
|
142
239
|
return {
|
|
143
240
|
install(app: App, options: { router: Router }) {
|
|
144
241
|
const bladePages = { ...pages };
|
|
@@ -147,27 +244,33 @@ export const createDynamicAppModule = (args: {
|
|
|
147
244
|
notificationTemplates: args?.notificationTemplates,
|
|
148
245
|
moduleComponents: args?.moduleComponents,
|
|
149
246
|
};
|
|
247
|
+
|
|
150
248
|
const moduleUid = _.uniqueId("module_");
|
|
151
|
-
Object.entries(schemaCopy).forEach(([, JsonSchema], index) => {
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
249
|
+
Object.entries(schemaCopy).forEach(([key, JsonSchema], index) => {
|
|
250
|
+
const bladeId = JsonSchema.settings.id;
|
|
251
|
+
const registerArgs = {
|
|
252
|
+
app,
|
|
253
|
+
component: bladePages[JsonSchema.settings.component as keyof typeof bladePages] as BladeInstanceConstructor,
|
|
254
|
+
composables: { ...args.composables },
|
|
255
|
+
mixin: args.mixin?.[JsonSchema.settings.id] ? args.mixin[JsonSchema.settings.id] : undefined,
|
|
256
|
+
json: JsonSchema,
|
|
257
|
+
options,
|
|
258
|
+
moduleUid,
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
if (installedBladeIds.has(bladeId)) {
|
|
262
|
+
// Blade already installed, updating it
|
|
263
|
+
updateBlade(kebabToPascal(bladeId), JsonSchema, registerArgs, index === 0 ? appModuleContent : undefined);
|
|
165
264
|
return;
|
|
166
265
|
}
|
|
266
|
+
|
|
267
|
+
installedBladeIds.add(bladeId);
|
|
268
|
+
|
|
269
|
+
register(registerArgs, index === 0 ? appModuleContent : undefined);
|
|
167
270
|
});
|
|
168
271
|
},
|
|
169
272
|
};
|
|
170
|
-
}
|
|
273
|
+
}
|
|
171
274
|
|
|
172
275
|
export * from "./factories";
|
|
173
276
|
export * from "./types";
|
|
@@ -84,6 +84,7 @@ import {
|
|
|
84
84
|
toRefs,
|
|
85
85
|
provide,
|
|
86
86
|
toRef,
|
|
87
|
+
type VNode,
|
|
87
88
|
} from "vue";
|
|
88
89
|
import { DynamicDetailsSchema, FormContentSchema, SettingsSchema } from "../types";
|
|
89
90
|
import { reactiveComputed, refDefault, toReactive, useMounted, useTemplateRefsList } from "@vueuse/core";
|
|
@@ -98,12 +99,13 @@ import {
|
|
|
98
99
|
DetailsBladeExposed,
|
|
99
100
|
} from "../../../index";
|
|
100
101
|
import SchemaRender from "../components/SchemaRender";
|
|
101
|
-
import { VcSelect } from "../../../../ui/components";
|
|
102
|
+
import { VcSelect, VcImage } from "../../../../ui/components";
|
|
102
103
|
import { useToolbarReducer } from "../composables/useToolbarReducer";
|
|
103
104
|
import { useBeforeUnload } from "../../../../core/composables/useBeforeUnload";
|
|
104
105
|
import * as _ from "lodash-es";
|
|
105
|
-
import { useNotifications } from "../../../../core/composables";
|
|
106
|
+
import { useLanguages, useNotifications } from "../../../../core/composables";
|
|
106
107
|
import { notification } from "../../../components";
|
|
108
|
+
import { ComponentSlots } from "../../../utilities/vueUtils";
|
|
107
109
|
|
|
108
110
|
interface Props {
|
|
109
111
|
expanded?: boolean;
|
|
@@ -114,6 +116,7 @@ interface Props {
|
|
|
114
116
|
[x: string]: unknown;
|
|
115
117
|
};
|
|
116
118
|
composables?: Record<string, (...args: any[]) => Record<string, any>>;
|
|
119
|
+
mixinFn?: ((...args: any[]) => any)[];
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
interface Emits {
|
|
@@ -133,13 +136,18 @@ const emit = defineEmits<Emits>();
|
|
|
133
136
|
const { t } = useI18n({ useScope: "global" });
|
|
134
137
|
|
|
135
138
|
const { showConfirmation } = usePopup();
|
|
139
|
+
const { getFlag } = useLanguages();
|
|
136
140
|
|
|
137
141
|
const widgetsRefs = useTemplateRefsList<{ el: HTMLDivElement; component: ConcreteComponent }>();
|
|
142
|
+
const isMixinReady = ref(false);
|
|
138
143
|
|
|
139
144
|
if (typeof props.composables?.[props.model?.settings?.composable ?? ""] === "undefined") {
|
|
140
145
|
throw new Error(`Composable ( ${props.model?.settings?.composable} ) is not defined`);
|
|
141
146
|
}
|
|
142
|
-
|
|
147
|
+
|
|
148
|
+
const settings = computed(() => props.model?.settings);
|
|
149
|
+
|
|
150
|
+
let { loading, item, validationState, scope, load, remove, saveChanges, bladeTitle } = props.composables
|
|
143
151
|
? (props.composables?.[props.model?.settings?.composable ?? ""]({ emit, props, mounted: useMounted() }) as UseDetails<
|
|
144
152
|
Record<string, any>,
|
|
145
153
|
DetailsBaseBladeScope
|
|
@@ -155,12 +163,39 @@ const { loading, item, validationState, scope, load, remove, saveChanges, bladeT
|
|
|
155
163
|
bladeTitle: undefined,
|
|
156
164
|
} as unknown as UseDetails<Record<string, any>, DetailsBaseBladeScope>);
|
|
157
165
|
|
|
166
|
+
if (props.mixinFn?.length) {
|
|
167
|
+
const mixinResults = props.mixinFn?.map((mixin) =>
|
|
168
|
+
mixin({ loading, item, validationState, scope, load, remove, saveChanges, bladeTitle }),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const mergedResults = mixinResults.reduce((acc, result) => {
|
|
172
|
+
return {
|
|
173
|
+
...acc,
|
|
174
|
+
...result,
|
|
175
|
+
};
|
|
176
|
+
}, {});
|
|
177
|
+
|
|
178
|
+
loading = mergedResults.loading ?? loading;
|
|
179
|
+
item = mergedResults.item ?? item;
|
|
180
|
+
validationState = mergedResults.validationState ?? validationState;
|
|
181
|
+
scope = mergedResults.scope ?? scope;
|
|
182
|
+
load = mergedResults.load ?? load;
|
|
183
|
+
|
|
184
|
+
remove = mergedResults.remove ?? remove;
|
|
185
|
+
saveChanges = mergedResults.saveChanges ?? saveChanges;
|
|
186
|
+
bladeTitle = mergedResults.bladeTitle ?? bladeTitle;
|
|
187
|
+
|
|
188
|
+
isMixinReady.value = true;
|
|
189
|
+
} else {
|
|
190
|
+
isMixinReady.value = true;
|
|
191
|
+
}
|
|
192
|
+
|
|
158
193
|
const { onBeforeClose } = useBladeNavigation();
|
|
159
194
|
const title = ref();
|
|
160
195
|
const isReady = ref(false);
|
|
161
196
|
const activeWidgetExposed = ref<CoreBladeExposed>();
|
|
162
197
|
const isBladeEditable = computed(() => !toValue("disabled" in toValue(scope || {}) && toValue(scope || {}).disabled));
|
|
163
|
-
|
|
198
|
+
|
|
164
199
|
const unreffedScope = reactiveComputed(() => toValue(scope) ?? {});
|
|
165
200
|
|
|
166
201
|
const { moduleNotifications, markAsRead } = useNotifications(settings.value?.pushNotificationType);
|
|
@@ -223,6 +258,26 @@ const bladeStatus = computed(() => {
|
|
|
223
258
|
return null;
|
|
224
259
|
});
|
|
225
260
|
|
|
261
|
+
const localeOptions = ref();
|
|
262
|
+
|
|
263
|
+
watch(
|
|
264
|
+
() => toValue(unreffedScope).multilanguage?.localesOptions,
|
|
265
|
+
(newVal) => {
|
|
266
|
+
localeOptions.value = newVal;
|
|
267
|
+
},
|
|
268
|
+
{ immediate: true, deep: true },
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
watch(
|
|
272
|
+
() => localeOptions.value,
|
|
273
|
+
async (newVal) => {
|
|
274
|
+
for (const lang of newVal) {
|
|
275
|
+
lang.flag = await getFlag(lang.value);
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{ deep: true },
|
|
279
|
+
);
|
|
280
|
+
|
|
226
281
|
const bladeMultilanguage = reactiveComputed(() => {
|
|
227
282
|
if (
|
|
228
283
|
scope &&
|
|
@@ -232,19 +287,45 @@ const bladeMultilanguage = reactiveComputed(() => {
|
|
|
232
287
|
) {
|
|
233
288
|
return {
|
|
234
289
|
component: () => {
|
|
235
|
-
return h(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
290
|
+
return h(
|
|
291
|
+
VcSelect as Component,
|
|
292
|
+
{
|
|
293
|
+
name: "currentLocale",
|
|
294
|
+
modelValue: toValue(unreffedScope).multilanguage?.currentLocale,
|
|
295
|
+
options: localeOptions.value,
|
|
296
|
+
optionValue: "value",
|
|
297
|
+
optionLabel: "label",
|
|
298
|
+
disabled: "disabled" in toValue(unreffedScope) && toValue(unreffedScope).disabled,
|
|
299
|
+
required: true,
|
|
300
|
+
clearable: false,
|
|
301
|
+
"onUpdate:modelValue": (e: string) => {
|
|
302
|
+
toValue(unreffedScope).multilanguage?.setLocale(e);
|
|
303
|
+
},
|
|
246
304
|
},
|
|
247
|
-
|
|
305
|
+
["selected-item", "option"].reduce(
|
|
306
|
+
(obj, slot) => {
|
|
307
|
+
obj[slot] = (
|
|
308
|
+
scope: Parameters<ComponentSlots<typeof VcSelect>["option"]>["0"] & {
|
|
309
|
+
opt: { flag: string; label: string };
|
|
310
|
+
},
|
|
311
|
+
) => {
|
|
312
|
+
return h("div", { class: "tw-flex tw-items-center tw-gap-2" }, [
|
|
313
|
+
h(VcImage, { src: scope.opt.flag, class: "tw-w-6 tw-h-6", emptyIcon: "" }),
|
|
314
|
+
h("span", { class: "tw-text-sm" }, scope.opt.label),
|
|
315
|
+
]);
|
|
316
|
+
};
|
|
317
|
+
return obj;
|
|
318
|
+
},
|
|
319
|
+
{} as Record<
|
|
320
|
+
string,
|
|
321
|
+
(
|
|
322
|
+
scope: Parameters<ComponentSlots<typeof VcSelect>["option"]>["0"] & {
|
|
323
|
+
opt: { flag: string; label: string };
|
|
324
|
+
},
|
|
325
|
+
) => VNode
|
|
326
|
+
>,
|
|
327
|
+
),
|
|
328
|
+
);
|
|
248
329
|
},
|
|
249
330
|
currentLocale: toValue(unreffedScope).multilanguage?.currentLocale,
|
|
250
331
|
};
|
|
@@ -345,9 +426,7 @@ async function updateActiveWidgetCount() {
|
|
|
345
426
|
}
|
|
346
427
|
|
|
347
428
|
async function init() {
|
|
348
|
-
|
|
349
|
-
await load({ id: unref(props.param) });
|
|
350
|
-
}
|
|
429
|
+
await load({ id: unref(props.param) });
|
|
351
430
|
|
|
352
431
|
await nextTick(() => {
|
|
353
432
|
isReady.value = true;
|
|
@@ -355,7 +434,7 @@ async function init() {
|
|
|
355
434
|
}
|
|
356
435
|
|
|
357
436
|
onBeforeMount(async () => {
|
|
358
|
-
if (props.composables) await init();
|
|
437
|
+
if (props.composables && isMixinReady.value) await init();
|
|
359
438
|
});
|
|
360
439
|
|
|
361
440
|
onBeforeClose(async () => {
|
|
@@ -594,7 +594,7 @@ const onPaginationClick = async (page: number) => {
|
|
|
594
594
|
}
|
|
595
595
|
};
|
|
596
596
|
|
|
597
|
-
const onHeaderClick = (item: ITableColumns) => {
|
|
597
|
+
const onHeaderClick = (item: Partial<ITableColumns>) => {
|
|
598
598
|
const sortOptions = ["DESC", "ASC", ""];
|
|
599
599
|
|
|
600
600
|
if (item.sortable) {
|
|
@@ -78,22 +78,8 @@
|
|
|
78
78
|
<!-- TODO add to localization -->
|
|
79
79
|
OR
|
|
80
80
|
</div>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
v-for="external in loginProviders"
|
|
84
|
-
:key="external.authenticationType"
|
|
85
|
-
outline
|
|
86
|
-
@click="externalSignOn(external.authenticationType ?? '')"
|
|
87
|
-
>
|
|
88
|
-
<div class="vc-login-page__external-button-content">
|
|
89
|
-
<img
|
|
90
|
-
:src="externalAuthIcon(external.authenticationType ?? '')"
|
|
91
|
-
:alt="external.authenticationType"
|
|
92
|
-
class="vc-login-page__external-icon"
|
|
93
|
-
/>{{ external.displayName }}
|
|
94
|
-
</div>
|
|
95
|
-
</VcButton>
|
|
96
|
-
</div>
|
|
81
|
+
|
|
82
|
+
<ExternalProviders :providers="loginProviders" />
|
|
97
83
|
</div>
|
|
98
84
|
</template>
|
|
99
85
|
<template v-else>
|
|
@@ -181,9 +167,10 @@ import { useRouter } from "vue-router";
|
|
|
181
167
|
import { useIsFormValid, Field, useIsFormDirty, useForm } from "vee-validate";
|
|
182
168
|
import { useSettings, useUser } from "./../../../../../core/composables";
|
|
183
169
|
import { RequestPasswordResult } from "./../../../../../core/types";
|
|
184
|
-
import AzureAdIcon from "./../../../../../assets/img/AzureAd.svg";
|
|
185
170
|
import { ExternalSignInProviderInfo, SignInResult } from "./../../../../../core/api/platform";
|
|
186
171
|
import { useI18n } from "vue-i18n";
|
|
172
|
+
import { default as ExternalProviders } from "./../../../../../shared/components/sign-in/external-providers.vue";
|
|
173
|
+
import { useExternalProvider } from "./../../../../../shared/components/sign-in/useExternalProvider";
|
|
187
174
|
|
|
188
175
|
type ForgotPasswordFunc = (args: { loginOrEmail: string }) => Promise<void>;
|
|
189
176
|
|
|
@@ -205,7 +192,9 @@ let useLogin;
|
|
|
205
192
|
const signInResult = ref({ succeeded: true }) as Ref<SignInResult & { status?: number; error?: any }>;
|
|
206
193
|
const requestPassResult = ref<RequestPasswordResult>({ succeeded: true });
|
|
207
194
|
const forgotPasswordRequestSent = ref(false);
|
|
208
|
-
const { signIn, loading,
|
|
195
|
+
const { signIn, loading, user } = useUser();
|
|
196
|
+
const { getProviders } = useExternalProvider();
|
|
197
|
+
|
|
209
198
|
const isLogin = ref(true);
|
|
210
199
|
const isValid = useIsFormValid();
|
|
211
200
|
const isDirty = useIsFormDirty();
|
|
@@ -224,14 +213,9 @@ if (props.composable && typeof props.composable === "function") {
|
|
|
224
213
|
}
|
|
225
214
|
|
|
226
215
|
onMounted(async () => {
|
|
227
|
-
loginProviders.value = await
|
|
216
|
+
loginProviders.value = await getProviders();
|
|
228
217
|
});
|
|
229
218
|
|
|
230
|
-
const externalAuthIcon = (authenticationType: string) => {
|
|
231
|
-
if (authenticationType === "AzureAD") return AzureAdIcon;
|
|
232
|
-
else return;
|
|
233
|
-
};
|
|
234
|
-
|
|
235
219
|
const customization = computed(() => {
|
|
236
220
|
return {
|
|
237
221
|
logo: !customizationLoading.value ? uiSettings.value?.logo || props.logo : "",
|
|
@@ -305,10 +289,6 @@ const togglePassRequest = () => {
|
|
|
305
289
|
}
|
|
306
290
|
};
|
|
307
291
|
|
|
308
|
-
const externalSignOn = async (authenticationType: string) => {
|
|
309
|
-
await externalSignIn(authenticationType, window.location.pathname);
|
|
310
|
-
};
|
|
311
|
-
|
|
312
292
|
console.debug("Init login-page");
|
|
313
293
|
</script>
|
|
314
294
|
|
|
@@ -348,18 +328,6 @@ console.debug("Init login-page");
|
|
|
348
328
|
@apply tw-flex tw-items-center tw-text-center tw-uppercase tw-text-[color:var(--login-separator-text)] before:tw-content-[''] before:tw-flex-1 before:tw-border-b before:tw-border-b-[color:var(--login-separator)] before:tw-mr-2 after:tw-content-[''] after:tw-flex-1 after:tw-border-b after:tw-border-b-[color:var(--login-separator)] after:tw-ml-2;
|
|
349
329
|
}
|
|
350
330
|
|
|
351
|
-
&__external-buttons {
|
|
352
|
-
@apply tw-flex tw-justify-center tw-mt-4 tw-flex-wrap tw-gap-2;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
&__external-button-content {
|
|
356
|
-
@apply tw-flex tw-flex-row tw-items-center;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
&__external-icon {
|
|
360
|
-
@apply tw-h-5 tw-mr-2;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
331
|
&__error-hint {
|
|
364
332
|
@apply tw-mt-3 tw-text-[color:var(--login-error)];
|
|
365
333
|
}
|