Browse Source

Merge pull request #1263 from doccano/enhancement/#1219

[Enhancement] display shortcut keys
pull/1273/head
Hiroki Nakayama 3 years ago
committed by GitHub
parent
commit
cf470f323e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 273 additions and 16 deletions
  1. 46
      frontend/components/tasks/textClassification/LabelGroup.vue
  2. 46
      frontend/components/tasks/textClassification/LabelSelect.vue
  3. 74
      frontend/components/tasks/textClassification/multiLabel/LabelGroup.vue
  4. 5
      frontend/components/tasks/textClassification/multiLabel/LabelSelect.vue
  5. 69
      frontend/components/tasks/textClassification/singleLabel/LabelGroup.vue
  6. 5
      frontend/components/tasks/textClassification/singleLabel/LabelSelect.vue
  7. 1
      frontend/components/tasks/toolbar/ToolbarLaptop.vue
  8. 8
      frontend/pages/demo/sentiment-analysis/index.vue
  9. 35
      frontend/pages/projects/_id/text-classification/index.vue

46
frontend/components/tasks/textClassification/LabelGroup.vue

@ -0,0 +1,46 @@
<template>
<label-group-single
v-if="singleLabel"
:annotations="annotations"
:labels="labels"
@add="$emit('add', $event)"
@remove="$emit('remove', $event)"
/>
<label-group-multi
v-else
:annotations="annotations"
:labels="labels"
@add="$emit('add', $event)"
@remove="$emit('remove', $event)"
/>
</template>
<script>
import LabelGroupSingle from './singleLabel/LabelGroup.vue'
import LabelGroupMulti from './multiLabel/LabelGroup.vue'
export default {
components: {
LabelGroupSingle,
LabelGroupMulti
},
props: {
labels: {
type: Array,
default: () => [],
required: true
},
annotations: {
type: Array,
default: () => ([]),
required: true
},
singleLabel: {
type: Boolean,
default: false,
required: true
}
}
}
</script>

46
frontend/components/tasks/textClassification/LabelSelect.vue

@ -0,0 +1,46 @@
<template>
<label-select-single
v-if="singleLabel"
:annotations="annotations"
:labels="labels"
@add="$emit('add', $event)"
@remove="$emit('remove', $event)"
/>
<label-select-multi
v-else
:annotations="annotations"
:labels="labels"
@add="$emit('add', $event)"
@remove="$emit('remove', $event)"
/>
</template>
<script>
import LabelSelectSingle from './singleLabel/LabelSelect.vue'
import LabelSelectMulti from './multiLabel/LabelSelect.vue'
export default {
components: {
LabelSelectSingle,
LabelSelectMulti
},
props: {
labels: {
type: Array,
default: () => [],
required: true
},
annotations: {
type: Array,
default: () => ([]),
required: true
},
singleLabel: {
type: Boolean,
default: false,
required: true
}
}
}
</script>

74
frontend/components/tasks/textClassification/multiLabel/LabelGroup.vue

@ -0,0 +1,74 @@
<template>
<v-chip-group
:value="annotatedLabel"
column
multiple
@change="addOrRemove"
>
<v-chip
v-for="item in labels"
:key="item.id"
:color="item.backgroundColor"
filter
:text-color="$contrastColor(item.backgroundColor)"
>
{{ item.text }}
<v-avatar
right
color="white"
class="black--text font-weight-bold"
>
{{ item.suffixKey }}
</v-avatar>
</v-chip>
</v-chip-group>
</template>
<script>
import _ from 'lodash'
export default {
props: {
labels: {
type: Array,
default: () => [],
required: true
},
annotations: {
type: Array,
default: () => ([]),
required: true
}
},
computed: {
annotatedLabel() {
const labelIds = this.annotations.map(item => item.label)
return labelIds.map(id => this.labels.findIndex(item => item.id === id))
}
},
methods: {
addOrRemove(indexes) {
if (indexes.length > this.annotatedLabel.length) {
const index = _.difference(indexes, this.annotatedLabel)
const label = this.labels[index]
this.add(label)
} else {
const index = _.difference(this.annotatedLabel, indexes)
const label = this.labels[index]
this.remove(label)
}
},
add(label) {
this.$emit('add', label.id)
},
remove(label) {
const annotation = this.annotations.find(item => item.label === label.id)
this.$emit('remove', annotation.id)
}
}
}
</script>

frontend/components/tasks/textClassification/TextClassification.vue → frontend/components/tasks/textClassification/multiLabel/LabelSelect.vue

@ -1,12 +1,13 @@
<template> <template>
<v-combobox <v-combobox
v-model="annotatedLabels" v-model="annotatedLabels"
chips
:items="labels" :items="labels"
item-text="text" item-text="text"
:label="$t('labels.labels')"
hide-details
hide-selected hide-selected
chips
multiple multiple
class="pt-0"
:search-input.sync="search" :search-input.sync="search"
@change="search=''" @change="search=''"
> >

69
frontend/components/tasks/textClassification/singleLabel/LabelGroup.vue

@ -0,0 +1,69 @@
<template>
<v-chip-group
:value="annotatedLabel"
column
@change="addOrRemove"
>
<v-chip
v-for="item in labels"
:key="item.id"
:color="item.backgroundColor"
filter
:text-color="$contrastColor(item.backgroundColor)"
>
{{ item.text }}
<v-avatar
right
color="white"
class="black--text font-weight-bold"
>
{{ item.suffixKey }}
</v-avatar>
</v-chip>
</v-chip-group>
</template>
<script>
export default {
props: {
labels: {
type: Array,
default: () => [],
required: true
},
annotations: {
type: Array,
default: () => ([]),
required: true
}
},
computed: {
annotatedLabel() {
const labelIds = this.annotations.map(item => item.label)
return this.labels.findIndex(item => labelIds.includes(item.id))
}
},
methods: {
addOrRemove(index) {
if (index === undefined) {
const label = this.labels[this.annotatedLabel]
this.remove(label)
} else {
const label = this.labels[index]
this.add(label)
}
},
add(label) {
this.$emit('add', label.id)
},
remove(label) {
const annotation = this.annotations.find(item => item.label === label.id)
this.$emit('remove', annotation.id)
}
}
}
</script>

