Skip to content

Commit d861350

Browse files
committed
Implement label import/export feature
1 parent a7f7fae commit d861350

File tree

6 files changed

+222
-45
lines changed

6 files changed

+222
-45
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<template>
2+
<div>
3+
<action-menu
4+
:items="menuItems"
5+
@create="createDialog=true"
6+
@upload="importDialog=true"
7+
@download="handleDownload"
8+
/>
9+
<base-dialog :dialog="createDialog">
10+
<label-creation-form
11+
:create-label="createLabel"
12+
@close="createDialog=false"
13+
/>
14+
</base-dialog>
15+
<base-dialog :dialog="importDialog">
16+
<label-import-form
17+
:import-label="importLabels"
18+
@close="importDialog=false"
19+
/>
20+
</base-dialog>
21+
</div>
22+
</template>
23+
24+
<script>
25+
import { mapActions } from 'vuex'
26+
import ActionMenu from '@/components/molecules/ActionMenu'
27+
import BaseDialog from '@/components/molecules/BaseDialog'
28+
import LabelCreationForm from '@/components/organisms/labels/LabelCreationForm'
29+
import LabelImportForm from '@/components/organisms/labels/LabelImportForm'
30+
31+
export default {
32+
components: {
33+
ActionMenu,
34+
BaseDialog,
35+
LabelCreationForm,
36+
LabelImportForm
37+
},
38+
39+
data() {
40+
return {
41+
createDialog: false,
42+
importDialog: false,
43+
menuItems: [
44+
{ title: 'Create a Label', icon: 'mdi-pencil', event: 'create' },
45+
{ title: 'Import Labels', icon: 'mdi-upload', event: 'upload' },
46+
{ title: 'Export Labels', icon: 'mdi-download', event: 'download' }
47+
]
48+
}
49+
},
50+
51+
created() {
52+
this.setCurrentProject(this.$route.params.id)
53+
},
54+
55+
methods: {
56+
...mapActions('labels', ['createLabel', 'importLabels', 'exportLabels']),
57+
...mapActions('projects', ['setCurrentProject']),
58+
59+
handleDownload() {
60+
this.exportLabels({
61+
projectId: this.$route.params.id
62+
})
63+
}
64+
}
65+
}
66+
</script>

frontend/components/containers/labels/LabelCreationButton.vue

Lines changed: 0 additions & 30 deletions
This file was deleted.

frontend/components/containers/labels/LabelDeletionButton.vue

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
11
<template>
2-
<confirm-dialog
3-
title="Delete Label"
4-
message="Are you sure you want to remove these labels from this project?"
5-
item-key="text"
6-
:disabled="!isLabelSelected"
7-
:items="selected"
8-
@ok="handleDeleteLabel()"
9-
/>
2+
<div>
3+
<v-btn
4+
class="text-capitalize"
5+
outlined
6+
:disabled="!isLabelSelected"
7+
@click="dialog=true"
8+
>
9+
Delete
10+
</v-btn>
11+
<base-dialog :dialog="dialog">
12+
<confirm-form
13+
title="Delete Label"
14+
message="Are you sure you want to delete these labels from this project?"
15+
item-key="text"
16+
:items="selected"
17+
@ok="deleteLabel($route.params.id);dialog=false"
18+
/>
19+
</base-dialog>
20+
</div>
1021
</template>
1122

