Skip to content

Commit a97c7ec

Browse files
committed
feat: add entity popover
1 parent 4167b4f commit a97c7ec

14 files changed

+387
-0
lines changed

components.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ declare module 'vue' {
212212
EmptyStateAction: typeof import('./src/components/EmptyState/EmptyStateAction.vue')['default']
213213
EmptyStateImage: typeof import('./src/components/EmptyState/EmptyStateImage.vue')['default']
214214
EmptyStateLabel: typeof import('./src/components/EmptyState/EmptyStateLabel.vue')['default']
215+
EntityPopover: typeof import('./src/components/EntityPopover/EntityPopover.vue')['default']
216+
EntityPopoverInfo: typeof import('./src/components/EntityPopover/EntityPopoverInfo.vue')['default']
217+
EntityPopoverMentionExcerpt: typeof import('./src/components/EntityPopover/EntityPopoverMentionExcerpt.vue')['default']
218+
EntityPopoverMentionOccurrences: typeof import('./src/components/EntityPopover/EntityPopoverMentionOccurrences.vue')['default']
219+
EntityPopoverMentions: typeof import('./src/components/EntityPopover/EntityPopoverMentions.vue')['default']
220+
EntityPopoverTabs: typeof import('./src/components/EntityPopover/EntityPopoverTabs.vue')['default']
215221
Extensions: typeof import('./src/components/Extensions.vue')['default']
216222
ExtractingForm: typeof import('./src/components/ExtractingForm.vue')['default']
217223
ExtractingFormOcrControl: typeof import('./src/components/ExtractingFormOcrControl.vue')['default']
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<template>
2+
<b-popover
3+
teleport-to="body"
4+
:target="target"
5+
:manual="manual"
6+
:model-value="modelValue"
7+
:no-auto-close="noAutoClose"
8+
:placement="placement"
9+
custom-class="document-download-popover"
10+
@update:modelValue="$emit('update:modelValue')"
11+
>
12+
<entity-popover-tabs v-bind="mentionTabsProps" />
13+
</b-popover>
14+
</template>
15+
<script setup>
16+
import { computed } from 'vue'
17+
18+
import EntityPopoverTabs from '@/components/EntityPopover/EntityPopoverTabs'
19+
20+
const props = defineProps({
21+
/**
22+
* The target element
23+
*/
24+
target: {
25+
type: Object
26+
},
27+
/**
28+
* Toggle value when the popover is open
29+
*/
30+
modelValue: {
31+
type: Boolean
32+
},
33+
/**
34+
* True if the popover is open manually
35+
*/
36+
manual: {
37+
type: Boolean
38+
},
39+
/**
40+
* Disable auto close
41+
*/
42+
noAutoClose: {
43+
type: Boolean
44+
},
45+
/**
46+
* The placement of the popover
47+
*/
48+
placement: {
49+
type: String
50+
},
51+
mention: { type: String },
52+
excerpt: { type: String },
53+
projects: { type: Array, default: () => [] },
54+
nbMentions: { type: Number },
55+
language: { type: String },
56+
model: { type: String }
57+
})
58+
59+
const mentionTabsProps = computed(() => {
60+
return {
61+
mention: props.mention,
62+
excerpt: props.excerpt,
63+
projects: props.projects,
64+
nbMentions: props.nbMentions,
65+
language: props.language,
66+
model: props.model
67+
}
68+
})
69+
</script>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script setup>
2+
import { useI18n } from 'vue-i18n'
3+
4+
const props = defineProps({
5+
language: { type: String },
6+
model: { type: String }
7+
})
8+
const { t } = useI18n()
9+
const content = t('entityPopoverInfo.content')
10+
const propertyHtml = (property) => {
11+
return `<span class="font-monospace border border-tertiary rounded-1 p-1 cursor-pointer">${property}</span>`
12+
}
13+
const modelLabel = t('entityPopoverInfo.model', { model: propertyHtml(props.model) })
14+
const languageLabel = t('entityPopoverInfo.language', { language: propertyHtml(props.language) })
15+
const sentence = `${modelLabel} ${languageLabel}`
16+
</script>
17+
18+
<template>
19+
<div class="entity-popover-info">
20+
<p class="text-secondary-emphasis">
21+
{{ content }}
22+
</p>
23+
24+
<span v-html="sentence" />
25+
</div>
26+
</template>
27+
<style scoped lang="scss">
28+
.entity-popover-info {
29+
&__property {
30+
font-family: $font-family-monospace;
31+
}
32+
}
33+
</style>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script setup>
2+
import { computed } from 'vue'
3+
4+
const props = defineProps({
5+
mention: {
6+
type: String
7+
},
8+
excerpt: {
9+
type: String
10+
}
11+
})
12+
const replacement = `<span class="entity-popover-mention-excerpt__mark">${props.mention}</span>`
13+
const content = computed(() => {
14+
return props.excerpt.replace(new RegExp(props.mention, 'g'), replacement)
15+
})
16+
</script>
17+
18+
<template>
19+
<p class="entity-popover-mention-excerpt text-center m-0" v-html="content" />
20+
</template>
21+
22+
<style lang="scss">
23+
.entity-popover-mention-excerpt {
24+
&::before,
25+
&::after {
26+
content: '...';
27+
}
28+
&__mark {
29+
font-weight: $font-weight-bold;
30+
}
31+
}
32+
</style>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script setup>
2+
import { useI18n } from 'vue-i18n'
3+
4+
import ProjectLink from '@/components/Project/ProjectLink'
5+
6+
const props = defineProps({
7+
nbMentions: {
8+
type: Number
9+
},
10+
projects: {
11+
type: Array,
12+
default: () => []
13+
}
14+
})
15+
const { t, n } = useI18n()
16+
const nbProjects = props.projects?.length ?? 0
17+
const occurrences = t('entityPopoverMentionOccurrences.occurrences', {
18+
n: props.nbMentions,
19+
nbMentions: n(props.nbMentions)
20+
})
21+
const projectList = t('entityPopoverMentionOccurrences.projectList', { n: nbProjects })
22+
</script>
23+
24+
<template>
25+
<div class="entity-popover-mention-occurrences">
26+
<p>{{ `${occurrences} ${projectList}` }}</p>
27+
<div class="d-flex gap-2">
28+
<project-link v-for="(project, index) in projects" :key="index" :project="project" />
29+
</div>
30+
</div>
31+
</template>
32+
33+
<style scoped lang="scss"></style>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script setup>
2+
import { TinyPagination } from '@icij/murmur-next'
3+
4+
import EntityPopoverMentionOccurrences from '@/components/EntityPopover/EntityPopoverMentionOccurrences'
5+
import EntityPopoverMentionExcerpt from '@/components/EntityPopover/EntityPopoverMentionExcerpt'
6+
const mentionIndex = defineModel({ type: Number })
7+
defineProps({
8+
mention: { type: String },
9+
excerpt: { type: String },
10+
projects: { type: Array, default: () => [] },
11+
nbMentions: { type: Number }
12+
})
13+
</script>
14+
<template>
15+
<div class="d-flex flex-column align-items-center gap-3">
16+
<entity-popover-mention-excerpt :mention="mention" :excerpt="excerpt" />
17+
<tiny-pagination v-model="mentionIndex" :per-page="1" :total-rows="nbMentions" compact />
18+
<entity-popover-mention-occurrences
19+
:nb-mentions="nbMentions"
20+
:projects="projects"
21+
class="text-secondary-emphasis"
22+
/>
23+
</div>
24+
</template>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<template>
2+
<b-tabs
3+
class="entity-popover-tabs"
4+
active-nav-item-class="border-bottom border-primary "
5+
nav-item-class="text-action-emphasis d-inline-flex align-items-center gap-2 bg-action-subtle"
6+
active-tab-class="my-4"
7+
>
8+
<b-tab>
9+
<template #title
10+
><phosphor-icon name="list-magnifying-glass" />{{ mentionsLabel }}
11+
<b-badge pill variant="tertiary">{{ props.nbMentions }}</b-badge>
12+
</template>
13+
<entity-popover-mentions v-bind="mentionsProps" />
14+
</b-tab>
15+
<b-tab>
16+
<template #title><phosphor-icon name="info" /> {{ infoLabel }}</template>
17+
<entity-popover-info v-bind="infoProps" />
18+
</b-tab>
19+
</b-tabs>
20+
</template>
21+
<script setup>
22+
import { computed } from 'vue'
23+
import { PhosphorIcon } from '@icij/murmur-next'
24+
import { useI18n } from 'vue-i18n'
25+
26+
import EntityPopoverMentions from '@/components/EntityPopover/EntityPopoverMentions'
27+
import EntityPopoverInfo from '@/components/EntityPopover/EntityPopoverInfo'
28+
const props = defineProps({
29+
mention: { type: String },
30+
excerpt: { type: String },
31+
projects: { type: Array, default: () => [] },
32+
nbMentions: { type: Number },
33+
language: { type: String },
34+
model: { type: String }
35+
})
36+
37+
const mentionsProps = computed(() => {
38+
return {
39+
mention: props.mention,
40+
excerpt: props.excerpt,
41+
projects: props.projects,
42+
nbMentions: props.nbMentions
43+
}
44+
})
45+
const infoProps = computed(() => {
46+
return {
47+
language: props.language,
48+
model: props.model
49+
}
50+
})
51+
const { t } = useI18n()
52+
const infoLabel = t('entityPopoverTabs.info')
53+
const mentionsLabel = t('entityPopoverTabs.mentions')
54+
</script>

src/lang/en.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@
103103
"sectionContentType": "What's the document's type",
104104
"sectionDescription": "Once downloaded, how do I open it ?"
105105
},
106+
"entityPopoverInfo": {
107+
"content": "This entity was extracted with:",
108+
"model": "{model} model",
109+
"language": "in {language} language."
110+
},
111+
"entityPopoverMentionOccurrences": {
112+
"occurrences": "This mention appears {nbMentions} times | This mention appears {nbMentions} time | This mention appears {nbMentions} times",
113+
"projectList": "in {n} projects | in {n} project | in {n} projects:"
114+
},
115+
"entityPopoverTabs": {
116+
"mentions": "Mentions",
117+
"info": "Info"
118+
},
106119
"error": {
107120
"title": "Something's wrong here",
108121
"description": "An error has occurred. Please try again later or contact your administrator if the problem persists.",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import EntityPopover from '@/components/EntityPopover/EntityPopover'
2+
3+
export default {
4+
title: 'Components/EntityPopover/EntityPopover',
5+
component: EntityPopover,
6+
tags: ['autodocs'],
7+
args: {
8+
language: 'English',
9+
model: 'CoreNLP',
10+
mention: 'Bruno Mars',
11+
excerpt: 'Lorem ipsum Bruno Mars dolor ipset',
12+
nbMentions: 5033,
13+
projects: ['banana papers', 'citrus confidential']
14+
},
15+
render: (args) => ({
16+
components: {
17+
EntityPopover
18+
},
19+
setup: () => ({ args }),
20+
computed: {
21+
trigger() {
22+
return `btn-${this.$.uid}`
23+
},
24+
title() {
25+
return args.document.title
26+
}
27+
},
28+
template: `
29+
<div class="p-sm-5 p-3 text-center">
30+
<button type="button" class="btn btn-outline-primary" :id="trigger">
31+
Mentions of <var class="text-decoration-underline">{{ args.mention }}</var>
32+
</button>
33+
<entity-popover v-bind="args" :target="trigger" />
34+
</div>
35+
`
36+
})
37+
}
38+
export const Default = {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import EntityPopoverInfo from '@/components/EntityPopover/EntityPopoverInfo'
2+
3+
export default {
4+
title: 'Components/EntityPopover/EntityPopoverInfo',
5+
component: EntityPopoverInfo,
6+
tags: ['autodocs'],
7+
args: {
8+
language: 'english',
9+
model: 'CoreNLP'
10+
}
11+
}
12+
export const Default = {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import EntityPopoverMentionExcerpt from '@/components/EntityPopover/EntityPopoverMentionExcerpt'
2+
3+
export default {
4+
title: 'Components/EntityPopover/EntityPopoverMentionExcerpt',
5+
component: EntityPopoverMentionExcerpt,
6+
tags: ['autodocs'],
7+
args: {
8+
mention: 'Bruno Mars',
9+
excerpt: 'Lorem ipsum Bruno Mars dolor ipset '
10+
}
11+
}
12+
export const Default = {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import EntityPopoverMentionOccurrences from '@/components/EntityPopover/EntityPopoverMentionOccurrences'
2+
3+
export default {
4+
title: 'Components/EntityPopover/EntityPopoverMentionOccurrences',
5+
component: EntityPopoverMentionOccurrences,
6+
tags: ['autodocs'],
7+
args: {
8+
nbMentions: 5033,
9+
projects: ['banana papers', 'citrus confidential']
10+
}
11+
}
12+
export const Default = {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { computed, ref } from 'vue'
2+
3+
import EntityPopoverMentions from '@/components/EntityPopover/EntityPopoverMentions'
4+
const excerpt = 'Lorem ipsum Bruno Mars dolor ipset'
5+
const excerpts = [excerpt, 'Lorem ipsum dolor ipset Bruno Mars', 'Bruno Mars Lorem ipsum dolor ipset']
6+
export default {
7+
title: 'Components/EntityPopover/EntityPopoverMentions',
8+
component: EntityPopoverMentions,
9+
tags: ['autodocs'],
10+
args: {
11+
mention: 'Bruno Mars',
12+
projects: ['banana papers', 'citrus confidential'],
13+
nbMentions: excerpts.length,
14+
excerpt,
15+
excerpts
16+
},
17+
render: (args) => ({
18+
components: {
19+
EntityPopoverMentions
20+
},
21+
setup: () => {
22+
const index = ref(1)
23+
const current = computed(() => excerpts[index.value - 1])
24+
return { args, index, current }
25+
},
26+
27+
template: `
28+
29+
<entity-popover-mentions v-bind="args" :excerpt="current" v-model="index" />
30+
`
31+
})
32+
}
33+
export const Default = {}

0 commit comments

Comments
 (0)