@drax/identity-vue 0.0.10
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/README.md +61 -0
- package/package.json +65 -0
- package/src/assets/base.css +86 -0
- package/src/assets/logo.svg +1 -0
- package/src/assets/main.css +35 -0
- package/src/combobox/PermissionCombobox.vue +38 -0
- package/src/combobox/RoleCombobox.vue +37 -0
- package/src/components/IdentityChangeOwnPassword/IdentityChangeOwnPassword.vue +139 -0
- package/src/components/IdentityLogin/IdentityLogin.vue +124 -0
- package/src/components/IdentityProfileAvatar/IdentityProfileAvatar.vue +38 -0
- package/src/components/IdentityProfileDrawer/IdentityProfileDrawer.vue +82 -0
- package/src/components/IdentityProfileView/IdentityProfileView.vue +31 -0
- package/src/components/PermissionSelector/PermissionSelector.vue +89 -0
- package/src/composables/useAuth.ts +53 -0
- package/src/composables/useI18nValidation.ts +11 -0
- package/src/composables/useRole.ts +93 -0
- package/src/composables/useUser.ts +96 -0
- package/src/cruds/role-crud/RoleCrud.vue +165 -0
- package/src/cruds/role-crud/RoleList.vue +110 -0
- package/src/cruds/user-crud/UserCrud.vue +222 -0
- package/src/cruds/user-crud/UserList.vue +100 -0
- package/src/forms/RoleForm.vue +44 -0
- package/src/forms/UserCreateForm.vue +101 -0
- package/src/forms/UserEditForm.vue +87 -0
- package/src/forms/UserPasswordForm.vue +81 -0
- package/src/i18n/I18n.ts +10 -0
- package/src/i18n/I18nMessages.ts +21 -0
- package/src/icons/IconCommunity.vue +7 -0
- package/src/index.ts +51 -0
- package/src/pages/RoleCrudPage.vue +12 -0
- package/src/pages/UserCrudPage.vue +12 -0
- package/src/stores/auth/AuthStore.ts +38 -0
- package/src/views/RoleView.vue +32 -0
- package/src/views/UserView.vue +34 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import {defineProps, ref} from "vue";
|
|
4
|
+
import {useRole} from "../../composables/useRole";
|
|
5
|
+
import {useAuth} from "../../composables/useAuth";
|
|
6
|
+
import {useI18n} from "vue-i18n";
|
|
7
|
+
|
|
8
|
+
const {hasPermission} = useAuth()
|
|
9
|
+
const {paginateRole} = useRole()
|
|
10
|
+
const {t} = useI18n()
|
|
11
|
+
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
filterEnable: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false,
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const itemsPerPage = ref(5)
|
|
20
|
+
const page = ref(1)
|
|
21
|
+
const headers = ref([
|
|
22
|
+
//{title: 'ID', align: 'start', sortable: false, key: 'id'},
|
|
23
|
+
{ title: t('role.name'), key: 'name', align: 'start' },
|
|
24
|
+
{ title: t('role.permissions'), key: 'permissions', align: 'start' },
|
|
25
|
+
{ title: t('role.readonly'), key: 'readonly', align: 'start' },
|
|
26
|
+
{ title: '', key: 'actions', align: 'start', minWidth: '150px' },
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
const serverItems = ref([])
|
|
30
|
+
const totalItems = ref(0)
|
|
31
|
+
const loading = ref(false)
|
|
32
|
+
const search = ref('')
|
|
33
|
+
|
|
34
|
+
async function loadItems(){
|
|
35
|
+
try{
|
|
36
|
+
loading.value = true
|
|
37
|
+
const r = await paginateRole(page.value,itemsPerPage.value, search.value)
|
|
38
|
+
serverItems.value = r.items
|
|
39
|
+
totalItems.value = r.total
|
|
40
|
+
}catch (e){
|
|
41
|
+
console.error(e)
|
|
42
|
+
}finally {
|
|
43
|
+
loading.value = false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
defineExpose({
|
|
50
|
+
loadItems
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<v-data-table-server
|
|
57
|
+
v-if="hasPermission('user:manage')"
|
|
58
|
+
v-model:items-per-page="itemsPerPage"
|
|
59
|
+
v-model:page="page"
|
|
60
|
+
:headers="headers"
|
|
61
|
+
:items="serverItems"
|
|
62
|
+
:items-length="totalItems"
|
|
63
|
+
:loading="loading"
|
|
64
|
+
:search="search"
|
|
65
|
+
item-value="name"
|
|
66
|
+
@update:options="loadItems"
|
|
67
|
+
>
|
|
68
|
+
<template v-slot:top>
|
|
69
|
+
<v-toolbar border density="compact" v-if="filterEnable" class="grey-lighten-1">
|
|
70
|
+
<v-toolbar-title>{{ $t('action.filter') }}</v-toolbar-title>
|
|
71
|
+
<v-spacer></v-spacer>
|
|
72
|
+
<v-text-field v-model="search" hide-details
|
|
73
|
+
density="compact" class="mr-2"
|
|
74
|
+
variant="outlined"
|
|
75
|
+
append-inner-icon="mdi-magnify"
|
|
76
|
+
:label="$t('action.search')"
|
|
77
|
+
single-line clearable @click:clear="() => search = ''"
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
</v-toolbar>
|
|
81
|
+
</template>
|
|
82
|
+
<template v-slot:item.permissions="{ value }" >
|
|
83
|
+
<v-chip v-for="permission in value"
|
|
84
|
+
:key="permission" color="green"
|
|
85
|
+
class="ma-1"
|
|
86
|
+
>
|
|
87
|
+
{{$t ? $t(`permission.${permission}`) : permission }}
|
|
88
|
+
</v-chip>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<template v-slot:item.readonly="{ value }" >
|
|
92
|
+
<v-chip v-if="value" color="red" >
|
|
93
|
+
<v-icon class="mdi mdi-pencil-off-outline"></v-icon>
|
|
94
|
+
</v-chip>
|
|
95
|
+
<v-chip v-else color="green">
|
|
96
|
+
<v-icon class="mdi mdi-pencil-outline"></v-icon>
|
|
97
|
+
</v-chip>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<template v-slot:item.actions="{item}" >
|
|
101
|
+
<v-btn v-if="hasPermission('user:update')" :disabled="item.readonly" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
|
|
102
|
+
<v-btn v-if="hasPermission('user:delete')" :disabled="item.readonly" 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>
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {computed, ref} from 'vue'
|
|
3
|
+
import UserList from "./UserList.vue";
|
|
4
|
+
import {useUser} from "../../composables/useUser";
|
|
5
|
+
import type {IUser} from "@drax/identity-front";
|
|
6
|
+
import type {IUserCreate, IUserUpdate, IUserPassword} from "@drax/identity-front/src/interfaces/IUser";
|
|
7
|
+
import UserCreateForm from "../../forms/UserCreateForm.vue";
|
|
8
|
+
import UserEditForm from "../../forms/UserEditForm.vue";
|
|
9
|
+
import UserPasswordForm from "../../forms/UserPasswordForm.vue";
|
|
10
|
+
import UserView from "../../views/UserView.vue";
|
|
11
|
+
|
|
12
|
+
const {createUser, editUser, changeUserPassword, deleteUser, loading, userError, inputErrors} = useUser()
|
|
13
|
+
|
|
14
|
+
interface UserList {
|
|
15
|
+
loadItems: () => void;
|
|
16
|
+
items: IUser[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type DialogMode = 'create' | 'edit' | 'delete' | 'changePassword' | null;
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
let dialog = ref(false);
|
|
23
|
+
let dialogMode = ref<DialogMode>(null);
|
|
24
|
+
let dialogTitle = ref('');
|
|
25
|
+
const userList = ref<UserList | null>(null);
|
|
26
|
+
let createForm = ref<IUserCreate>({name: "", username: "", password: "", email: "", phone: "", role: "", active: true})
|
|
27
|
+
let editForm = ref<IUserUpdate>({name: "", username: "", email: "", phone: "", role: "", active: true})
|
|
28
|
+
let passwordForm = ref<IUserPassword>({newPassword: "", confirmPassword: ""})
|
|
29
|
+
let passwordChanged = ref(false);
|
|
30
|
+
let target = ref<IUser>();
|
|
31
|
+
let targetId = ref<string>('');
|
|
32
|
+
let actionButtonEnable = ref(true);
|
|
33
|
+
let filterEnable = ref(false);
|
|
34
|
+
|
|
35
|
+
function cancel() {
|
|
36
|
+
dialog.value = false
|
|
37
|
+
inputErrors.value = {}
|
|
38
|
+
userError.value = '';
|
|
39
|
+
dialogMode.value = null
|
|
40
|
+
dialogTitle.value = ''
|
|
41
|
+
targetId.value = ''
|
|
42
|
+
target.value = undefined
|
|
43
|
+
actionButtonEnable.value = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function save() {
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
if (dialogMode.value === 'create') {
|
|
50
|
+
await createUser(createForm.value)
|
|
51
|
+
} else if (dialogMode.value === 'edit') {
|
|
52
|
+
await editUser(targetId.value, editForm.value)
|
|
53
|
+
} else if (dialogMode.value === 'changePassword') {
|
|
54
|
+
if (passwordForm.value.newPassword === passwordForm.value.confirmPassword) {
|
|
55
|
+
passwordChanged.value = await changeUserPassword(targetId.value, passwordForm.value.newPassword)
|
|
56
|
+
actionButtonEnable.value = false
|
|
57
|
+
return
|
|
58
|
+
} else {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
} else if (dialogMode.value === 'delete') {
|
|
62
|
+
await deleteUser(targetId.value)
|
|
63
|
+
}
|
|
64
|
+
dialog.value = false
|
|
65
|
+
inputErrors.value = {}
|
|
66
|
+
userError.value = '';
|
|
67
|
+
if (userList.value !== null) {
|
|
68
|
+
userList.value.loadItems()
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.error(e)
|
|
72
|
+
if (e instanceof Error) {
|
|
73
|
+
userError.value = e.message
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let buttonText = computed(() => {
|
|
79
|
+
switch (dialogMode.value) {
|
|
80
|
+
case 'create':
|
|
81
|
+
return 'action.create'
|
|
82
|
+
case 'edit':
|
|
83
|
+
return 'action.update'
|
|
84
|
+
case 'delete':
|
|
85
|
+
return 'action.delete'
|
|
86
|
+
default:
|
|
87
|
+
return 'action.sent'
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
function toCreate() {
|
|
92
|
+
actionButtonEnable.value = true
|
|
93
|
+
dialogMode.value = 'create';
|
|
94
|
+
dialogTitle.value = 'user.creating';
|
|
95
|
+
createForm.value = {name: "", username: "", password: "", email: "", phone: "", role: "", active: true}
|
|
96
|
+
dialog.value = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function toEdit(item: IUser) {
|
|
100
|
+
actionButtonEnable.value = true
|
|
101
|
+
dialogMode.value = 'edit';
|
|
102
|
+
dialogTitle.value = 'user.updating';
|
|
103
|
+
const {id, ...rest} = item;
|
|
104
|
+
targetId.value = id;
|
|
105
|
+
rest.role = rest.role ? rest.role.id : null
|
|
106
|
+
editForm.value = {...rest}
|
|
107
|
+
dialog.value = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function toDelete(item: IUser) {
|
|
111
|
+
actionButtonEnable.value = true
|
|
112
|
+
dialogMode.value = 'delete';
|
|
113
|
+
dialogTitle.value = 'user.deleting';
|
|
114
|
+
target.value = item
|
|
115
|
+
const {id} = item;
|
|
116
|
+
targetId.value = id;
|
|
117
|
+
dialog.value = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function toChangePassword(item: IUser) {
|
|
121
|
+
actionButtonEnable.value = true
|
|
122
|
+
dialogMode.value = 'changePassword';
|
|
123
|
+
dialogTitle.value = 'user.changingPassword';
|
|
124
|
+
target.value = item
|
|
125
|
+
const {id} = item;
|
|
126
|
+
targetId.value = id;
|
|
127
|
+
dialog.value = true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<template>
|
|
134
|
+
<v-container>
|
|
135
|
+
|
|
136
|
+
<v-sheet border rounded>
|
|
137
|
+
<v-toolbar>
|
|
138
|
+
<v-toolbar-title>{{ $t('user.managing') }}</v-toolbar-title>
|
|
139
|
+
<v-spacer></v-spacer>
|
|
140
|
+
<v-btn icon @click="filterEnable = !filterEnable">
|
|
141
|
+
<v-icon>{{ filterEnable ? 'mdi-filter' : 'mdi-filter-off' }}</v-icon>
|
|
142
|
+
</v-btn>
|
|
143
|
+
<v-btn color="primary" @click="toCreate">
|
|
144
|
+
{{$t('action.create') }}
|
|
145
|
+
</v-btn>
|
|
146
|
+
</v-toolbar>
|
|
147
|
+
<v-theme-provider with-background class="pa-2 rounded-b">
|
|
148
|
+
<UserList
|
|
149
|
+
ref="userList"
|
|
150
|
+
@toEdit="toEdit"
|
|
151
|
+
@toDelete="toDelete"
|
|
152
|
+
@toChangePassword="toChangePassword"
|
|
153
|
+
:filterEnable="filterEnable"
|
|
154
|
+
/>
|
|
155
|
+
</v-theme-provider>
|
|
156
|
+
</v-sheet>
|
|
157
|
+
|
|
158
|
+
<v-dialog v-model="dialog" max-width="800">
|
|
159
|
+
<v-sheet border>
|
|
160
|
+
<v-toolbar>
|
|
161
|
+
<v-toolbar-title>{{ $t(dialogTitle) }}</v-toolbar-title>
|
|
162
|
+
</v-toolbar>
|
|
163
|
+
<v-card class="pa-10">
|
|
164
|
+
<v-card-text v-if="userError">
|
|
165
|
+
<v-alert type="error">{{ userError }}</v-alert>
|
|
166
|
+
</v-card-text>
|
|
167
|
+
<v-card-text>
|
|
168
|
+
<UserCreateForm
|
|
169
|
+
v-if="dialogMode === 'create'"
|
|
170
|
+
v-model="createForm"
|
|
171
|
+
:inputErrors="inputErrors"
|
|
172
|
+
/>
|
|
173
|
+
|
|
174
|
+
<UserEditForm
|
|
175
|
+
v-if="dialogMode === 'edit'"
|
|
176
|
+
v-model="editForm"
|
|
177
|
+
:inputErrors="inputErrors"
|
|
178
|
+
/>
|
|
179
|
+
|
|
180
|
+
<UserView v-if="dialogMode === 'delete'
|
|
181
|
+
&& target" :user="target"
|
|
182
|
+
/>
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
<UserPasswordForm
|
|
186
|
+
v-if="dialogMode === 'changePassword'&& target"
|
|
187
|
+
v-model="passwordForm"
|
|
188
|
+
:inputErrors="inputErrors"
|
|
189
|
+
:passwordChanged="passwordChanged"
|
|
190
|
+
/>
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
</v-card-text>
|
|
194
|
+
<v-card-actions>
|
|
195
|
+
<v-spacer></v-spacer>
|
|
196
|
+
<v-btn
|
|
197
|
+
variant="text"
|
|
198
|
+
@click="cancel"
|
|
199
|
+
:loading="loading">
|
|
200
|
+
{{ actionButtonEnable ? $t('action.cancel') : $t('action.close') }}
|
|
201
|
+
</v-btn>
|
|
202
|
+
<v-btn
|
|
203
|
+
v-if="actionButtonEnable"
|
|
204
|
+
variant="flat"
|
|
205
|
+
:color="dialogMode==='delete' ? 'red' : 'primary'"
|
|
206
|
+
@click="save"
|
|
207
|
+
:loading="loading"
|
|
208
|
+
>
|
|
209
|
+
{{ $t(buttonText) }}
|
|
210
|
+
</v-btn>
|
|
211
|
+
</v-card-actions>
|
|
212
|
+
|
|
213
|
+
</v-card>
|
|
214
|
+
</v-sheet>
|
|
215
|
+
</v-dialog>
|
|
216
|
+
|
|
217
|
+
</v-container>
|
|
218
|
+
</template>
|
|
219
|
+
|
|
220
|
+
<style scoped>
|
|
221
|
+
|
|
222
|
+
</style>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import {ref, defineProps} from "vue";
|
|
4
|
+
import {useUser} from "../../composables/useUser";
|
|
5
|
+
import {useAuth} from "../../composables/useAuth";
|
|
6
|
+
import {useI18n} from "vue-i18n";
|
|
7
|
+
|
|
8
|
+
const {hasPermission} = useAuth()
|
|
9
|
+
const {paginateUser} = useUser()
|
|
10
|
+
const {t} = useI18n()
|
|
11
|
+
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
filterEnable: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false,
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const itemsPerPage = ref(5)
|
|
20
|
+
const page = ref(1)
|
|
21
|
+
const headers = ref([
|
|
22
|
+
//{title: 'ID', align: 'start', sortable: false, key: 'id'},
|
|
23
|
+
{ title: t('user.name'), key: 'name', align: 'start' },
|
|
24
|
+
{ title: t('user.username'), key: 'username', align: 'start' },
|
|
25
|
+
{ title: t('user.email'), key: 'email', align: 'start' },
|
|
26
|
+
{ title: t('user.role'), key: 'role.name', align: 'start' },
|
|
27
|
+
{ title: t('user.active'), key: 'active', align: 'start' },
|
|
28
|
+
{ title: '', key: 'actions', align: 'start', fixed:true },
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
const serverItems = ref([])
|
|
32
|
+
const totalItems = ref(0)
|
|
33
|
+
const loading = ref(false)
|
|
34
|
+
const search = ref('')
|
|
35
|
+
|
|
36
|
+
async function loadItems(){
|
|
37
|
+
try{
|
|
38
|
+
loading.value = true
|
|
39
|
+
const r = await paginateUser(page.value,itemsPerPage.value, search.value)
|
|
40
|
+
serverItems.value = r.items
|
|
41
|
+
totalItems.value = r.total
|
|
42
|
+
}catch (e){
|
|
43
|
+
console.error(e)
|
|
44
|
+
}finally {
|
|
45
|
+
loading.value = false
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
defineExpose({
|
|
52
|
+
loadItems
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<template>
|
|
58
|
+
<v-data-table-server
|
|
59
|
+
v-if="hasPermission('user:manage')"
|
|
60
|
+
v-model:items-per-page="itemsPerPage"
|
|
61
|
+
v-model:page="page"
|
|
62
|
+
:headers="headers"
|
|
63
|
+
:items="serverItems"
|
|
64
|
+
:items-length="totalItems"
|
|
65
|
+
:loading="loading"
|
|
66
|
+
:search="search"
|
|
67
|
+
item-value="name"
|
|
68
|
+
@update:options="loadItems"
|
|
69
|
+
>
|
|
70
|
+
<template v-slot:top>
|
|
71
|
+
<v-toolbar border density="compact" v-if="filterEnable" class="grey-lighten-1">
|
|
72
|
+
<v-toolbar-title>{{ $t('action.filter') }}</v-toolbar-title>
|
|
73
|
+
<v-spacer></v-spacer>
|
|
74
|
+
<v-text-field v-model="search" hide-details
|
|
75
|
+
density="compact" class="mr-2"
|
|
76
|
+
variant="outlined"
|
|
77
|
+
append-inner-icon="mdi-magnify"
|
|
78
|
+
:label="$t('action.search')"
|
|
79
|
+
single-line clearable @click:clear="() => search = ''"
|
|
80
|
+
/>
|
|
81
|
+
</v-toolbar>
|
|
82
|
+
</template>
|
|
83
|
+
<template v-slot:item.active="{ value }" >
|
|
84
|
+
<v-chip :color="value ? 'green':'red'" >
|
|
85
|
+
{{ value ? 'Active' : 'Inactive' }}
|
|
86
|
+
</v-chip>
|
|
87
|
+
</template>
|
|
88
|
+
|
|
89
|
+
<template v-slot:item.actions="{item}" >
|
|
90
|
+
<v-btn v-if="hasPermission('user:update')" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
|
|
91
|
+
<v-btn v-if="hasPermission('user:update')" icon="mdi-lock" variant="text" color="orange" @click="$emit('toChangePassword', item)"></v-btn>
|
|
92
|
+
<v-btn v-if="hasPermission('user:delete')" icon="mdi-delete" class="mr-1" variant="text" color="red" @click="$emit('toDelete', item)"></v-btn>
|
|
93
|
+
</template>
|
|
94
|
+
|
|
95
|
+
</v-data-table-server>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<style scoped>
|
|
99
|
+
|
|
100
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {defineModel, type PropType} from "vue";
|
|
3
|
+
import type {IRole} from "@drax/identity-front";
|
|
4
|
+
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
5
|
+
import type {IClientInputError} from "@drax/common-front";
|
|
6
|
+
import PermissionSelector from "../components/PermissionSelector/PermissionSelector.vue";
|
|
7
|
+
|
|
8
|
+
const {$ta} = useI18nValidation()
|
|
9
|
+
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
inputErrors: {
|
|
12
|
+
type: Object as PropType<IClientInputError>,
|
|
13
|
+
default: () => ({name: "", permissions: "", readonly: ""})
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const form = defineModel<IRole>({
|
|
18
|
+
type: Object,
|
|
19
|
+
default: () => ({name: "", permissions: [], readonly: false})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<form>
|
|
26
|
+
<v-text-field
|
|
27
|
+
variant="outlined"
|
|
28
|
+
id="name-input"
|
|
29
|
+
label="Name"
|
|
30
|
+
v-model="form.name"
|
|
31
|
+
prepend-inner-icon="mdi-card-account-details"
|
|
32
|
+
required
|
|
33
|
+
:error-messages="$ta(inputErrors.name)"
|
|
34
|
+
></v-text-field>
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<PermissionSelector v-model="form.permissions"></PermissionSelector>
|
|
38
|
+
|
|
39
|
+
</form>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<style scoped>
|
|
43
|
+
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {ref, defineModel, type PropType} from "vue";
|
|
3
|
+
import RoleCombobox from "../combobox/RoleCombobox.vue";
|
|
4
|
+
import type {IClientInputError} from "@drax/common-front";
|
|
5
|
+
import type {IUserCreate} from "@drax/identity-front/src/interfaces/IUser";
|
|
6
|
+
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
7
|
+
|
|
8
|
+
const {$ta} = useI18nValidation()
|
|
9
|
+
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
inputErrors: {
|
|
12
|
+
type: Object as PropType<IClientInputError>,
|
|
13
|
+
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", active: ""})
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const form = defineModel<IUserCreate>({
|
|
18
|
+
type: Object,
|
|
19
|
+
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", active: true})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
let passwordVisibility = ref(false)
|
|
23
|
+
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<form>
|
|
28
|
+
|
|
29
|
+
<v-text-field
|
|
30
|
+
variant="outlined"
|
|
31
|
+
id="name-input"
|
|
32
|
+
label="Name"
|
|
33
|
+
v-model="form.name"
|
|
34
|
+
prepend-inner-icon="mdi-card-account-details"
|
|
35
|
+
required
|
|
36
|
+
:error-messages="$ta(inputErrors.name)"
|
|
37
|
+
></v-text-field>
|
|
38
|
+
|
|
39
|
+
<v-text-field
|
|
40
|
+
variant="outlined"
|
|
41
|
+
id="username-input"
|
|
42
|
+
label="Username"
|
|
43
|
+
v-model="form.username"
|
|
44
|
+
prepend-inner-icon="mdi-account-question"
|
|
45
|
+
required
|
|
46
|
+
autocomplete="new-username"
|
|
47
|
+
:error-messages="$ta(inputErrors.username)"
|
|
48
|
+
></v-text-field>
|
|
49
|
+
<v-text-field
|
|
50
|
+
variant="outlined"
|
|
51
|
+
id="password-input"
|
|
52
|
+
label="Password"
|
|
53
|
+
v-model="form.password"
|
|
54
|
+
:type="passwordVisibility ? 'text': 'password'"
|
|
55
|
+
required
|
|
56
|
+
prepend-inner-icon="mdi-lock-outline"
|
|
57
|
+
:append-inner-icon="passwordVisibility ? 'mdi-eye-off': 'mdi-eye'"
|
|
58
|
+
@click:append-inner="passwordVisibility = !passwordVisibility"
|
|
59
|
+
autocomplete="new-password"
|
|
60
|
+
:error-messages="$ta(inputErrors.password)"
|
|
61
|
+
></v-text-field>
|
|
62
|
+
|
|
63
|
+
<RoleCombobox
|
|
64
|
+
v-model="form.role"
|
|
65
|
+
:error-messages="$ta(inputErrors.role)"
|
|
66
|
+
></RoleCombobox>
|
|
67
|
+
|
|
68
|
+
<v-text-field
|
|
69
|
+
v-model="form.email"
|
|
70
|
+
variant="outlined"
|
|
71
|
+
id="email-input"
|
|
72
|
+
label="Email"
|
|
73
|
+
prepend-inner-icon="mdi-email"
|
|
74
|
+
required
|
|
75
|
+
:error-messages="$ta(inputErrors.email)"
|
|
76
|
+
></v-text-field>
|
|
77
|
+
|
|
78
|
+
<v-text-field
|
|
79
|
+
v-model="form.phone"
|
|
80
|
+
variant="outlined"
|
|
81
|
+
id="phone-input"
|
|
82
|
+
label="Phone"
|
|
83
|
+
prepend-inner-icon="mdi-phone"
|
|
84
|
+
required
|
|
85
|
+
:error-messages="$ta(inputErrors.phone)"
|
|
86
|
+
></v-text-field>
|
|
87
|
+
|
|
88
|
+
<v-switch
|
|
89
|
+
id="active-input"
|
|
90
|
+
v-model="form.active"
|
|
91
|
+
color="primary"
|
|
92
|
+
label="Active"
|
|
93
|
+
:true-value="true"
|
|
94
|
+
:false-value="false"
|
|
95
|
+
></v-switch>
|
|
96
|
+
</form>
|
|
97
|
+
</template>
|
|
98
|
+
|
|
99
|
+
<style scoped>
|
|
100
|
+
|
|
101
|
+
</style>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {ref, defineModel, type PropType} from "vue";
|
|
3
|
+
import RoleCombobox from "../combobox/RoleCombobox.vue";
|
|
4
|
+
import type {IClientInputError} from "@drax/common-front";
|
|
5
|
+
import type {IUserUpdate} from "@drax/identity-front/src/interfaces/IUser";
|
|
6
|
+
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
7
|
+
const {$ta} = useI18nValidation()
|
|
8
|
+
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
inputErrors: {
|
|
11
|
+
type: Object as PropType<IClientInputError>,
|
|
12
|
+
default: () => ({name: "", username: "", email: "", phone: "", role: "", active: ""})
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const form = defineModel<IUserUpdate>({
|
|
17
|
+
type: Object,
|
|
18
|
+
default: () => ({name: "", username: "", email: "", phone: "", role: "", active: true})
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<form>
|
|
26
|
+
<v-sheet>
|
|
27
|
+
</v-sheet>
|
|
28
|
+
|
|
29
|
+
<v-text-field
|
|
30
|
+
variant="outlined"
|
|
31
|
+
id="name-input"
|
|
32
|
+
label="Name"
|
|
33
|
+
v-model="form.name"
|
|
34
|
+
prepend-inner-icon="mdi-card-account-details"
|
|
35
|
+
required
|
|
36
|
+
:error-messages="$ta(inputErrors.name)"
|
|
37
|
+
></v-text-field>
|
|
38
|
+
<v-text-field
|
|
39
|
+
variant="outlined"
|
|
40
|
+
id="username-input"
|
|
41
|
+
label="Username"
|
|
42
|
+
v-model="form.username"
|
|
43
|
+
prepend-inner-icon="mdi-account-question"
|
|
44
|
+
required
|
|
45
|
+
:error-messages="$ta(inputErrors.username)"
|
|
46
|
+
autocomplete="new-username"
|
|
47
|
+
></v-text-field>
|
|
48
|
+
|
|
49
|
+
<RoleCombobox
|
|
50
|
+
v-model="form.role"
|
|
51
|
+
:error-messages="$ta(inputErrors.role)"
|
|
52
|
+
></RoleCombobox>
|
|
53
|
+
|
|
54
|
+
<v-text-field
|
|
55
|
+
v-model="form.email"
|
|
56
|
+
variant="outlined"
|
|
57
|
+
id="email-input"
|
|
58
|
+
label="Email"
|
|
59
|
+
prepend-inner-icon="mdi-email"
|
|
60
|
+
required
|
|
61
|
+
:error-messages="$ta(inputErrors.email)"
|
|
62
|
+
></v-text-field>
|
|
63
|
+
|
|
64
|
+
<v-text-field
|
|
65
|
+
v-model="form.phone"
|
|
66
|
+
variant="outlined"
|
|
67
|
+
id="phone-input"
|
|
68
|
+
label="Phone"
|
|
69
|
+
prepend-inner-icon="mdi-phone"
|
|
70
|
+
required
|
|
71
|
+
:error-messages="$ta(inputErrors.phone)"
|
|
72
|
+
></v-text-field>
|
|
73
|
+
|
|
74
|
+
<v-switch
|
|
75
|
+
id="active-input"
|
|
76
|
+
v-model="form.active"
|
|
77
|
+
color="primary"
|
|
78
|
+
label="Active"
|
|
79
|
+
:true-value="true"
|
|
80
|
+
:false-value="false"
|
|
81
|
+
></v-switch>
|
|
82
|
+
</form>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<style scoped>
|
|
86
|
+
|
|
87
|
+
</style>
|