From 9b0fc2226b930ea05e41ed2419dce837b3c02688 Mon Sep 17 00:00:00 2001 From: BeritJanssen Date: Thu, 28 Mar 2024 12:54:33 +0100 Subject: [PATCH 01/73] add Elasticsearch annotated-text plugin --- DockerfileElastic | 3 +++ docker-compose.yaml | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 DockerfileElastic diff --git a/DockerfileElastic b/DockerfileElastic new file mode 100644 index 000000000..2b908c5fb --- /dev/null +++ b/DockerfileElastic @@ -0,0 +1,3 @@ +FROM docker.elastic.co/elasticsearch/elasticsearch:8.10.2 + +RUN bin/elasticsearch-plugin install mapper-annotated-text diff --git a/docker-compose.yaml b/docker-compose.yaml index 9277df751..f3f4d63b3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -52,7 +52,9 @@ services: target: /frontend/build command: sh -c "yarn prebuild && yarn start-docker" elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 + build: + context: . + dockerfile: DockerfileElastic environment: - node.name=ianalyzer-node - discovery.type=single-node From ffdfe30f584cf2a262439c51c8ca05d25d8d70d6 Mon Sep 17 00:00:00 2001 From: BeritJanssen Date: Thu, 28 Mar 2024 12:54:51 +0100 Subject: [PATCH 02/73] extend FoundDocument with entities --- frontend/src/_utilities.scss | 5 +++ .../document-view.component.html | 1 + .../document-view/document-view.component.ts | 2 +- .../document-preview.component.html | 8 ++-- .../document-preview.component.scss | 3 ++ frontend/src/app/document/document.module.ts | 2 + .../entity-legend.component.html | 3 ++ .../entity-legend.component.scss | 7 +++ .../entity-legend.component.spec.ts | 25 +++++++++++ .../entity-legend/entity-legend.component.ts | 21 +++++++++ .../src/app/models/found-document.spec.ts | 44 ++++++++++++++----- frontend/src/app/models/found-document.ts | 21 +++++++-- frontend/src/app/models/search-results.ts | 5 +++ .../src/app/services/download.service.spec.ts | 2 - .../app/services/elastic-search.service.ts | 11 +++-- frontend/src/app/services/entity.service.ts | 18 ++++++++ .../src/app/services/search.service.spec.ts | 2 - frontend/src/mock-data/constructor-helpers.ts | 4 +- frontend/src/mock-data/elastic-search.ts | 2 +- frontend/src/mock-data/search.ts | 5 ++- frontend/src/styles.scss | 13 ++++++ 21 files changed, 175 insertions(+), 29 deletions(-) create mode 100644 frontend/src/app/document/entity-legend/entity-legend.component.html create mode 100644 frontend/src/app/document/entity-legend/entity-legend.component.scss create mode 100644 frontend/src/app/document/entity-legend/entity-legend.component.spec.ts create mode 100644 frontend/src/app/document/entity-legend/entity-legend.component.ts create mode 100644 frontend/src/app/services/entity.service.ts diff --git a/frontend/src/_utilities.scss b/frontend/src/_utilities.scss index 225735d40..15315baae 100644 --- a/frontend/src/_utilities.scss +++ b/frontend/src/_utilities.scss @@ -30,6 +30,11 @@ $section-padding: 3rem 1.5rem; $boxShadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); $boxShadowHover: 0px 5px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px $primary; +$entity-person: #88CCEE; +$entity-location:#44AA99; +$entity-organization: #DDCC77; +$entity-miscellaneous: #AA4499; + @import "~bulma/sass/utilities/_all"; // based on the Bulma loader diff --git a/frontend/src/app/document-view/document-view.component.html b/frontend/src/app/document-view/document-view.component.html index e3fa71a3d..dbfef7c9b 100644 --- a/frontend/src/app/document-view/document-view.component.html +++ b/frontend/src/app/document-view/document-view.component.html @@ -42,6 +42,7 @@ [attr.lang]="document.language(field)" [innerHtml]="formatInnerHtml(field)"> + diff --git a/frontend/src/app/document-view/document-view.component.ts b/frontend/src/app/document-view/document-view.component.ts index 3452d4906..b13790d2f 100644 --- a/frontend/src/app/document-view/document-view.component.ts +++ b/frontend/src/app/document-view/document-view.component.ts @@ -4,7 +4,6 @@ import { CorpusField, FoundDocument, Corpus, QueryModel } from '../models/index' import { DocumentView } from '../models/document-page'; import * as _ from 'lodash'; import { documentIcons } from '../shared/icons'; -import { findByName } from '../utils/utils'; @Component({ selector: 'ia-document-view', @@ -53,6 +52,7 @@ export class DocumentViewComponent implements OnChanges { ngOnChanges(changes: SimpleChanges): void { if (changes.view) { this.activeTab = this.tabFromView(this.view); + this.document.fetchEntities(); } } diff --git a/frontend/src/app/document/document-preview/document-preview.component.html b/frontend/src/app/document/document-preview/document-preview.component.html index 87429833f..dba6cf8ad 100644 --- a/frontend/src/app/document/document-preview/document-preview.component.html +++ b/frontend/src/app/document/document-preview/document-preview.component.html @@ -1,4 +1,7 @@ +
+ Relevance: +
@@ -24,10 +27,9 @@
-
- Relevance: + -
- + - + @@ -40,7 +40,7 @@
+ [innerHtml]="field | elasticsearchHighlight:document">
diff --git a/frontend/src/app/document-view/document-view.component.ts b/frontend/src/app/document-view/document-view.component.ts index b13790d2f..1f5171d79 100644 --- a/frontend/src/app/document-view/document-view.component.ts +++ b/frontend/src/app/document-view/document-view.component.ts @@ -76,62 +76,4 @@ export class DocumentViewComponent implements OnChanges { return field.mappingType === 'geo_point'; } - displayGeoPointField(field: CorpusField) { - let latitude = this.document.fieldValue(field)[field.name][1]; - let longitude = this.document.fieldValue(field)[field.name][0]; - // Round to 2 decimal places - latitude = Math.round(latitude * 100) / 100; - longitude = Math.round(longitude * 100) / 100; - return `Lat: ${latitude}; Lon: ${longitude}`; - } - - /** - * Checks if user has selected fields in the queryModel and whether current field is among them - * Used to check which fields need to be highlighted - */ - selectedFieldsContain(field: CorpusField) { - if (this.queryModel && this.queryModel.searchFields && this.queryModel.searchFields.includes(field)) { - return true; - } else if (this.queryModel && !this.queryModel.searchFields) { - return true; // if there are no selected fields, return true for all fields - } else { - return false; - } - } - - stripTags(htmlString: string){ - const parseHTML= new DOMParser().parseFromString(htmlString, 'text/html'); - return parseHTML.body.textContent || ''; - } - - formatInnerHtml(field: CorpusField) { - const fieldValue = this.document.fieldValues[field.name]; - - if (_.isEmpty(fieldValue)) { - return; - } - - const highlighted = this.highlightedInnerHtml(field); - return this.addParagraphTags(highlighted); - } - - - highlightedInnerHtml(field: CorpusField) { - let highlighted = this.document.fieldValues[field.name]; - if (this.document.highlight && this.document.highlight.hasOwnProperty(field.name) && - this.selectedFieldsContain(field)) { // only apply highlights to selected search fields - for (const highlight of this.document.highlight[field.name]) { - const stripped_highlight = this.stripTags(highlight); - highlighted = highlighted.replace(stripped_highlight, highlight); - } - return highlighted; - } else { - return this.document.fieldValues[field.name]; - } - } - - addParagraphTags(content: string | string[]) { - const paragraphs = typeof content === 'string' ? content.split('\n') : content; - return paragraphs.map(p => `

${p}

`).join(' '); - } } diff --git a/frontend/src/app/document/document-preview/document-preview.component.html b/frontend/src/app/document/document-preview/document-preview.component.html index dba6cf8ad..ed4e8a2bc 100644 --- a/frontend/src/app/document/document-preview/document-preview.component.html +++ b/frontend/src/app/document/document-preview/document-preview.component.html @@ -18,7 +18,7 @@ diff --git a/frontend/src/app/document/document.module.ts b/frontend/src/app/document/document.module.ts index 62f5ed5f9..6802c8c8a 100644 --- a/frontend/src/app/document/document.module.ts +++ b/frontend/src/app/document/document.module.ts @@ -10,8 +10,7 @@ import { DocumentPopupComponent } from './document-popup/document-popup.componen import { DialogModule } from 'primeng/dialog'; import { DocumentPreviewComponent } from './document-preview/document-preview.component'; import { EntityLegendComponent } from './entity-legend/entity-legend.component'; - - +import { ElasticsearchHighlightPipe, GeoDataPipe, SnippetPipe } from '../pipes'; @NgModule({ declarations: [ @@ -21,6 +20,9 @@ import { EntityLegendComponent } from './entity-legend/entity-legend.component'; DocumentPopupComponent, DocumentPreviewComponent, EntityLegendComponent, + ElasticsearchHighlightPipe, + GeoDataPipe, + SnippetPipe ], imports: [ DialogModule, diff --git a/frontend/src/app/manual/manual-navigation.component.html b/frontend/src/app/manual/manual-navigation.component.html index 85a3e1183..6f2055ef7 100644 --- a/frontend/src/app/manual/manual-navigation.component.html +++ b/frontend/src/app/manual/manual-navigation.component.html @@ -16,7 +16,7 @@ - + diff --git a/frontend/src/app/manual/manual.module.ts b/frontend/src/app/manual/manual.module.ts index ac0d5b3fe..fc13467d9 100644 --- a/frontend/src/app/manual/manual.module.ts +++ b/frontend/src/app/manual/manual.module.ts @@ -4,7 +4,7 @@ import { ManualNavigationComponent } from './manual-navigation.component'; import { ManualComponent } from './manual.component'; import { AboutComponent } from '../about/about.component'; import { PrivacyComponent } from '../privacy/privacy.component'; - +import { RegexHighlightPipe } from '../pipes'; @NgModule({ @@ -13,6 +13,7 @@ import { PrivacyComponent } from '../privacy/privacy.component'; ManualComponent, ManualNavigationComponent, PrivacyComponent, + RegexHighlightPipe ], imports: [ SharedModule diff --git a/frontend/src/app/pipes/elasticsearch-highlight.pipe.ts b/frontend/src/app/pipes/elasticsearch-highlight.pipe.ts new file mode 100644 index 000000000..3a35ae3cb --- /dev/null +++ b/frontend/src/app/pipes/elasticsearch-highlight.pipe.ts @@ -0,0 +1,51 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { CorpusField, FoundDocument } from '../models'; +import * as _ from 'lodash'; + +@Pipe({ + name: 'elasticsearchHighlight' +}) +export class ElasticsearchHighlightPipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) { + } + + /** + * Transforms a text to display highlights fetched from Elasticsearch + * + * @param document a FoundDocument, containing the fetched highlights + */ + transform(field: CorpusField, document: FoundDocument) { + const fieldValue = document.fieldValues[field.name]; + + if (_.isEmpty(fieldValue)) { + return; + } + + const highlighted = this.highlightedInnerHtml(field, document); + const paragraphs = this.addParagraphTags(highlighted); + return this.sanitizer.bypassSecurityTrustHtml(paragraphs); + } + + highlightedInnerHtml(field: CorpusField, document: FoundDocument) { + let highlighted = document.fieldValues[field.name]; + if (document.highlight && document.highlight.hasOwnProperty(field.name)) { + for (const highlight of document.highlight[field.name]) { + const strippedHighlight = this.stripTags(highlight); + highlighted = highlighted.replace(strippedHighlight, highlight); + } + } + return highlighted; + } + + addParagraphTags(content: string | string[]) { + const paragraphs = typeof content === 'string' ? content.split('\n') : content; + return paragraphs.map(p => `

${p}

`).join(' '); + } + + stripTags(htmlString: string){ + const parseHTML= new DOMParser().parseFromString(htmlString, 'text/html'); + return parseHTML.body.textContent || ''; + } + +} diff --git a/frontend/src/app/pipes/geo-data.pipe.ts b/frontend/src/app/pipes/geo-data.pipe.ts new file mode 100644 index 000000000..cf7b18a23 --- /dev/null +++ b/frontend/src/app/pipes/geo-data.pipe.ts @@ -0,0 +1,25 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { CorpusField, FoundDocument } from '../models'; +@Pipe({ + name: 'geoData' +}) +export class GeoDataPipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) { + } + + /** + * Transforms GeoJSON data + * + * @param document FoundDocument holding the actual data + */ + transform(field: CorpusField, document: FoundDocument) { + let latitude = document.fieldValue(field)[field.name][1]; + let longitude = document.fieldValue(field)[field.name][0]; + // Round to 2 decimal places + latitude = Math.round(latitude * 100) / 100; + longitude = Math.round(longitude * 100) / 100; + return `Lat: ${latitude}; Lon: ${longitude}`; + } + +} diff --git a/frontend/src/app/pipes/index.ts b/frontend/src/app/pipes/index.ts new file mode 100644 index 000000000..a20091083 --- /dev/null +++ b/frontend/src/app/pipes/index.ts @@ -0,0 +1,4 @@ +export * from './elasticsearch-highlight.pipe'; +export * from './geo-data.pipe'; +export * from './regex-highlight.pipe'; +export * from './snippet.pipe'; diff --git a/frontend/src/app/search/highlight.pipe.ts b/frontend/src/app/pipes/regex-highlight.pipe.ts similarity index 72% rename from frontend/src/app/search/highlight.pipe.ts rename to frontend/src/app/pipes/regex-highlight.pipe.ts index 3ee84d437..323292ffa 100644 --- a/frontend/src/app/search/highlight.pipe.ts +++ b/frontend/src/app/pipes/regex-highlight.pipe.ts @@ -3,22 +3,20 @@ import { DomSanitizer } from '@angular/platform-browser'; import { HighlightService } from '../services/highlight.service'; @Pipe({ - name: 'highlight' + name: 'regexHighlight' }) -export class HighlightPipe implements PipeTransform { +export class RegexHighlightPipe implements PipeTransform { constructor(private sanitizer: DomSanitizer, private highlightService: HighlightService) { } /** * Transforms a text to highlight all the text matching the specified query. - * - * @param snippets Only show snippets. When this enabled, line breaks will also be replaced with -- */ - transform(text: string, query: string, snippets: boolean = false) { + transform(text: string, query: string) { const highlights = this.highlightService.highlight(text, query); - const parts = snippets ? this.highlightService.snippets(highlights) : Array.from(highlights); + const parts = Array.from(highlights); const highlightedText = parts.map(part => { - const sanitizedText = this.sanitizedLineBreaks(part.substring, snippets ? ' — ' : '
'); + const sanitizedText = this.sanitizedLineBreaks(part.substring, '
'); return part.isHit ? `${sanitizedText}` : sanitizedText; }).join(''); diff --git a/frontend/src/app/pipes/snippet.pipe.ts b/frontend/src/app/pipes/snippet.pipe.ts new file mode 100644 index 000000000..4634395cb --- /dev/null +++ b/frontend/src/app/pipes/snippet.pipe.ts @@ -0,0 +1,20 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +@Pipe({ + name: 'snippet' +}) +export class SnippetPipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) { + } + + /** + * Transforms a text to only show its leading characters with an ellipsis + * + * @param nCharacters Specifies how many leading characters should be displayed + */ + transform(text: string, nCharacters=100) { + const snippedText = text.slice(0, nCharacters).concat('...'); + return this.sanitizer.bypassSecurityTrustHtml(snippedText); + } + +} diff --git a/frontend/src/app/search/index.ts b/frontend/src/app/search/index.ts index 11e8bc3bf..40905695a 100644 --- a/frontend/src/app/search/index.ts +++ b/frontend/src/app/search/index.ts @@ -1,4 +1,3 @@ -export * from './highlight.pipe'; export * from './search.component'; export * from './search-relevance.component'; export * from './search-results.component'; diff --git a/frontend/src/app/services/highlight.service.ts b/frontend/src/app/services/highlight.service.ts index 4fdc2a4ea..3ee28b96c 100644 --- a/frontend/src/app/services/highlight.service.ts +++ b/frontend/src/app/services/highlight.service.ts @@ -5,10 +5,7 @@ import { Injectable } from '@angular/core'; * a more scalable approach would need to be implemented if rendering many hits is required. */ const maxHits = 100; -/** - * The maximum number of snippets. - */ -const maxSnippetsCount = 7; + /** * The maximum character length of all the text snippets combined. */ @@ -78,39 +75,6 @@ export class HighlightService { } } - /** - * Gets short snippets from the text part to give the user a short overview of the text content. - */ - public snippets(parts: IterableIterator): TextPart[] { - const snippets: TextPart[] = []; - for ( - let i = 0, next = parts.next(); - !next.done && i < maxSnippetsCount; - i++, next = parts.next() - ) { - snippets.push(next.value); - } - - const lengths = this.getSnippetLengths( - snippets.map((snippet) => snippet.substring.length), - maxSnippetsLength - ); - - snippets.forEach((part, index) => { - part.substring = this.cropSnippetText( - part.substring, - lengths[index], - index === snippets.length - 1 - ? 'left' - : index === 0 - ? 'right' - : 'middle' - ); - }); - - return snippets; - } - /** * Convert the query to a regular expression matching any hit in a string. * @@ -151,79 +115,6 @@ export class HighlightService { ); } - private getSnippetLengths( - actualLengths: number[], - maxTotalLength: number, - croppedSnippets = actualLengths.length - ): number[] { - const targetLengths: number[] = []; - let remainingCharacters = maxTotalLength; - const maxLength = Math.max( - 1, - Math.floor(maxTotalLength / croppedSnippets) - ); - - let remainingSnippets = 0; - - let i = 0; - for (; i < actualLengths.length && remainingCharacters > 0; i++) { - const actualLength = actualLengths[i]; - const targetLength = Math.min(actualLength, maxLength); - - remainingCharacters -= targetLength; - targetLengths[i] = targetLength; - - if (actualLength > targetLength) { - // only the cropped snippets could become longer - remainingSnippets++; - } - } - for (; i < actualLengths.length; i++) { - targetLengths[i] = 0; - } - - if (remainingCharacters && remainingSnippets) { - // if a snippet is shorter than the maximum snippet length, allow the remaining snippets to become longer - const additionalLengths = this.getSnippetLengths( - actualLengths.map( - (length, index) => length - targetLengths[index] - ), - remainingCharacters, - remainingSnippets - ); - return targetLengths.map( - (length, index) => length + additionalLengths[index] - ); - } - - return targetLengths; - } - - private cropSnippetText( - text: string, - maxLength: number, - location: 'left' | 'middle' | 'right' - ): string { - if (text.length <= maxLength) { - return text; - } - - switch (location) { - case 'left': - return text.substr(0, maxLength) + omissionString; - - case 'middle': - return ( - text.substr(0, maxLength / 2) + - omissionString + - text.substr(text.length - maxLength / 2) - ); - - case 'right': - return omissionString + text.slice(-maxLength); - } - } - /** * Get the word patterns match in a query. * diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 8f25fd406..b19f89b05 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -12,7 +12,6 @@ import { BalloonDirective } from '../balloon.directive'; import { DatePickerComponent } from '../corpus-selection/corpus-filter/date-picker/date-picker.component'; import { ErrorComponent } from '../error/error.component'; import { ScrollToDirective } from '../scroll-to.directive'; -import { HighlightPipe } from '../search'; import { DropdownModule } from './dropdown/dropdown.module'; import { TabPanelDirective } from './tabs/tab-panel.directive'; import { TabsComponent } from './tabs/tabs.component'; @@ -22,7 +21,6 @@ import { TabsComponent } from './tabs/tabs.component'; DatePickerComponent, ErrorComponent, BalloonDirective, - HighlightPipe, ScrollToDirective, TabsComponent, TabPanelDirective, @@ -43,7 +41,6 @@ import { TabsComponent } from './tabs/tabs.component'; FormsModule, FontAwesomeModule, BalloonDirective, - HighlightPipe, HttpClientModule, HttpClientXsrfModule, RouterModule, From cb1f833340c3ff22b4b379e129fbd93403e432f6 Mon Sep 17 00:00:00 2001 From: BeritJanssen Date: Thu, 18 Apr 2024 15:23:42 +0200 Subject: [PATCH 06/73] revert show entities on document previews --- .../document-preview/document-preview.component.html | 10 ++++------ .../document-preview/document-preview.component.scss | 3 --- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/document/document-preview/document-preview.component.html b/frontend/src/app/document/document-preview/document-preview.component.html index ed4e8a2bc..87429833f 100644 --- a/frontend/src/app/document/document-preview/document-preview.component.html +++ b/frontend/src/app/document/document-preview/document-preview.component.html @@ -1,7 +1,4 @@ -
- Relevance: -
Your tags @@ -21,9 +21,9 @@ + [innerHtml]="field | elasticsearchHighlight:document"> {{displayGeoPointField(field)}}{{field | geoData:document}} {{document.fieldValue(field)}} + [innerHtml]="document.fieldValue(field) | snippet">
@@ -18,7 +15,7 @@ @@ -27,9 +24,10 @@
-
From 1deb9e640a790316d345ed83998c047b8deb4d68 Mon Sep 17 00:00:00 2001 From: BeritJanssen Date: Thu, 25 Apr 2024 13:49:31 +0200 Subject: [PATCH 09/73] feat: working display of named entities --- .../app/document-view/document-view.component.html | 2 +- frontend/src/app/models/found-document.ts | 2 +- frontend/src/app/pipes/entity.pipe.ts | 12 +++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/document-view/document-view.component.html b/frontend/src/app/document-view/document-view.component.html index 3730d2adf..9314fe57a 100644 --- a/frontend/src/app/document-view/document-view.component.html +++ b/frontend/src/app/document-view/document-view.component.html @@ -40,7 +40,7 @@
+ [innerHtml]="document.annotations$ | async | entity:document:field.name">
response.annotations) + map( response => response.annotations || []) ); } diff --git a/frontend/src/app/pipes/entity.pipe.ts b/frontend/src/app/pipes/entity.pipe.ts index 92bc99e99..ebb556edf 100644 --- a/frontend/src/app/pipes/entity.pipe.ts +++ b/frontend/src/app/pipes/entity.pipe.ts @@ -1,7 +1,10 @@ import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; -import { CorpusField, FoundDocument } from '../models'; +import { Observable } from 'rxjs'; + +import { FoundDocument } from '../models'; import * as _ from 'lodash'; + @Pipe({ name: 'entity' }) @@ -14,10 +17,9 @@ export class EntityPipe implements PipeTransform { * * @param document FoundDocument holding the actual data */ - transform(field: CorpusField, document: FoundDocument) { - const newText = document.annotations$.map( - (annotation)=> _.set(document.fieldValues, _.keys(annotation)[0], _.values(annotation)[0])); - return newText; + transform(annotations$: Observable<{[fieldName: string]: string}[]>, document: FoundDocument, fieldName: string) { + const newText = annotations$[fieldName]; + return newText || document.fieldValues[fieldName]; } } From e08b20e76f1a71cd4771d76d7bc26ad2870fc2f1 Mon Sep 17 00:00:00 2001 From: BeritJanssen Date: Thu, 25 Apr 2024 14:07:05 +0200 Subject: [PATCH 10/73] fix: update backend parsing of annotations --- backend/es/tests/test_named_entity_search.py | 5 ++--- backend/es/views.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/es/tests/test_named_entity_search.py b/backend/es/tests/test_named_entity_search.py index bb12328c6..81afc8460 100644 --- a/backend/es/tests/test_named_entity_search.py +++ b/backend/es/tests/test_named_entity_search.py @@ -3,9 +3,8 @@ def test_ner_search_view(es_ner_search_client, client, times_user): client.force_login(times_user) - route = '/api/es/times/named_entities' - data = {'id': 'my_identifier'} - response = client.post(route, data, content_type='application/json') + route = '/api/es/times/my_identifier/named_entities' + response = client.get(route, content_type='application/json') assert response.status_code == 200 diff --git a/backend/es/views.py b/backend/es/views.py index ceabd6dc3..645fe86e6 100644 --- a/backend/es/views.py +++ b/backend/es/views.py @@ -168,7 +168,7 @@ def add_terms(self, fields: list[str]) -> list[dict]: def find_entities(self, input_text: str, entity_classes: set) -> str: # regex pattern to match annotations of format "[Wally](Person)" and split it into two groups - pattern = re.compile('(\[[a-zA-Z ]+\])(\([a-zA-Z ]+\))') + pattern = re.compile('(\[[^]]+\])(\([A-Z]+\))') annotations = list(set(pattern.findall(input_text))) for annotation in annotations: input_text = self.substitute_annotation_with_tag( From e41db24310ea37e4c562b35a148c6610261efddc Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Wed, 15 May 2024 16:47:43 +0200 Subject: [PATCH 11/73] add corpus definitions link --- .../corpus-selection.component.html | 9 +++++++++ .../corpus-selection/corpus-selection.component.ts | 14 +++++++++++++- frontend/src/app/shared/icons.ts | 4 ++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/corpus-selection/corpus-selection.component.html b/frontend/src/app/corpus-selection/corpus-selection.component.html index cc90ff34a..a4c4fd1c2 100644 --- a/frontend/src/app/corpus-selection/corpus-selection.component.html +++ b/frontend/src/app/corpus-selection/corpus-selection.component.html @@ -1,11 +1,20 @@
+ + + Corpus definitions + +

Welcome

Select a corpus to search through

+
diff --git a/frontend/src/app/corpus-selection/corpus-selection.component.ts b/frontend/src/app/corpus-selection/corpus-selection.component.ts index 6bcdac5cb..f22a3dc87 100644 --- a/frontend/src/app/corpus-selection/corpus-selection.component.ts +++ b/frontend/src/app/corpus-selection/corpus-selection.component.ts @@ -1,6 +1,10 @@ import { Component, Input, OnInit } from '@angular/core'; import { Corpus } from '../models/corpus'; import * as _ from 'lodash'; +import { AuthService } from '../services'; +import { map } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { actionIcons } from '../shared/icons'; @Component({ @@ -14,7 +18,15 @@ export class CorpusSelectionComponent implements OnInit { filteredItems: Corpus[]; - constructor() { } + showManageLink$: Observable; + + actionIcons = actionIcons; + + constructor(private authService: AuthService) { + this.showManageLink$ = this.authService.currentUser$.pipe( + map((user) => user?.isAdmin) + ); + } get displayItems(): Corpus[] { if (_.isUndefined(this.filteredItems)) { diff --git a/frontend/src/app/shared/icons.ts b/frontend/src/app/shared/icons.ts index 0d5dd8676..f90ea0e55 100644 --- a/frontend/src/app/shared/icons.ts +++ b/frontend/src/app/shared/icons.ts @@ -7,7 +7,7 @@ import { faAngleDown, faAngleUp, faArrowLeft, faArrowRight, faAt, faBook, faBookOpen, faChartColumn, faCheck, faChevronDown, faChevronLeft, faChevronRight, faCog, faCogs, faDatabase, faDiagramProject, faDownload, faEdit, faEnvelope, faEye, faFilter, faHistory, faImage, faInfo, faInfoCircle, faLink, faList, faLock, - faMinus, faPalette, faPlus, faQuestionCircle, faSearch, faSearchMinus, faSearchPlus, faSignOut, + faMinus, faPalette, faPencil, faPlus, faQuestionCircle, faSearch, faSearchMinus, faSearchPlus, faSignOut, faSortAlphaAsc, faSortAlphaDesc, faSortNumericAsc, faSortNumericDesc, faSquare, faTable, faTags, faTimes, faTrashCan, faUndo, faUser } from '@fortawesome/free-solid-svg-icons'; @@ -52,7 +52,7 @@ export const actionIcons: Icons = { add: faPlus, remove: faTimes, delete: faTrashCan, - edit: faEdit, + edit: faPencil, view: faEye, }; From 74b1235e2b5f412e6c0b1bf9840e3014052fcf0a Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Wed, 15 May 2024 16:53:39 +0200 Subject: [PATCH 12/73] generate definitions overview component --- frontend/src/app/app.module.ts | 6 +++++ .../corpus-definitions.module.ts | 15 +++++++++++++ .../definitions-overview.component.html | 1 + .../definitions-overview.component.scss | 0 .../definitions-overview.component.spec.ts | 22 +++++++++++++++++++ .../definitions-overview.component.ts | 15 +++++++++++++ 6 files changed, 59 insertions(+) create mode 100644 frontend/src/app/corpus-definitions/corpus-definitions.module.ts create mode 100644 frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html create mode 100644 frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.scss create mode 100644 frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.spec.ts create mode 100644 frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index aeafe617b..224be1404 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -50,6 +50,7 @@ import { SharedModule } from './shared/shared.module'; import { WordModelsComponent } from './word-models/word-models.component'; import { WordModelsModule } from './word-models/word-models.module'; import { TagOverviewComponent } from './tag/tag-overview/tag-overview.component'; +import { DefinitionsOverviewComponent } from './corpus-definitions/definitions-overview/definitions-overview.component'; export const appRoutes: Routes = [ { @@ -132,6 +133,11 @@ export const appRoutes: Routes = [ component: TagOverviewComponent, canActivate: [LoggedOnGuard], }, + { + path: 'corpus-definitions', + component: DefinitionsOverviewComponent, + canActivate: [LoggedOnGuard], + }, { path: '', redirectTo: 'home', diff --git a/frontend/src/app/corpus-definitions/corpus-definitions.module.ts b/frontend/src/app/corpus-definitions/corpus-definitions.module.ts new file mode 100644 index 000000000..e2194a088 --- /dev/null +++ b/frontend/src/app/corpus-definitions/corpus-definitions.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { DefinitionsOverviewComponent } from './definitions-overview/definitions-overview.component'; + + + +@NgModule({ + declarations: [ + DefinitionsOverviewComponent + ], + imports: [ + CommonModule + ] +}) +export class CorpusDefinitionsModule { } diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html new file mode 100644 index 000000000..7de1976e0 --- /dev/null +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -0,0 +1 @@ +

definitions-overview works!

diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.scss b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.spec.ts b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.spec.ts new file mode 100644 index 000000000..736a0188b --- /dev/null +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { DefinitionsOverviewComponent } from './definitions-overview.component'; +import { commonTestBed } from 'src/app/common-test-bed'; + +describe('DefinitionsOverviewComponent', () => { + let component: DefinitionsOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + commonTestBed().testingModule.compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(DefinitionsOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts new file mode 100644 index 000000000..68ca5b456 --- /dev/null +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'ia-definitions-overview', + templateUrl: './definitions-overview.component.html', + styleUrls: ['./definitions-overview.component.scss'] +}) +export class DefinitionsOverviewComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} From 9540010da4e213613f3cb243e60873580bd03ad2 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Wed, 15 May 2024 17:08:20 +0200 Subject: [PATCH 13/73] basic interface for definitions overview --- frontend/src/app/app.module.ts | 2 + .../corpus-definitions.module.ts | 17 ++++--- .../definitions-overview.component.html | 48 ++++++++++++++++++- .../definitions-overview.component.ts | 14 +++--- 4 files changed, 67 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 224be1404..cce4bb0ea 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -51,6 +51,7 @@ import { WordModelsComponent } from './word-models/word-models.component'; import { WordModelsModule } from './word-models/word-models.module'; import { TagOverviewComponent } from './tag/tag-overview/tag-overview.component'; import { DefinitionsOverviewComponent } from './corpus-definitions/definitions-overview/definitions-overview.component'; +import { CorpusDefinitionsModule } from './corpus-definitions/corpus-definitions.module'; export const appRoutes: Routes = [ { @@ -164,6 +165,7 @@ export const imports: any[] = [ SharedModule, // Feature Modules CorpusModule, + CorpusDefinitionsModule, CorpusSelectionModule, DialogModule, DocumentModule, diff --git a/frontend/src/app/corpus-definitions/corpus-definitions.module.ts b/frontend/src/app/corpus-definitions/corpus-definitions.module.ts index e2194a088..f4187a679 100644 --- a/frontend/src/app/corpus-definitions/corpus-definitions.module.ts +++ b/frontend/src/app/corpus-definitions/corpus-definitions.module.ts @@ -1,15 +1,18 @@ import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { DefinitionsOverviewComponent } from './definitions-overview/definitions-overview.component'; +import { SharedModule } from '../shared/shared.module'; @NgModule({ - declarations: [ - DefinitionsOverviewComponent - ], - imports: [ - CommonModule - ] + declarations: [ + DefinitionsOverviewComponent + ], + exports: [ + DefinitionsOverviewComponent, + ], + imports: [ + SharedModule + ] }) export class CorpusDefinitionsModule { } diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html index 7de1976e0..fdc5c5e00 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -1 +1,47 @@ -

definitions-overview works!

+
+
+

Corpus definitions

+ +
+ +
+ +
+
+ [innerHtml]="document.fieldValue(field) | highlight:query:true">
+ [innerHtml]="document.fieldValue(field) | snippet">
+ + + + + + + + + + + + +
CorpusActions
Test + + + +
+ + + diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts index 68ca5b456..7ad4b1c80 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.ts @@ -1,15 +1,17 @@ import { Component, OnInit } from '@angular/core'; +import { actionIcons } from '../../shared/icons'; @Component({ - selector: 'ia-definitions-overview', - templateUrl: './definitions-overview.component.html', - styleUrls: ['./definitions-overview.component.scss'] + selector: 'ia-definitions-overview', + templateUrl: './definitions-overview.component.html', + styleUrls: ['./definitions-overview.component.scss'] }) export class DefinitionsOverviewComponent implements OnInit { + actionIcons = actionIcons; - constructor() { } + constructor() { } - ngOnInit(): void { - } + ngOnInit(): void { + } } From cc9521bc572cd0403c3f046bb6eea9dd22a049a8 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Wed, 15 May 2024 17:42:34 +0200 Subject: [PATCH 14/73] add APICorpusDefinition interface --- frontend/src/app/models/corpus-definition.ts | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 frontend/src/app/models/corpus-definition.ts diff --git a/frontend/src/app/models/corpus-definition.ts b/frontend/src/app/models/corpus-definition.ts new file mode 100644 index 000000000..6442ddf31 --- /dev/null +++ b/frontend/src/app/models/corpus-definition.ts @@ -0,0 +1,55 @@ +export interface APICorpusField { + name: string; + display_name: string; + description: string; + type: 'text-content'|'text_metadata'|'url'|'integer'|'float'|'date'|'boolean'|'geo_point'; + options: { + search: boolean; + filter: 'show'|'hide'|'none'; + preview: boolean; + visualize: boolean; + sort: boolean; + hidden: boolean; + }; + language?: string; + extract: { + column: string; + }; +} + +export interface APICorpusDefinition { + name: string; + id?: number; + meta: { + title: string; + category: string; + description: string; + languages: string[]; + date_range: { + min: string; + max: string; + }; + }; + source_data: { + type: 'csv'; + options?: { + delimiter?: ','|';'|'\t'; + }; + }; + fields: APICorpusField[]; + options?: { + language_field?: string; + document_context?: { + context_fields: string[]; + context_display_name: string; + sort?: { + field: string; + ascending: boolean; + }; + }; + default_sort?: { + field: string; + ascending: boolean; + }; + }; +}; From ce9206c148c2b8210b245d397862fd5935ac5fb5 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Wed, 15 May 2024 17:53:32 +0200 Subject: [PATCH 15/73] fetch definitions in overview --- .../definitions-overview.component.html | 8 +++++--- .../definitions-overview.component.ts | 13 ++++++++----- frontend/src/app/services/api.service.ts | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html index fdc5c5e00..c932d2ae9 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -11,7 +11,7 @@

Corpus definitions

-
+
@@ -20,19 +20,21 @@

Corpus definitions

- - + +
Test
{{definition.meta.title}} +   +   + + + diff --git a/frontend/src/app/corpus-definitions/create-definition/create-definition.component.scss b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/corpus-definitions/create-definition/create-definition.component.spec.ts b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.spec.ts new file mode 100644 index 000000000..77a9c51c8 --- /dev/null +++ b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { CreateDefinitionComponent } from './create-definition.component'; +import { commonTestBed } from '../../common-test-bed'; + +describe('CreateDefinitionComponent', () => { + let component: CreateDefinitionComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + commonTestBed().testingModule.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateDefinitionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/corpus-definitions/create-definition/create-definition.component.ts b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.ts new file mode 100644 index 000000000..d4ea3bac0 --- /dev/null +++ b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { actionIcons } from '../../shared/icons'; + +@Component({ + selector: 'ia-create-definition', + templateUrl: './create-definition.component.html', + styleUrls: ['./create-definition.component.scss'] +}) +export class CreateDefinitionComponent implements OnInit { + + actionIcons = actionIcons; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html index c932d2ae9..513ef27c1 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -3,12 +3,12 @@

Corpus definitions

@@ -23,17 +23,12 @@

Corpus definitions

{{definition.meta.title}} - -   - +   {{definition.meta.title}} + [routerLink]="['edit', definition.id]"> diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html new file mode 100644 index 000000000..caf98db32 --- /dev/null +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html @@ -0,0 +1,26 @@ +
+
+

Edit corpus

+ +

+ You can download this corpus definition as a JSON file, or upload a JSON + file to update it. +

+ +
+ +   + +
+
+
diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.scss b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.spec.ts b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.spec.ts new file mode 100644 index 000000000..42a4f7838 --- /dev/null +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { EditDefinitionComponent } from './edit-definition.component'; +import { commonTestBed } from '../../common-test-bed'; + +describe('EditDefinitionComponent', () => { + let component: EditDefinitionComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + commonTestBed().testingModule.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(EditDefinitionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts new file mode 100644 index 000000000..3221df79f --- /dev/null +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { actionIcons } from '../../shared/icons'; + +@Component({ + selector: 'ia-edit-definition', + templateUrl: './edit-definition.component.html', + styleUrls: ['./edit-definition.component.scss'] +}) +export class EditDefinitionComponent implements OnInit { + + actionIcons = actionIcons; + + constructor() { } + + ngOnInit(): void { + } + +} From 63ca156dab2ba717763dd5f05f69a8c50d24d648 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Thu, 16 May 2024 11:44:45 +0200 Subject: [PATCH 18/73] add breadcrumbs --- .../create-definition/create-definition.component.html | 8 ++++++++ .../definitions-overview.component.html | 7 +++++++ .../edit-definition/edit-definition.component.html | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/frontend/src/app/corpus-definitions/create-definition/create-definition.component.html b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.html index 8034cc2bd..375899335 100644 --- a/frontend/src/app/corpus-definitions/create-definition/create-definition.component.html +++ b/frontend/src/app/corpus-definitions/create-definition/create-definition.component.html @@ -1,5 +1,13 @@
+ +

New corpus

diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html index b593aac20..79cd9ecec 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -1,5 +1,12 @@

+ +

Corpus definitions

diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html index caf98db32..4c20561f1 100644 --- a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html @@ -1,5 +1,13 @@
+ +

Edit corpus

From c9a634039eeda40a196451f1a82ce0199d3954c4 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Thu, 16 May 2024 11:53:45 +0200 Subject: [PATCH 19/73] use router state in edit definition component --- .../edit-definition.component.html | 8 +++--- .../edit-definition.component.ts | 26 ++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html index 4c20561f1..51ab7189e 100644 --- a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.html @@ -1,14 +1,14 @@

-
+
-

Edit corpus

+

Edit corpus "{{definition.meta.title}}"

You can download this corpus definition as a JSON file, or upload a JSON diff --git a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts index 3221df79f..888696dad 100644 --- a/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts +++ b/frontend/src/app/corpus-definitions/edit-definition/edit-definition.component.ts @@ -1,18 +1,36 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { actionIcons } from '../../shared/icons'; +import { Observable, combineLatest } from 'rxjs'; +import { APICorpusDefinition } from '../../models/corpus-definition'; +import { ApiService } from '../../services'; +import { ActivatedRoute } from '@angular/router'; +import { map, tap } from 'rxjs/operators'; @Component({ selector: 'ia-edit-definition', templateUrl: './edit-definition.component.html', styleUrls: ['./edit-definition.component.scss'] }) -export class EditDefinitionComponent implements OnInit { +export class EditDefinitionComponent { actionIcons = actionIcons; - constructor() { } + definition$: Observable; - ngOnInit(): void { + constructor( + private apiService: ApiService, + private route: ActivatedRoute + ) { + const corpusID$ = this.route.params.pipe( + map(params => parseInt(params['corpusID'], 10)) + ); + this.definition$ = combineLatest([ + this.apiService.corpusDefinitions(), + corpusID$, + ]).pipe( + tap(values => console.log(values)), + map(([definitions, id]) => definitions.find(def => def.id === id)) + ); } } From 9855b77091e6d3667ea783deccb72d11e74f10d6 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Thu, 16 May 2024 12:01:36 +0200 Subject: [PATCH 20/73] include search link in overview --- .../definitions-overview.component.html | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html index 79cd9ecec..34936ea70 100644 --- a/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html +++ b/frontend/src/app/corpus-definitions/definitions-overview/definitions-overview.component.html @@ -10,7 +10,7 @@

Corpus definitions

{{definition.meta.title}} + + + + + +   @@ -37,7 +44,7 @@

Corpus definitions

  -