@drax/identity-vue 0.5.4 → 0.5.9

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.
Files changed (35) hide show
  1. package/package.json +5 -5
  2. package/src/combobox/RoleCombobox.vue +9 -1
  3. package/src/combobox/TenantCombobox.vue +11 -9
  4. package/src/components/IdentityChangeOwnPassword/IdentityChangeOwnPassword.vue +4 -4
  5. package/src/components/IdentityProfileDrawer/IdentityProfileDrawer.vue +2 -2
  6. package/src/cruds/role-crud/RoleCrud.ts +9 -1
  7. package/src/cruds/role-crud/RoleForm.vue +116 -0
  8. package/src/cruds/tenant-crud/TenantCrud.ts +8 -0
  9. package/src/cruds/user-crud/PasswordUpdateButton.vue +25 -0
  10. package/src/cruds/user-crud/UserCrud.ts +11 -0
  11. package/src/cruds/user-crud/UserCrud.vue +4 -17
  12. package/src/cruds/user-crud/UserForm.vue +177 -0
  13. package/src/cruds/user-crud/UserPasswordDialog.vue +94 -0
  14. package/src/{forms → cruds/user-crud}/UserPasswordForm.vue +4 -2
  15. package/src/index.ts +7 -21
  16. package/src/pages/ProfilePage.vue +1 -1
  17. package/src/pages/{RoleCrudPage.vue → crud/RoleCrudPage.vue} +11 -10
  18. package/src/pages/{TenantCrudPage.vue → crud/TenantCrudPage.vue} +1 -1
  19. package/src/pages/{UserApiKeyCrudPage.vue → crud/UserApiKeyCrudPage.vue} +1 -1
  20. package/src/pages/crud/UserCrudPage.vue +61 -0
  21. package/src/routes/IdentityRoutes.ts +5 -35
  22. package/src/cruds/role-crud/RoleCrud.vue +0 -171
  23. package/src/cruds/role-crud/RoleList.vue +0 -129
  24. package/src/cruds/tenant-crud/TenantCrud.vue +0 -168
  25. package/src/cruds/tenant-crud/TenantList.vue +0 -108
  26. package/src/cruds/user-crud/UserList.vue +0 -110
  27. package/src/forms/RoleForm.vue +0 -89
  28. package/src/forms/RoleFormOld.vue +0 -57
  29. package/src/forms/TenantForm.vue +0 -48
  30. package/src/forms/UserCreateForm.vue +0 -115
  31. package/src/forms/UserEditForm.vue +0 -101
  32. package/src/pages/RoleCrudCustomPage.vue +0 -12
  33. package/src/pages/TenantCrudCustomPage.vue +0 -12
  34. package/src/pages/UserCrudCustomPage.vue +0 -12
  35. package/src/pages/UserCrudPage.vue +0 -18
