add new workspaces for users
This commit is contained in:
@@ -43,6 +43,14 @@ export function useUserTable() {
|
||||
sortable: true,
|
||||
style: 'width: 120px; max-width: 120px;',
|
||||
},
|
||||
{
|
||||
name: 'workspaces',
|
||||
align: 'left' as const,
|
||||
label: i18n.global.t('workspaces'),
|
||||
field: 'workspaces',
|
||||
sortable: true,
|
||||
style: 'width: 120px; max-width: 120px;',
|
||||
},
|
||||
{
|
||||
name: 'expiration',
|
||||
align: 'left' as const,
|
||||
@@ -59,9 +67,9 @@ export function useUserTable() {
|
||||
const loading = ref(false);
|
||||
|
||||
//updates user list from database
|
||||
function updateUsers() {
|
||||
async function updateUsers() {
|
||||
loading.value = true;
|
||||
appApi
|
||||
await appApi
|
||||
.get('users')
|
||||
.then((resp) => {
|
||||
if (resp.data === null) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:loading-label="$t('loading')"
|
||||
:rows-per-page-label="$t('recordsPerPage')"
|
||||
:selected-rows-label="(val) => val + ' ' + $t('recordSelected')"
|
||||
:rows="users"
|
||||
:rows="localUsers"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
v-model:pagination="pagination"
|
||||
@@ -23,17 +23,11 @@
|
||||
>
|
||||
<template v-slot:top-left>
|
||||
<q-btn-group push flat style="color: grey">
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('userSettings', 'write')"
|
||||
dense
|
||||
flat
|
||||
icon="add"
|
||||
@click="openAllValueDialog(null)"
|
||||
>
|
||||
<q-btn v-if="writePermission" dense flat icon="add" @click="openAllValueDialog(null)">
|
||||
<q-tooltip>{{ $t('addNewUser') }}</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('userSettings', 'write')"
|
||||
v-if="writePermission"
|
||||
dense
|
||||
flat
|
||||
style="color: grey"
|
||||
@@ -43,7 +37,9 @@
|
||||
<q-tooltip>{{ $t('selectUserOptions') }}</q-tooltip>
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
<div v-if="selectOption && selected.length > 0">
|
||||
<div
|
||||
v-if="selectOption && selected.length > 0 && user.isPermittedTo('userSettings', 'delete')"
|
||||
>
|
||||
<q-btn flat dense icon="more_vert" @click="openSubmenu = true" />
|
||||
<q-menu v-if="openSubmenu" anchor="bottom middle" self="top middle">
|
||||
<q-item
|
||||
@@ -71,13 +67,9 @@
|
||||
<template v-slot:body-cell="props">
|
||||
<q-td
|
||||
:props="props"
|
||||
:style="
|
||||
autorized(props.row) && user.isPermittedTo('userSettings', 'write')
|
||||
? 'cursor: pointer'
|
||||
: ''
|
||||
"
|
||||
:style="autorized(props.row) && writePermission ? 'cursor: pointer' : ''"
|
||||
@click="
|
||||
autorized(props.row) && user.isPermittedTo('userSettings', 'write')
|
||||
autorized(props.row) && writePermission
|
||||
? openSingleValueDialog(props.col.label, props.col.name, props.row)
|
||||
: ''
|
||||
"
|
||||
@@ -101,7 +93,11 @@
|
||||
<template v-slot:body-cell-role="props">
|
||||
<q-td :props="props">
|
||||
<q-select
|
||||
:readonly="!user.isPermittedTo('userSettings', 'write') || !autorized(props.row)"
|
||||
:readonly="
|
||||
user.user?.id === props.row.id ||
|
||||
!user.isPermittedTo('userSettings', 'write', props.row.role) ||
|
||||
!autorized(props.row)
|
||||
"
|
||||
dense
|
||||
v-model="props.row.role"
|
||||
:options="localRoles"
|
||||
@@ -110,16 +106,25 @@
|
||||
></q-select>
|
||||
</q-td>
|
||||
</template>
|
||||
<template v-slot:body-cell-workspaces="props">
|
||||
<q-td :props="props">
|
||||
<q-select
|
||||
:readonly="props.row.id === user.user?.id || !autorized(props.row) || !writePermission"
|
||||
dense
|
||||
v-model="props.row.workspaces"
|
||||
:options="localWorkspaces"
|
||||
option-label="name"
|
||||
multiple
|
||||
@update:model-value="updateUser(props.row)"
|
||||
></q-select>
|
||||
</q-td>
|
||||
</template>
|
||||
<template v-slot:body-cell-expiration="props">
|
||||
<q-td
|
||||
:props="props"
|
||||
:style="
|
||||
autorized(props.row) && user.isPermittedTo('userSettings', 'write')
|
||||
? 'cursor: pointer'
|
||||
: ''
|
||||
"
|
||||
:style="autorized(props.row) && writePermission ? 'cursor: pointer' : ''"
|
||||
@click="
|
||||
autorized(props.row) && user.isPermittedTo('userSettings', 'write')
|
||||
autorized(props.row) && writePermission
|
||||
? openSingleValueDialog(props.col.label, props.col.name, props.row)
|
||||
: ''
|
||||
"
|
||||
@@ -148,7 +153,7 @@
|
||||
query-id
|
||||
v-on:update="(val) => updateUser(val)"
|
||||
></EditOneDialog>
|
||||
<EditAllDialog ref="editAllDialog" :roles="roles" v-on:update="updateUsers"></EditAllDialog>
|
||||
<EditAllDialog ref="editAllDialog" :roles="localRoles" v-on:update="updateUsers"></EditAllDialog>
|
||||
<OkDialog
|
||||
ref="okDialog"
|
||||
:dialog-label="$t('delete')"
|
||||
@@ -177,34 +182,73 @@ import { i18n } from 'src/boot/lang';
|
||||
import { useUserStore } from 'src/vueLib/login/userStore';
|
||||
import ChangePassword from 'src/vueLib/login/ChangePassword.vue';
|
||||
import SearchableInput from '../components/SearchableInput.vue';
|
||||
import { useWorkspaceTable } from '../workspaces/WorkspaceTable';
|
||||
|
||||
const { NotifyResponse } = useNotify();
|
||||
const { users, pagination, loading, columns, updateUsers } = useUserTable();
|
||||
const { updateRoles } = useRoleTable();
|
||||
const { updateWorkspaces } = useWorkspaceTable();
|
||||
const user = useUserStore();
|
||||
|
||||
const editOneDialog = ref();
|
||||
const editAllDialog = ref();
|
||||
const okDialog = ref();
|
||||
const deleteText = ref('');
|
||||
const localRoles = computed(() => {
|
||||
return roles.value.filter((role) => {
|
||||
if (user.user?.role.role.includes('admin') || !user.user?.role.role.includes('admin'))
|
||||
return role;
|
||||
|
||||
const localUsers = computed(() => {
|
||||
return users.value.filter((u) => {
|
||||
if (user.isAdmin() || user.user?.id === u.id) return user;
|
||||
const roleP = u.role?.permissions.find((p) => p.name === 'userSettings')?.permission;
|
||||
const userP = user.user?.permissions?.find((p) => p.name === 'userSettings')?.permission;
|
||||
const notInWorkspace = u.workspaces?.some((w) => currentUser.value.workspaces.includes(w.name));
|
||||
|
||||
if (
|
||||
roleP === undefined ||
|
||||
userP === undefined ||
|
||||
(!notInWorkspace && u.workspaces?.length !== 0)
|
||||
)
|
||||
return;
|
||||
if (userP > roleP) return user;
|
||||
});
|
||||
});
|
||||
|
||||
const localRoles = computed(() => {
|
||||
return roles.value.filter((role) => {
|
||||
const roleP = role.permissions.find((p) => p.name === 'userSettings')?.permission;
|
||||
const userP = user.user?.permissions?.find((p) => p.name === 'userSettings')?.permission;
|
||||
if (roleP === undefined || userP === undefined) return;
|
||||
if (userP < roleP) return;
|
||||
if (user.isAdmin() || !role.role.includes('admin')) return role;
|
||||
});
|
||||
});
|
||||
|
||||
const localWorkspaces = computed(() => {
|
||||
return users.value.filter((u) => u.id === user.user?.id)[0]?.workspaces;
|
||||
});
|
||||
|
||||
const selectOption = ref(false);
|
||||
const selected = ref<Users>([]);
|
||||
const openSubmenu = ref(false);
|
||||
const filter = ref('');
|
||||
const currentUser = ref();
|
||||
const { users, pagination, loading, columns, updateUsers } = useUserTable();
|
||||
const { updateRoles } = useRoleTable();
|
||||
const user = useUserStore();
|
||||
const changePwdDialog = ref();
|
||||
|
||||
const writePermission = computed(() => user.isPermittedTo('userSettings', 'write'));
|
||||
|
||||
//load on mounting page
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
currentUser.value = user.user;
|
||||
updateUsers();
|
||||
updateRoles().catch((err) => NotifyResponse(err, 'error'));
|
||||
|
||||
await updateUsers().finally(() => {
|
||||
const targetUser = users.value.find((u) => u.id === currentUser.value.id);
|
||||
if (targetUser && targetUser.workspaces) {
|
||||
currentUser.value.workspaces = targetUser.workspaces.map((ws) => ws.name);
|
||||
}
|
||||
});
|
||||
await updateRoles().catch((err) => NotifyResponse(err, 'error'));
|
||||
await updateWorkspaces().catch((err) => NotifyResponse(err, 'error'));
|
||||
// get workspaces of current user
|
||||
});
|
||||
|
||||
//check authorization
|
||||
@@ -264,7 +308,7 @@ function removeUser(...removeUsers: Users) {
|
||||
appApi
|
||||
.post('users/delete?id=' + currentUser.value.id, { ids: userIds })
|
||||
.then(() => {
|
||||
updateUsers();
|
||||
updateUsers().catch((err) => NotifyResponse(err, 'error'));
|
||||
selected.value = [];
|
||||
})
|
||||
.catch((err) => NotifyResponse(err, 'error'))
|
||||
@@ -278,6 +322,7 @@ function updateUser(user: User) {
|
||||
if (user.role?.id) {
|
||||
user.roleId = user.role?.id;
|
||||
}
|
||||
|
||||
appApi
|
||||
.post('/users/update', user)
|
||||
.then(() => NotifyResponse(i18n.global.t('userUpdated')))
|
||||
|
||||
78
src/vueLib/tables/workspaces/WorkspaceTable.ts
Normal file
78
src/vueLib/tables/workspaces/WorkspaceTable.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { appApi } from 'src/boot/axios';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useNotify } from 'src/vueLib/general/useNotify';
|
||||
import { i18n } from 'boot/lang';
|
||||
import type { Workspaces } from 'src/vueLib/models/workspaces';
|
||||
// import { useUserStore } from 'src/vueLib/login/userStore';
|
||||
// import { useLogin } from 'src/vueLib/login/useLogin';
|
||||
|
||||
export const workspaces = ref<Workspaces>([]);
|
||||
|
||||
export function useWorkspaceTable() {
|
||||
const pagination = ref({
|
||||
sortBy: 'name',
|
||||
descending: false,
|
||||
page: 1,
|
||||
rowsPerPage: 20,
|
||||
});
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'name',
|
||||
align: 'left' as const,
|
||||
label: i18n.global.t('name'),
|
||||
field: 'name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
align: 'left' as const,
|
||||
label: i18n.global.t('description'),
|
||||
field: 'description',
|
||||
style: 'width: 120px; max-width: 120px;',
|
||||
},
|
||||
{ name: 'option', align: 'center' as const, label: '', field: 'option', icon: 'option' },
|
||||
]);
|
||||
|
||||
const { NotifyResponse } = useNotify();
|
||||
|
||||
const loading = ref(false);
|
||||
// const userStore = useUserStore();
|
||||
// const login = useLogin();
|
||||
|
||||
//updates user list from database
|
||||
async function updateWorkspaces() {
|
||||
loading.value = true;
|
||||
await appApi
|
||||
.get('workspaces?id=0')
|
||||
.then((resp) => {
|
||||
if (resp.data === null) {
|
||||
workspaces.value = [];
|
||||
return;
|
||||
}
|
||||
workspaces.value = resp.data as Workspaces;
|
||||
|
||||
if (workspaces.value === null) {
|
||||
workspaces.value = [];
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
NotifyResponse(err, 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
await appApi
|
||||
.post('users/update', { id: 1, workspaces: workspaces.value })
|
||||
.catch((err) => NotifyResponse(err, 'error'));
|
||||
}
|
||||
return {
|
||||
workspaces,
|
||||
pagination,
|
||||
columns,
|
||||
loading,
|
||||
updateWorkspaces,
|
||||
};
|
||||
}
|
||||
226
src/vueLib/tables/workspaces/WorkspaceTable.vue
Normal file
226
src/vueLib/tables/workspaces/WorkspaceTable.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<q-table
|
||||
flat
|
||||
bordered
|
||||
ref="tableRef"
|
||||
title="Workspaces"
|
||||
title-class="text-bold text-blue-9"
|
||||
:no-data-label="$t('noDataAvailable')"
|
||||
:loading-label="$t('loading')"
|
||||
:rows-per-page-label="$t('recordsPerPage')"
|
||||
:selected-rows-label="(val) => val + ' ' + $t('recordSelected')"
|
||||
:rows="workspaces"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
v-model:pagination="pagination"
|
||||
:loading="loading"
|
||||
:filter="filter"
|
||||
:selection="selectOption ? 'multiple' : 'none'"
|
||||
v-model:selected="selected"
|
||||
binary-state-sort
|
||||
dense
|
||||
class="bigger-table-text"
|
||||
>
|
||||
<template v-slot:top-left>
|
||||
<q-btn-group push flat style="color: grey">
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('userSettings', 'write')"
|
||||
dense
|
||||
flat
|
||||
icon="add"
|
||||
@click="openAllValueDialog(null)"
|
||||
>
|
||||
<q-tooltip>{{ $t('addNewWorkspace') }}</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('userSettings', 'write')"
|
||||
dense
|
||||
flat
|
||||
style="color: grey"
|
||||
:icon="selectOption ? 'check_box' : 'check_box_outline_blank'"
|
||||
@click="selectOption = !selectOption"
|
||||
>
|
||||
<q-tooltip>{{ $t('selectWorkspaceOptions') }}</q-tooltip>
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
<div v-if="selectOption && selected.length > 0">
|
||||
<q-btn flat dense icon="more_vert" @click="openSubmenu = true" />
|
||||
<q-menu v-if="openSubmenu" anchor="bottom middle" self="top middle">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="openRemoveDialog(...selected)"
|
||||
class="text-negative"
|
||||
>{{ $t('delete') }}</q-item
|
||||
>
|
||||
</q-menu>
|
||||
</div>
|
||||
<div v-if="selectOption && selected.length > 0" class="q-ml-md text-weight-bold">
|
||||
{{ $t('selected') }}: {{ selected.length }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- top right of table-->
|
||||
|
||||
<template v-slot:top-right>
|
||||
<SearchableInput v-model="filter" :placeholder="$t('search')" />
|
||||
</template>
|
||||
|
||||
<!-- table body content-->
|
||||
|
||||
<template v-slot:body-cell="props">
|
||||
<q-td
|
||||
:props="props"
|
||||
:style="user.isPermittedTo('userSettings', 'write') ? 'cursor: pointer' : ''"
|
||||
@click="
|
||||
user.isPermittedTo('userSettings', 'write')
|
||||
? openSingleValueDialog(props.col.label, props.col.name, props.row)
|
||||
: ''
|
||||
"
|
||||
>
|
||||
{{ props.value }}
|
||||
</q-td>
|
||||
</template>
|
||||
<template v-slot:body-cell-option="props">
|
||||
<q-td :props="props">
|
||||
<q-btn
|
||||
v-if="user.isPermittedTo('userSettings', 'delete')"
|
||||
flat
|
||||
dense
|
||||
icon="delete"
|
||||
color="negative"
|
||||
@click="openRemoveDialog(props.row)"
|
||||
>
|
||||
<q-tooltip> {{ $t('delete') }} </q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
<EditOneDialog
|
||||
ref="editOneDialog"
|
||||
endpoint="workspaces/update"
|
||||
query-id
|
||||
v-on:update="updateWorkspaces"
|
||||
></EditOneDialog>
|
||||
<EditAllDialog ref="editAllDialog" v-on:update="updateWorkspaces"></EditAllDialog>
|
||||
<OkDialog
|
||||
ref="okDialog"
|
||||
:dialog-label="$t('delete')"
|
||||
:text="$t('doYouWantToDelete') + ' ' + deleteText"
|
||||
label-color="red"
|
||||
:button-cancel-label="$t('cancel')"
|
||||
:button-ok-label="$t('confirm')"
|
||||
:button-ok-flat="false"
|
||||
button-ok-color="red"
|
||||
v-on:update-confirm="(val) => removeWorkspace(...val)"
|
||||
></OkDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { appApi } from 'src/boot/axios';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import type { Workspaces, Workspace } from 'src/vueLib/models/workspaces';
|
||||
import EditOneDialog from 'src/components/EditOneDialog.vue';
|
||||
import EditAllDialog from 'src/components/WorkspaceEditAllDialog.vue';
|
||||
import OkDialog from 'src/components/dialog/OkDialog.vue';
|
||||
import { useNotify } from 'src/vueLib/general/useNotify';
|
||||
import { useWorkspaceTable } from './WorkspaceTable';
|
||||
import { i18n } from 'src/boot/lang';
|
||||
import { QTable } from 'quasar';
|
||||
import { useUserStore } from 'src/vueLib/login/userStore';
|
||||
import SearchableInput from '../components/SearchableInput.vue';
|
||||
import type { User } from 'src/vueLib/models/user';
|
||||
import { workspace } from 'src/vueLib/models/settings';
|
||||
|
||||
const { NotifyResponse } = useNotify();
|
||||
const editOneDialog = ref();
|
||||
const editAllDialog = ref();
|
||||
const okDialog = ref();
|
||||
const deleteText = ref('');
|
||||
const selectOption = ref(false);
|
||||
const selected = ref<Workspaces>([]);
|
||||
const openSubmenu = ref(false);
|
||||
const currentUser = ref<User>();
|
||||
const filter = ref('');
|
||||
const user = useUserStore();
|
||||
|
||||
const { workspaces, pagination, loading, columns, updateWorkspaces } = useWorkspaceTable();
|
||||
|
||||
//load on mounting page
|
||||
onMounted(() => {
|
||||
loading.value = true;
|
||||
if (user.user) {
|
||||
currentUser.value = user.user;
|
||||
}
|
||||
updateWorkspaces().catch((err) => NotifyResponse(err, 'error'));
|
||||
});
|
||||
|
||||
// opens dialog for all workspace values
|
||||
function openSingleValueDialog(label: string, field: string, workspace: Workspace) {
|
||||
editOneDialog.value?.open(label, field, workspace);
|
||||
}
|
||||
|
||||
//opens dialog for one value
|
||||
function openAllValueDialog(workspace: Workspace | null, typ?: 'permissions') {
|
||||
editAllDialog.value?.open(workspace, typ);
|
||||
}
|
||||
|
||||
//opens remove dialog
|
||||
function openRemoveDialog(...workspaces: Workspaces) {
|
||||
if (workspaces.length === 1) {
|
||||
deleteText.value = "'" + workspaces[0]?.name + "'";
|
||||
} else {
|
||||
deleteText.value = String(workspaces.length) + ' ' + i18n.global.t('workspaces');
|
||||
}
|
||||
okDialog.value?.open(workspaces);
|
||||
}
|
||||
|
||||
//remove workspace from database
|
||||
function removeWorkspace(...removeWorkspaces: Workspaces) {
|
||||
const workspaces: Workspace[] = [];
|
||||
|
||||
removeWorkspaces.forEach((workspace: Workspace) => {
|
||||
if (workspace.id === currentUser.value?.settings?.workspace) {
|
||||
NotifyResponse(i18n.global.t('notPossibleToDeleteUsedWorkspace'), 'error');
|
||||
} else if (workspace.id) {
|
||||
workspaces.push(workspace);
|
||||
}
|
||||
});
|
||||
|
||||
appApi
|
||||
.post('workspaces/delete', {
|
||||
workspaces: workspaces,
|
||||
})
|
||||
.then(() => {
|
||||
const storageWorkspace = localStorage.getItem('workspace');
|
||||
if (workspaces.some((w) => w.uuid === storageWorkspace)) {
|
||||
workspace.value = '';
|
||||
localStorage.removeItem('workspace');
|
||||
}
|
||||
updateWorkspaces().catch((err) => NotifyResponse(err, 'error'));
|
||||
if (workspaces.length === 1) {
|
||||
NotifyResponse("'" + workspaces[0]?.name + "' " + i18n.global.t('deleted'), 'warning');
|
||||
} else {
|
||||
NotifyResponse(i18n.global.t('deleteWorkspaces'), 'warning');
|
||||
}
|
||||
selected.value = [];
|
||||
})
|
||||
.catch((err) => NotifyResponse(err, 'error'))
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
selectOption.value = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bigger-table-text .q-table__middle td {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.bigger-table-text .q-table__top,
|
||||
.bigger-table-text .q-table__bottom,
|
||||
.bigger-table-text th {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user