@tager/admin-administrators 1.0.0 → 1.0.2

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.
@@ -1,44 +1,56 @@
1
1
  <template>
2
2
  <Page :title="pageTitle" :is-content-loading="isContentLoading">
3
3
  <form novalidate @submit.prevent>
4
+ <TabList v-model:tab-id="selectedTabId" :tab-list="tabList" />
5
+
6
+ <template v-if="selectedTabId === 'general'">
4
7
  <FormField
5
- v-model:value="values.name"
6
- name="name"
7
- :error="errors.name"
8
- :label="$i18n.t('administrators:name')"
8
+ v-model:value="values.name"
9
+ name="name"
10
+ :error="errors.name"
11
+ :label="$i18n.t('administrators:name')"
9
12
  />
10
13
  <FormField
11
- v-model:value="values.email"
12
- name="email"
13
- :error="errors.email"
14
- :label="$i18n.t('administrators:email')"
14
+ v-model:value="values.email"
15
+ name="email"
16
+ :error="errors.email"
17
+ :label="$i18n.t('administrators:email')"
15
18
  />
16
19
  <FormFieldMultiSelect
17
- v-model:selected-options="values.roles"
18
- name="roles"
19
- :label="$i18n.t('administrators:roles')"
20
- :options="roleOptionList"
21
- :error="errors.roles"
20
+ v-model:selected-options="values.roles"
21
+ name="roles"
22
+ :label="$i18n.t('administrators:roles')"
23
+ :options="roleOptionList"
24
+ :error="errors.roles"
22
25
  />
23
26
  <FormField
24
- v-model:value="values.password"
25
- name="password"
26
- :error="errors.password"
27
- :label="
27
+ v-model:value="values.password"
28
+ name="password"
29
+ :error="errors.password"
30
+ :label="
28
31
  isCreation
29
32
  ? $i18n.t('administrators:password')
30
33
  : $i18n.t('administrators:newPassword')
31
34
  "
32
35
  />
36
+ </template>
37
+
38
+ <template v-if="selectedTabId === 'params'">
39
+ <DynamicField
40
+ v-for="field of templateValues"
41
+ :key="field.config.name"
42
+ :field="field"
43
+ />
44
+ </template>
33
45
  </form>
34
46
 
35
47
  <template #footer>
36
48
  <FormFooter
37
- :back-href="backButtonUrl"
38
- @submit="submitForm"
39
- :is-submitting="isSubmitting"
40
- :is-creation="isCreation"
41
- :can-create-another="isCreation"
49
+ :back-href="backButtonUrl"
50
+ :is-submitting="isSubmitting"
51
+ :is-creation="isCreation"
52
+ :can-create-another="isCreation"
53
+ @submit="submitForm"
42
54
  />
43
55
  </template>
44
56
  </Page>
@@ -50,44 +62,69 @@ import {
50
62
  defineComponent,
51
63
  onMounted,
52
64
  ref,
53
- SetupContext,
65
+ type SetupContext,
54
66
  watch,
55
67
  } from 'vue';
68
+ import { useRoute, useRouter } from 'vue-router';
56
69
 
57
- import {Page} from "@tager/admin-layout";
58
-
70
+ import { Page } from '@tager/admin-layout';
59
71
  import {
60
- convertRequestErrorToMap, navigateBack,
61
- Nullable,
62
- useResource, useToast,
72
+ convertRequestErrorToMap,
73
+ navigateBack,
74
+ notEmpty,
75
+ type Nullable,
76
+ useResource,
77
+ useToast,
63
78
  } from '@tager/admin-services';