@@ -1,168 +0,0 @@
1
- <script setup lang="ts">
2
- import {computed, ref} from 'vue'
3
- import TenantList from "./TenantList.vue";
4
- import {useTenant} from "../../composables/useTenant";
5
- import type {ITenant, ITenantBase} from "@drax/identity-share";
6
- import TenantForm from "../../forms/TenantForm.vue";
7
- import TenantView from "../../views/TenantView.vue";
8
- import {useI18n} from "vue-i18n";
9
- const {t} = useI18n()
10
- const {createTenant, editTenant, deleteTenant, loading, tenantError, inputErrors} = useTenant()
11
-
12
- interface TenantList {
13
- loadItems: () => void;
14
- items: ITenant[];
15
- }
16
-
17
- type DialogMode = 'create' | 'edit' | 'delete' | null;
18
-
19
-
20
- let dialog = ref(false);
21
- let dialogMode = ref<DialogMode>(null);
22
- let dialogTitle = ref('');
23
- const tenantList = ref<TenantList | null>(null);
24
- let form = ref<ITenantBase>({name: ""})
25
- let target = ref<ITenant>();
26
- let targetId = ref<string>('');
27
- let filterEnable = ref(false);
28
-
29
- function cancel() {
30
- dialog.value = false
31
- inputErrors.value = {}
32
- tenantError.value = '';
33
- dialogMode.value = null
34
- dialogTitle.value = ''
35
- targetId.value = ''
36
- target.value = undefined
37
- }
38
-
39
- async function save() {
40
-
41
- try {
42
- if (dialogMode.value === 'create') {
43
- await createTenant(form.value)
44
- } else if (dialogMode.value === 'edit') {
45
- await editTenant(targetId.value, form.value)
46
- } else if (dialogMode.value === 'delete') {
47
- await deleteTenant(targetId.value)
48
- }
49
- dialog.value = false
50
- inputErrors.value = {}
51
- tenantError.value = '';
52
- if (tenantList.value !== null) {
53
- tenantList.value.loadItems()
54
- }
55
- } catch (e) {
56
- console.error(e)
57
- if (e instanceof Error) {
58
- tenantError.value = e.message
59
- }
60
- }
61
- }
62
-
63
- let buttonText = computed(() => {
64
- switch (dialogMode.value) {
65
- case 'create':
66
- return 'action.create'
67
- case 'edit':
68
- return 'action.update'
69
- case 'delete':
70
- return 'action.delete'
71
- default:
72
- return 'action.sent'
73
- }
74
- })
75
-
76
- function toCreate() {
77
- dialogMode.value = 'create';
78
- dialogTitle.value = 'tenant.creating';
79
- form.value = {name: ""}
80
- dialog.value = true;
81
- }
82
-
83
- function toEdit(item: ITenant) {
84
- console.log('toEdit', item)
85
- dialogMode.value = 'edit';
86
- dialogTitle.value = 'tenant.updating';
87
- targetId.value = item.id;
88
- form.value = {
89
- name: item.name
90
- }
91
- dialog.value = true;
92
- }
93
-
94
- function toDelete(item: ITenant) {
95
- console.log('toDelete', item)
96
- dialogMode.value = 'delete';
97
- dialogTitle.value = 'tenant.deleting';
98
- target.value = item
99
- const {id} = item;
100
- targetId.value = id;
101
- dialog.value = true;
102
- }
103
-
104
- </script>
105
-
106
- <template>
107
- <v-container fluid>
108
-
109
- <v-card border rounded >
110
- <v-toolbar class="bg-toolbar">
111
- <v-toolbar-title>{{ t('tenant.managing') }}</v-toolbar-title>
112
- <v-spacer></v-spacer>
113
- <v-btn icon @click="filterEnable = !filterEnable">
114
- <v-icon>{{ filterEnable ? 'mdi-filter' : 'mdi-filter-off' }}</v-icon>
115
- </v-btn>
116
- <v-btn class="font-weight-bold" color="primary" @click="toCreate">
117
- {{ t('action.create') }}
118
- </v-btn>
119
- </v-toolbar>
120
- <v-theme-provider with-background class="pa-2 rounded-b">
121
- <TenantList
122
- ref="tenantList"
123
- @toEdit="toEdit"
124
- @toDelete="toDelete"
125
- :filterEnable="filterEnable"
126
- />
127
- </v-theme-provider>
128
- </v-card>
129
-
130
- <v-dialog v-model="dialog" max-width="800">
131
- <v-sheet border>
132
- <v-toolbar>
133
- <v-toolbar-title>{{ dialogTitle ? t(dialogTitle) : '-' }}</v-toolbar-title>
134
- </v-toolbar>
135
- <v-card class="pa-10">
136
- <v-card-text v-if="tenantError">
137
- <v-alert type="error">{{ tenantError }}</v-alert>
138
- </v-card-text>
139
- <v-card-text>
140
- <TenantForm v-if="dialogMode === 'create' || dialogMode === 'edit'"
141
- v-model="form"
142
- :inputErrors="inputErrors"
143
- @formSubmit="save"
144
- />
145
- <TenantView v-if="dialogMode === 'delete' && target" :tenant="target"></TenantView>
146
- </v-card-text>
147
- <v-card-actions>
148
- <v-spacer></v-spacer>
149
- <v-btn variant="text" @click="cancel" :loading="loading">Cancelar</v-btn>
150
- <v-btn variant="flat"
151
- :color="dialogMode==='delete' ? 'red' : 'primary'"
152
- @click="save"
153
- :loading="loading"
154
- >
155
- {{ t(buttonText) }}
156
- </v-btn>
157
- </v-card-actions>
158
-
159
- </v-card>
160
- </v-sheet>
161
- </v-dialog>
162
-
163
- </v-container>
164
- </template>
165
-
166
- <style scoped>
167
-
168
- </style>
@@ -1,108 +0,0 @@
1
- <script setup lang="ts">
2
- import {defineProps, type Ref, ref} from "vue";
3
- import {useTenant} from "../../composables/useTenant";
4
- import {useAuth} from "../../composables/useAuth";
5
- import {useI18n} from "vue-i18n";
6
- import type {ITenant} from "@drax/identity-share";
7
- import {formatDateTime} from "@drax/common-front";
8
-
9
- const {hasPermission} = useAuth()
10
- const {paginateTenant} = useTenant()
11
- const {t} = useI18n()
12
-
13
- defineProps({
14
- filterEnable: {
15
- type: Boolean,
16
- default: false,
17
- }
18
- })
19
-
20
- const itemsPerPage = ref(5)
21
- const page = ref(1)
22
- const serverItems: Ref<ITenant[]> = ref([]);
23
- const totalItems = ref(0)
24
- const loading = ref(false)
25
- const search = ref('')
26
- const sortBy : Ref<any> = ref([])
27
-
28
- const headers = ref<any>([
29
- { title: t('tenant.name') as string, key: 'name', align: 'start' },
30
- { title: t('tenant.createdAt') as string, key: 'createdAt', align: 'start' },
31
- { title: '', key: 'actions', align: 'end', minWidth: '150px' },
32
- ])
33
-
34
-
35
- async function loadItems(){
36
- try{
37
- loading.value = true
38
- const r = await paginateTenant({
39
- page: page.value,
40
- limit: itemsPerPage.value,
41
- orderBy: sortBy.value[0]?.key,
42
- order: sortBy.value[0]?.order,
43
- search: search.value})
44
- serverItems.value = r.items
45
- totalItems.value = r.total
46
- }catch (e){
47
- console.error(e)
48
- }finally {
49
- loading.value = false
50
- }
51
- }
52
-
53
-
54
-
55
- defineExpose({
56
- loadItems
57
- });
58
-
59
- </script>
60
-
61
- <template>
62
- <v-data-table-server
63
- class="border"
64
- v-if="hasPermission('user:manage')"
65
- v-model:items-per-page="itemsPerPage"
66
- :items-per-page-options="[5, 10, 20, 50]"
67
- v-model:page="page"
68
- v-model:sort-by="sortBy"
69
- :headers="headers"
70
- :items="serverItems"
71
- :items-length="totalItems"
72
- :loading="loading"
73
- :search="search"
74
- :multi-sort="false"
75
- item-value="name"
76
- @update:options="loadItems"
77
- >
78
- <template v-slot:top>
79
- <v-toolbar density="compact" v-if="filterEnable">
80
- <v-toolbar-title>{{ t('action.filters') }}</v-toolbar-title>
81
- <v-spacer></v-spacer>
82
- <v-text-field v-model="search" hide-details
83
- density="compact" class="mr-2"
84
- variant="outlined"
85
- append-inner-icon="mdi-magnify"
86
- :label="t('action.search')"
87
- single-line clearable @click:clear="() => search = ''"
88
- />
89
-
90
- </v-toolbar>
91
- </template>
92
-
93
- <template v-slot:item.createdAt="{ value }" >
94
- {{formatDateTime(value)}}
95
- </template>
96
-
97
-
98
- <template v-slot:item.actions="{item}" >
99
- <v-btn v-if="hasPermission('tenant:update')" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
100
- <v-btn v-if="hasPermission('tenant:delete')" icon="mdi-delete" class="mr-1" variant="text" color="red" @click="$emit('toDelete', item)"></v-btn>
101
- </template>
102
-
103
- </v-data-table-server>
104
- </template>
105
-
106
- <style scoped>
107
-
108
- </style>
@@ -1,110 +0,0 @@
1
- <script setup lang="ts">
2
-
3
- import {ref, defineProps, type Ref} from "vue";
4
- import {useUser} from "../../composables/useUser";
5
- import {useAuth} from "../../composables/useAuth";
6
- import {useI18n} from "vue-i18n";
7
- import type {IUser} from "@drax/identity-share";
8
-
9
- const {hasPermission} = useAuth()
10
- const {paginateUser} = useUser()
11
- const {t} = useI18n()
12
-
13
- defineProps({
14
- filterEnable: {
15
- type: Boolean,
16
- default: false,
17
- }
18
- })
19
-
20
- const itemsPerPage = ref(5)
21
- const page = ref(1)
22
- const headers = ref<any>([
23
- //{title: 'ID', align: 'start', sortable: false, key: 'id'},
24
- { title: t('user.name') as string, key: 'name', align: 'start' },
25
- { title: t('user.username') as string, key: 'username', align: 'start' },
26
- { title: t('user.email') as string, key: 'email', align: 'start' },
27
- { title: t('user.role') as string, key: 'role.name', align: 'start' },
28
- { title: t('user.tenant') as string, key: 'tenant.name', align: 'start' },
29
- { title: t('user.active') as string, key: 'active', align: 'start' },
30
- { title: '', key: 'actions', align: 'end', fixed:true },
31
- ])
32
-
33
- const serverItems: Ref<IUser[]> = ref([]);
34
- const totalItems = ref(0)
35
- const loading = ref(false)
36
- const search = ref('')
37
- const sortBy : Ref<any> = ref([])
38
-
39
- async function loadItems(){
40
- try{
41
- loading.value = true
42
- const r = await paginateUser({
43
- page: page.value,
44
- limit: itemsPerPage.value,
45
- orderBy: sortBy.value[0]?.key,
46
- order: sortBy.value[0]?.order,
47
- search: search.value})
48
- serverItems.value = r.items
49
- totalItems.value = r.total
50
- }catch (e){
51
- console.error(e)
52
- }finally {
53
- loading.value = false
54
- }
55
- }
56
-
57
-
58
-
59
- defineExpose({
60
- loadItems
61
- });
62
-
63
- </script>
64
-
65
- <template>
66
- <v-data-table-server
67
- v-if="hasPermission('user:manage')"
68
- v-model:items-per-page="itemsPerPage"
69
- v-model:page="page"
70
- v-model:sort-by="sortBy"
71
- :items-per-page-options="[5, 10, 20, 50]"
72
- :headers="headers"
73
- :items="serverItems"
74
- :items-length="totalItems"
75
- :loading="loading"
76
- :search="search"
77
- item-value="name"
78
- @update:options="loadItems"
79
- >
80
- <template v-slot:top>
81
- <v-toolbar density="compact" v-if="filterEnable">
82
- <v-toolbar-title>{{ t('action.filters') }}</v-toolbar-title>
83
- <v-spacer></v-spacer>
84
- <v-text-field v-model="search" hide-details
85
- density="compact" class="mr-2"
86
- variant="outlined"
87
- append-inner-icon="mdi-magnify"
88
- :label="t('action.search')"
89
- single-line clearable @click:clear="() => search = ''"
90
- />
91
- </v-toolbar>
92
- </template>
93
- <template v-slot:item.active="{ value }" >
94
- <v-chip :color="value ? 'green':'red'" >
95
- {{ value ? 'Active' : 'Inactive' }}
96
- </v-chip>
97
- </template>
98
-
99
- <template v-slot:item.actions="{item}" >
100
- <v-btn v-if="hasPermission('user:update')" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
101
- <v-btn v-if="hasPermission('user:update')" icon="mdi-lock" variant="text" color="orange" @click="$emit('toChangePassword', item)"></v-btn>
102
- <v-btn v-if="hasPermission('user:delete')" icon="mdi-delete" class="mr-1" variant="text" color="red" @click="$emit('toDelete', item)"></v-btn>
103
- </template>
104
-
105
- </v-data-table-server>
106
- </template>
107
-
108
- <style scoped>
109
-
110
- </style>
@@ -1,89 +0,0 @@
1
- <script setup lang="ts">
2
- import {useFormUtils, useCrudStore} from "@drax/crud-vue";
3
- import {defineEmits, defineModel, defineProps, ref} from "vue";
4
- import {useI18nValidation} from "@drax/common-vue";
5
- import PermissionSelector from "../components/PermissionSelector/PermissionSelector.vue";
6
- import RoleCombobox from "../combobox/RoleCombobox.vue";
7
-
8
- const {$ta} = useI18nValidation()
9
- import {useI18n} from "vue-i18n";
10
-
11
- const {t} = useI18n()
12
-
13
- const valueModel = defineModel({type: [Object]})
14
-
15
- defineProps({
16
- error: {type: String, required: false},
17
- })
18
-
19
- const emit = defineEmits(['submit', 'cancel'])
20
-
21
- const store = useCrudStore()
22
-
23
- const valid = ref()
24
- const formRef = ref()
25
-
26
- async function submit() {
27
- store.resetErrors()
28
- await formRef.value.validate()
29
-
30
- if(valid.value) {
31
- emit('submit',valueModel.value)
32
- }else{
33
- console.log('Invalid form')
34
- }
35
- }
36
-
37
- function cancel() {
38
- emit('cancel')
39
- }
40
-
41
- const {
42
- variant, submitColor, readonly
43
- } = useFormUtils(store.operation)
44
-
45
- </script>
46
-
47
- <template>
48
- <v-form v-model="valid" ref="formRef" @submit.prevent="submit">
49
- <v-text-field
50
- id="name-input"
51
- name="name"
52
- :label="$t('role.fields.name')"
53
- v-model="valueModel.name"
54
- prepend-inner-icon="mdi-card-account-details"
55
- :variant="variant"
56
- :error-messages="$ta(store.inputErrors?.name)"
57
- :rules="[v => !!v || 'validation.required']"
58
- density="default"
59
- :readonly="readonly"
60
- :clearable="false"
61
- ></v-text-field>
62
-
63
- <RoleCombobox
64
- v-model="valueModel.childRoles"
65
- :error-messages="$ta(store.inputErrors?.role)"
66
- multiple
67
- :readonly="readonly"
68
- :variant="variant"
69
- ></RoleCombobox>
70
-
71
- <PermissionSelector
72
- v-model="valueModel.permissions"
73
- :readonly="readonly"
74
- ></PermissionSelector>
75
-
76
- <v-card-actions>
77
- <v-spacer></v-spacer>
78
- <v-btn variant="text" color="grey" @click="cancel">{{ t('action.cancel') }}</v-btn>
79
- <v-btn variant="flat" v-if="store.operation != 'view'" :color="submitColor" @click="submit">
80
- {{ store.operation ? t('action.' + store.operation) : t('action.sent') }}
81
- </v-btn>
82
- </v-card-actions>
83
-
84
- </v-form>
85
- </template>
86
-
87
- <style scoped>
88
-
89
- </style>
@@ -1,57 +0,0 @@
1
- <script setup lang="ts">
2
- import {defineModel, type PropType} from "vue";
3
- import type {IRoleBase} from "@drax/identity-share";
4
- import {useI18nValidation} from "@drax/common-vue";
5
- import type {IClientInputError} from "@drax/common-front";
6
- import PermissionSelector from "../components/PermissionSelector/PermissionSelector.vue";
7
- import RoleCombobox from "../combobox/RoleCombobox.vue";
8
-
9
- const {$ta} = useI18nValidation()
10
-
11
- defineProps({
12
- inputErrors: {
13
- type: Object as PropType<IClientInputError>,
14
- default: () => ({name: "", permissions: "", readonly: ""})
15
- }
16
- })
17
-
18
- const form = defineModel<IRoleBase>({
19
- type: Object,
20
- default: () => ({name: "", permissions: [], readonly: false})
21
- })
22
-
23
- const emits = defineEmits(['formSubmit'])
24
-
25
- // Function to call when form is attempted to be submitted
26
- const onSubmit = () => {
27
- emits('formSubmit', form); // Emitting an event with the form data
28
- }
29
-
30
- </script>
31
-
32
- <template>
33
- <form @submit.prevent="onSubmit">
34
- <v-text-field
35
- variant="outlined"
36
- id="name-input"
37
- label="Name"
38
- v-model="form.name"
39
- prepend-inner-icon="mdi-card-account-details"
40
- required
41
- :error-messages="$ta(inputErrors.name)"
42
- ></v-text-field>
43
-
44
- <RoleCombobox
45
- v-model="form.childRoles"
46
- :error-messages="$ta(inputErrors.role)"
47
- multiple
48
- ></RoleCombobox>
49
-
50
- <PermissionSelector v-model="form.permissions"></PermissionSelector>
51
-
52
- </form>
53
- </template>
54
-
55
- <style scoped>
56
-
57
- </style>
@@ -1,48 +0,0 @@
1
- <script setup lang="ts">
2
- import {defineModel, type PropType} from "vue";
3
- import type {ITenantBase} from "@drax/identity-share";
4
- import {useI18nValidation} from "@drax/common-vue";
5
- import type {IClientInputError} from "@drax/common-front";
6
-
7
- const {$ta} = useI18nValidation()
8
-
9
- defineProps({
10
- inputErrors: {
11
- type: Object as PropType<IClientInputError>,
12
- default: () => ({name: ""})
13
- }
14
- })
15
-
16
- const form = defineModel<ITenantBase>({
17
- type: Object,
18
- default: () => ({name: ""})
19
- })
20
-
21
- // Define emits
22
- const emits = defineEmits(['formSubmit'])
23
-
24
- // Function to call when form is attempted to be submitted
25
- const onSubmit = () => {
26
- emits('formSubmit', form); // Emitting an event with the form data
27
- }
28
-
29
- </script>
30
-
31
- <template>
32
- <form @submit.prevent="onSubmit">
33
- <v-text-field
34
- variant="outlined"
35
- id="name-input"
36
- label="Name"
37
- v-model="form.name"
38
- prepend-inner-icon="mdi-card-account-details"
39
- required
40
- :error-messages="$ta(inputErrors.name)"
41
- ></v-text-field>
42
-
43
- </form>
44
- </template>
45
-
46
- <style scoped>
47
-
48
- </style>
@@ -1,115 +0,0 @@
1
- <script setup lang="ts">
2
- import {ref, defineModel, type PropType} from "vue";
3
- import RoleCombobox from "../combobox/RoleCombobox.vue";
4
- import TenantCombobox from "../combobox/TenantCombobox.vue";
5
- import type {IClientInputError} from "@drax/common-front";
6
- import type {IUserCreate} from "@drax/identity-share";
7
- import {useI18nValidation} from "@drax/common-vue";
8
-
9
- const {$ta} = useI18nValidation()
10
-
11
- defineProps({
12
- inputErrors: {
13
- type: Object as PropType<IClientInputError>,
14
- default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: ""})
15
- }
16
- })
17
-
18
- const form = defineModel<IUserCreate>({
19
- type: Object,
20
- default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: true})
21
- })
22
-
23
- let passwordVisibility = ref(false)
24
-
25
- // Define emits
26
- const emits = defineEmits(['formSubmit'])
27
-
28
- // Function to call when form is attempted to be submitted
29
- const onSubmit = () => {
30
- emits('formSubmit', form); // Emitting an event with the form data
31
- }
32
- </script>
33
-
34
- <template>
35
- <form @submit.prevent="onSubmit">
36
-
37
- <v-text-field
38
- variant="outlined"
39
- id="name-input"
40
- label="Name"
41
- v-model="form.name"
42
- prepend-inner-icon="mdi-card-account-details"
43
- required
44
- :error-messages="$ta(inputErrors.name)"
45
- ></v-text-field>
46
-
47
- <v-text-field
48
- variant="outlined"
49
- id="username-input"
50
- label="Username"
51
- v-model="form.username"
52
- prepend-inner-icon="mdi-account-question"
53
- required
54
- autocomplete="new-username"
55
- :error-messages="$ta(inputErrors.username)"
56
- ></v-text-field>
57
- <v-text-field
58
- variant="outlined"
59
- id="password-input"
60
- label="Password"
61
- v-model="form.password"
62
- :type="passwordVisibility ? 'text': 'password'"
63
- required
64
- prepend-inner-icon="mdi-lock-outline"
65
- :append-inner-icon="passwordVisibility ? 'mdi-eye-off': 'mdi-eye'"
66
- @click:append-inner="passwordVisibility = !passwordVisibility"
67
- autocomplete="new-password"
68
- :error-messages="$ta(inputErrors.password)"
69
- ></v-text-field>
70
-
71
- <RoleCombobox
72
- v-model="form.role"
73
- :error-messages="$ta(inputErrors.role)"
74
- ></RoleCombobox>
75
-
76
- <TenantCombobox
77
- v-model="form.tenant"
78
- :error-messages="$ta(inputErrors.tenant)"
79
- clearable
80
- ></TenantCombobox>
81
-
82
- <v-text-field
83
- v-model="form.email"
84
- variant="outlined"
85
- id="email-input"
86
- label="Email"
87
- prepend-inner-icon="mdi-email"
88
- required
89
- :error-messages="$ta(inputErrors.email)"
90
- ></v-text-field>
91
-
92
- <v-text-field
93
- v-model="form.phone"
94
- variant="outlined"
95
- id="phone-input"
96
- label="Phone"
97
- prepend-inner-icon="mdi-phone"
98
- required
99
- :error-messages="$ta(inputErrors.phone)"
100
- ></v-text-field>
101
-
102
- <v-switch
103
- id="active-input"
104
- v-model="form.active"
105
- color="primary"
106
- label="Active"
107
- :true-value="true"
108
- :false-value="false"
109
- ></v-switch>
110
- </form>
111
- </template>
112
-
113
- <style scoped>
114
-
115
- </style>