Skip to content

Commit

Permalink
feat(labels + segments): disable Done if duplicate name
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulHax committed Mar 1, 2024
1 parent ef9de04 commit badca45
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 22 deletions.
18 changes: 15 additions & 3 deletions src/components/LabelControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { AnnotationTool } from '@/src/types/annotation-tool';
import { Maybe } from '@/src/types';
import ToolLabelEditor from '@/src/components/ToolLabelEditor.vue';
import IsolatedDialog from '@/src/components/IsolatedDialog.vue';
import { nonNullable } from '@/src/utils';
const props = defineProps<{
labelsStore: LabelsStore<Pick<AnnotationTool, 'strokeWidth'>>;
Expand Down Expand Up @@ -42,6 +43,17 @@ const editingLabel = computed(() => {
return props.labelsStore.labels[editingLabelID.value];
});
const invalidNames = computed(() => {
const names = new Set(
Object.values(props.labelsStore.labels)
.map(({ labelName }) => labelName)
.filter(nonNullable)
);
const currentName = editingLabel.value?.labelName;
if (currentName) names.delete(currentName); // allow current name
return names;
});
const makeUniqueName = (name: string) => {
const existingNames = new Set(
Object.values(props.labelsStore.labels).map((label) => label.labelName)
Expand Down Expand Up @@ -99,7 +111,7 @@ function deleteEditingLabel() {
@create="createLabel"
>
<template #item-prepend="{ item }">
<!-- dot container keeps overflowing name from squishing dot width -->
<!-- dot-container class keeps overflowing name from squishing dot width -->
<div class="dot-container mr-3">
<div class="color-dot" :style="{ background: item.color }" />
</div>
Expand All @@ -120,15 +132,15 @@ function deleteEditingLabel() {
</v-card>

<isolated-dialog v-model="editDialog" max-width="800px">
<ToolLabelEditor
<tool-label-editor
v-if="editingLabelID"
v-model:name="editState.labelName"
v-model:stroke-width="editState.strokeWidth"
v-model:color="editState.color"
@delete="deleteEditingLabel"
@cancel="stopEditing(false)"
@done="stopEditing(true)"
:labelsStore="labelsStore"
:invalidNames="invalidNames"
/>
</isolated-dialog>
</template>
Expand Down
10 changes: 6 additions & 4 deletions src/components/LabelEditor.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script setup lang="ts">
import { toRefs } from 'vue';
import { computed, toRefs } from 'vue';
const emit = defineEmits(['done', 'cancel', 'delete', 'update:color']);
const props = defineProps({
color: String,
const props = defineProps<{ color: string; valid: boolean }>();
const { color, valid } = toRefs(props);
const doneDisabled = computed(() => {
return !valid.value;
});
const { color } = toRefs(props);
const done = () => {
emit('done');
Expand Down Expand Up @@ -40,6 +41,7 @@ const onDelete = () => {
color="secondary"
variant="elevated"
@click="done"
:disabled="doneDisabled"
data-testid="edit-label-done-button"
>
Done
Expand Down
22 changes: 19 additions & 3 deletions src/components/SegmentEditor.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
<script setup lang="ts">
import LabelEditor from '@/src/components/LabelEditor.vue';
import { computed } from 'vue';
defineEmits(['done', 'cancel', 'delete', 'update:name', 'update:color']);
defineProps({
name: String,
color: String,
const props = defineProps<{
name: string;
color: string;
invalidNames: Set<string>;
}>();
function isUniqueEditingName(name: string) {
return !props.invalidNames.has(name.trim());
}
function uniqueNameRule(name: string) {
return isUniqueEditingName(name) || 'Name is not unique';
}
const valid = computed(() => {
return isUniqueEditingName(props.name);
});
</script>

<template>
<label-editor
:color="color"
:valid="valid"
@update:color="$emit('update:color', $event)"
@delete="$emit('delete')"
@cancel="$emit('cancel')"
Expand All @@ -24,6 +39,7 @@ defineProps({
:model-value="name"
@update:model-value="$emit('update:name', $event)"
@keydown.stop.enter="done"
:rules="[uniqueNameRule]"
/>
</template>
</label-editor>
Expand Down
7 changes: 7 additions & 0 deletions src/components/SegmentList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ const editingSegment = computed(() => {
if (editingSegmentValue.value == null) return null;
return segmentGroupStore.getSegment(groupId.value, editingSegmentValue.value);
});
const invalidNames = computed(() => {
const names = new Set(segments.value.map((seg) => seg.name));
const currentName = editingSegment.value?.name;
if (currentName) names.delete(currentName); // allow current name
return names;
});
function startEditing(value: number) {
editDialog.value = true;
Expand Down Expand Up @@ -145,6 +151,7 @@ function deleteEditingSegment() {
@delete="deleteEditingSegment"
@cancel="stopEditing(false)"
@done="stopEditing(true)"
:invalidNames="invalidNames"
/>
</isolated-dialog>
</template>
Expand Down
20 changes: 8 additions & 12 deletions src/components/ToolLabelEditor.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<script setup lang="ts">
import { computed } from 'vue';
import LabelEditor from '@/src/components/LabelEditor.vue';
import type { LabelsStore } from '../store/tools/useLabels';
import type { AnnotationTool } from '../types/annotation-tool';
defineEmits([
'done',
Expand All @@ -17,28 +15,26 @@ const props = defineProps<{
name: string;
strokeWidth: number;
color: string;
labelsStore: LabelsStore<Pick<AnnotationTool, 'strokeWidth'>>;
invalidNames: Set<string>;
}>();
const existingNames = computed(
() =>
new Set(
Object.values(props.labelsStore.labels).map((label) => label.labelName)
)
);
function isUniqueEditingName(name: string) {
return !existingNames.value.has(name);
return !props.invalidNames.has(name.trim());
}
function uniqueNameRule(name: string) {
return isUniqueEditingName(name) || 'Name is not unique';
}
const valid = computed(() => {
return isUniqueEditingName(props.name);
});
</script>

<template>
<label-editor
:color="color"
:valid="valid"
@update:color="$emit('update:color', $event)"
@cancel="$emit('cancel')"
@done="$emit('done')"
Expand All @@ -53,7 +49,7 @@ function uniqueNameRule(name: string) {
<v-text-field
label="Name"
class="flex-grow-0"
:model-value="name"
:model-value="props.name"
@update:model-value="$emit('update:name', $event)"
@keydown.stop.enter="done"
:rules="[uniqueNameRule]"
Expand Down

0 comments on commit badca45

Please sign in to comment.