Skip to content

Commit

Permalink
feat: add entity popover
Browse files Browse the repository at this point in the history
  • Loading branch information
caro3801 committed Sep 3, 2024
1 parent 4167b4f commit a97c7ec
Show file tree
Hide file tree
Showing 14 changed files with 387 additions and 0 deletions.
6 changes: 6 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ declare module 'vue' {
EmptyStateAction: typeof import('./src/components/EmptyState/EmptyStateAction.vue')['default']
EmptyStateImage: typeof import('./src/components/EmptyState/EmptyStateImage.vue')['default']
EmptyStateLabel: typeof import('./src/components/EmptyState/EmptyStateLabel.vue')['default']
EntityPopover: typeof import('./src/components/EntityPopover/EntityPopover.vue')['default']
EntityPopoverInfo: typeof import('./src/components/EntityPopover/EntityPopoverInfo.vue')['default']
EntityPopoverMentionExcerpt: typeof import('./src/components/EntityPopover/EntityPopoverMentionExcerpt.vue')['default']
EntityPopoverMentionOccurrences: typeof import('./src/components/EntityPopover/EntityPopoverMentionOccurrences.vue')['default']
EntityPopoverMentions: typeof import('./src/components/EntityPopover/EntityPopoverMentions.vue')['default']
EntityPopoverTabs: typeof import('./src/components/EntityPopover/EntityPopoverTabs.vue')['default']
Extensions: typeof import('./src/components/Extensions.vue')['default']
ExtractingForm: typeof import('./src/components/ExtractingForm.vue')['default']
ExtractingFormOcrControl: typeof import('./src/components/ExtractingFormOcrControl.vue')['default']
Expand Down
69 changes: 69 additions & 0 deletions src/components/EntityPopover/EntityPopover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<template>
<b-popover
teleport-to="body"
:target="target"
:manual="manual"
:model-value="modelValue"
:no-auto-close="noAutoClose"
:placement="placement"
custom-class="document-download-popover"
@update:modelValue="$emit('update:modelValue')"
>
<entity-popover-tabs v-bind="mentionTabsProps" />
</b-popover>
</template>
<script setup>
import { computed } from 'vue'
import EntityPopoverTabs from '@/components/EntityPopover/EntityPopoverTabs'
const props = defineProps({
/**
* The target element
*/
target: {
type: Object
},
/**
* Toggle value when the popover is open
*/
modelValue: {
type: Boolean
},
/**
* True if the popover is open manually
*/
manual: {
type: Boolean
},
/**
* Disable auto close
*/
noAutoClose: {
type: Boolean
},
/**
* The placement of the popover
*/
placement: {
type: String
},
mention: { type: String },
excerpt: { type: String },
projects: { type: Array, default: () => [] },
nbMentions: { type: Number },
language: { type: String },
model: { type: String }
})
const mentionTabsProps = computed(() => {
return {
mention: props.mention,
excerpt: props.excerpt,
projects: props.projects,
nbMentions: props.nbMentions,
language: props.language,
model: props.model
}
})
</script>
33 changes: 33 additions & 0 deletions src/components/EntityPopover/EntityPopoverInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup>
import { useI18n } from 'vue-i18n'
const props = defineProps({
language: { type: String },
model: { type: String }
})
const { t } = useI18n()
const content = t('entityPopoverInfo.content')
const propertyHtml = (property) => {
return `<span class="font-monospace border border-tertiary rounded-1 p-1 cursor-pointer">${property}</span>`
}
const modelLabel = t('entityPopoverInfo.model', { model: propertyHtml(props.model) })
const languageLabel = t('entityPopoverInfo.language', { language: propertyHtml(props.language) })
const sentence = `${modelLabel} ${languageLabel}`
</script>

<template>
<div class="entity-popover-info">
<p class="text-secondary-emphasis">
{{ content }}
</p>

<span v-html="sentence" />
</div>
</template>
<style scoped lang="scss">
.entity-popover-info {
&__property {
font-family: $font-family-monospace;
}
}
</style>
32 changes: 32 additions & 0 deletions src/components/EntityPopover/EntityPopoverMentionExcerpt.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup>
import { computed } from 'vue'
const props = defineProps({
mention: {
type: String
},
excerpt: {
type: String
}
})
const replacement = `<span class="entity-popover-mention-excerpt__mark">${props.mention}</span>`
const content = computed(() => {
return props.excerpt.replace(new RegExp(props.mention, 'g'), replacement)
})
</script>

<template>
<p class="entity-popover-mention-excerpt text-center m-0" v-html="content" />
</template>

<style lang="scss">
.entity-popover-mention-excerpt {
&::before,
&::after {
content: '...';
}
&__mark {
font-weight: $font-weight-bold;
}
}
</style>
33 changes: 33 additions & 0 deletions src/components/EntityPopover/EntityPopoverMentionOccurrences.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup>
import { useI18n } from 'vue-i18n'
import ProjectLink from '@/components/Project/ProjectLink'
const props = defineProps({
nbMentions: {
type: Number
},
projects: {
type: Array,
default: () => []
}
})
const { t, n } = useI18n()
const nbProjects = props.projects?.length ?? 0
const occurrences = t('entityPopoverMentionOccurrences.occurrences', {
n: props.nbMentions,
nbMentions: n(props.nbMentions)
})
const projectList = t('entityPopoverMentionOccurrences.projectList', { n: nbProjects })
</script>
<template>
<div class="entity-popover-mention-occurrences">
<p>{{ `${occurrences} ${projectList}` }}</p>
<div class="d-flex gap-2">
<project-link v-for="(project, index) in projects" :key="index" :project="project" />
</div>
</div>
</template>
<style scoped lang="scss"></style>
24 changes: 24 additions & 0 deletions src/components/EntityPopover/EntityPopoverMentions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup>
import { TinyPagination } from '@icij/murmur-next'
import EntityPopoverMentionOccurrences from '@/components/EntityPopover/EntityPopoverMentionOccurrences'
import EntityPopoverMentionExcerpt from '@/components/EntityPopover/EntityPopoverMentionExcerpt'
const mentionIndex = defineModel({ type: Number })
defineProps({
mention: { type: String },
excerpt: { type: String },
projects: { type: Array, default: () => [] },
nbMentions: { type: Number }
})
</script>
<template>
<div class="d-flex flex-column align-items-center gap-3">
<entity-popover-mention-excerpt :mention="mention" :excerpt="excerpt" />
<tiny-pagination v-model="mentionIndex" :per-page="1" :total-rows="nbMentions" compact />
<entity-popover-mention-occurrences
:nb-mentions="nbMentions"
:projects="projects"
class="text-secondary-emphasis"
/>
</div>
</template>
54 changes: 54 additions & 0 deletions src/components/EntityPopover/EntityPopoverTabs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<b-tabs
class="entity-popover-tabs"
active-nav-item-class="border-bottom border-primary "
nav-item-class="text-action-emphasis d-inline-flex align-items-center gap-2 bg-action-subtle"
active-tab-class="my-4"
>
<b-tab>
<template #title
><phosphor-icon name="list-magnifying-glass" />{{ mentionsLabel }}
<b-badge pill variant="tertiary">{{ props.nbMentions }}</b-badge>
</template>
<entity-popover-mentions v-bind="mentionsProps" />
</b-tab>
<b-tab>
<template #title><phosphor-icon name="info" /> {{ infoLabel }}</template>
<entity-popover-info v-bind="infoProps" />
</b-tab>
</b-tabs>
</template>
<script setup>
import { computed } from 'vue'
import { PhosphorIcon } from '@icij/murmur-next'
import { useI18n } from 'vue-i18n'
import EntityPopoverMentions from '@/components/EntityPopover/EntityPopoverMentions'
import EntityPopoverInfo from '@/components/EntityPopover/EntityPopoverInfo'
const props = defineProps({
mention: { type: String },
excerpt: { type: String },
projects: { type: Array, default: () => [] },
nbMentions: { type: Number },
language: { type: String },
model: { type: String }
})
const mentionsProps = computed(() => {
return {
mention: props.mention,
excerpt: props.excerpt,
projects: props.projects,
nbMentions: props.nbMentions
}
})
const infoProps = computed(() => {
return {
language: props.language,
model: props.model
}
})
const { t } = useI18n()
const infoLabel = t('entityPopoverTabs.info')
const mentionsLabel = t('entityPopoverTabs.mentions')
</script>
13 changes: 13 additions & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@
"sectionContentType": "What's the document's type",
"sectionDescription": "Once downloaded, how do I open it ?"
},
"entityPopoverInfo": {
"content": "This entity was extracted with:",
"model": "{model} model",
"language": "in {language} language."
},
"entityPopoverMentionOccurrences": {
"occurrences": "This mention appears {nbMentions} times | This mention appears {nbMentions} time | This mention appears {nbMentions} times",
"projectList": "in {n} projects | in {n} project | in {n} projects:"
},
"entityPopoverTabs": {
"mentions": "Mentions",
"info": "Info"
},
"error": {
"title": "Something's wrong here",
"description": "An error has occurred. Please try again later or contact your administrator if the problem persists.",
Expand Down
38 changes: 38 additions & 0 deletions src/stories/components/EntityPopover/EntityPopover.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import EntityPopover from '@/components/EntityPopover/EntityPopover'

export default {
title: 'Components/EntityPopover/EntityPopover',
component: EntityPopover,
tags: ['autodocs'],
args: {
language: 'English',
model: 'CoreNLP',
mention: 'Bruno Mars',
excerpt: 'Lorem ipsum Bruno Mars dolor ipset',
nbMentions: 5033,
projects: ['banana papers', 'citrus confidential']
},
render: (args) => ({
components: {
EntityPopover
},
setup: () => ({ args }),
computed: {
trigger() {
return `btn-${this.$.uid}`
},
title() {
return args.document.title
}
},
template: `
<div class="p-sm-5 p-3 text-center">
<button type="button" class="btn btn-outline-primary" :id="trigger">
Mentions of <var class="text-decoration-underline">{{ args.mention }}</var>
</button>
<entity-popover v-bind="args" :target="trigger" />
</div>
`
})
}
export const Default = {}
12 changes: 12 additions & 0 deletions src/stories/components/EntityPopover/EntityPopoverInfo.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import EntityPopoverInfo from '@/components/EntityPopover/EntityPopoverInfo'

export default {
title: 'Components/EntityPopover/EntityPopoverInfo',
component: EntityPopoverInfo,
tags: ['autodocs'],
args: {
language: 'english',
model: 'CoreNLP'
}
}
export const Default = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import EntityPopoverMentionExcerpt from '@/components/EntityPopover/EntityPopoverMentionExcerpt'

export default {
title: 'Components/EntityPopover/EntityPopoverMentionExcerpt',
component: EntityPopoverMentionExcerpt,
tags: ['autodocs'],
args: {
mention: 'Bruno Mars',
excerpt: 'Lorem ipsum Bruno Mars dolor ipset '
}
}
export const Default = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import EntityPopoverMentionOccurrences from '@/components/EntityPopover/EntityPopoverMentionOccurrences'

export default {
title: 'Components/EntityPopover/EntityPopoverMentionOccurrences',
component: EntityPopoverMentionOccurrences,
tags: ['autodocs'],
args: {
nbMentions: 5033,
projects: ['banana papers', 'citrus confidential']
}
}
export const Default = {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { computed, ref } from 'vue'

import EntityPopoverMentions from '@/components/EntityPopover/EntityPopoverMentions'
const excerpt = 'Lorem ipsum Bruno Mars dolor ipset'
const excerpts = [excerpt, 'Lorem ipsum dolor ipset Bruno Mars', 'Bruno Mars Lorem ipsum dolor ipset']
export default {
title: 'Components/EntityPopover/EntityPopoverMentions',
component: EntityPopoverMentions,
tags: ['autodocs'],
args: {
mention: 'Bruno Mars',
projects: ['banana papers', 'citrus confidential'],
nbMentions: excerpts.length,
excerpt,
excerpts
},
render: (args) => ({
components: {
EntityPopoverMentions
},
setup: () => {
const index = ref(1)
const current = computed(() => excerpts[index.value - 1])
return { args, index, current }
},

template: `
<entity-popover-mentions v-bind="args" :excerpt="current" v-model="index" />
`
})
}
export const Default = {}
Loading

0 comments on commit a97c7ec

Please sign in to comment.