Skip to content

Commit 4e7f7b8

Browse files
authored
[sc-4135] Restore action menu in expanded tile (#612)
* Add menu in expanded tile when provided by viewer or searchResults widget * Setup tile menu in dashboard's search results * Attempt to fix separator display when no result navigator. Seems like there is a bug in Svelte which make $$slots.default being true even if the slot is not there. The code should work once sveltejs/svelte#8304 is fixed. * Update our package versions * Use ng14 branch of Pastanaga the time for us to upgrade our apps to ng15 * Fix tests
1 parent 222d0c5 commit 4e7f7b8

File tree

28 files changed

+410
-67
lines changed

28 files changed

+410
-67
lines changed

app.babel

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9579,6 +9579,26 @@
95799579
</translation>
95809580
</translations>
95819581
</concept_node>
9582+
<concept_node>
9583+
<name>resource.delete_resource_title</name>
9584+
<description/>
9585+
<comment/>
9586+
<default_text/>
9587+
<translations>
9588+
<translation>
9589+
<language>ca-ES</language>
9590+
<approved>false</approved>
9591+
</translation>
9592+
<translation>
9593+
<language>en-US</language>
9594+
<approved>false</approved>
9595+
</translation>
9596+
<translation>
9597+
<language>es-ES</language>
9598+
<approved>false</approved>
9599+
</translation>
9600+
</translations>
9601+
</concept_node>
95829602
<concept_node>
95839603
<name>resource.delete_resource_warning</name>
95849604
<description/>
@@ -9619,6 +9639,26 @@
96199639
</translation>
96209640
</translations>
96219641
</concept_node>
9642+
<concept_node>
9643+
<name>resource.delete_resources_title</name>
9644+
<description/>
9645+
<comment/>
9646+
<default_text/>
9647+
<translations>
9648+
<translation>
9649+
<language>ca-ES</language>
9650+
<approved>false</approved>
9651+
</translation>
9652+
<translation>
9653+
<language>en-US</language>
9654+
<approved>false</approved>
9655+
</translation>
9656+
<translation>
9657+
<language>es-ES</language>
9658+
<approved>false</approved>
9659+
</translation>
9660+
</translations>
9661+
</concept_node>
96229662
<concept_node>
96239663
<name>resource.delete_resources_warning</name>
96249664
<description/>
@@ -10659,6 +10699,46 @@
1065910699
</translation>
1066010700
</translations>
1066110701
</concept_node>
10702+
<concept_node>
10703+
<name>resource.reprocess_resource_description</name>
10704+
<description/>
10705+
<comment/>
10706+
<default_text/>
10707+
<translations>
10708+
<translation>
10709+
<language>ca-ES</language>
10710+
<approved>false</approved>
10711+
</translation>
10712+
<translation>
10713+
<language>en-US</language>
10714+
<approved>false</approved>
10715+
</translation>
10716+
<translation>
10717+
<language>es-ES</language>
10718+
<approved>false</approved>
10719+
</translation>
10720+
</translations>
10721+
</concept_node>
10722+
<concept_node>
10723+
<name>resource.reprocess_resource_title</name>
10724+
<description/>
10725+
<comment/>
10726+
<default_text/>
10727+
<translations>
10728+
<translation>
10729+
<language>ca-ES</language>
10730+
<approved>false</approved>
10731+
</translation>
10732+
<translation>
10733+
<language>en-US</language>
10734+
<approved>false</approved>
10735+
</translation>
10736+
<translation>
10737+
<language>es-ES</language>
10738+
<approved>false</approved>
10739+
</translation>
10740+
</translations>
10741+
</concept_node>
1066210742
<concept_node>
1066310743
<name>resource.resource_page_number</name>
1066410744
<description/>

apps/dashboard/src/app/resources/resource-list.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export class ResourceListComponent implements OnInit, OnDestroy {
322322
.openConfirm({
323323
title,
324324
description: message,
325+
confirmLabel: 'generic.delete',
325326
isDestructive: true,
326327
})
327328
.onClose.pipe(

apps/dashboard/src/app/resources/resource-viewer.service.ts

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1-
import { filter, map, switchMap, take, tap } from 'rxjs';
1+
import { filter, map, Observable, switchMap, take, tap } from 'rxjs';
22
import { SisModalService } from '@nuclia/sistema';
33
import { SDKService, STFTrackingService } from '@flaps/core';
4-
import { Injectable } from '@angular/core';
4+
import { Injectable, NgZone } from '@angular/core';
55
import { TranslateService } from '@ngx-translate/core';
66
import { Router } from '@angular/router';
7+
import { FieldFullId } from '@nuclia/core';
78

89
@Injectable({
910
providedIn: 'root',
1011
})
1112
export class ResourceViewerService {
13+
private widgetId?: string;
14+
1215
constructor(
1316
private router: Router,
1417
private sdk: SDKService,
1518
private translation: TranslateService,
1619
private modalService: SisModalService,
1720
private trackingService: STFTrackingService,
21+
private zone: NgZone,
1822
) {}
1923

2024
init(widgetId: string) {
25+
this.widgetId = widgetId;
2126
this.sdk.currentKb.pipe(take(1)).subscribe((kb) => {
2227
const waitForWidget = window.setInterval(() => {
2328
const widget = document.getElementById(widgetId) as unknown as any;
@@ -32,18 +37,33 @@ export class ResourceViewerService {
3237
if (kb.admin || kb.contrib) {
3338
actions.push(
3439
{
35-
label: this.translation.instant('generic.edit'),
40+
label: this.translation.instant('resource.menu.edit'),
3641
destructive: false,
3742
action: this.edit.bind(this),
3843
},
44+
{
45+
label: this.translation.instant('resource.menu.annotate'),
46+
destructive: false,
47+
action: this.annotate.bind(this),
48+
},
49+
{
50+
label: this.translation.instant('resource.menu.classify'),
51+
destructive: false,
52+
action: this.classify.bind(this),
53+
},
54+
{
55+
label: this.translation.instant('generic.reindex'),
56+
destructive: false,
57+
action: this.reindex.bind(this),
58+
},
3959
{
4060
label: this.translation.instant('generic.delete'),
4161
destructive: true,
4262
action: this.delete.bind(this),
4363
},
4464
);
4565
}
46-
widget.setActions(actions);
66+
widget.setTileMenu(actions);
4767
widget.addEventListener('search', () => this.trackingService.logEvent('search'));
4868
clearInterval(waitForWidget);
4969
}
@@ -60,48 +80,77 @@ export class ResourceViewerService {
6080
});
6181
}
6282

63-
delete(uid: string) {
83+
delete(fullId: FieldFullId) {
6484
this.modalService
6585
.openConfirm({
66-
title: 'generic.alert',
86+
title: 'resource.delete_resource_title',
6787
description: 'resource.delete_resource_warning',
6888
confirmLabel: 'generic.delete',
6989
isDestructive: true,
7090
})
7191
.onClose.pipe(
7292
filter((confirm) => !!confirm),
93+
tap(() => this.closeViewer()),
7394
switchMap(() => this.sdk.currentKb),
7495
take(1),
75-
switchMap((kb) => kb.getResource(uid)),
96+
switchMap((kb) => kb.getResource(fullId.resourceId)),
7697
switchMap((res) => res.delete()),
77-
tap(() => this.closeViewer()),
7898
)
7999
.subscribe(() => {
100+
this.reloadSearch();
80101
setTimeout(() => {
81102
this.sdk.refreshCounter(true);
82103
}, 1000);
83104
});
84105
}
85106

86-
edit(uid: string) {
87-
this.sdk.currentKb
88-
.pipe(
107+
edit(fullId: FieldFullId) {
108+
this.getResourcesBasePath().subscribe((basePath) => {
109+
this.closeViewer();
110+
this.navigateTo(`${basePath}/${fullId.resourceId}/edit`);
111+
});
112+
}
113+
114+
annotate(fullId: FieldFullId) {
115+
this.getResourcesBasePath().subscribe((basePath) => {
116+
this.closeViewer();
117+
this.navigateTo(`${basePath}/${fullId.resourceId}/edit/annotation`);
118+
});
119+
}
120+
121+
classify(fullId: FieldFullId) {
122+
this.getResourcesBasePath().subscribe((basePath) => {
123+
this.closeViewer();
124+
this.navigateTo(`${basePath}/${fullId.resourceId}/edit/classification`);
125+
});
126+
}
127+
128+
reindex(fullId: FieldFullId) {
129+
this.modalService
130+
.openConfirm({
131+
title: 'resource.reprocess_resource_title',
132+
description: 'resource.reprocess_resource_description',
133+
})
134+
.onClose.pipe(
135+
filter((confirm) => !!confirm),
136+
tap(() => this.closeViewer()),
137+
switchMap(() => this.sdk.currentKb),
89138
take(1),
90-
filter((kb) => !!kb.admin || !!kb.contrib),
139+
switchMap((kb) => kb.getResource(fullId.resourceId)),
140+
switchMap((res) => res.reprocess()),
91141
)
92-
.subscribe((kb) => {
93-
this.closeViewer();
94-
this.router.navigate([`/at/${kb.account}/${kb.slug}/resources/${uid}/edit/profile`]);
95-
});
142+
.subscribe();
96143
}
97144

98-
showUID(uid: string) {
145+
showUID(fullId: FieldFullId) {
99146
this.sdk.currentKb
100147
.pipe(
101148
take(1),
102149
map(
103150
(kb) =>
104-
`<pre><code class="endpoint">${this.sdk.nuclia.rest.getFullUrl(kb.path)}/resource/${uid}</code></pre>`,
151+
`<pre><code class="endpoint">${this.sdk.nuclia.rest.getFullUrl(kb.path)}/resource/${
152+
fullId.resourceId
153+
}</code></pre>`,
105154
),
106155
switchMap(
107156
(uidEndpoint) =>
@@ -117,6 +166,26 @@ export class ResourceViewerService {
117166
}
118167

119168
closeViewer() {
120-
(document.getElementById('search-widget') as unknown as any)?.displayResource('');
169+
if (this.widgetId) {
170+
(document.getElementById(this.widgetId) as unknown as any)?.closePreview();
171+
}
172+
}
173+
174+
reloadSearch() {
175+
const searchBar = document.querySelector('nuclia-search-bar') as any;
176+
if (typeof searchBar?.reloadSearch === 'function') {
177+
searchBar.reloadSearch();
178+
}
179+
}
180+
181+
private getResourcesBasePath(): Observable<string> {
182+
return this.sdk.currentKb.pipe(
183+
take(1),
184+
filter((kb) => !!kb.admin || !!kb.contrib),
185+
map((kb) => `/at/${kb.account}/${kb.slug}/resources`),
186+
);
187+
}
188+
private navigateTo(path: string) {
189+
this.zone.run(() => this.router.navigate([path]));
121190
}
122191
}

apps/dashboard/src/app/search/search.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { BackendConfigurationService, SDKService } from '@flaps/core';
66
import { TranslateService } from '@ngx-translate/core';
77
import { of } from 'rxjs';
88
import { Nuclia, WritableKnowledgeBox } from '@nuclia/core';
9+
import { ResourceViewerService } from '../resources/resource-viewer.service';
910

1011
describe('SearchComponent', () => {
1112
let component: SearchComponent;
@@ -31,6 +32,7 @@ describe('SearchComponent', () => {
3132
}),
3233
MockProvider(BackendConfigurationService),
3334
MockProvider(TranslateService),
35+
MockProvider(ResourceViewerService),
3436
],
3537
}).compileComponents();
3638

apps/dashboard/src/app/search/search.component.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { ChangeDetectionStrategy, Component, OnDestroy } from '@angular/core';
1+
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
22
import { BackendConfigurationService, SDKService } from '@flaps/core';
33
import { distinctUntilKeyChanged, forkJoin, map, switchMap, tap } from 'rxjs';
44
import { DEFAULT_FEATURES_LIST } from '../widgets/widget-features';
55
import { DomSanitizer } from '@angular/platform-browser';
66
import { TranslateService } from '@ngx-translate/core';
77
import { TrainingType } from '@nuclia/core';
8+
import { ResourceViewerService } from '../resources/resource-viewer.service';
89

910
const searchWidgetId = 'search-bar';
1011
const searchResultsId = 'search-results';
@@ -15,7 +16,7 @@ const searchResultsId = 'search-results';
1516
styleUrls: ['./search.component.scss'],
1617
changeDetection: ChangeDetectionStrategy.OnPush,
1718
})
18-
export class SearchComponent implements OnDestroy {
19+
export class SearchComponent implements OnDestroy, OnInit {
1920
searchWidget = this.sdk.currentKb.pipe(
2021
distinctUntilKeyChanged('id'),
2122
tap(() => {
@@ -59,15 +60,20 @@ export class SearchComponent implements OnDestroy {
5960
private sanitized: DomSanitizer,
6061
private backendConfig: BackendConfigurationService,
6162
private translation: TranslateService,
63+
private viewerService: ResourceViewerService,
6264
) {}
6365

66+
ngOnInit() {
67+
this.viewerService.init(searchResultsId);
68+
}
69+
6470
ngOnDestroy() {
6571
const searchBarElement = document.querySelector('nuclia-search-bar') as any;
6672
const searchResultsElement = document.querySelector('nuclia-search-results') as any;
67-
if (typeof searchBarElement.$destroy === 'function') {
73+
if (typeof searchBarElement?.$destroy === 'function') {
6874
searchBarElement.$destroy();
6975
}
70-
if (typeof searchResultsElement.$destroy === 'function') {
76+
if (typeof searchResultsElement?.$destroy === 'function') {
7177
searchResultsElement.$destroy();
7278
}
7379
}

0 commit comments

Comments
 (0)