@drax/identity-vue 0.0.15 → 0.0.17
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/package.json +3 -3
- package/src/combobox/RoleCombobox.vue +10 -0
- package/src/combobox/TenantCombobox.vue +37 -0
- package/src/components/PermissionSelector/PermissionSelector.vue +5 -2
- package/src/composables/useTenant.ts +86 -0
- package/src/cruds/role-crud/RoleCrud.vue +6 -5
- package/src/cruds/role-crud/RoleList.vue +13 -3
- package/src/cruds/tenant-crud/TenantCrud.vue +166 -0
- package/src/cruds/tenant-crud/TenantList.vue +92 -0
- package/src/cruds/user-crud/UserCrud.vue +9 -5
- package/src/cruds/user-crud/UserList.vue +2 -1
- package/src/forms/RoleForm.vue +14 -1
- package/src/forms/TenantForm.vue +48 -0
- package/src/forms/UserCreateForm.vue +16 -3
- package/src/forms/UserEditForm.vue +17 -4
- package/src/forms/UserPasswordForm.vue +7 -1
- package/src/index.ts +30 -13
- package/src/pages/TenantCrudPage.vue +12 -0
- package/src/views/TenantView.vue +24 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.17",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./src/index.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"format": "prettier --write src/"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@drax/common-front": "^0.0.
|
|
27
|
+
"@drax/common-front": "^0.0.17",
|
|
28
28
|
"vue-i18n": "^9.13.1"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"vue-tsc": "^2.0.11",
|
|
62
62
|
"vuetify": "^3.6.4"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "10c296881a942de671414c7494afecb7c2614e7d"
|
|
65
65
|
}
|
|
@@ -5,6 +5,14 @@ import type { PropType } from 'vue'
|
|
|
5
5
|
const props = defineProps({
|
|
6
6
|
errorMessages: {
|
|
7
7
|
type: String as PropType<string | string[] | undefined>,
|
|
8
|
+
},
|
|
9
|
+
multiple:{
|
|
10
|
+
type: Boolean,
|
|
11
|
+
default: false,
|
|
12
|
+
},
|
|
13
|
+
clearable:{
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false,
|
|
8
16
|
}
|
|
9
17
|
})
|
|
10
18
|
|
|
@@ -29,6 +37,8 @@ onMounted(async () => {
|
|
|
29
37
|
item-value="id"
|
|
30
38
|
variant="outlined"
|
|
31
39
|
:error-messages="errorMessages"
|
|
40
|
+
:multiple="multiple"
|
|
41
|
+
:clearable="clearable"
|
|
32
42
|
></v-select>
|
|
33
43
|
</template>
|
|
34
44
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import {ref, onMounted, defineModel} from 'vue'
|
|
4
|
+
import type { PropType } from 'vue'
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
errorMessages: {
|
|
7
|
+
type: String as PropType<string | string[] | undefined>,
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const model = defineModel()
|
|
12
|
+
import {useTenant} from "../composables/useTenant";
|
|
13
|
+
const {fetchTenant} = useTenant()
|
|
14
|
+
let items = ref([])
|
|
15
|
+
|
|
16
|
+
onMounted(async () => {
|
|
17
|
+
items.value = await fetchTenant()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<v-select
|
|
25
|
+
v-model="model"
|
|
26
|
+
label="Tenant"
|
|
27
|
+
:items="items"
|
|
28
|
+
item-title="name"
|
|
29
|
+
item-value="id"
|
|
30
|
+
variant="outlined"
|
|
31
|
+
:error-messages="errorMessages"
|
|
32
|
+
></v-select>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style scoped>
|
|
36
|
+
|
|
37
|
+
</style>
|
|
@@ -69,12 +69,15 @@ const permissionGroups = computed(() => {
|
|
|
69
69
|
v-slot="{ isSelected, toggle }"
|
|
70
70
|
:value="permission"
|
|
71
71
|
>
|
|
72
|
-
|
|
72
|
+
|
|
73
|
+
<v-chip
|
|
73
74
|
:color="isSelected? 'green' : 'grey-darken-3'" class=""
|
|
74
75
|
@click="toggle" variant="flat" :rounded="false" border
|
|
75
76
|
>
|
|
76
77
|
{{ $t ? $t('permission.'+permission) : permission }}
|
|
77
|
-
</v-
|
|
78
|
+
</v-chip>
|
|
79
|
+
|
|
80
|
+
|
|
78
81
|
</v-item>
|
|
79
82
|
</v-card-text>
|
|
80
83
|
</v-card>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {inject, ref} from "vue";
|
|
2
|
+
import type {ITenant, TenantSystem} from "@drax/identity-front";
|
|
3
|
+
import {ClientError} from "@drax/common-front";
|
|
4
|
+
import type { IClientInputError} from "@drax/common-front";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export function useTenant() {
|
|
8
|
+
|
|
9
|
+
const tenantSystem = inject('TenantSystem') as TenantSystem
|
|
10
|
+
|
|
11
|
+
let tenantError = ref<string>('')
|
|
12
|
+
let inputErrors = ref<IClientInputError>()
|
|
13
|
+
let loading = ref(false);
|
|
14
|
+
|
|
15
|
+
async function fetchTenant(page = 1, perPage = 5) {
|
|
16
|
+
loading.value = true
|
|
17
|
+
let tenants = tenantSystem.fetchTenant()
|
|
18
|
+
loading.value = false
|
|
19
|
+
return tenants
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function paginateTenant(page = 1, perPage = 5, string = "") {
|
|
23
|
+
loading.value = true
|
|
24
|
+
let paginatedtenant = tenantSystem.paginateTenant(page, perPage,string)
|
|
25
|
+
loading.value = false
|
|
26
|
+
return paginatedtenant
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function createTenant(tenantData: ITenant) {
|
|
30
|
+
try {
|
|
31
|
+
loading.value = true
|
|
32
|
+
let tenant: ITenant = await tenantSystem.createTenant(tenantData)
|
|
33
|
+
return tenant
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (err instanceof ClientError) {
|
|
36
|
+
inputErrors.value = err.inputErrors
|
|
37
|
+
}if(err instanceof Error) {
|
|
38
|
+
tenantError.value = err.message
|
|
39
|
+
}
|
|
40
|
+
throw err
|
|
41
|
+
}finally {
|
|
42
|
+
loading.value = false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function editTenant(id: string, tenantData: ITenant) {
|
|
48
|
+
try {
|
|
49
|
+
loading.value = true
|
|
50
|
+
let tenant: ITenant = await tenantSystem.editTenant(id, tenantData)
|
|
51
|
+
return tenant
|
|
52
|
+
} catch (err) {
|
|
53
|
+
|
|
54
|
+
if (err instanceof ClientError) {
|
|
55
|
+
inputErrors.value = err.inputErrors
|
|
56
|
+
}
|
|
57
|
+
if(err instanceof Error) {
|
|
58
|
+
tenantError.value = err.message
|
|
59
|
+
}
|
|
60
|
+
throw err
|
|
61
|
+
}finally {
|
|
62
|
+
loading.value = false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function deleteTenant(id: string) {
|
|
67
|
+
try {
|
|
68
|
+
loading.value = true
|
|
69
|
+
await tenantSystem.deleteTenant(id)
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.log("composable deleteTenant error: ", err, )
|
|
72
|
+
if (err instanceof ClientError) {
|
|
73
|
+
inputErrors.value = err.inputErrors
|
|
74
|
+
}
|
|
75
|
+
if(err instanceof Error) {
|
|
76
|
+
tenantError.value = err.message
|
|
77
|
+
}
|
|
78
|
+
throw err
|
|
79
|
+
}finally {
|
|
80
|
+
loading.value = false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {fetchTenant, paginateTenant, createTenant, editTenant, deleteTenant, loading, tenantError, inputErrors}
|
|
85
|
+
|
|
86
|
+
}
|
|
@@ -20,7 +20,7 @@ let dialog = ref(false);
|
|
|
20
20
|
let dialogMode = ref<DialogMode>(null);
|
|
21
21
|
let dialogTitle = ref('');
|
|
22
22
|
const roleList = ref<RoleList | null>(null);
|
|
23
|
-
let form = ref<IRole>({name: "", permissions: [], readonly: false})
|
|
23
|
+
let form = ref<IRole>({name: "", permissions: [], childRoles:[], readonly: false})
|
|
24
24
|
let target = ref<IRole>();
|
|
25
25
|
let targetId = ref<string>('');
|
|
26
26
|
let filterEnable = ref(false);
|
|
@@ -75,15 +75,15 @@ let buttonText = computed(() => {
|
|
|
75
75
|
function toCreate() {
|
|
76
76
|
dialogMode.value = 'create';
|
|
77
77
|
dialogTitle.value = 'role.creating';
|
|
78
|
-
form.value = {name: "", permissions: [], readonly: false}
|
|
78
|
+
form.value = {name: "", permissions: [], childRoles:[], readonly: false}
|
|
79
79
|
dialog.value = true;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
function toEdit(item: IRole) {
|
|
83
|
-
console.log('toEdit', item)
|
|
84
83
|
dialogMode.value = 'edit';
|
|
85
84
|
dialogTitle.value = 'role.updating';
|
|
86
85
|
const {id, ...rest} = item;
|
|
86
|
+
rest.childRoles = rest.childRoles ? rest.childRoles.map(c => c.id) : []
|
|
87
87
|
targetId.value = id;
|
|
88
88
|
form.value = {...rest}
|
|
89
89
|
dialog.value = true;
|
|
@@ -102,7 +102,7 @@ function toDelete(item: IRole) {
|
|
|
102
102
|
</script>
|
|
103
103
|
|
|
104
104
|
<template>
|
|
105
|
-
<v-container>
|
|
105
|
+
<v-container fluid>
|
|
106
106
|
|
|
107
107
|
<v-sheet border rounded>
|
|
108
108
|
<v-toolbar>
|
|
@@ -128,7 +128,7 @@ function toDelete(item: IRole) {
|
|
|
128
128
|
<v-dialog v-model="dialog" max-width="800">
|
|
129
129
|
<v-sheet border>
|
|
130
130
|
<v-toolbar>
|
|
131
|
-
<v-toolbar-title>{{ $t(dialogTitle) }}</v-toolbar-title>
|
|
131
|
+
<v-toolbar-title>{{ dialogTitle ? $t(dialogTitle) : '-' }}</v-toolbar-title>
|
|
132
132
|
</v-toolbar>
|
|
133
133
|
<v-card class="pa-10">
|
|
134
134
|
<v-card-text v-if="roleError">
|
|
@@ -138,6 +138,7 @@ function toDelete(item: IRole) {
|
|
|
138
138
|
<RoleForm v-if="dialogMode === 'create' || dialogMode === 'edit'"
|
|
139
139
|
v-model="form"
|
|
140
140
|
:inputErrors="inputErrors"
|
|
141
|
+
@formSubmit="save"
|
|
141
142
|
/>
|
|
142
143
|
<RoleView v-if="dialogMode === 'delete' && target" :role="target"></RoleView>
|
|
143
144
|
</v-card-text>
|
|
@@ -21,9 +21,10 @@ const page = ref(1)
|
|
|
21
21
|
const headers = ref([
|
|
22
22
|
//{title: 'ID', align: 'start', sortable: false, key: 'id'},
|
|
23
23
|
{ title: t('role.name'), key: 'name', align: 'start' },
|
|
24
|
+
{ title: t('role.childRoles'), key: 'childRoles', align: 'start' },
|
|
24
25
|
{ title: t('role.permissions'), key: 'permissions', align: 'start' },
|
|
25
26
|
{ title: t('role.readonly'), key: 'readonly', align: 'start' },
|
|
26
|
-
{ title: '', key: 'actions', align: '
|
|
27
|
+
{ title: '', key: 'actions', align: 'end', minWidth: '150px' },
|
|
27
28
|
])
|
|
28
29
|
|
|
29
30
|
const serverItems = ref([])
|
|
@@ -88,6 +89,15 @@ defineExpose({
|
|
|
88
89
|
</v-chip>
|
|
89
90
|
</template>
|
|
90
91
|
|
|
92
|
+
<template v-slot:item.childRoles="{ value }" >
|
|
93
|
+
<v-chip v-for="role in value"
|
|
94
|
+
:key="role" color="blue"
|
|
95
|
+
class="ma-1"
|
|
96
|
+
>
|
|
97
|
+
{{role.name}}
|
|
98
|
+
</v-chip>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
91
101
|
<template v-slot:item.readonly="{ value }" >
|
|
92
102
|
<v-chip v-if="value" color="red" >
|
|
93
103
|
<v-icon class="mdi mdi-pencil-off-outline"></v-icon>
|
|
@@ -98,8 +108,8 @@ defineExpose({
|
|
|
98
108
|
</template>
|
|
99
109
|
|
|
100
110
|
<template v-slot:item.actions="{item}" >
|
|
101
|
-
<v-btn v-if="hasPermission('
|
|
102
|
-
<v-btn v-if="hasPermission('
|
|
111
|
+
<v-btn v-if="hasPermission('role:update')" :disabled="!!item.readonly" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
|
|
112
|
+
<v-btn v-if="hasPermission('role:delete')" :disabled="!!item.readonly" icon="mdi-delete" class="mr-1" variant="text" color="red" @click="$emit('toDelete', item)"></v-btn>
|
|
103
113
|
</template>
|
|
104
114
|
|
|
105
115
|
</v-data-table-server>
|
|
@@ -0,0 +1,166 @@
|
|
|
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} from "@drax/identity-front";
|
|
6
|
+
import TenantForm from "../../forms/TenantForm.vue";
|
|
7
|
+
import TenantView from "../../views/TenantView.vue";
|
|
8
|
+
|
|
9
|
+
const {createTenant, editTenant, deleteTenant, loading, tenantError, inputErrors} = useTenant()
|
|
10
|
+
|
|
11
|
+
interface TenantList {
|
|
12
|
+
loadItems: () => void;
|
|
13
|
+
items: ITenant[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type DialogMode = 'create' | 'edit' | 'delete' | null;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
let dialog = ref(false);
|
|
20
|
+
let dialogMode = ref<DialogMode>(null);
|
|
21
|
+
let dialogTitle = ref('');
|
|
22
|
+
const tenantList = ref<TenantList | null>(null);
|
|
23
|
+
let form = ref<ITenant>({name: ""})
|
|
24
|
+
let target = ref<ITenant>();
|
|
25
|
+
let targetId = ref<string>('');
|
|
26
|
+
let filterEnable = ref(false);
|
|
27
|
+
|
|
28
|
+
function cancel() {
|
|
29
|
+
dialog.value = false
|
|
30
|
+
inputErrors.value = {}
|
|
31
|
+
tenantError.value = '';
|
|
32
|
+
dialogMode.value = null
|
|
33
|
+
dialogTitle.value = ''
|
|
34
|
+
targetId.value = ''
|
|
35
|
+
target.value = undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function save() {
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
if (dialogMode.value === 'create') {
|
|
42
|
+
await createTenant(form.value)
|
|
43
|
+
} else if (dialogMode.value === 'edit') {
|
|
44
|
+
await editTenant(targetId.value, form.value)
|
|
45
|
+
} else if (dialogMode.value === 'delete') {
|
|
46
|
+
await deleteTenant(targetId.value)
|
|
47
|
+
}
|
|
48
|
+
dialog.value = false
|
|
49
|
+
inputErrors.value = {}
|
|
50
|
+
tenantError.value = '';
|
|
51
|
+
if (tenantList.value !== null) {
|
|
52
|
+
tenantList.value.loadItems()
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.error(e)
|
|
56
|
+
if (e instanceof Error) {
|
|
57
|
+
tenantError.value = e.message
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let buttonText = computed(() => {
|
|
63
|
+
switch (dialogMode.value) {
|
|
64
|
+
case 'create':
|
|
65
|
+
return 'action.create'
|
|
66
|
+
case 'edit':
|
|
67
|
+
return 'action.update'
|
|
68
|
+
case 'delete':
|
|
69
|
+
return 'action.delete'
|
|
70
|
+
default:
|
|
71
|
+
return 'action.sent'
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
function toCreate() {
|
|
76
|
+
dialogMode.value = 'create';
|
|
77
|
+
dialogTitle.value = 'tenant.creating';
|
|
78
|
+
form.value = {name: ""}
|
|
79
|
+
dialog.value = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function toEdit(item: ITenant) {
|
|
83
|
+
console.log('toEdit', item)
|
|
84
|
+
dialogMode.value = 'edit';
|
|
85
|
+
dialogTitle.value = 'tenant.updating';
|
|
86
|
+
const {id, ...rest} = item;
|
|
87
|
+
targetId.value = id;
|
|
88
|
+
form.value = {...rest}
|
|
89
|
+
dialog.value = true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function toDelete(item: ITenant) {
|
|
93
|
+
console.log('toDelete', item)
|
|
94
|
+
dialogMode.value = 'delete';
|
|
95
|
+
dialogTitle.value = 'tenant.deleting';
|
|
96
|
+
target.value = item
|
|
97
|
+
const {id} = item;
|
|
98
|
+
targetId.value = id;
|
|
99
|
+
dialog.value = true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<template>
|
|
105
|
+
<v-container fluid>
|
|
106
|
+
|
|
107
|
+
<v-sheet border rounded>
|
|
108
|
+
<v-toolbar>
|
|
109
|
+
<v-toolbar-title>{{ $t('tenant.managing') }}</v-toolbar-title>
|
|
110
|
+
<v-spacer></v-spacer>
|
|
111
|
+
<v-btn icon @click="filterEnable = !filterEnable">
|
|
112
|
+
<v-icon>{{ filterEnable ? 'mdi-filter' : 'mdi-filter-off' }}</v-icon>
|
|
113
|
+
</v-btn>
|
|
114
|
+
<v-btn color="primary" @click="toCreate">
|
|
115
|
+
{{ $t('action.create') }}
|
|
116
|
+
</v-btn>
|
|
117
|
+
</v-toolbar>
|
|
118
|
+
<v-theme-provider with-background class="pa-2 rounded-b">
|
|
119
|
+
<TenantList
|
|
120
|
+
ref="tenantList"
|
|
121
|
+
@toEdit="toEdit"
|
|
122
|
+
@toDelete="toDelete"
|
|
123
|
+
:filterEnable="filterEnable"
|
|
124
|
+
/>
|
|
125
|
+
</v-theme-provider>
|
|
126
|
+
</v-sheet>
|
|
127
|
+
|
|
128
|
+
<v-dialog v-model="dialog" max-width="800">
|
|
129
|
+
<v-sheet border>
|
|
130
|
+
<v-toolbar>
|
|
131
|
+
<v-toolbar-title>{{ dialogTitle ? $t(dialogTitle) : '-' }}</v-toolbar-title>
|
|
132
|
+
</v-toolbar>
|
|
133
|
+
<v-card class="pa-10">
|
|
134
|
+
<v-card-text v-if="tenantError">
|
|
135
|
+
<v-alert type="error">{{ tenantError }}</v-alert>
|
|
136
|
+
</v-card-text>
|
|
137
|
+
<v-card-text>
|
|
138
|
+
<TenantForm v-if="dialogMode === 'create' || dialogMode === 'edit'"
|
|
139
|
+
v-model="form"
|
|
140
|
+
:inputErrors="inputErrors"
|
|
141
|
+
@formSubmit="save"
|
|
142
|
+
/>
|
|
143
|
+
<TenantView v-if="dialogMode === 'delete' && target" :tenant="target"></TenantView>
|
|
144
|
+
</v-card-text>
|
|
145
|
+
<v-card-actions>
|
|
146
|
+
<v-spacer></v-spacer>
|
|
147
|
+
<v-btn variant="text" @click="cancel" :loading="loading">Cancelar</v-btn>
|
|
148
|
+
<v-btn variant="flat"
|
|
149
|
+
:color="dialogMode==='delete' ? 'red' : 'primary'"
|
|
150
|
+
@click="save"
|
|
151
|
+
:loading="loading"
|
|
152
|
+
>
|
|
153
|
+
{{ $t(buttonText) }}
|
|
154
|
+
</v-btn>
|
|
155
|
+
</v-card-actions>
|
|
156
|
+
|
|
157
|
+
</v-card>
|
|
158
|
+
</v-sheet>
|
|
159
|
+
</v-dialog>
|
|
160
|
+
|
|
161
|
+
</v-container>
|
|
162
|
+
</template>
|
|
163
|
+
|
|
164
|
+
<style scoped>
|
|
165
|
+
|
|
166
|
+
</style>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import {defineProps, ref} from "vue";
|
|
4
|
+
import {useTenant} from "../../composables/useTenant";
|
|
5
|
+
import {useAuth} from "../../composables/useAuth";
|
|
6
|
+
import {useI18n} from "vue-i18n";
|
|
7
|
+
|
|
8
|
+
const {hasPermission} = useAuth()
|
|
9
|
+
const {paginateTenant} = useTenant()
|
|
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('tenant.name'), key: 'name', align: 'start' },
|
|
24
|
+
{ title: '', key: 'actions', align: 'end', minWidth: '150px' },
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
const serverItems = ref([])
|
|
28
|
+
const totalItems = ref(0)
|
|
29
|
+
const loading = ref(false)
|
|
30
|
+
const search = ref('')
|
|
31
|
+
|
|
32
|
+
async function loadItems(){
|
|
33
|
+
try{
|
|
34
|
+
loading.value = true
|
|
35
|
+
const r = await paginateTenant(page.value,itemsPerPage.value, search.value)
|
|
36
|
+
serverItems.value = r.items
|
|
37
|
+
totalItems.value = r.total
|
|
38
|
+
}catch (e){
|
|
39
|
+
console.error(e)
|
|
40
|
+
}finally {
|
|
41
|
+
loading.value = false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
defineExpose({
|
|
48
|
+
loadItems
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<v-data-table-server
|
|
55
|
+
v-if="hasPermission('user:manage')"
|
|
56
|
+
v-model:items-per-page="itemsPerPage"
|
|
57
|
+
v-model:page="page"
|
|
58
|
+
:headers="headers"
|
|
59
|
+
:items="serverItems"
|
|
60
|
+
:items-length="totalItems"
|
|
61
|
+
:loading="loading"
|
|
62
|
+
:search="search"
|
|
63
|
+
item-value="name"
|
|
64
|
+
@update:options="loadItems"
|
|
65
|
+
>
|
|
66
|
+
<template v-slot:top>
|
|
67
|
+
<v-toolbar border density="compact" v-if="filterEnable" class="grey-lighten-1">
|
|
68
|
+
<v-toolbar-title>{{ $t('action.filter') }}</v-toolbar-title>
|
|
69
|
+
<v-spacer></v-spacer>
|
|
70
|
+
<v-text-field v-model="search" hide-details
|
|
71
|
+
density="compact" class="mr-2"
|
|
72
|
+
variant="outlined"
|
|
73
|
+
append-inner-icon="mdi-magnify"
|
|
74
|
+
:label="$t('action.search')"
|
|
75
|
+
single-line clearable @click:clear="() => search = ''"
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
</v-toolbar>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
<template v-slot:item.actions="{item}" >
|
|
83
|
+
<v-btn v-if="hasPermission('tenant:update')" :disabled="item.readonly" icon="mdi-pencil" variant="text" color="primary" @click="$emit('toEdit', item)"></v-btn>
|
|
84
|
+
<v-btn v-if="hasPermission('tenant:delete')" :disabled="item.readonly" icon="mdi-delete" class="mr-1" variant="text" color="red" @click="$emit('toDelete', item)"></v-btn>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
</v-data-table-server>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<style scoped>
|
|
91
|
+
|
|
92
|
+
</style>
|
|
@@ -23,8 +23,8 @@ let dialog = ref(false);
|
|
|
23
23
|
let dialogMode = ref<DialogMode>(null);
|
|
24
24
|
let dialogTitle = ref('');
|
|
25
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})
|
|
26
|
+
let createForm = ref<IUserCreate>({name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: true})
|
|
27
|
+
let editForm = ref<IUserUpdate>({name: "", username: "", email: "", phone: "", role: "", tenant: "", active: true})
|
|
28
28
|
let passwordForm = ref<IUserPassword>({newPassword: "", confirmPassword: ""})
|
|
29
29
|
let passwordChanged = ref(false);
|
|
30
30
|
let target = ref<IUser>();
|
|
@@ -92,7 +92,7 @@ function toCreate() {
|
|
|
92
92
|
actionButtonEnable.value = true
|
|
93
93
|
dialogMode.value = 'create';
|
|
94
94
|
dialogTitle.value = 'user.creating';
|
|
95
|
-
createForm.value = {name: "", username: "", password: "", email: "", phone: "", role: "", active: true}
|
|
95
|
+
createForm.value = {name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: true}
|
|
96
96
|
dialog.value = true;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -103,6 +103,7 @@ function toEdit(item: IUser) {
|
|
|
103
103
|
const {id, ...rest} = item;
|
|
104
104
|
targetId.value = id;
|
|
105
105
|
rest.role = rest.role ? rest.role.id : null
|
|
106
|
+
rest.tenant = rest.tenant ? rest.tenant.id : null
|
|
106
107
|
editForm.value = {...rest}
|
|
107
108
|
dialog.value = true;
|
|
108
109
|
}
|
|
@@ -131,7 +132,7 @@ function toChangePassword(item: IUser) {
|
|
|
131
132
|
</script>
|
|
132
133
|
|
|
133
134
|
<template>
|
|
134
|
-
<v-container>
|
|
135
|
+
<v-container fluid>
|
|
135
136
|
|
|
136
137
|
<v-sheet border rounded>
|
|
137
138
|
<v-toolbar>
|
|
@@ -158,7 +159,7 @@ function toChangePassword(item: IUser) {
|
|
|
158
159
|
<v-dialog v-model="dialog" max-width="800">
|
|
159
160
|
<v-sheet border>
|
|
160
161
|
<v-toolbar>
|
|
161
|
-
<v-toolbar-title>{{ $t(dialogTitle) }}</v-toolbar-title>
|
|
162
|
+
<v-toolbar-title>{{ dialogTitle ? $t(dialogTitle) : '-' }}</v-toolbar-title>
|
|
162
163
|
</v-toolbar>
|
|
163
164
|
<v-card class="pa-10">
|
|
164
165
|
<v-card-text v-if="userError">
|
|
@@ -169,12 +170,14 @@ function toChangePassword(item: IUser) {
|
|
|
169
170
|
v-if="dialogMode === 'create'"
|
|
170
171
|
v-model="createForm"
|
|
171
172
|
:inputErrors="inputErrors"
|
|
173
|
+
@formSubmit="save"
|
|
172
174
|
/>
|
|
173
175
|
|
|
174
176
|
<UserEditForm
|
|
175
177
|
v-if="dialogMode === 'edit'"
|
|
176
178
|
v-model="editForm"
|
|
177
179
|
:inputErrors="inputErrors"
|
|
180
|
+
@formSubmit="save"
|
|
178
181
|
/>
|
|
179
182
|
|
|
180
183
|
<UserView v-if="dialogMode === 'delete'
|
|
@@ -187,6 +190,7 @@ function toChangePassword(item: IUser) {
|
|
|
187
190
|
v-model="passwordForm"
|
|
188
191
|
:inputErrors="inputErrors"
|
|
189
192
|
:passwordChanged="passwordChanged"
|
|
193
|
+
@formSubmit="save"
|
|
190
194
|
/>
|
|
191
195
|
|
|
192
196
|
|
|
@@ -24,8 +24,9 @@ const headers = ref([
|
|
|
24
24
|
{ title: t('user.username'), key: 'username', align: 'start' },
|
|
25
25
|
{ title: t('user.email'), key: 'email', align: 'start' },
|
|
26
26
|
{ title: t('user.role'), key: 'role.name', align: 'start' },
|
|
27
|
+
{ title: t('user.tenant'), key: 'tenant.name', align: 'start' },
|
|
27
28
|
{ title: t('user.active'), key: 'active', align: 'start' },
|
|
28
|
-
{ title: '', key: 'actions', align: '
|
|
29
|
+
{ title: '', key: 'actions', align: 'end', fixed:true },
|
|
29
30
|
])
|
|
30
31
|
|
|
31
32
|
const serverItems = ref([])
|
package/src/forms/RoleForm.vue
CHANGED
|
@@ -4,6 +4,7 @@ import type {IRole} from "@drax/identity-front";
|
|
|
4
4
|
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
5
5
|
import type {IClientInputError} from "@drax/common-front";
|
|
6
6
|
import PermissionSelector from "../components/PermissionSelector/PermissionSelector.vue";
|
|
7
|
+
import RoleCombobox from "../combobox/RoleCombobox.vue";
|
|
7
8
|
|
|
8
9
|
const {$ta} = useI18nValidation()
|
|
9
10
|
|
|
@@ -19,10 +20,17 @@ const form = defineModel<IRole>({
|
|
|
19
20
|
default: () => ({name: "", permissions: [], readonly: false})
|
|
20
21
|
})
|
|
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
|
+
|
|
22
30
|
</script>
|
|
23
31
|
|
|
24
32
|
<template>
|
|
25
|
-
<form>
|
|
33
|
+
<form @submit.prevent="onSubmit">
|
|
26
34
|
<v-text-field
|
|
27
35
|
variant="outlined"
|
|
28
36
|
id="name-input"
|
|
@@ -33,6 +41,11 @@ const form = defineModel<IRole>({
|
|
|
33
41
|
:error-messages="$ta(inputErrors.name)"
|
|
34
42
|
></v-text-field>
|
|
35
43
|
|
|
44
|
+
<RoleCombobox
|
|
45
|
+
v-model="form.childRoles"
|
|
46
|
+
:error-messages="$ta(inputErrors.role)"
|
|
47
|
+
multiple
|
|
48
|
+
></RoleCombobox>
|
|
36
49
|
|
|
37
50
|
<PermissionSelector v-model="form.permissions"></PermissionSelector>
|
|
38
51
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {defineModel, type PropType} from "vue";
|
|
3
|
+
import type {ITenant} from "@drax/identity-front";
|
|
4
|
+
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
5
|
+
import type {IClientInputError} from "@drax/common-front";
|
|
6
|
+
|
|
7
|
+
const {$ta} = useI18nValidation()
|
|
8
|
+
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
inputErrors: {
|
|
11
|
+
type: Object as PropType<IClientInputError>,
|
|
12
|
+
default: () => ({name: ""})
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const form = defineModel<ITenant>({
|
|
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,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {ref, defineModel, type PropType} from "vue";
|
|
3
3
|
import RoleCombobox from "../combobox/RoleCombobox.vue";
|
|
4
|
+
import TenantCombobox from "../combobox/TenantCombobox.vue";
|
|
4
5
|
import type {IClientInputError} from "@drax/common-front";
|
|
5
6
|
import type {IUserCreate} from "@drax/identity-front/src/interfaces/IUser";
|
|
6
7
|
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
@@ -10,21 +11,28 @@ const {$ta} = useI18nValidation()
|
|
|
10
11
|
const props = defineProps({
|
|
11
12
|
inputErrors: {
|
|
12
13
|
type: Object as PropType<IClientInputError>,
|
|
13
|
-
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", active: ""})
|
|
14
|
+
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: ""})
|
|
14
15
|
}
|
|
15
16
|
})
|
|
16
17
|
|
|
17
18
|
const form = defineModel<IUserCreate>({
|
|
18
19
|
type: Object,
|
|
19
|
-
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", active: true})
|
|
20
|
+
default: () => ({name: "", username: "", password: "", email: "", phone: "", role: "", tenant: "", active: true})
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
let passwordVisibility = ref(false)
|
|
23
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
|
+
}
|
|
24
32
|
</script>
|
|
25
33
|
|
|
26
34
|
<template>
|
|
27
|
-
<form>
|
|
35
|
+
<form @submit.prevent="onSubmit">
|
|
28
36
|
|
|
29
37
|
<v-text-field
|
|
30
38
|
variant="outlined"
|
|
@@ -65,6 +73,11 @@ let passwordVisibility = ref(false)
|
|
|
65
73
|
:error-messages="$ta(inputErrors.role)"
|
|
66
74
|
></RoleCombobox>
|
|
67
75
|
|
|
76
|
+
<TenantCombobox
|
|
77
|
+
v-model="form.tenant"
|
|
78
|
+
:error-messages="$ta(inputErrors.tenant)"
|
|
79
|
+
></TenantCombobox>
|
|
80
|
+
|
|
68
81
|
<v-text-field
|
|
69
82
|
v-model="form.email"
|
|
70
83
|
variant="outlined"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {defineModel, type PropType} from "vue";
|
|
3
3
|
import RoleCombobox from "../combobox/RoleCombobox.vue";
|
|
4
|
+
import TenantCombobox from "../combobox/TenantCombobox.vue";
|
|
4
5
|
import type {IClientInputError} from "@drax/common-front";
|
|
5
6
|
import type {IUserUpdate} from "@drax/identity-front/src/interfaces/IUser";
|
|
6
7
|
import {useI18nValidation} from "../composables/useI18nValidation";
|
|
@@ -9,20 +10,27 @@ const {$ta} = useI18nValidation()
|
|
|
9
10
|
const props = defineProps({
|
|
10
11
|
inputErrors: {
|
|
11
12
|
type: Object as PropType<IClientInputError>,
|
|
12
|
-
default: () => ({name: "", username: "", email: "", phone: "", role: "", active: ""})
|
|
13
|
+
default: () => ({name: "", username: "", email: "", phone: "", role: "", tenant: "", active: ""})
|
|
13
14
|
}
|
|
14
15
|
})
|
|
15
16
|
|
|
16
17
|
const form = defineModel<IUserUpdate>({
|
|
17
18
|
type: Object,
|
|
18
|
-
default: () => ({name: "", username: "", email: "", phone: "", role: "", active: true})
|
|
19
|
+
default: () => ({name: "", username: "", email: "", phone: "", role: "", tenant: "", active: true})
|
|
19
20
|
})
|
|
20
21
|
|
|
22
|
+
// Define emits
|
|
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
|
+
}
|
|
21
29
|
|
|
22
30
|
</script>
|
|
23
31
|
|
|
24
32
|
<template>
|
|
25
|
-
<form>
|
|
33
|
+
<form @submit.prevent="onSubmit">
|
|
26
34
|
<v-sheet>
|
|
27
35
|
</v-sheet>
|
|
28
36
|
|
|
@@ -51,6 +59,11 @@ const form = defineModel<IUserUpdate>({
|
|
|
51
59
|
:error-messages="$ta(inputErrors.role)"
|
|
52
60
|
></RoleCombobox>
|
|
53
61
|
|
|
62
|
+
<TenantCombobox
|
|
63
|
+
v-model="form.tenant"
|
|
64
|
+
:error-messages="$ta(inputErrors.tenant)"
|
|
65
|
+
></TenantCombobox>
|
|
66
|
+
|
|
54
67
|
<v-text-field
|
|
55
68
|
v-model="form.email"
|
|
56
69
|
variant="outlined"
|
|
@@ -31,7 +31,13 @@ function confirmPasswordRule(value: string) {
|
|
|
31
31
|
return form.value.newPassword === form.value.confirmPassword || t('validation.password.confirmed')
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Define emits
|
|
35
|
+
const emits = defineEmits(['formSubmit'])
|
|
34
36
|
|
|
37
|
+
// Function to call when form is attempted to be submitted
|
|
38
|
+
const onSubmit = () => {
|
|
39
|
+
emits('formSubmit', form); // Emitting an event with the form data
|
|
40
|
+
}
|
|
35
41
|
</script>
|
|
36
42
|
|
|
37
43
|
<template>
|
|
@@ -42,7 +48,7 @@ function confirmPasswordRule(value: string) {
|
|
|
42
48
|
</v-alert>
|
|
43
49
|
</v-sheet>
|
|
44
50
|
<v-sheet v-else>
|
|
45
|
-
<form ref="changeUserPassword">
|
|
51
|
+
<form ref="changeUserPassword" @submit.prevent="onSubmit">
|
|
46
52
|
|
|
47
53
|
<div class="text-subtitle-1 text-medium-emphasis">{{ $t('user.newPassword') }}</div>
|
|
48
54
|
<v-text-field
|
package/src/index.ts
CHANGED
|
@@ -2,20 +2,31 @@ import IdentityLogin from "./components/IdentityLogin/IdentityLogin.vue";
|
|
|
2
2
|
import IdentityProfileAvatar from "./components/IdentityProfileAvatar/IdentityProfileAvatar.vue";
|
|
3
3
|
import IdentityProfileDrawer from "./components/IdentityProfileDrawer/IdentityProfileDrawer.vue";
|
|
4
4
|
import IdentityProfileView from "./components/IdentityProfileView/IdentityProfileView.vue";
|
|
5
|
+
|
|
5
6
|
import UserCrud from "./cruds/user-crud/UserCrud.vue";
|
|
6
7
|
import UserList from "./cruds/user-crud/UserList.vue";
|
|
7
8
|
import UserCrudPage from "./pages/UserCrudPage.vue";
|
|
8
9
|
import UserCreateForm from "./forms/UserCreateForm.vue";
|
|
9
10
|
import UserEditForm from "./forms/UserEditForm.vue";
|
|
10
|
-
import
|
|
11
|
+
import UserView from "./views/UserView.vue";
|
|
11
12
|
|
|
13
|
+
import RoleForm from "./forms/RoleForm.vue";
|
|
14
|
+
import RoleView from "./views/RoleView.vue";
|
|
12
15
|
import RoleCrud from "./cruds/role-crud/RoleCrud.vue";
|
|
13
16
|
import RoleList from "./cruds/role-crud/RoleList.vue";
|
|
14
17
|
import RoleCrudPage from "./pages/RoleCrudPage.vue";
|
|
15
18
|
|
|
19
|
+
|
|
20
|
+
import TenantForm from "./forms/TenantForm.vue";
|
|
21
|
+
import TenantView from "./views/TenantView.vue";
|
|
22
|
+
import TenantCrud from "./cruds/tenant-crud/TenantCrud.vue";
|
|
23
|
+
import TenantList from "./cruds/tenant-crud/TenantList.vue";
|
|
24
|
+
import TenantCrudPage from "./pages/TenantCrudPage.vue";
|
|
25
|
+
|
|
16
26
|
import {useAuth} from "./composables/useAuth.js";
|
|
17
27
|
import {useUser} from "./composables/useUser.js";
|
|
18
28
|
import {useRole} from "./composables/useRole.js";
|
|
29
|
+
import {useTenant} from "./composables/useTenant.js";
|
|
19
30
|
import {useAuthStore} from "./stores/auth/AuthStore.js";
|
|
20
31
|
|
|
21
32
|
export {
|
|
@@ -25,26 +36,32 @@ export {
|
|
|
25
36
|
IdentityProfileView,
|
|
26
37
|
IdentityProfileDrawer,
|
|
27
38
|
|
|
28
|
-
//
|
|
39
|
+
//User
|
|
40
|
+
UserView,
|
|
29
41
|
UserCreateForm,
|
|
30
42
|
UserEditForm,
|
|
31
|
-
RoleForm,
|
|
32
|
-
|
|
33
|
-
//Vue Composables
|
|
34
|
-
useAuth,
|
|
35
|
-
useUser,
|
|
36
|
-
useRole,
|
|
37
|
-
|
|
38
|
-
//Cruds
|
|
39
43
|
UserCrud,
|
|
40
44
|
UserList,
|
|
45
|
+
UserCrudPage,
|
|
46
|
+
useAuth,
|
|
47
|
+
useUser,
|
|
41
48
|
|
|
49
|
+
//Role
|
|
50
|
+
RoleView,
|
|
51
|
+
RoleForm,
|
|
42
52
|
RoleCrud,
|
|
43
53
|
RoleList,
|
|
44
|
-
|
|
45
|
-
//Pages
|
|
46
|
-
UserCrudPage,
|
|
47
54
|
RoleCrudPage,
|
|
55
|
+
useRole,
|
|
56
|
+
|
|
57
|
+
//Tenant
|
|
58
|
+
TenantView,
|
|
59
|
+
TenantForm,
|
|
60
|
+
TenantCrud,
|
|
61
|
+
TenantList,
|
|
62
|
+
TenantCrudPage,
|
|
63
|
+
useTenant,
|
|
64
|
+
|
|
48
65
|
|
|
49
66
|
//Stores
|
|
50
67
|
useAuthStore
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {PropType} from "vue";
|
|
3
|
+
import type {ITenant} from "@drax/identity-front";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
tenant:{
|
|
7
|
+
type: Object as PropType<ITenant>,
|
|
8
|
+
required: true,
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<v-sheet border class="position-relative d-flex justify-center align-center" height="150">
|
|
15
|
+
<v-sheet class="text-center">
|
|
16
|
+
<h6 class="text-h6">{{$t ? $t('tenant.name') : 'Name'}} : {{ tenant.name }}</h6>
|
|
17
|
+
</v-sheet>
|
|
18
|
+
</v-sheet>
|
|
19
|
+
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<style scoped>
|
|
23
|
+
|
|
24
|
+
</style>
|