64
- import {OptionType, FormFooter, TagerFormSubmitEvent, FormField, FormFieldMultiSelect} from '@tager/admin-ui';
65
-
66
- import {useI18n} from "@tager/admin-services";
67
-
68
- import {AdminType, RoleType} from '../../typings/model';
79
+ import {
80
+ type OptionType,
81
+ FormFooter,
82
+ type TagerFormSubmitEvent,
83
+ FormField,
84
+ FormFieldMultiSelect,
85
+ type TabType,
86
+ TabList,
87
+ } from '@tager/admin-ui';
88
+ import { useI18n } from '@tager/admin-services';
89
+ import {
90
+ DynamicField,
91
+ type FieldConfigUnion,
92
+ type FieldShortType,
93
+ type FieldUnion,
94
+ type IncomingValueUnion,
95
+ universalFieldUtils,
96
+ } from '@tager/admin-dynamic-field';
97
+
98
+ import { type AdminType, type RoleType } from '../../typings/model';
69
99
  import {
70
100
  createAdmin,
71
101
  getAdmin,
102
+ getFieldList,
72
103
  getRoleList,
73
104
  updateAdmin,
74
105
  } from '../../services/requests';
75
- import {getAdminFormUrl, getAdminListUrl, getRoleFormUrl, getRoleListUrl} from '../../utils/paths';
106
+ import { getAdminFormUrl, getAdminListUrl } from '../../utils/paths';
76
107
 
77
108
  import {
78
109
  convertFormValuesToAdminCreationPayload,
79
110
  convertFormValuesToAdminUpdatePayload,
80
111
  convertAdminToFormValues,
81
112
  convertRoleListToOptions,
82
- FormValues,
113
+ type FormValues,
83
114
  } from './AdminForm.helpers';
84
- import {useRoute, useRouter} from "vue-router";
85
115
 
