Skip to content
Snippets Groups Projects
Commit 29fc19d9 authored by Bastien Abadie's avatar Bastien Abadie
Browse files

Merge branch 'overflow-warning' into 'master'

Show entity overlap warning

Closes #782

See merge request !1070
parents cde293a6 ba49e13c
No related branches found
No related tags found
1 merge request!1070Show entity overlap warning
......@@ -9,7 +9,7 @@
{
"uid": "c6eae96a2c1f3eb7261f445f47f3598e",
"css": "flow-tree",
"code": 59392,
"code": 59393,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -23,7 +23,7 @@
{
"uid": "cb0fb378c65a1d1f7d342f45d5855f03",
"css": "edit-alt",
"code": 59393,
"code": 59394,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -37,7 +37,7 @@
{
"uid": "560e50dfcfbf395901bff6588654487f",
"css": "menu-outline",
"code": 59394,
"code": 59395,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -51,7 +51,7 @@
{
"uid": "b0e4aedb15b370fd6d9e9c35e260d25e",
"css": "award",
"code": 59395,
"code": 59396,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -65,7 +65,7 @@
{
"uid": "21886ddfb8c0718fb4bdc8b24e3f9997",
"css": "user",
"code": 59396,
"code": 59397,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -79,7 +79,7 @@
{
"uid": "9de88e5c52ef715408d87748f822aaf3",
"css": "search",
"code": 59397,
"code": 59398,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -93,7 +93,7 @@
{
"uid": "62d5c374c32bc9a99627ac1d47565027",
"css": "git",
"code": 59398,
"code": 59399,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -107,7 +107,7 @@
{
"uid": "1b381aeccbbe4e96e2916fb173014483",
"css": "feather",
"code": 59399,
"code": 59400,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -121,7 +121,7 @@
{
"uid": "bb79a5ee239225fa9b3dc97da5727866",
"css": "globe",
"code": 59400,
"code": 59401,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -135,7 +135,7 @@
{
"uid": "627ccf054f25895eac4bc4e3aaba4e07",
"css": "lock",
"code": 59401,
"code": 59402,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -149,7 +149,7 @@
{
"uid": "b62c21b60c0f2cc0b3a778f93d65deab",
"css": "teklia-e",
"code": 59402,
"code": 59403,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -163,7 +163,7 @@
{
"uid": "d4c3826f33dd7a3a6a36fb98a47c9a31",
"css": "down-open",
"code": 59403,
"code": 59404,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -177,7 +177,7 @@
{
"uid": "ade1c7073f5b5c55fb779c9944b78609",
"css": "asterisk",
"code": 59404,
"code": 59405,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -191,7 +191,7 @@
{
"uid": "fd051023abda27bbd7253f6c5cf8709e",
"css": "number",
"code": 59405,
"code": 59406,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -205,7 +205,7 @@
{
"uid": "313dadbbdbf8d4d55ff52a1ef8680813",
"css": "edit",
"code": 59406,
"code": 59407,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -219,7 +219,7 @@
{
"uid": "7c8bffca570ab459e4647cd8d1d4c5ad",
"css": "bookmark",
"code": 59407,
"code": 59408,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -233,7 +233,7 @@
{
"uid": "7b2f5044ca73aa386357e351ca6ecc89",
"css": "check",
"code": 59408,
"code": 59409,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -247,7 +247,7 @@
{
"uid": "8c969c2e548b65445502db0f43c3ac8b",
"css": "date",
"code": 59409,
"code": 59410,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -261,7 +261,7 @@
{
"uid": "d899efcf870be93ab64b09048b30869a",
"css": "undo",
"code": 59410,
"code": 59411,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -275,7 +275,7 @@
{
"uid": "30b8c1de747d2d67413c0113c9aa015d",
"css": "help",
"code": 59411,
"code": 59412,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -541,7 +541,7 @@
{
"uid": "408d1725a2db2001f7491bfb4c2514cb",
"css": "plus",
"code": 59413,
"code": 59392,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -555,7 +555,7 @@
{
"uid": "d02ba5ee814fb77f6762a4ea172da748",
"css": "organization",
"code": 59412,
"code": 59422,
"src": "custom_icons",
"selected": true,
"svg": {
......@@ -637,6 +637,12 @@
"css": "sort-desc",
"code": 61793,
"src": "fontawesome"
},
{
"uid": "c76b7947c957c9b78b11741173c8349b",
"css": "warning",
"code": 59413,
"src": "fontawesome"
}
]
}
\ No newline at end of file
This diff is collapsed.
No preview for this file type
This diff is collapsed.
......@@ -6,7 +6,7 @@ import { orderBy } from 'lodash'
* @param {string} text Transcription text to place the entities on.
* @param {EntityTranscription[]} entities EntityTranscriptions from the API to place onto the text.
* @param {number} textOffset Global offset to apply to the text when parsing only a portion of the text.
* @returns {{offset: number, text: string, entity?: object, children: EntityTranscription[]}[]}
* @returns {{offset: number, text: string, entity?: object, children: EntityTranscription[], overflow?: boolean}[]}
* Sets of properties to be used on the Token component for display.
*/
export const parseEntities = (text, entities, textOffset = 0) => {
......@@ -31,18 +31,26 @@ export const parseEntities = (text, entities, textOffset = 0) => {
continue
}
if (offset + length - textOffset > text.length) {
// eslint-disable-next-line no-console
console.error(`Entity ${entity.id} exceeds the transcription's or the parent entity's text length.`)
}
// There might be some text without an entity before this entity
const prefix = text.substring(cursor - textOffset, offset - textOffset)
if (prefix) tokens.push({ offset: offset - prefix.length, text: prefix, children: [] })
if (prefix) {
tokens.push({
offset: offset - prefix.length,
text: prefix,
children: []
})
}
cursor = offset + length
const entityText = text.substring(offset - textOffset, cursor - textOffset)
tokens.push({ offset, entity, text: entityText, children: [] })
tokens.push({
offset,
entity,
text: entityText,
children: [],
// Detects if this entity exceeds the transcription's or the parent entity's text, an unsupported edge case
overflow: offset + length - textOffset > text.length
})
}
// There might be some text without entities after all the tokens
......
......@@ -69,7 +69,8 @@ describe('Element/Transcription/Box.vue', () => {
offset: 0,
text: 'Vulpix used EMBER!',
entity: null,
children: []
children: [],
overflow: false
}
])
})
......@@ -80,13 +81,15 @@ describe('Element/Transcription/Box.vue', () => {
offset: 0,
text: 'Vulpix',
entity: entity1,
children: []
children: [],
overflow: false
},
{
offset: 6,
text: ' used EMBER!',
entity: null,
children: []
children: [],
overflow: false
}
])
})
......@@ -117,13 +120,15 @@ describe('Element/Transcription/Box.vue', () => {
length: 5,
entity: entity2
}
]
],
overflow: false
},
{
offset: 17,
text: '!',
entity: null,
children: []
children: [],
overflow: false
}
])
})
......
import assert from 'assert'
import sinon from 'sinon'
import { shallowMount, RouterLinkStub, createLocalVue } from '@vue/test-utils'
import Token from '~/vue/Element/Transcription/Token'
......@@ -17,20 +16,6 @@ describe('Element/Transcription/Token.vue', () => {
type: 'misc'
}
var spy
before('set up console.error spy', () => {
spy = sinon.spy(console, 'error')
})
beforeEach(() => {
spy.resetHistory()
})
after('tear down console.error spy', () => {
spy.restore()
})
it('displays regular text', () => {
const wrapper = shallowMount(Token, {
localVue,
......@@ -65,9 +50,10 @@ describe('Element/Transcription/Token.vue', () => {
offset: 0,
text: 'Vulpix',
entity: null,
children: []
children: [],
overflow: false
})
assert.ok(spy.notCalled)
assert.ok(!wrapper.find('.icon-warning').exists())
})
it('supports nested entities', () => {
......@@ -86,7 +72,8 @@ describe('Element/Transcription/Token.vue', () => {
length: 4,
entity: entity2
}
]
],
overflow: false
}
})
const type = wrapper.get('.entity-type')
......@@ -97,22 +84,25 @@ describe('Element/Transcription/Token.vue', () => {
offset: 0,
text: 'Vulpix ',
entity: null,
children: []
children: [],
overflow: false
},
{
offset: 7,
text: 'used',
entity: entity2,
children: []
children: [],
overflow: false
},
{
offset: 11,
text: ' EMBER',
entity: null,
children: []
children: [],
overflow: false
}
])
assert.ok(spy.notCalled)
assert.ok(!wrapper.find('.icon-warning').exists())
})
it('warns on overlapping entities', () => {
......@@ -131,26 +121,10 @@ describe('Element/Transcription/Token.vue', () => {
length: 10,
entity: entity2
}
]
],
overflow: true
}
})
const type = wrapper.get('.entity-type')
assert.strictEqual(type.attributes('title'), 'person - Vulpix')
assert.strictEqual(type.text(), 'person')
assert.deepStrictEqual(wrapper.findAll('token-stub').wrappers.map(w => w.props()), [
{
offset: 0,
text: 'Vulpix ',
entity: null,
children: []
},
{
offset: 7,
text: 'used',
entity: entity2,
children: []
}
])
assert.ok(spy.calledOnceWithExactly("Entity entity2 exceeds the transcription's or the parent entity's text length."))
assert.ok(wrapper.find('.icon-warning').exists())
})
})
......@@ -49,7 +49,8 @@ describe('helpers/entity', () => {
offset: 0,
entity: entity1,
children: [],
text: 'Vulpix'
text: 'Vulpix',
overflow: false
},
{
offset: 6,
......@@ -60,7 +61,8 @@ describe('helpers/entity', () => {
offset: 12,
entity: entity2,
children: [],
text: 'EMBER'
text: 'EMBER',
overflow: false
},
{
offset: 17,
......@@ -105,7 +107,8 @@ describe('helpers/entity', () => {
offset: 0,
text: 'Vulpix',
entity: entity1,
children: []
children: [],
overflow: false
},
{
offset: 6,
......@@ -131,11 +134,12 @@ describe('helpers/entity', () => {
offset: 0,
text: 'Vulpix',
entity: entity1,
children: []
children: [],
overflow: true
}
]
)
assert.ok(spy.calledOnceWithExactly("Entity entity1 exceeds the transcription's or the parent entity's text length."))
assert.ok(spy.notCalled)
})
it('supports parsing a portion of text', () => {
......@@ -157,7 +161,8 @@ describe('helpers/entity', () => {
offset: 12,
entity: entity2,
children: [],
text: 'EMBER'
text: 'EMBER',
overflow: false
},
{
offset: 17,
......@@ -194,7 +199,8 @@ describe('helpers/entity', () => {
length: 5,
entity: entity2
}
]
],
overflow: false
}
]
)
......@@ -225,11 +231,15 @@ describe('helpers/entity', () => {
children: [
{
offset: 7,
// The length exceeds "Vulpix used", so we will get a warning about an entity exceeding the text
/*
* The length exceeds "Vulpix used", so we will get a warning about an entity exceeding the text
* once the component calls parseEntities on the children.
*/
length: 10,
entity: entity2
}
]
],
overflow: false
},
{
offset: 11,
......
<template>
<router-link
class="entity"
:style="entityStyle"
v-if="entity"
:to="{ name: 'entity-details', params: { id: entity.id } }"
>
<span
class="entity-type"
:style="entityTypeStyle"
:title="`${entity.type} - ${entity.name}`"
>{{ entityType }}</span>
<template v-if="tokens.length">
<Token
v-for="(token, index) in tokens"
:key="index"
v-bind="token"
/>
</template>
<span>
<router-link
class="entity"
:style="entityStyle"
v-if="entity"
:to="{ name: 'entity-details', params: { id: entity.id } }"
>
<span
class="entity-type"
:style="entityTypeStyle"
:title="`${entity.type} - ${entity.name}`"
>{{ entityType }}</span>
<template v-if="tokens.length">
<Token
v-for="(token, index) in tokens"
:key="index"
v-bind="token"
/>
</template>
<span class="entity-text" v-else>{{ cleanText }}</span>
</router-link>
<span class="entity-text" v-else>{{ cleanText }}</span>
</router-link>
<span class="entity-text" v-else>{{ cleanText }}</span>
<span
v-if="overflow"
class="icon has-text-warning has-tooltip-bottom"
data-tooltip="This entity exceeds the parent's text length"
>
<i class="icon-warning"></i>
</span>
</span>
</template>
<script>
......@@ -45,6 +54,11 @@ export default {
children: {
type: Array,
default: () => []
},
// Show a warning about an entity overflowing its parent
overflow: {
type: Boolean,
default: false
}
},
computed: {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment