UI: Add resources in use dialog with force to delete
This commit is contained in:
parent
cd6063fd09
commit
caf9063638
@ -22,7 +22,13 @@ import {
|
|||||||
EntityTableConfig
|
EntityTableConfig
|
||||||
} from '@home/models/entity/entities-table-config.models';
|
} from '@home/models/entity/entities-table-config.models';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Resource, ResourceInfo, ResourceType, ResourceTypeTranslationMap } from '@shared/models/resource.models';
|
import {
|
||||||
|
Resource,
|
||||||
|
ResourceInfo, ResourceInfoWithReferences,
|
||||||
|
ResourceType,
|
||||||
|
ResourceTypeTranslationMap,
|
||||||
|
toResourceDeleteResult
|
||||||
|
} from '@shared/models/resource.models';
|
||||||
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
|
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
@ -35,9 +41,19 @@ import { Authority } from '@shared/models/authority.enum';
|
|||||||
import { ResourcesLibraryComponent } from '@home/components/resources/resources-library.component';
|
import { ResourcesLibraryComponent } from '@home/components/resources/resources-library.component';
|
||||||
import { PageLink } from '@shared/models/page/page-link';
|
import { PageLink } from '@shared/models/page/page-link';
|
||||||
import { EntityAction } from '@home/models/entity/entity-component.models';
|
import { EntityAction } from '@home/models/entity/entity-component.models';
|
||||||
import { map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component';
|
import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component';
|
||||||
import { ResourceLibraryTabsComponent } from '@home/pages/admin/resource/resource-library-tabs.component';
|
import { ResourceLibraryTabsComponent } from '@home/pages/admin/resource/resource-library-tabs.component';
|
||||||
|
import { forkJoin, of } from "rxjs";
|
||||||
|
import {
|
||||||
|
ResourcesInUseDialogComponent,
|
||||||
|
ResourcesInUseDialogData
|
||||||
|
} from "@shared/components/resource/resources-in-use-dialog.component";
|
||||||
|
import { parseHttpErrorMessage } from "@core/utils";
|
||||||
|
import { ActionNotificationShow } from "@core/notification/notification.actions";
|
||||||
|
import { ResourcesDatasource } from "@home/pages/admin/resource/resources-datasource";
|
||||||
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
|
import { DialogService } from "@core/services/dialog.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ResourcesLibraryTableConfigResolver {
|
export class ResourcesLibraryTableConfigResolver {
|
||||||
@ -49,6 +65,8 @@ export class ResourcesLibraryTableConfigResolver {
|
|||||||
private resourceService: ResourceService,
|
private resourceService: ResourceService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private dialogService: DialogService,
|
||||||
private datePipe: DatePipe) {
|
private datePipe: DatePipe) {
|
||||||
|
|
||||||
this.config.entityType = EntityType.TB_RESOURCE;
|
this.config.entityType = EntityType.TB_RESOURCE;
|
||||||
@ -76,19 +94,27 @@ export class ResourcesLibraryTableConfigResolver {
|
|||||||
icon: 'file_download',
|
icon: 'file_download',
|
||||||
isEnabled: () => true,
|
isEnabled: () => true,
|
||||||
onAction: ($event, entity) => this.downloadResource($event, entity)
|
onAction: ($event, entity) => this.downloadResource($event, entity)
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: this.translate.instant('resource.delete'),
|
||||||
|
icon: 'delete',
|
||||||
|
isEnabled: (resource) => this.config.deleteEnabled(resource),
|
||||||
|
onAction: ($event, entity) => this.deleteResource($event, entity)
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.config.deleteEntityTitle = resource => this.translate.instant('resource.delete-resource-title',
|
this.config.groupActionDescriptors = [{
|
||||||
{ resourceTitle: resource.title });
|
name: this.translate.instant('action.delete'),
|
||||||
this.config.deleteEntityContent = () => this.translate.instant('resource.delete-resource-text');
|
icon: 'delete',
|
||||||
this.config.deleteEntitiesTitle = count => this.translate.instant('resource.delete-resources-title', {count});
|
isEnabled: true,
|
||||||
this.config.deleteEntitiesContent = () => this.translate.instant('resource.delete-resources-text');
|
onAction: ($event, entities) => this.deleteResources($event, entities)
|
||||||
|
}];
|
||||||
|
|
||||||
|
this.config.entitiesDeleteEnabled = false;
|
||||||
|
|
||||||
this.config.entitiesFetchFunction = pageLink => this.resourceService.getResources(pageLink, this.config.componentsData.resourceType);
|
this.config.entitiesFetchFunction = pageLink => this.resourceService.getResources(pageLink, this.config.componentsData.resourceType);
|
||||||
this.config.loadEntity = id => this.resourceService.getResourceInfoById(id.id);
|
this.config.loadEntity = id => this.resourceService.getResourceInfoById(id.id);
|
||||||
this.config.saveEntity = resource => this.saveResource(resource);
|
this.config.saveEntity = resource => this.saveResource(resource);
|
||||||
this.config.deleteEntity = id => this.resourceService.deleteResource(id.id);
|
|
||||||
|
|
||||||
this.config.onEntityAction = action => this.onResourceAction(action);
|
this.config.onEntityAction = action => this.onResourceAction(action);
|
||||||
}
|
}
|
||||||
@ -147,6 +173,8 @@ export class ResourcesLibraryTableConfigResolver {
|
|||||||
case 'downloadResource':
|
case 'downloadResource':
|
||||||
this.downloadResource(action.event, action.entity);
|
this.downloadResource(action.event, action.entity);
|
||||||
return true;
|
return true;
|
||||||
|
case 'deleteLibrary':
|
||||||
|
this.deleteResource(action.event, action.entity);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -165,4 +193,138 @@ export class ResourcesLibraryTableConfigResolver {
|
|||||||
return authority === Authority.SYS_ADMIN;
|
return authority === Authority.SYS_ADMIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private deleteResource($event: Event, resource: ResourceInfo) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.dialogService.confirm(
|
||||||
|
this.translate.instant('resource.delete-resource-title', { resourceTitle: resource.title }),
|
||||||
|
this.translate.instant('resource.delete-resource-text'),
|
||||||
|
this.translate.instant('action.no'),
|
||||||
|
this.translate.instant('action.yes'),
|
||||||
|
true
|
||||||
|
).subscribe((result) => {
|
||||||
|
if (result) {
|
||||||
|
this.resourceService.deleteResource(resource.id.id, false, {ignoreErrors: true}).pipe(
|
||||||
|
map(() => toResourceDeleteResult(resource)),
|
||||||
|
catchError((err) => of(toResourceDeleteResult(resource, err)))
|
||||||
|
).subscribe(
|
||||||
|
(deleteResult) => {
|
||||||
|
if (deleteResult.success) {
|
||||||
|
if (this.config.getEntityDetailsPage()) {
|
||||||
|
this.config.getEntityDetailsPage().goBack();
|
||||||
|
} else {
|
||||||
|
this.config.updateData(true);
|
||||||
|
}
|
||||||
|
} else if (deleteResult.resourceIsReferencedError) {
|
||||||
|
const resources: ResourceInfoWithReferences[] = [{...resource, ...{references: deleteResult.references}}];
|
||||||
|
const data = {
|
||||||
|
multiple: false,
|
||||||
|
resources,
|
||||||
|
configuration: {
|
||||||
|
title: 'resource.resource-is-in-use',
|
||||||
|
message: this.translate.instant('resource.resource-is-in-use-text', {title: resources[0].title}),
|
||||||
|
deleteText: 'resource.delete-resource-in-use-text',
|
||||||
|
selectedText: 'resource.selected-resources',
|
||||||
|
columns: ['select', 'title', 'references']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.dialog.open<ResourcesInUseDialogComponent, ResourcesInUseDialogData,
|
||||||
|
ResourceInfo[]>(ResourcesInUseDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
|
data
|
||||||
|
}).afterClosed().subscribe((resources) => {
|
||||||
|
if (resources) {
|
||||||
|
this.resourceService.deleteResource(resource.id.id, true).subscribe(() => {
|
||||||
|
if (this.config.getEntityDetailsPage()) {
|
||||||
|
this.config.getEntityDetailsPage().goBack();
|
||||||
|
} else {
|
||||||
|
this.config.updateData(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const errorMessageWithTimeout = parseHttpErrorMessage(deleteResult.error, this.translate);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.store.dispatch(new ActionNotificationShow({message: errorMessageWithTimeout.message, type: 'error'}));
|
||||||
|
}, errorMessageWithTimeout.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private deleteResources($event: Event, resources: ResourceInfo[]) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
if (resources && resources.length) {
|
||||||
|
const title = this.translate.instant('resource.delete-resources-title', {count: resources.length});
|
||||||
|
const content = this.translate.instant('resource.delete-resources-text');
|
||||||
|
this.dialogService.confirm(title, content,
|
||||||
|
this.translate.instant('action.no'),
|
||||||
|
this.translate.instant('action.yes')).subscribe((result) => {
|
||||||
|
if (result) {
|
||||||
|
const tasks = resources.map((resource) =>
|
||||||
|
this.resourceService.deleteResource(resource.id.id, false, {ignoreErrors: true}).pipe(
|
||||||
|
map(() => toResourceDeleteResult(resource)),
|
||||||
|
catchError((err) => of(toResourceDeleteResult(resource, err)))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
forkJoin(tasks).subscribe(
|
||||||
|
(deleteResults) => {
|
||||||
|
const anySuccess = deleteResults.some(res => res.success);
|
||||||
|
const referenceErrors = deleteResults.filter(res => res.resourceIsReferencedError);
|
||||||
|
const otherError = deleteResults.find(res => !res.success);
|
||||||
|
if (anySuccess) {
|
||||||
|
this.config.updateData();
|
||||||
|
}
|
||||||
|
if (referenceErrors?.length) {
|
||||||
|
const resourcesWithReferences: ResourceInfoWithReferences[] =
|
||||||
|
referenceErrors.map(ref => ({...ref.resource, ...{references: ref.references}}));
|
||||||
|
const data = {
|
||||||
|
multiple: true,
|
||||||
|
resources: resourcesWithReferences,
|
||||||
|
configuration: {
|
||||||
|
title: 'resource.resources-are-in-use',
|
||||||
|
message: this.translate.instant('resource.resources-are-in-use-text'),
|
||||||
|
deleteText: 'resource.delete-resource-in-use-text',
|
||||||
|
selectedText: 'resource.selected-resources',
|
||||||
|
datasource: new ResourcesDatasource(this.resourceService, resourcesWithReferences, () => true),
|
||||||
|
columns: ['select', 'title', 'references']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.dialog.open<ResourcesInUseDialogComponent, ResourcesInUseDialogData,
|
||||||
|
ResourceInfo[]>(ResourcesInUseDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
|
data
|
||||||
|
}).afterClosed().subscribe((forceDeleteResources) => {
|
||||||
|
if (forceDeleteResources && forceDeleteResources.length) {
|
||||||
|
const forceDeleteTasks = forceDeleteResources.map((resource) =>
|
||||||
|
this.resourceService.deleteResource(resource.id.id, true)
|
||||||
|
);
|
||||||
|
forkJoin(forceDeleteTasks).subscribe(
|
||||||
|
() => {
|
||||||
|
this.config.updateData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (otherError) {
|
||||||
|
const errorMessageWithTimeout = parseHttpErrorMessage(otherError.error, this.translate);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.store.dispatch(new ActionNotificationShow({message: errorMessageWithTimeout.message, type: 'error'}));
|
||||||
|
}, errorMessageWithTimeout.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4497,7 +4497,12 @@
|
|||||||
"scada-symbol": "Scada symbol",
|
"scada-symbol": "Scada symbol",
|
||||||
"extension": "Extension",
|
"extension": "Extension",
|
||||||
"module": "Module"
|
"module": "Module"
|
||||||
}
|
},
|
||||||
|
"resource-is-in-use": "Resource is used by other entities",
|
||||||
|
"resources-are-in-use": "Resources are used by other entities",
|
||||||
|
"resource-is-in-use-text": "The Resource <b>'{{title}}'</b> was not deleted because it is used by the following entities:",
|
||||||
|
"resources-are-in-use-text": "Not all Resources have been deleted because they are used by other entities.</br>You can view referenced entities by clicking the <b>References</b> button in the corresponding resource row.</br>If you still want to delete these resources, select them in the table below and click the <b>Delete selected</b> button.",
|
||||||
|
"delete-resource-in-use-text": "If you still want to delete the resource, click the <b>Delete anyway</b> button."
|
||||||
},
|
},
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"add": "Add JavaScript resource",
|
"add": "Add JavaScript resource",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user