web: add delete group button
Co-authored-by: Sphereso <Sphereso@users.noreply.github.com>
This commit is contained in:
parent
56ead89983
commit
0ce8e9765b
7 changed files with 244 additions and 99 deletions
|
@ -13,6 +13,7 @@
|
|||
"@vueuse/core": "^10.11.0",
|
||||
"axios": "^1.7.2",
|
||||
"lucide-vue-next": "^0.402.0",
|
||||
"minisearch": "^7.0.0",
|
||||
"roboto-fontface": "*",
|
||||
"vue": "^3.4.21",
|
||||
"vuetify": "^3.5.8"
|
||||
|
|
|
@ -23,6 +23,9 @@ importers:
|
|||
lucide-vue-next:
|
||||
specifier: ^0.402.0
|
||||
version: 0.402.0(vue@3.4.31(typescript@5.5.3))
|
||||
minisearch:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
roboto-fontface:
|
||||
specifier: '*'
|
||||
version: 0.10.0
|
||||
|
@ -594,6 +597,9 @@ packages:
|
|||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minisearch@7.0.0:
|
||||
resolution: {integrity: sha512-0OIJ3hUE+YBJNruDCqbTMFmk/IoB1CpZzuGfl11khFIel66ew9UoLF/+gfq3bdyrneqr3P7BTjFZApUbmk+9Dg==}
|
||||
|
||||
ms@2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
|
||||
|
@ -1279,6 +1285,8 @@ snapshots:
|
|||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minisearch@7.0.0: {}
|
||||
|
||||
ms@2.1.2: {}
|
||||
|
||||
muggle-string@0.4.1: {}
|
||||
|
|
|
@ -1,7 +1,60 @@
|
|||
<template>
|
||||
<div class="mt-3">
|
||||
<h2>{{ props.licenseGroupName }}:</h2>
|
||||
<li v-for="license in licenses" :key="license.id">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="11">
|
||||
<h2>{{ licenseGroup.name }}:</h2>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn
|
||||
block
|
||||
class="ml-7"
|
||||
flat
|
||||
size="small"
|
||||
color="isHovering ? 'red' : undefined"
|
||||
variant="text"
|
||||
v-model="deleteDialog"
|
||||
@click="deleteDialog = true"
|
||||
>
|
||||
<Trash />
|
||||
</v-btn>
|
||||
<v-dialog v-model="deleteDialog" width="600" persistent>
|
||||
<v-card max-width="600">
|
||||
<v-card-title>
|
||||
<span class="headline">Delete group</span>
|
||||
</v-card-title>
|
||||
<v-card-subtitle>
|
||||
<span>Delete a group inside the database</span>
|
||||
</v-card-subtitle>
|
||||
<v-card-text>
|
||||
<h4>This action is irreversible!</h4>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-row>
|
||||
<v-col cols="8" align="right" no-gutters>
|
||||
<v-btn
|
||||
class="ms-auto"
|
||||
text="Cancel"
|
||||
color="blue darken-1"
|
||||
@click="deleteDialog = false"
|
||||
></v-btn>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-btn
|
||||
class="ms-auto"
|
||||
text="Confirm Delete"
|
||||
type="submit"
|
||||
color="red darken-1"
|
||||
@click="deleteMutate"
|
||||
></v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<li v-for="license in licenseGroup.licenses" :key="license.id">
|
||||
<ListViewElement :license="license" />
|
||||
</li>
|
||||
</div>
|
||||
|
@ -9,9 +62,32 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import ListViewElement from "./ListViewElement.vue";
|
||||
import { License } from "@/types";
|
||||
import { LicenseGroup } from "@/types";
|
||||
import { Trash } from "lucide-vue-next";
|
||||
import { ref } from "vue";
|
||||
import { useMutation, useQueryClient } from "@tanstack/vue-query";
|
||||
import { axiosInstance } from "@/client";
|
||||
|
||||
const props = defineProps<{ licenseGroupName: string; licenses: License[] }>();
|
||||
const { licenseGroup } = defineProps<{ licenseGroup: LicenseGroup }>();
|
||||
|
||||
const deleteDialog = ref(false);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const id = licenseGroup.id;
|
||||
|
||||
const { mutate: deleteMutate } = useMutation({
|
||||
mutationFn: async () => {
|
||||
await axiosInstance.delete(`/groups/${id}`);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["licenses"] });
|
||||
deleteDialog.value = false;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -179,7 +179,6 @@
|
|||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
|
||||
<!-- Search -->
|
||||
<v-text-field
|
||||
class="compact-form mr-2"
|
||||
|
@ -190,6 +189,7 @@
|
|||
hide-details
|
||||
single-line
|
||||
clearable
|
||||
v-model="search"
|
||||
rounded="pill"
|
||||
></v-text-field>
|
||||
|
||||
|
@ -214,6 +214,7 @@ import UsersDialog from "./NavBarIcons/UsersDialog.vue";
|
|||
import UsersEditActions from "./NavBarIcons/UsersEditActions.vue";
|
||||
import { axiosInstance } from "@/client";
|
||||
import { LicenseGroup, CreateLicenseDto, CreateGroupDto, User } from "@/types";
|
||||
import { search } from "@/store";
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<template v-if="visible">
|
||||
<v-sheet elevation="4" width="96vw" rounded="lg" class="mt-3">
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel>
|
||||
|
@ -53,7 +54,9 @@
|
|||
class="logo mr-1"
|
||||
width="24"
|
||||
/>
|
||||
<span v-if="license.amount == null || license.amount == undefined">
|
||||
<span
|
||||
v-if="license.amount == null || license.amount == undefined"
|
||||
>
|
||||
<Infinity />
|
||||
</span>
|
||||
<span v-else>
|
||||
|
@ -87,12 +90,15 @@
|
|||
</v-expansion-panels>
|
||||
</v-sheet>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { License } from "@/types";
|
||||
import { Infinity, KeyRound, CalendarCheck, CalendarX } from "lucide-vue-next";
|
||||
import UpdateDialog from "./UpdateDialog.vue";
|
||||
import DeleteDialog from "./DeleteDialog.vue";
|
||||
import { ComputedRef, inject, ref, watch } from "vue";
|
||||
import { key } from "@/store";
|
||||
|
||||
const { license } = defineProps<{
|
||||
license: License;
|
||||
|
@ -104,6 +110,21 @@ const { license } = defineProps<{
|
|||
amount?: number;
|
||||
notes?: string;*/
|
||||
}>();
|
||||
|
||||
const visible = ref(true);
|
||||
|
||||
const { searching, visibleIds } = inject(key) as {
|
||||
searching: ComputedRef<boolean>;
|
||||
visibleIds: ComputedRef<string[]>;
|
||||
};
|
||||
|
||||
watch([searching, visibleIds], ([searching, visibleIds]) => {
|
||||
if (!searching) {
|
||||
visible.value = true;
|
||||
} else {
|
||||
visible.value = visibleIds.includes(license.id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -6,10 +6,7 @@
|
|||
<div v-else-if="isError">Error: {{ error?.message }}</div>
|
||||
<ul v-else-if="data">
|
||||
<li v-for="group in data" :key="group.id">
|
||||
<CategoryContainer
|
||||
:licenseGroupName="group.name"
|
||||
:licenses="group.licenses"
|
||||
/>
|
||||
<CategoryContainer :licenseGroup="group" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -21,7 +18,10 @@ import HeaderBar from "./HeaderBar.vue";
|
|||
import CategoryContainer from "./CategoryContainer.vue";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import { axiosInstance } from "@/client";
|
||||
import { LicenseGroup } from "@/types";
|
||||
import { LicenseGroup, License } from "@/types";
|
||||
import { search, key } from "@/store";
|
||||
import MiniSearch from "minisearch";
|
||||
import { computed, provide } from "vue";
|
||||
|
||||
const { isPending, isError, data, error } = useQuery({
|
||||
queryKey: ["licenses"],
|
||||
|
@ -31,6 +31,36 @@ const { isPending, isError, data, error } = useQuery({
|
|||
return res.data;
|
||||
},
|
||||
});
|
||||
|
||||
const searchEngine = computed(() => {
|
||||
let minisearch = new MiniSearch({
|
||||
fields: ["name", "description", "id"],
|
||||
searchOptions: {
|
||||
boost: { name: 2 },
|
||||
prefix: true,
|
||||
},
|
||||
});
|
||||
let licenses: License[] = [];
|
||||
data.value?.forEach((group) => {
|
||||
group.licenses.forEach((license) => licenses.push(license));
|
||||
});
|
||||
console.log(licenses);
|
||||
minisearch.addAll(licenses);
|
||||
return minisearch;
|
||||
});
|
||||
|
||||
const searching = computed(() => search.value !== "");
|
||||
|
||||
const visibleIds = computed(() => {
|
||||
return searchEngine.value.search(search.value).map((searchResult) => {
|
||||
return searchResult.id;
|
||||
});
|
||||
});
|
||||
|
||||
provide(key, {
|
||||
visibleIds,
|
||||
searching,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
import { reactive } from 'vue';
|
||||
import { ComputedRef, InjectionKey, reactive, ref } from "vue";
|
||||
|
||||
export const store = reactive<{token: string | null, setToken: (token: string | null) => void}>({
|
||||
token: localStorage.getItem('token') || null,
|
||||
export const store = reactive<{
|
||||
token: string | null;
|
||||
setToken: (token: string | null) => void;
|
||||
}>({
|
||||
token: localStorage.getItem("token") || null,
|
||||
setToken: (token: string | null) => {
|
||||
store.token = token
|
||||
store.token = token;
|
||||
if (token) {
|
||||
localStorage.setItem('token', token)
|
||||
localStorage.setItem("token", token);
|
||||
} else {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
localStorage.removeItem("token");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const search = ref("");
|
||||
|
||||
export const key = Symbol() as InjectionKey<{
|
||||
searching: ComputedRef<boolean>;
|
||||
visibleIds: ComputedRef<string[]>;
|
||||
}>;
|
||||
|
|
Loading…
Reference in a new issue