Merge remote-tracking branch 'origin/master' into refactor
This commit is contained in:
commit
3fd9d12526
@ -157,12 +157,12 @@ export class FileAttributesCsvImportDialogComponent extends ListingComponent<IFi
|
||||
|
||||
async save() {
|
||||
const newPrimary = !!this.activeFields.find(attr => attr.primaryAttribute);
|
||||
let fileAttributeConfigs = this.data.existingConfiguration.fileAttributeConfigs;
|
||||
let fileAttributeConfigs = this.data.existingConfiguration.fileAttributeConfigs ?? [];
|
||||
if (newPrimary) {
|
||||
fileAttributeConfigs = fileAttributeConfigs.map(attr => new FileAttributeConfig({ ...attr, primaryAttribute: false }));
|
||||
}
|
||||
|
||||
const fileAttributes = {
|
||||
const fileAttributes: IFileAttributesConfig = {
|
||||
...this.baseConfigForm.getRawValue(),
|
||||
fileAttributeConfigs: [
|
||||
...fileAttributeConfigs.filter(a => !this.allEntities.find(entity => entity.csvColumn === a.csvColumnHeader)),
|
||||
@ -173,12 +173,14 @@ export class FileAttributesCsvImportDialogComponent extends ListingComponent<IFi
|
||||
label: field.name,
|
||||
type: field.type,
|
||||
primaryAttribute: field.primaryAttribute,
|
||||
displayedInFileList: null,
|
||||
filterable: null,
|
||||
})),
|
||||
],
|
||||
};
|
||||
|
||||
try {
|
||||
await this._fileAttributesService.setFileAttributesConfig(fileAttributes, this.data.dossierTemplateId).toPromise();
|
||||
await this._fileAttributesService.setFileAttributeConfig(fileAttributes, this.data.dossierTemplateId).toPromise();
|
||||
this._toaster.success(_('file-attributes-csv-import.save.success'), { params: { count: this.activeFields.length } });
|
||||
} catch (e) {
|
||||
this._toaster.error(_('file-attributes-csv-import.save.error'));
|
||||
|
||||
@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||
import { SearchScreenComponent } from './screens/search-screen/search-screen.component';
|
||||
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
|
||||
import { FilesGuard } from './utils/file.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -17,6 +18,7 @@ const routes: Routes = [
|
||||
{
|
||||
path: ':dossierId/file/:fileId',
|
||||
component: FilePreviewScreenComponent,
|
||||
canActivate: [FilesGuard],
|
||||
data: {
|
||||
reuse: true,
|
||||
},
|
||||
|
||||
@ -40,6 +40,7 @@ import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { SharedDossiersModule } from './shared/shared-dossiers.module';
|
||||
import { PlatformSearchService } from './shared/services/platform-search.service';
|
||||
import { ResizeAnnotationDialogComponent } from './dialogs/resize-annotation-dialog/resize-annotation-dialog.component';
|
||||
import { FilesGuard } from './utils/file.guard';
|
||||
|
||||
const screens = [FilePreviewScreenComponent, SearchScreenComponent];
|
||||
|
||||
@ -90,7 +91,7 @@ const services = [
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
providers: [...services],
|
||||
providers: [...services, FilesGuard],
|
||||
imports: [CommonModule, SharedModule, SharedDossiersModule, FileUploadDownloadModule, DossiersRoutingModule, OverlayModule],
|
||||
})
|
||||
export class DossiersModule {}
|
||||
|
||||
@ -5,8 +5,9 @@ import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { FilesService } from '@services/entity-services/files.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { map, switchMapTo } from 'rxjs/operators';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-details-stats',
|
||||
@ -29,14 +30,15 @@ export class DossierDetailsStatsComponent implements OnInit {
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _filesService: FilesService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
readonly dossiersService: DossiersService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.dossierStats$ = this._dossierStatsService.watch$(this.dossier.dossierId);
|
||||
this.deletedFilesCount$ = this._filesService.getDeletedFilesFor(this.dossier.id).pipe(
|
||||
this.deletedFilesCount$ = this._filesMapService.get$(this.dossier.dossierId).pipe(
|
||||
switchMapTo(this._filesService.getDeletedFilesFor(this.dossier.id)),
|
||||
map(files => files.length),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
<div class="mt-16">
|
||||
<div class="all-caps-label" translate="dossier-details.members"></div>
|
||||
<redaction-team-members
|
||||
(openAssignDossierMembersDialog)="openAssignDossierMembersDialog.emit()"
|
||||
(openAssignDossierMembersDialog)="openEditDossierDialog(dossier, 'members')"
|
||||
[memberIds]="dossier.memberIds"
|
||||
[perLine]="9"
|
||||
></redaction-team-members>
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
<div [class.mt-24]="!stats.hasFiles" class="pb-32">
|
||||
<redaction-dossier-details-stats
|
||||
(openDossierDictionaryDialog)="openDossierDictionaryDialog.emit()"
|
||||
(openDossierDictionaryDialog)="openEditDossierDialog(dossier, 'dossierDictionary')"
|
||||
[dossierAttributes]="dossierAttributes"
|
||||
[dossier]="dossier"
|
||||
></redaction-dossier-details-stats>
|
||||
|
||||
@ -12,6 +12,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
import { pluck, switchMap } from 'rxjs/operators';
|
||||
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-details',
|
||||
@ -22,8 +23,6 @@ import { pluck, switchMap } from 'rxjs/operators';
|
||||
export class DossierDetailsComponent {
|
||||
editingOwner = false;
|
||||
@Input() dossierAttributes: DossierAttributeWithValue[];
|
||||
@Output() readonly openAssignDossierMembersDialog = new EventEmitter();
|
||||
@Output() readonly openDossierDictionaryDialog = new EventEmitter();
|
||||
@Output() readonly toggleCollapse = new EventEmitter();
|
||||
collapseTooltip = _('dossier-details.collapse');
|
||||
expandTooltip = _('dossier-details.expand');
|
||||
@ -43,6 +42,7 @@ export class DossierDetailsComponent {
|
||||
private readonly _userService: UserService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
activatedRoute: ActivatedRoute,
|
||||
) {
|
||||
this.dossierId = activatedRoute.snapshot.paramMap.get('dossierId');
|
||||
@ -77,4 +77,11 @@ export class DossierDetailsComponent {
|
||||
const dossierName = dossier.dossierName;
|
||||
this._toaster.info(_('assignment.owner'), { params: { ownerName, dossierName } });
|
||||
}
|
||||
|
||||
openEditDossierDialog(dossier: Dossier, section: string): void {
|
||||
const data = { dossierId: this.dossierId, section };
|
||||
this._dialogService.openDialog('editDossier', null, data, async () => {
|
||||
await this.appStateService.getFiles(dossier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,8 +46,6 @@
|
||||
|
||||
<div [class.collapsed]="collapsedDetails" class="right-container" iqserHasScrollbar>
|
||||
<redaction-dossier-details
|
||||
(openAssignDossierMembersDialog)="openAssignDossierMembersDialog()"
|
||||
(openDossierDictionaryDialog)="openDossierDictionaryDialog()"
|
||||
(toggleCollapse)="collapsedDetails = !collapsedDetails"
|
||||
[dossierAttributes]="dossierAttributes"
|
||||
></redaction-dossier-details>
|
||||
|
||||
@ -20,7 +20,6 @@ import * as moment from 'moment';
|
||||
import { Observable, timer } from 'rxjs';
|
||||
import { switchMap, tap } from 'rxjs/operators';
|
||||
import { convertFiles, Files, handleFileDrop } from '@utils/index';
|
||||
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
DefaultListingServices,
|
||||
@ -84,7 +83,6 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _fileUploadService: FileUploadService,
|
||||
private readonly _statusOverlayService: StatusOverlayService,
|
||||
private readonly _fileDropOverlayService: FileDropOverlayService,
|
||||
@ -150,7 +148,10 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
|
||||
this.addSubscription = this._fileMapService
|
||||
.get$(this.dossierId)
|
||||
.pipe(tap(files => this.entitiesService.setEntities(files)))
|
||||
.pipe(
|
||||
tap(files => this.entitiesService.setEntities(files)),
|
||||
tap(() => this._computeAllFilters()),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this._fileDropOverlayService.initFileDropHandling(this.dossierId);
|
||||
@ -226,20 +227,6 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
(this._fileInput as any).nativeElement.value = null;
|
||||
}
|
||||
|
||||
openAssignDossierMembersDialog(): void {
|
||||
const data = { dossierId: this.dossierId, section: 'members' };
|
||||
this._dialogService.openDialog('editDossier', null, data, async () => {
|
||||
await this.reloadFiles();
|
||||
});
|
||||
}
|
||||
|
||||
openDossierDictionaryDialog() {
|
||||
const data = { dossierId: this.dossierId, section: 'dossierDictionary' };
|
||||
this._dialogService.openDialog('editDossier', null, data, async () => {
|
||||
await this.reloadFiles();
|
||||
});
|
||||
}
|
||||
|
||||
recentlyModifiedChecker = (file: File) =>
|
||||
moment(file.lastUpdated).add(this._appConfigService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<div>
|
||||
<redaction-simple-doughnut-chart
|
||||
[config]="dossiersChartData$ | async"
|
||||
*ngIf="dossiersChartData$ | async as config"
|
||||
[config]="config"
|
||||
[radius]="80"
|
||||
[strokeWidth]="15"
|
||||
[subtitle]="'dossier-listing.stats.charts.dossiers' | translate"
|
||||
|
||||
@ -3,7 +3,7 @@ import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/si
|
||||
import { FilterService, mapEach } from '@iqser/common-ui';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { Dossier, DossierStats, DossierStatuses, FileCountPerWorkflowStatus, StatusSorter } from '@red/domain';
|
||||
import { Dossier, DossierStats, FileCountPerWorkflowStatus, StatusSorter } from '@red/domain';
|
||||
import { workflowFileStatusTranslations } from '../../../../translations/file-status-translations';
|
||||
import { TranslateChartService } from '@services/translate-chart.service';
|
||||
import { filter, map, switchMap } from 'rxjs/operators';
|
||||
@ -33,16 +33,15 @@ export class DossiersListingDetailsComponent {
|
||||
map(stats => this._toChartData(stats)),
|
||||
);
|
||||
|
||||
this.dossiersChartData$ = this.dossiersService.all$.pipe(map(dossiers => this._toDossierChartData(dossiers)));
|
||||
this.dossiersChartData$ = this.dossiersService.all$.pipe(switchMap(dossiers => this._toDossierChartData(dossiers)));
|
||||
}
|
||||
|
||||
private _toDossierChartData(dossiers: Dossier[]): DoughnutChartConfig[] {
|
||||
const activeDossiersCount = dossiers.filter(p => p.status === DossierStatuses.ACTIVE).length;
|
||||
const inactiveDossiersCount = dossiers.length - activeDossiersCount;
|
||||
|
||||
private async _toDossierChartData(dossiers: Dossier[]): Promise<DoughnutChartConfig[]> {
|
||||
// TODO: deleted dossiers count should come with stats
|
||||
const deletedDossiers = await this.dossiersService.getDeleted();
|
||||
return [
|
||||
{ value: activeDossiersCount, color: 'ACTIVE', label: _('active') },
|
||||
{ value: inactiveDossiersCount, color: 'DELETED', label: _('archived') },
|
||||
{ value: dossiers.length, color: 'ACTIVE', label: _('active') },
|
||||
{ value: deletedDossiers.length, color: 'DELETED', label: _('archived') },
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
32
apps/red-ui/src/app/modules/dossier/utils/file.guard.ts
Normal file
32
apps/red-ui/src/app/modules/dossier/utils/file.guard.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Injectable()
|
||||
export class FilesGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _router: Router,
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
const dossierId = route.paramMap.get('dossierId');
|
||||
const fileId = route.paramMap.get('fileId');
|
||||
|
||||
if (!this._filesMapService.get(dossierId, fileId)) {
|
||||
const dossier = this._dossiersService.find(dossierId);
|
||||
await this._appStateService.getFiles(dossier);
|
||||
|
||||
if (!this._filesMapService.get(dossierId, fileId)) {
|
||||
await this._router.navigate([dossier.routerLink]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,7 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
|
||||
return combineLatest([dossier$, stats$]).pipe(
|
||||
map(([updatedDossier]) => new Dossier(updatedDossier)),
|
||||
tap(newDossier => this.replace(newDossier)),
|
||||
tap(newDossier => this.replace([newDossier])),
|
||||
catchError(showToast),
|
||||
);
|
||||
}
|
||||
|
||||
@ -13,6 +13,10 @@ export class FilesMapService {
|
||||
constructor(private readonly _filesService: FilesService) {}
|
||||
|
||||
get$(dossierId: string) {
|
||||
if (!this._map.has(dossierId)) {
|
||||
this._map.set(dossierId, new BehaviorSubject<File[]>([]));
|
||||
}
|
||||
|
||||
return this._map.get(dossierId).asObservable();
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ export class UserService extends EntitiesService<User, IUser> {
|
||||
const userId = (<{ sub: string }>decoded).sub;
|
||||
|
||||
const roles = this._keycloakService.getUserRoles(true).filter(role => role.startsWith('RED_'));
|
||||
this.replace(new User(await this._keycloakService.loadUserProfile(true), roles, userId));
|
||||
this.replace([new User(await this._keycloakService.loadUserProfile(true), roles, userId)]);
|
||||
|
||||
this._currentUser$.next(this.find(userId));
|
||||
}
|
||||
|
||||
@ -112,9 +112,7 @@ export class AppStateService {
|
||||
const dossierIds = dossiers.map(dossier => dossier.dossierId);
|
||||
await this._dossierStatsService.getFor(dossierIds).toPromise();
|
||||
|
||||
dossiers.forEach(dossier => {
|
||||
this._dossiersService.replace(new Dossier(dossier));
|
||||
});
|
||||
this._dossiersService.replace(dossiers.map(dossier => new Dossier(dossier)));
|
||||
}
|
||||
|
||||
async reloadFile(dossierId: string, fileId: string) {
|
||||
@ -175,7 +173,7 @@ export class AppStateService {
|
||||
await this._fileAttributesService.getFileAttributesConfig(dossierTemplateId).toPromise();
|
||||
|
||||
const newDossierTemplate = new DossierTemplate(dossierTemplate);
|
||||
this._dossierTemplatesService.replace(newDossierTemplate);
|
||||
this._dossierTemplatesService.replace([newDossierTemplate]);
|
||||
|
||||
await this.refreshDossierTemplateDictionaryData(dossierTemplateId);
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 74fcbf080b593622220bb2c7de08f69163acab04
|
||||
Subproject commit 17c65675b934698a61a2c80435f532e5a77f0c97
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "redaction",
|
||||
"version": "3.25.0",
|
||||
"version": "3.30.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user