frontend/components/tasks/textClassification/SingleLabel.vue → frontend/components/tasks/textClassification/singleLabel/LabelSelect.vue

@ -1,12 +1,13 @@
<template> <template>
<v-select <v-select
:value="annotatedLabel" :value="annotatedLabel"
chips
:items="labels" :items="labels"
item-text="text" item-text="text"
:label="$t('labels.labels')"
hide-details
hide-selected hide-selected
return-object return-object
chips
class="pt-0"
@change="addOrRemove" @change="addOrRemove"
> >
<template v-slot:selection="{ attrs, item, select, selected }"> <template v-slot:selection="{ attrs, item, select, selected }">

1
frontend/components/tasks/toolbar/ToolbarLaptop.vue

@ -59,6 +59,7 @@
/> />
</v-dialog> </v-dialog>
</v-btn-toggle> </v-btn-toggle>
<slot />
<v-spacer /> <v-spacer />
<button-pagination <button-pagination
:value="page" :value="page"

8
frontend/pages/demo/sentiment-analysis/index.vue

@ -5,13 +5,15 @@
<v-col cols="12" md="9"> <v-col cols="12" md="9">
<v-card> <v-card>
<v-card-title> <v-card-title>
<text-classification
<label-group
:labels="items" :labels="items"
:annotations="currentDoc.annotations" :annotations="currentDoc.annotations"
single-label="true"
@add="addLabel" @add="addLabel"
@remove="removeLabel" @remove="removeLabel"
/> />
</v-card-title> </v-card-title>
<v-divider />
<v-card-text class="title"> <v-card-text class="title">
{{ currentDoc.text }} {{ currentDoc.text }}
</v-card-text> </v-card-text>
@ -27,13 +29,13 @@
<script> <script>
import ListMetadata from '@/components/tasks/metadata/ListMetadata' import ListMetadata from '@/components/tasks/metadata/ListMetadata'
import TextClassification from '@/components/tasks/textClassification/TextClassification'
import LabelGroup from '@/components/tasks/textClassification/LabelGroup'
export default { export default {
layout: 'demo', layout: 'demo',
components: { components: {
TextClassification,
LabelGroup,
ListMetadata ListMetadata
}, },

35
frontend/pages/projects/_id/text-classification/index.vue

@ -11,7 +11,20 @@
class="d-none d-sm-block" class="d-none d-sm-block"
@click:clear-label="clear" @click:clear-label="clear"
@click:review="approve" @click:review="approve"
/>
>
<v-btn-toggle
v-model="labelOption"
mandatory
class="ms-2"
>
<v-btn icon>
<v-icon>mdi-format-list-bulleted</v-icon>
</v-btn>
<v-btn icon>
<v-icon>mdi-text</v-icon>
</v-btn>
</v-btn-toggle>
</toolbar-laptop>
<toolbar-mobile <toolbar-mobile
:total="docs.count" :total="docs.count"
class="d-flex d-sm-none" class="d-flex d-sm-none"
@ -23,21 +36,24 @@
@shortkey="addOrRemove" @shortkey="addOrRemove"
> >
<v-card-title> <v-card-title>
<single-label
v-if="project.singleClassClassification"
<label-group
v-if="labelOption === 0"
:labels="labels" :labels="labels"
:annotations="annotations" :annotations="annotations"
:single-label="project.singleClassClassification"
@add="add" @add="add"
@remove="remove" @remove="remove"
/> />
<text-classification
<label-select
v-else v-else
:labels="labels" :labels="labels"
:annotations="annotations" :annotations="annotations"
:single-label="project.singleClassClassification"
@add="add" @add="add"
@remove="remove" @remove="remove"
/> />
</v-card-title> </v-card-title>
<v-divider />
<v-card-text class="title highlight" v-text="doc.text" /> <v-card-text class="title highlight" v-text="doc.text" />
</v-card> </v-card>
</template> </template>
@ -49,10 +65,10 @@
<script> <script>
import _ from 'lodash' import _ from 'lodash'
import LabelGroup from '@/components/tasks/textClassification/LabelGroup'
import LabelSelect from '@/components/tasks/textClassification/LabelSelect'
import LayoutText from '@/components/tasks/layout/LayoutText' import LayoutText from '@/components/tasks/layout/LayoutText'
import ListMetadata from '@/components/tasks/metadata/ListMetadata' import ListMetadata from '@/components/tasks/metadata/ListMetadata'
import SingleLabel from '@/components/tasks/textClassification/SingleLabel'
import TextClassification from '@/components/tasks/textClassification/TextClassification'
import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop' import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile' import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
@ -60,10 +76,10 @@ export default {
layout: 'workspace', layout: 'workspace',
components: { components: {
LabelGroup,
LabelSelect,
LayoutText, LayoutText,
ListMetadata, ListMetadata,
SingleLabel,
TextClassification,
ToolbarLaptop, ToolbarLaptop,
ToolbarMobile ToolbarMobile
}, },
@ -89,7 +105,8 @@ export default {
docs: [], docs: [],
labels: [], labels: [],
project: {}, project: {},
enableAutoLabeling: false
enableAutoLabeling: false,
labelOption: 0
} }
}, },

Loading…
Cancel
Save