completed selected many actions
This commit is contained in:
parent
e2bb2122dd
commit
3fcd1a5a38
@ -69,4 +69,16 @@ export default {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
deleteMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => {
|
||||
try {
|
||||
const data = await $axios.delete(`v1/groups`, {
|
||||
data: {
|
||||
array: IDs,
|
||||
},
|
||||
});
|
||||
return [data, undefined];
|
||||
} catch (e: any) {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@ -71,4 +71,36 @@ export default {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
deleteMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => {
|
||||
try {
|
||||
const data = await $axios.delete(`v1/users`, {
|
||||
data: {
|
||||
array: IDs,
|
||||
},
|
||||
});
|
||||
return [data, undefined];
|
||||
} catch (e: any) {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
blockMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => {
|
||||
try {
|
||||
const data = await $axios.patch(`v1/users/block`, {
|
||||
array: IDs,
|
||||
});
|
||||
return [data, undefined];
|
||||
} catch (e: any) {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
unblockMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => {
|
||||
try {
|
||||
const data = await $axios.patch(`v1/users/unblock`, {
|
||||
array: IDs,
|
||||
});
|
||||
return [data, undefined];
|
||||
} catch (e: any) {
|
||||
return [undefined, e?.response?.data?.error ?? e.message];
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
2
src/components.d.ts
vendored
2
src/components.d.ts
vendored
@ -9,8 +9,10 @@ declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppFooter: typeof import('./components/AppFooter.vue')['default']
|
||||
ConfirmModal: typeof import('./components/ConfirmModal.vue')['default']
|
||||
copy: typeof import('./components/ConfirmModal copy.vue')['default']
|
||||
ErrorPlate: typeof import('./components/ErrorPlate.vue')['default']
|
||||
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
|
||||
InfoModal: typeof import('./components/InfoModal.vue')['default']
|
||||
LanguageSwitcher: typeof import('./components/LanguageSwitcher.vue')['default']
|
||||
LogoComponent: typeof import('./components/Icons/LogoComponent.vue')['default']
|
||||
NavigationDrawer: typeof import('./components/NavigationDrawer.vue')['default']
|
||||
|
||||
42
src/components/InfoModal.vue
Normal file
42
src/components/InfoModal.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { useConfirmationStore } from '@/stores/confirmation';
|
||||
import { useLocale } from 'vuetify';
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
const $confirmation = useConfirmationStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-dialog persistent :model-value="$confirmation.show" width="450">
|
||||
<v-card>
|
||||
<template v-slot:title>
|
||||
<v-card-title class="p-0 w-full flex items-center">
|
||||
<span class="mso mr-1 text-2xl">warning</span>
|
||||
<span>{{ $confirmation.title }}</span>
|
||||
</v-card-title>
|
||||
</template>
|
||||
|
||||
<v-card-text>{{ $confirmation.message }}</v-card-text>
|
||||
|
||||
<!-- Actions -->
|
||||
<v-card-actions class="flex justify-end p-5 gap-1">
|
||||
<!-- Cancel -->
|
||||
<v-btn
|
||||
variant="text"
|
||||
class="px-4"
|
||||
:text="t('$vuetify.actions.cancel')"
|
||||
@click="$confirmation.doDecline()"
|
||||
></v-btn>
|
||||
<!-- Confirm -->
|
||||
<v-btn
|
||||
variant="flat"
|
||||
color="primary"
|
||||
class="px-4"
|
||||
:text="t('$vuetify.actions.confirm')"
|
||||
@click="$confirmation.doConfirm()"
|
||||
></v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
@ -4,6 +4,7 @@
|
||||
"create-group": "Create group",
|
||||
"create-user": "Create user",
|
||||
"reset-password": "Reset password",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"block": "Block",
|
||||
"unblock": "Unblock",
|
||||
|
||||
@ -26,6 +26,10 @@
|
||||
"delete-one": {
|
||||
"title": "Delete group",
|
||||
"message": "Are you sure you want to delete group with ID {0}? This action cannot be undone"
|
||||
},
|
||||
"delete-many": {
|
||||
"title": "Delete groups",
|
||||
"message": "Are you sure you want to delete {0} groups? This action cannot be undone"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,10 @@
|
||||
"delete-one": {
|
||||
"title": "Delete user",
|
||||
"message": "Are you sure you want to delete user with ID {0}? This action cannot be undone"
|
||||
},
|
||||
"delete-many": {
|
||||
"title": "Delete users",
|
||||
"message": "Are you sure you want to delete {0} users? This action cannot be undone"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"create-group": "Создать группу",
|
||||
"create-user": "Создать пользователя",
|
||||
"reset-password": "Сбросить пароль",
|
||||
"delete": "Удалить",
|
||||
"edit": "Редактировать",
|
||||
"block": "Заблокировать",
|
||||
"unblock": "Разблокировать",
|
||||
|
||||
@ -26,6 +26,10 @@
|
||||
"delete-one": {
|
||||
"title": "Удаление группы",
|
||||
"message": "Вы уверены, что хотите удалить группу с ID {0}? Данное действие нельзя будет отменить"
|
||||
},
|
||||
"delete-many": {
|
||||
"title": "Удаление групп",
|
||||
"message": "Вы уверены, что хотите удалить {0} групп? Данное действие нельзя будет отменить"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,10 @@
|
||||
"delete-one": {
|
||||
"title": "Удаление пользователя",
|
||||
"message": "Вы уверены, что хотите удалить пользователя с ID {0}? Данное действие нельзя будет отменить"
|
||||
},
|
||||
"delete-many": {
|
||||
"title": "Удаление пользователей",
|
||||
"message": "Вы уверены, что хотите удалить {0} пользователей? Данное действие нельзя будет отменить"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +151,7 @@ watch(
|
||||
density="comfortable"
|
||||
class="mr-1"
|
||||
:disabled="isDeleted(item.deletedAt)"
|
||||
:loading="$groups.loadingActionsID.includes(item.ID)"
|
||||
@click="editGroup(item)"
|
||||
>
|
||||
<span class="mso text-xl">edit</span>
|
||||
@ -162,7 +163,7 @@ watch(
|
||||
variant="text"
|
||||
density="comfortable"
|
||||
:disabled="isDeleted(item.deletedAt)"
|
||||
:loading="$groups.loadingDeleteID === item.ID"
|
||||
:loading="$groups.loadingActionsID.includes(item.ID)"
|
||||
@click="deleteGroup(item)"
|
||||
>
|
||||
<span class="mso text-xl">close</span>
|
||||
|
||||
@ -204,6 +204,7 @@ watch(
|
||||
density="comfortable"
|
||||
class="mr-1"
|
||||
:disabled="isDeleted(item.deletedAt)"
|
||||
:loading="$users.loadingActionsID.includes(item.ID)"
|
||||
>
|
||||
<span class="mso text-xl">more_vert</span>
|
||||
</v-btn>
|
||||
@ -233,7 +234,7 @@ watch(
|
||||
variant="text"
|
||||
density="comfortable"
|
||||
:disabled="isDeleted(item.deletedAt)"
|
||||
:loading="$users.loadingDeleteID === item.ID"
|
||||
:loading="$users.loadingActionsID.includes(item.ID)"
|
||||
@click="deleteUser(item)"
|
||||
>
|
||||
<span class="mso text-xl">close</span>
|
||||
|
||||
@ -3,6 +3,7 @@ import { useLocale } from 'vuetify';
|
||||
import { UsersPageTabs } from '@/enums/user-tab.enum';
|
||||
import { useUsersStore } from '@/stores/users';
|
||||
import { useGroupsStore } from '@/stores/groups';
|
||||
import { useConfirmationStore } from '@/stores/confirmation';
|
||||
import ErrorPlate from '@/components/ErrorPlate.vue';
|
||||
import AddUser from './components/AddUser.vue';
|
||||
import AddGroup from './components/AddGroup.vue';
|
||||
@ -16,6 +17,7 @@ const { t } = useLocale();
|
||||
|
||||
const $users = useUsersStore();
|
||||
const $groups = useGroupsStore();
|
||||
const $confirmation = useConfirmationStore();
|
||||
|
||||
const tableHeight: Ref<number> = ref(500);
|
||||
setInterval(() => {
|
||||
@ -28,7 +30,7 @@ setInterval(() => {
|
||||
}, 100);
|
||||
|
||||
//
|
||||
// MARK: Tabs
|
||||
// Tabs
|
||||
//
|
||||
const tab: Ref<UsersPageTabs> = ref(UsersPageTabs.USERS);
|
||||
const parseURLSearch = () => {
|
||||
@ -87,14 +89,14 @@ watch(tab, () => {
|
||||
});
|
||||
|
||||
//
|
||||
// MARK: Creation
|
||||
// Creation
|
||||
//
|
||||
const openCreationModal = () => {
|
||||
tab.value === UsersPageTabs.USERS ? $users.openModal() : $groups.openModal();
|
||||
};
|
||||
|
||||
//
|
||||
// MARK: Search model
|
||||
// Search model
|
||||
//
|
||||
const $search: WritableComputedRef<string> = computed({
|
||||
get() {
|
||||
@ -107,14 +109,14 @@ const $search: WritableComputedRef<string> = computed({
|
||||
},
|
||||
});
|
||||
//
|
||||
// MARK: Error
|
||||
// Error
|
||||
//
|
||||
const $error: ComputedRef<string> = computed(() =>
|
||||
tab.value === UsersPageTabs.USERS ? $users.error : $groups.error,
|
||||
);
|
||||
|
||||
//
|
||||
// MARK: Common functions
|
||||
// Common functions
|
||||
//
|
||||
const getAll = () => {
|
||||
tab.value === UsersPageTabs.USERS ? $users.getAll() : $groups.getAll();
|
||||
@ -129,6 +131,43 @@ const resetActions = () => {
|
||||
$users.resetSelected();
|
||||
$groups.resetSelected();
|
||||
};
|
||||
const deleteMany = () => {
|
||||
const len =
|
||||
tab.value === UsersPageTabs.USERS
|
||||
? $users.selected.length
|
||||
: $groups.selected.length;
|
||||
$confirmation.openModal();
|
||||
$confirmation.setTitle(
|
||||
t(
|
||||
`$vuetify.${tab.value === UsersPageTabs.USERS ? 'users' : 'groups'}.delete.delete-many.title`,
|
||||
),
|
||||
);
|
||||
$confirmation.setMessage(
|
||||
t(
|
||||
`$vuetify.${tab.value === UsersPageTabs.USERS ? 'users' : 'groups'}.delete.delete-many.message`,
|
||||
[len],
|
||||
),
|
||||
);
|
||||
$confirmation.setOnConfirm(
|
||||
tab.value === UsersPageTabs.USERS
|
||||
? () => {
|
||||
$users.deleteMany($users.selected);
|
||||
$users.resetSelected();
|
||||
}
|
||||
: () => {
|
||||
$groups.deleteMany($groups.selected);
|
||||
$groups.resetSelected();
|
||||
},
|
||||
);
|
||||
};
|
||||
const blockMany = () => {
|
||||
$users.blockMany($users.selected);
|
||||
$users.resetSelected();
|
||||
};
|
||||
const unblockMany = () => {
|
||||
$users.unblockMany($users.selected);
|
||||
$users.resetSelected();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -164,6 +203,41 @@ const resetActions = () => {
|
||||
: $groups.selected?.length,
|
||||
])
|
||||
}}</span>
|
||||
<!-- Actions -->
|
||||
<!-- Delete -->
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
class="ml-10 mr-3 px-3"
|
||||
@click="deleteMany()"
|
||||
>
|
||||
<span class="mso mr-1 text-xl">{{
|
||||
tab === UsersPageTabs.USERS ? 'person_remove' : 'group_remove'
|
||||
}}</span>
|
||||
<span>{{ t('$vuetify.actions.delete') }}</span>
|
||||
</v-btn>
|
||||
<template v-if="tab === UsersPageTabs.USERS">
|
||||
<!-- Block -->
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
class="mr-3 px-3"
|
||||
@click="blockMany()"
|
||||
>
|
||||
<span class="mso mr-1 text-xl">person_cancel</span>
|
||||
<span>{{ t('$vuetify.actions.block') }}</span>
|
||||
</v-btn>
|
||||
<!-- Unblock -->
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
class="mr-3 px-3"
|
||||
@click="unblockMany()"
|
||||
>
|
||||
<span class="mso mr-1 text-xl">person_check</span>
|
||||
<span>{{ t('$vuetify.actions.unblock') }}</span>
|
||||
</v-btn>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
|
||||
@ -4,13 +4,13 @@ import { getAll } from './search';
|
||||
//
|
||||
// MARK: Delete group
|
||||
//
|
||||
const loadingDeleteID: Ref<number> = ref(0);
|
||||
const loadingActionsID: Ref<number[]> = ref([0]);
|
||||
const deleteGroup = async (ID: number) => {
|
||||
if (loadingDeleteID.value || !ID) {
|
||||
if (!ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingDelete(ID);
|
||||
setLoadingActions([ID]);
|
||||
|
||||
const [_, e] = await api.groups.delete(ID);
|
||||
if (e && typeof e === 'string') {
|
||||
@ -19,8 +19,24 @@ const deleteGroup = async (ID: number) => {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingDelete(0);
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const setLoadingDelete = (ID: number) => (loadingDeleteID.value = ID);
|
||||
const deleteMany = async (IDs: number[]) => {
|
||||
if (!IDs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
export { loadingDeleteID, deleteGroup };
|
||||
setLoadingActions(IDs);
|
||||
|
||||
const [_, e] = await api.groups.deleteMany(IDs);
|
||||
if (e && typeof e === 'string') {
|
||||
// TODO notify error
|
||||
} else {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const setLoadingActions = (IDs: number[]) => (loadingActionsID.value = IDs);
|
||||
|
||||
export { loadingActionsID, deleteGroup, deleteMany };
|
||||
|
||||
@ -4,13 +4,13 @@ import { getAll } from './search';
|
||||
//
|
||||
// MARK: Delete user
|
||||
//
|
||||
const loadingDeleteID: Ref<number> = ref(0);
|
||||
const loadingActionsID: Ref<number[]> = ref([0]);
|
||||
const deleteUser = async (ID: number) => {
|
||||
if (loadingDeleteID.value || !ID) {
|
||||
if (!ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingDelete(ID);
|
||||
setLoadingActions([ID]);
|
||||
|
||||
const [_, e] = await api.users.delete(ID);
|
||||
if (e && typeof e === 'string') {
|
||||
@ -19,8 +19,56 @@ const deleteUser = async (ID: number) => {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingDelete(0);
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const setLoadingDelete = (ID: number) => (loadingDeleteID.value = ID);
|
||||
const deleteMany = async (IDs: number[]) => {
|
||||
if (!IDs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
export { loadingDeleteID, deleteUser };
|
||||
setLoadingActions(IDs);
|
||||
|
||||
const [_, e] = await api.users.deleteMany(IDs);
|
||||
if (e && typeof e === 'string') {
|
||||
// TODO notify error
|
||||
} else {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const blockMany = async (IDs: number[]) => {
|
||||
if (!IDs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingActions(IDs);
|
||||
|
||||
const [_, e] = await api.users.blockMany(IDs);
|
||||
if (e && typeof e === 'string') {
|
||||
// TODO notify error
|
||||
} else {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const unblockMany = async (IDs: number[]) => {
|
||||
if (!IDs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingActions(IDs);
|
||||
|
||||
const [_, e] = await api.users.unblockMany(IDs);
|
||||
if (e && typeof e === 'string') {
|
||||
// TODO notify error
|
||||
} else {
|
||||
getAll();
|
||||
}
|
||||
|
||||
setLoadingActions([0]);
|
||||
};
|
||||
const setLoadingActions = (IDs: number[]) => (loadingActionsID.value = IDs);
|
||||
|
||||
export { loadingActionsID, deleteUser, deleteMany, blockMany, unblockMany };
|
||||
|
||||
@ -103,7 +103,6 @@ const startEditUser = async (u: User) => {
|
||||
realName: u.realName,
|
||||
groupID: u.groupID,
|
||||
};
|
||||
console.log(form.value, u);
|
||||
};
|
||||
const setIsEditing = (state: boolean) => (isEditing.value = state);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user