Skip to content

Commit 08fb263

Browse files
committed
Support bulk deleting of model data
1 parent e660944 commit 08fb263

File tree

6 files changed

+118
-12
lines changed

6 files changed

+118
-12
lines changed

components/modal/createModelData.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
<template>
9191
<ModalBase :id="id" @close="handleClose" size="lg">
9292
<form @submit="onSubmit">
93-
<h3 class="text-lg font-bold">Generate Model Data</h3>
93+
<h3 class="text-lg font-bold">Insert Model Data</h3>
9494
<div class="flex">
9595
<section class="form-control mt-2 w-full">
9696
<label class="mb-2 text-lg">No. of data:</label>

components/model/table.vue

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
<script lang="ts" setup>
2+
import { PlusIcon, TrashIcon } from '@heroicons/vue/24/outline';
23
import useModelData from '~~/stores/useModelData';
34
import ModalCreateModelData from '~~/components/modal/createModelData.vue';
5+
import ModalConfirm from '~~/components/modal/confirm.vue';
46
57
defineProps<{
68
schema: { name: string; type: string }[];
79
}>();
810
911
const modelData = useModelData();
12+
const select = useSelect();
13+
1014
const createModelDataModal = useModal(ModalCreateModelData, { id: 'create-model-data' });
15+
16+
const deleteModelDataModal = useModal(ModalConfirm, {
17+
id: 'confirm-delete-model-data',
18+
onConfirm: async (closeModal: () => void) => {
19+
const ids = Array.from(select.list.value).join(',');
20+
21+
await modelData.bulkDelete(ids);
22+
23+
closeModal();
24+
25+
select.clear();
26+
},
27+
});
1128
</script>
1229

1330
<template>
@@ -17,13 +34,34 @@
1734
<thead>
1835
<tr>
1936
<th>
20-
<Button
21-
:disabled="modelData.isLoading"
22-
size="sm"
23-
@click="createModelDataModal.open()"
24-
>
25-
Generate
26-
</Button>
37+
<input
38+
:checked="select.ticked(modelData.list)"
39+
class="checkbox"
40+
type="checkbox"
41+
@click="select.tick(modelData.list)"
42+
/>
43+
</th>
44+
<th>
45+
<div class="flex gap-x-2">
46+
<Button
47+
v-if="!select.isEmpty.value"
48+
:disabled="modelData.isLoading"
49+
color="error"
50+
size="sm"
51+
@click="deleteModelDataModal.open()"
52+
>
53+
<TrashIcon class="w-4 h-4" />
54+
</Button>
55+
<Button
56+
v-if="select.isEmpty.value"
57+
:disabled="modelData.isLoading"
58+
color="success"
59+
size="sm"
60+
@click="createModelDataModal.open()"
61+
>
62+
<PlusIcon class="w-4 h-4" />
63+
</Button>
64+
</div>
2765
</th>
2866
<th
2967
v-for="sch in schema"
@@ -36,7 +74,14 @@
3674
<tbody>
3775
<TableLoader v-if="modelData.isLoading" :colspan="4" />
3876
<tr v-for="md in modelData.list" v-else :key="md.id">
39-
<td />
77+
<td colspan="2">
78+
<input
79+
:checked="select.ticked(md.id)"
80+
class="checkbox"
81+
type="checkbox"
82+
@click="select.tick(md.id)"
83+
/>
84+
</td>
4085
<td
4186
v-for="sch in schema"
4287
class="font-normal normal-case text-base"
@@ -49,6 +94,10 @@
4994
</div>
5095
<ClientOnly>
5196
<component :is="createModelDataModal.component" />
97+
<component
98+
:is="deleteModelDataModal.component"
99+
content="Are you sure you want to delete the selected model data?"
100+
/>
52101
</ClientOnly>
53102
</div>
54103
</template>

composables/useSelect.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ type SelectProps = {
88
tick: (target: string | { id: string }[]) => void;
99
};
1010

11+
type ObjectWithId = {
12+
id: string;
13+
[key: string]: any;
14+
};
15+
1116
/**
1217
* A simple composable for storing list of resource data ID.
1318
*/
@@ -19,7 +24,7 @@ export function useSelect(): SelectProps {
1924
list.value.clear();
2025
};
2126

22-
const ticked = (target: string | { id: string }[]) => {
27+
const ticked = (target: string | ObjectWithId[]) => {
2328
if (Array.isArray(target)) {
2429
if (target.length === 0) {
2530
return false;
@@ -31,7 +36,7 @@ export function useSelect(): SelectProps {
3136
return list.value.has(target);
3237
};
3338

34-
const tick = (target: string | { id: string }[]) => {
39+
const tick = (target: string | ObjectWithId[]) => {
3540
if (Array.isArray(target)) {
3641
if (list.value.size !== target.length) {
3742
clear();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import ModelDataServices from '~~/server/services/modelDataServices';
2+
import extractAppKey from '~~/server/lib/extractAppKey';
3+
4+
type QueryParams = {
5+
ids: string;
6+
apiKey: string;
7+
};
8+
9+
export default defineEventHandler(async (event) => {
10+
const query = getQuery(event) as QueryParams;
11+
12+
await extractAppKey(event, query.apiKey);
13+
14+
const ids = query.ids.split(',');
15+
16+
const deleted = await new ModelDataServices(event).bulkDelete({
17+
ids,
18+
modelId: event.context.params?.id ?? '',
19+
});
20+
21+
return deleted;
22+
});

server/services/modelDataServices.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ export default class ModelDataService extends SupabaseService {
1616
);
1717
}
1818

19+
async bulkDelete(params: { ids: string[]; modelId: string }) {
20+
return await Promise.all(
21+
params.ids.map((id) => {
22+
return this.client
23+
.from('model_data')
24+
.update({
25+
deleted_at: new Date().toISOString(),
26+
})
27+
.eq('id', id)
28+
.eq('model_id', params.modelId)
29+
.select('*');
30+
})
31+
);
32+
}
33+
1934
async count(modelId: string) {
2035
const modelData = await this.client
2136
.from('model_data')

stores/useModelData.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,25 @@ export default defineStore('model-data', () => {
4343
if (modelId.value) {
4444
refresh();
4545
}
46-
})
46+
});
4747

4848
const list = computed(() => data.value || []);
4949
const isDisabled = computed(() => list.value.length === 50 || pending.value);
5050

51+
const bulkDelete = async (ids: string): Promise<void> => {
52+
await $fetch(`/models/${modelId.value}/model-data`, {
53+
method: 'DELETE',
54+
query: { ids, apiKey },
55+
async onResponse({ response }) {
56+
if (response.status === 200) {
57+
toast.success('Deleted the model data!');
58+
59+
await refresh();
60+
}
61+
},
62+
});
63+
};
64+
5165
const create = async (body: CreateProps, options: Options): Promise<void> => {
5266
await $fetch(`/models/${modelId.value}/model-data`, {
5367
method: 'POST',
@@ -78,6 +92,7 @@ export default defineStore('model-data', () => {
7892
list,
7993

8094
/** METHODS */
95+
bulkDelete,
8196
create,
8297
};
8398
});

0 commit comments

Comments
 (0)