1223
<script>
1324
import { mapState, mapGetters, mapActions } from 'vuex'
14-
import ConfirmDialog from '@/components/organisms/utils/ConfirmDialog'
25+
import BaseDialog from '@/components/molecules/BaseDialog'
26+
import ConfirmForm from '@/components/organisms/utils/ConfirmForm'
1527
1628
export default {
1729
components: {
18-
ConfirmDialog
30+
BaseDialog,
31+
ConfirmForm
32+
},
33+
34+
data() {
35+
return {
36+
dialog: false
37+
}
1938
},
2039
2140
computed: {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<template>
2+
<base-card
3+
title="Upload Label"
4+
agree-text="Upload"
5+
cancel-text="Cancel"
6+
:disabled="!valid"
7+
@agree="create"
8+
@cancel="cancel"
9+
>
10+
<template #content>
11+
<v-form
12+
ref="form"
13+
v-model="valid"
14+
>
15+
<v-alert
16+
v-show="showError"
17+
v-model="showError"
18+
type="error"
19+
dismissible
20+
>
21+
The file could not be uploaded. Maybe invalid format.
22+
Please check available formats carefully.
23+
</v-alert>
24+
<h2>Select a file</h2>
25+
<v-file-input
26+
v-model="file"
27+
accept=".json"
28+
:rules="uploadFileRules"
29+
label="File input"
30+
/>
31+
</v-form>
32+
</template>
33+
</base-card>
34+
</template>
35+
36+
<script>
37+
import BaseCard from '@/components/molecules/BaseCard'
38+
import { uploadFileRules } from '@/rules/index'
39+
40+
export default {
41+
components: {
42+
BaseCard
43+
},
44+
props: {
45+
importLabel: {
46+
type: Function,
47+
default: () => {},
48+
required: true
49+
}
50+
},
51+
data() {
52+
return {
53+
valid: false,
54+
file: null,
55+
uploadFileRules,
56+
showError: false
57+
}
58+
},
59+
60+
methods: {
61+
cancel() {
62+
this.$emit('close')
63+
},
64+
validate() {
65+
return this.$refs.form.validate()
66+
},
67+
reset() {
68+
this.$refs.form.reset()
69+
},
70+
create() {
71+
if (this.validate()) {
72+
this.importLabel({
73+
projectId: this.$route.params.id,
74+
file: this.file
75+
})
76+
.then((response) => {
77+
this.reset()
78+
this.cancel()
79+
})
80+
.catch(() => {
81+
this.showError = true
82+
})
83+
}
84+
}
85+
}
86+
}
87+
</script>

frontend/pages/projects/_id/labels/index.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<template>
22
<v-card>
3-
<v-card-title>
4-
<label-creation-button />
5-
<label-deletion-button />
3+
<v-card-title class="mb-2">
4+
<label-action-menu />
5+
<label-deletion-button class="ms-2" />
66
</v-card-title>
77
<label-list />
88
</v-card>
99
</template>
1010

1111
<script>
1212
import LabelList from '@/components/containers/labels/LabelList'
13-
import LabelCreationButton from '@/components/containers/labels/LabelCreationButton'
13+
import LabelActionMenu from '@/components/containers/labels/LabelActionMenu'
1414
import LabelDeletionButton from '@/components/containers/labels/LabelDeletionButton'
1515
1616
export default {
@@ -20,7 +20,7 @@ export default {
2020
2121
components: {
2222
LabelList,
23-
LabelCreationButton,
23+
LabelActionMenu,
2424
LabelDeletionButton
2525
},
2626

frontend/store/labels.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,40 @@ export const actions = {
7777
})
7878
}
7979
commit('resetSelected')
80+
},
81+
importLabels({ commit }, payload) {
82+
commit('setLoading', true)
83+
const formData = new FormData()
84+
formData.append('file', payload.file)
85+
const reader = new FileReader()
86+
reader.onload = (e) => {
87+
const labels = JSON.parse(e.target.result)
88+
for (const label of labels) {
89+
LabelService.addLabel(payload.projectId, label)
90+
.then((response) => {
91+
commit('addLabel', response.data)
92+
})
93+
}
94+
}
95+
reader.readAsText(payload.file)
96+
commit('setLoading', false)
97+
},
98+
exportLabels({ commit }, payload) {
99+
commit('setLoading', true)
100+
LabelService.getLabelList(payload.projectId)
101+
.then((response) => {
102+
const url = window.URL.createObjectURL(new Blob([JSON.stringify(response.data)]))
103+
const link = document.createElement('a')
104+
link.href = url
105+
link.setAttribute('download', `project_${payload.projectId}_labels.json`)
106+
document.body.appendChild(link)
107+
link.click()
108+
})
109+
.catch((error) => {
110+
alert(error)
111+
})
112+
.finally(() => {
113+
commit('setLoading', false)
114+
})
80115
}
81116
}

0 commit comments

Comments
 (0)