86
116
  export default defineComponent({
87
117
  name: 'AdminForm',
88
- components: {Page, FormFooter, FormField, FormFieldMultiSelect},
118
+ components: {
119
+ DynamicField,
120
+ TabList,
121
+ Page,
122
+ FormFooter,
123
+ FormField,
124
+ FormFieldMultiSelect,
125
+ },
89
126
  setup() {
90
- const {t} = useI18n();
127
+ const { t } = useI18n();
91
128
 
92
129
  const route = useRoute();
93
130
  const router = useRouter();
@@ -95,9 +132,11 @@ export default defineComponent({
95
132
 
96
133
  const adminId = computed(() => route.params.adminId as string | number);
97
134
 
98
- const isCreation = computed(() => adminId.value === "create");
135
+ const isCreation = computed(() => adminId.value === 'create');
99
136
 
100
- const [fetchAdmin, {data: admin, loading: isAdminLoading}] = useResource<Nullable<AdminType>>({
137
+ const [fetchAdmin, { data: admin, loading: isAdminLoading }] = useResource<
138
+ Nullable<AdminType>
139
+ >({
101
140
  fetchResource: () => getAdmin(adminId.value),
102
141
  initialValue: null,
103
142
  resourceName: 'Admin',
@@ -105,29 +144,35 @@ export default defineComponent({
105
144
 
106
145
  /** Fetch role list */
107
146
 
108
- const [
109
- fetchRoleList,
110
- {data: roleList, loading: isRoleListLoading},
111
- ] = useResource<Array<RoleType>>({
112
- fetchResource: getRoleList,
113
- initialValue: [],
114
- resourceName: 'Role list',
115
- });
147
+ const [fetchRoleList, { data: roleList, loading: isRoleListLoading }] =
148
+ useResource<Array<RoleType>>({
149
+ fetchResource: getRoleList,
150
+ initialValue: [],
151
+ resourceName: 'Role List',
152
+ });
153
+
154
+ const [fetchFieldList, { data: fieldList, loading: isFieldListLoading }] =
155
+ useResource<Array<FieldConfigUnion>>({
156
+ fetchResource: getFieldList,
157
+ initialValue: [],
158
+ resourceName: 'Field List',
159
+ });
116
160
 
117
161
  onMounted(() => {
118
162
  fetchRoleList();
163
+ fetchFieldList();
164
+ updateTemplateValues();
119
165
  if (isCreation.value) return;
120
-
121
166
  fetchAdmin();
122
167
  });
123
168
 
124
169
  /** Role Options */
125
170
  const roleOptionList = computed<Array<OptionType<number>>>(() =>
126
- convertRoleListToOptions(roleList.value)
171
+ convertRoleListToOptions(roleList.value)
127
172
  );
128
173
 
129
174
  const values = ref<FormValues>(
130
- convertAdminToFormValues(admin.value, roleOptionList.value)
175
+ convertAdminToFormValues(admin.value, roleOptionList.value)
131
176
  );
132
177
 
133
178
  const errors = ref<Record<string, string>>({});
@@ -135,8 +180,8 @@ export default defineComponent({
135
180
 
136
181
  watch([admin, roleOptionList], () => {
137
182
  values.value = convertAdminToFormValues(
138
- admin.value,
139
- roleOptionList.value
183
+ admin.value,
184
+ roleOptionList.value
140
185
  );
141
186
  });
142
187
 
@@ -146,65 +191,107 @@ export default defineComponent({
146
191
  if (admin.value && admin.value.isSelf) return;
147
192
 
148
193
  const creationBody = convertFormValuesToAdminCreationPayload(
149
- values.value
194
+ values.value,
195
+ templateValues.value
150
196
  );
151
197
 
152
- const updateBody = convertFormValuesToAdminUpdatePayload(values.value);
198
+ const updateBody = convertFormValuesToAdminUpdatePayload(
199
+ values.value,
200
+ templateValues.value
201
+ );
153
202
 
154
203
  const requestPromise = isCreation.value
155
- ? createAdmin(creationBody)
156
- : updateAdmin(adminId.value, updateBody);
204
+ ? createAdmin(creationBody)
205
+ : updateAdmin(adminId.value, updateBody);
157
206
 
158
207
  requestPromise
159
- .then(({data}) => {
160
- errors.value = {};
161
-
162
- if (event.type === "create") {
163
- router.push(getAdminFormUrl({adminId: data.id}));
164
- }
165
-
166
- if (event.type === "create_exit" || event.type === "save_exit") {
167
- navigateBack(router, getAdminListUrl());
168
- }
169
-
170
- if (event.type === 'create_create-another') {
171
- values.value = convertAdminToFormValues(null, roleOptionList.value);
172
- }
173
-
174
- toast.show({
175
- variant: 'success',
176
- title: t('administrators:success'),
177
- body: isCreation.value
178
- ? t('administrators:adminSuccessfullyCreated')
179
- : t('administrators:adminSuccessfullyUpdated'),
180
- });
181
- })
182
- .catch((error) => {
183
- console.error(error);
184
- errors.value = convertRequestErrorToMap(error);
185
- toast.show({
186
- variant: 'danger',
187
- title: t('administrators:error'),
188
- body: isCreation.value
189
- ? t('administrators:adminCreationError')
190
- : t('administrators:adminUpdateError'),
191
- });
192
- })
193
- .finally(() => {
194
- isSubmitting.value = false;
208
+ .then(({ data }) => {
209
+ errors.value = {};
210
+
211
+ if (event.type === 'create') {
212
+ router.push(getAdminFormUrl({ adminId: data.id }));
213
+ }
214
+
215
+ if (event.type === 'create_exit' || event.type === 'save_exit') {
216
+ navigateBack(router, getAdminListUrl());
217
+ }
218
+
219
+ if (event.type === 'create_create-another') {
220
+ values.value = convertAdminToFormValues(null, roleOptionList.value);
221
+ }
222
+
223
+ toast.show({
224
+ variant: 'success',
225
+ title: t('administrators:success'),
226
+ body: isCreation.value
227
+ ? t('administrators:adminSuccessfullyCreated')
228
+ : t('administrators:adminSuccessfullyUpdated'),
229
+ });
230
+ })
231
+ .catch((error) => {
232
+ console.error(error);
233
+ errors.value = convertRequestErrorToMap(error);
234
+ toast.show({
235
+ variant: 'danger',
236
+ title: t('administrators:error'),
237
+ body: isCreation.value
238
+ ? t('administrators:adminCreationError')
239
+ : t('administrators:adminUpdateError'),
195
240
  });
241
+ })
242
+ .finally(() => {
243
+ isSubmitting.value = false;
244
+ });
196
245
  }
197
246
 
198
247
  const pageTitle = computed<string>(() => {
199
248
  return isCreation.value
200
- ? t('administrators:createAdmin')
201
- : `${t('administrators:updateAdmin')} "${values.value.name}"`;
249
+ ? t('administrators:createAdmin')
250
+ : `${t('administrators:updateAdmin')} "${values.value.name}"`;
202
251
  });
203
252
 
204
253
  const isContentLoading = computed<boolean>(
205
- () => isAdminLoading.value || isRoleListLoading.value
254
+ () =>
255
+ isAdminLoading.value ||
256
+ isRoleListLoading.value ||
257
+ isFieldListLoading.value
206
258
  );
207
259
 
260
+ /** Tabs */
261
+
262
+ const shouldDisplayParamsTab = computed<boolean>(
263
+ () => fieldList.value.length > 0
264
+ );
265
+
266
+ const tabList = computed<Array<TabType>>(() => {
267
+ return [
268
+ { id: 'general', label: t('administrators:tabs.general') },
269
+ shouldDisplayParamsTab.value
270
+ ? { id: 'params', label: t('administrators:tabs.params') }
271
+ : null,
272
+ ].filter(notEmpty);
273
+ });
274
+
275
+ const selectedTabId = ref<string>(tabList.value[0].id);
276
+
277
+ const templateValues = ref<Array<FieldUnion>>([]);
278
+
279
+ function updateTemplateValues() {
280
+ const incomingFieldList: Array<FieldShortType<IncomingValueUnion>> =
281
+ admin.value?.params ?? [];
282
+
283
+ templateValues.value = fieldList.value.map((fieldConfig, index) =>
284
+ universalFieldUtils.createFormField(
285
+ fieldConfig,
286
+ incomingFieldList[index]?.value
287
+ )
288
+ );
289
+ }
290
+
291
+ watch([admin, fieldList], () => {
292
+ updateTemplateValues();
293
+ });
294
+
208
295
  return {
209
296
  t,
210
297
  backButtonUrl: getAdminListUrl(),
@@ -217,6 +304,9 @@ export default defineComponent({
217
304
  pageTitle,
218
305
  isCreation,
219
306
  roleOptionList,
307
+ tabList,
308
+ selectedTabId,
309
+ templateValues,
220
310
  };
221
311
  },
222
312
  });
@@ -14,7 +14,7 @@
14
14
  :loading="isRowDataLoading"
15
15
  :error-message="errorMessage"
16
16
  >
17
- <template v-slot:cell(roles)="{ row }">
17
+ <template #cell(roles)="{ row }">
18
18
  <ul>
19
19
  <li v-for="role of row.roles" :key="role.id">
20
20
  {{ role.name }}
@@ -49,14 +49,14 @@
49
49
  import {defineComponent, onMounted} from 'vue';
50
50
 
51
51
  import {useResourceDelete} from '@tager/admin-services';
52
- import {ColumnDefinition, DataTable, BaseButton, DeleteIcon, EditIcon, useDataTable} from '@tager/admin-ui';
52
+ import {type ColumnDefinition, DataTable, BaseButton, DeleteIcon, EditIcon, useDataTable} from '@tager/admin-ui';
53
53
  import {useI18n} from "@tager/admin-services";
54
+ import {Page} from "@tager/admin-layout";
54
55
 
55
- import {AdminType} from '../../typings/model';
56
+ import {type AdminType} from '../../typings/model';
56
57
  import {deleteAdmin, getAdminList} from '../../services/requests';
57
58
  import {getAdminFormUrl} from '../../utils/paths';
58
59
 
59
- import {Page} from "@tager/admin-layout";
60
60
 
61
61
  export default defineComponent({
62
62
  name: 'AdminList',
@@ -1,10 +1,10 @@
1
- import { Nullable } from '@tager/admin-services';
2
- import { OptionType } from '@tager/admin-ui';
1
+ import { type Nullable } from '@tager/admin-services';
2
+ import { type OptionType } from '@tager/admin-ui';
3
3
 
4
- import { RoleType, ScopeGroupsData } from '../../typings/model';
4
+ import { type RoleType, type ScopeGroupsData } from '../../typings/model';
5
5
  import {
6
- RoleCreationPayload,
7
- RoleUpdatePayload,
6
+ type RoleCreationPayload,
7
+ type RoleUpdatePayload,
8
8
  } from '../../services/requests';
9
9
 
10
10
  export type FormValues = {
@@ -20,10 +20,10 @@
20
20
  <template #footer>
21
21
  <FormFooter
22
22
  :back-href="backButtonUrl"
23
- @submit="submitForm"
24
23
  :is-submitting="isSubmitting"
25
24
  :is-creation="isCreation"
26
25
  :can-create-another="isCreation"
26
+ @submit="submitForm"
27
27
  />
28
28
  </template>
29
29
  </Page>
@@ -37,21 +37,19 @@ import {
37
37
  ref,
38
38
  watch,
39
39
  } from 'vue';
40
+ import {useRoute, useRouter} from "vue-router";
40
41
 
41
42
  import {Page} from "@tager/admin-layout";
42
-
43
43
  import {
44
44
  convertRequestErrorToMap, navigateBack,
45
- Nullable,
45
+ type Nullable,
46
46
  useResource, useToast,
47
47
  } from '@tager/admin-services';
48
-
49
48
  import {useI18n} from "@tager/admin-services";
50
-
51
49
  import {
52
- OptionType,
50
+ type OptionType,
53
51
  FormFooter,
54
- TagerFormSubmitEvent,
52
+ type TagerFormSubmitEvent,
55
53
  FormField, FormFieldMultiSelect
56
54
  } from '@tager/admin-ui';
57
55
 
@@ -61,7 +59,7 @@ import {
61
59
  getScopes,
62
60
  updateRole,
63
61
  } from '../../services/requests';
64
- import {RoleType, ScopeGroupsData} from '../../typings/model';
62
+ import {type RoleType, type ScopeGroupsData} from '../../typings/model';
65
63
  import {getRoleFormUrl, getRoleListUrl} from '../../utils/paths';
66
64
 
67
65
  import {
@@ -69,9 +67,8 @@ import {
69
67
  convertFormValuesToRoleUpdatePayload,
70
68
  convertRoleToFormValues,
71
69
  convertScopeDataToOptions,
72
- FormValues,
70
+ type FormValues,
73
71
  } from './RoleForm.helpers';
74
- import {useRoute, useRouter} from "vue-router";
75
72
 
76
73
  export default defineComponent({
77
74
  name: 'RoleForm',
@@ -79,7 +79,6 @@ import {defineComponent, onMounted} from "vue";
79
79
 
80
80
  import {useResourceDelete, useI18n} from '@tager/admin-services';
81
81
  import {Page} from "@tager/admin-layout";
82
-
83
82
  import {
84
83
  BaseButton,
85
84
  type ColumnDefinition,
@@ -89,7 +88,7 @@ import {
89
88
  useDataTable,
90
89
  } from "@tager/admin-ui";
91
90
 
92
- import {RoleType, ScopeType} from '../../typings/model';
91
+ import {type RoleType, type ScopeType} from '../../typings/model';
93
92
  import {deleteRole, getRoleList} from '../../services/requests';
94
93
  import {getRoleFormUrl} from '../../utils/paths';
95
94
 
@@ -136,7 +135,7 @@ export default defineComponent({
136
135
 
137
136
  function getScopeGroupList(
138
137
  scopes: Array<ScopeType>
139
- ): Array<{ module: string; scopes: ScopeType }> {
138
+ ): Array<{ module: string; scopes: Array<ScopeType> }> {
140
139
  const map = new Map();
141
140
  scopes.forEach((scope) => {
142
141
  const key = scope.module;