diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.html b/apps/red-ui/src/app/components/base-screen/base-screen.component.html index 400a065d2..7040eba5c 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.html +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.html @@ -25,16 +25,17 @@ - + + - + {{ item.name | translate }} - + diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts index 827c99fd8..12e8a0df5 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts @@ -13,6 +13,7 @@ import { FeaturesService } from '@services/features.service'; import { DOSSIERS_ARCHIVE } from '@utils/constants'; interface MenuItem { + readonly id: string; readonly name: string; readonly routerLink?: string; readonly show: boolean; @@ -31,21 +32,25 @@ export class BaseScreenComponent { readonly currentUser = this.userService.currentUser; readonly userMenuItems: readonly MenuItem[] = [ { + id: 'account', name: _('top-bar.navigation-items.my-account.children.account'), routerLink: '/main/account', show: true, }, { + id: 'admin', name: _('top-bar.navigation-items.my-account.children.admin'), routerLink: '/main/admin', show: this.currentUser.isManager || this.currentUser.isUserAdmin, }, { + id: 'downloads', name: _('top-bar.navigation-items.my-account.children.downloads'), routerLink: '/main/downloads', show: this.currentUser.isUser, }, { + id: 'trash', name: _('top-bar.navigation-items.my-account.children.trash'), routerLink: '/main/admin/trash', show: this.currentUser.isManager, diff --git a/apps/red-ui/src/app/models/file/annotation.permissions.ts b/apps/red-ui/src/app/models/file/annotation.permissions.ts index e86cec050..2c5d1e02d 100644 --- a/apps/red-ui/src/app/models/file/annotation.permissions.ts +++ b/apps/red-ui/src/app/models/file/annotation.permissions.ts @@ -37,7 +37,8 @@ export class AnnotationPermissions { const annotationEntity = entities.find(entity => entity.type === annotation.type); permissions.canMarkAsFalsePositive = annotation.canBeMarkedAsFalsePositive && annotationEntity.hasDictionary; - permissions.canRemoveOrSuggestToRemoveOnlyHere = (annotation.isRedacted || annotation.isHint) && !annotation.pending; + permissions.canRemoveOrSuggestToRemoveOnlyHere = + (annotation.isRedacted || annotation.isHint) && !annotation.pending && !annotation.isImage; permissions.canRemoveOrSuggestToRemoveFromDictionary = annotation.isModifyDictionary && (annotation.isRedacted || annotation.isSkipped || annotation.isHint) && diff --git a/apps/red-ui/src/app/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index 355c31935..509b98f4d 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -303,20 +303,24 @@ export class AnnotationWrapper implements IListable, Record { } } + private static _getLastRelevantManualChange(manualChanges: IManualChange[]) { + return manualChanges[manualChanges.length - 1]; + } + private static _setSuperType(annotationWrapper: AnnotationWrapper, redactionLogEntryWrapper: RedactionLogEntry) { if (redactionLogEntryWrapper.manualChanges?.length) { - const lastManualChange = redactionLogEntryWrapper.manualChanges[redactionLogEntryWrapper.manualChanges.length - 1]; + const lastRelevantManualChange = this._getLastRelevantManualChange(redactionLogEntryWrapper.manualChanges); - annotationWrapper.pending = !lastManualChange.processed; + annotationWrapper.pending = !lastRelevantManualChange.processed; annotationWrapper.superType = AnnotationWrapper._selectSuperType( redactionLogEntryWrapper, - lastManualChange, + lastRelevantManualChange, annotationWrapper.hintDictionary, ); - if (lastManualChange.annotationStatus === LogEntryStatus.REQUESTED) { - annotationWrapper.recategorizationType = lastManualChange.propertyChanges.type; + if (lastRelevantManualChange.annotationStatus === LogEntryStatus.REQUESTED) { + annotationWrapper.recategorizationType = lastRelevantManualChange.propertyChanges.type; } } else { if (redactionLogEntryWrapper.recommendation) { @@ -418,7 +422,7 @@ export class AnnotationWrapper implements IListable, Record { case LogEntryStatus.APPROVED: return SuperTypes.Redaction; case LogEntryStatus.DECLINED: - return SuperTypes.Skipped; + return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; case LogEntryStatus.REQUESTED: return SuperTypes.SuggestionForceRedaction; } @@ -444,7 +448,7 @@ export class AnnotationWrapper implements IListable, Record { } else if (redactionLogEntry.hint) { return SuperTypes.Hint; } else { - return SuperTypes.Skipped; + return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; } } case LogEntryStatus.REQUESTED: @@ -471,7 +475,7 @@ export class AnnotationWrapper implements IListable, Record { } else if (redactionLogEntry.hint) { return SuperTypes.Hint; } else { - return SuperTypes.Skipped; + return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; } case LogEntryStatus.REQUESTED: return SuperTypes.SuggestionResize; diff --git a/apps/red-ui/src/app/models/file/redaction-log.entry.ts b/apps/red-ui/src/app/models/file/redaction-log.entry.ts index e0b358d78..361d1e347 100644 --- a/apps/red-ui/src/app/models/file/redaction-log.entry.ts +++ b/apps/red-ui/src/app/models/file/redaction-log.entry.ts @@ -29,6 +29,7 @@ export class RedactionLogEntry implements IRedactionLogEntry { readonly textBefore?: string; readonly type?: string; readonly value?: string; + readonly sourceId?: string; reason?: string; @@ -69,5 +70,6 @@ export class RedactionLogEntry implements IRedactionLogEntry { this.type = redactionLogEntry.type; this.value = redactionLogEntry.value; this.imported = redactionLogEntry.imported; + this.sourceId = redactionLogEntry.sourceId; } } diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts index 891f59285..b13bdebea 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -12,7 +12,7 @@ import { UserListingScreenComponent } from './screens/user-listing/user-listing- import { DossierTemplateBreadcrumbsComponent } from './components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component'; import { ColorPickerModule } from 'ngx-color-picker'; import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component'; -import { AddEditCloneDossierTemplateDialogComponent } from './dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component'; +import { AddEditDossierTemplateDialogComponent } from './dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component'; import { AddEntityDialogComponent } from './dialogs/add-entity-dialog/add-entity-dialog.component'; import { EditColorDialogComponent } from './dialogs/edit-color-dialog/edit-color-dialog.component'; import { ComboChartComponent, ComboSeriesVerticalComponent } from './components/combo-chart'; @@ -48,11 +48,13 @@ import { A11yModule } from '@angular/cdk/a11y'; import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component'; import { TrashTableItemComponent } from './screens/trash/trash-table-item/trash-table-item.component'; import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; +import { CloneDossierTemplateDialogComponent } from './dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component'; const dialogs = [ - AddEditCloneDossierTemplateDialogComponent, + AddEditDossierTemplateDialogComponent, AddEntityDialogComponent, AddEditFileAttributeDialogComponent, + CloneDossierTemplateDialogComponent, EditColorDialogComponent, SmtpAuthDialogComponent, AddEditUserDialogComponent, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.html similarity index 81% rename from apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html rename to apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.html index 149a08ad1..a5d11d920 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.html @@ -1,19 +1,19 @@ - + - + - {{ 'add-edit-clone-dossier-template.form.valid-from' | translate }} + {{ 'add-edit-dossier-template.form.valid-from' | translate }} - {{ 'add-edit-clone-dossier-template.form.valid-to' | translate }} + {{ 'add-edit-dossier-template.form.valid-to' | translate }} @@ -83,7 +83,7 @@ - {{ 'add-edit-clone-dossier-template.save' | translate }} + {{ 'add-edit-dossier-template.save' | translate }} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.scss rename to apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.scss diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts similarity index 64% rename from apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts rename to apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts index a05cf3c1e..8a5534542 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts @@ -12,16 +12,11 @@ import { DictionaryService } from '@services/entity-services/dictionary.service' import { firstValueFrom } from 'rxjs'; import dayjs, { Dayjs } from 'dayjs'; -interface EditCloneTemplateData { - dossierTemplateId: string; - clone?: boolean; -} - @Component({ - templateUrl: './add-edit-clone-dossier-template-dialog.component.html', - styleUrls: ['./add-edit-clone-dossier-template-dialog.component.scss'], + templateUrl: './add-edit-dossier-template-dialog.component.html', + styleUrls: ['./add-edit-dossier-template-dialog.component.scss'], }) -export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogComponent { +export class AddEditDossierTemplateDialogComponent extends BaseDialogComponent { hasValidFrom: boolean; hasValidTo: boolean; downloadTypesEnum: DownloadFileType[] = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED']; @@ -41,12 +36,12 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon private readonly _dictionaryService: DictionaryService, private readonly _formBuilder: FormBuilder, protected readonly _injector: Injector, - protected readonly _dialogRef: MatDialogRef, + protected readonly _dialogRef: MatDialogRef, private readonly _loadingService: LoadingService, - @Inject(MAT_DIALOG_DATA) readonly data: EditCloneTemplateData, + @Inject(MAT_DIALOG_DATA) readonly dossierTemplateId: string, ) { - super(_injector, _dialogRef, !!data && !data.clone); - this.dossierTemplate = this._dossierTemplatesService.find(this.data?.dossierTemplateId); + super(_injector, _dialogRef, !!dossierTemplateId); + this.dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId); this.form = this._getForm(); this.initialFormValue = this.form.getRawValue(); this.hasValidFrom = !!this.dossierTemplate?.validFrom; @@ -81,24 +76,18 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon this._loadingService.start(); try { const dossierTemplate = { - dossierTemplateId: !this.data?.clone ? this.dossierTemplate?.dossierTemplateId : null, + dossierTemplateId: this.dossierTemplate?.dossierTemplateId, ...this.form.getRawValue(), validFrom: this.hasValidFrom ? this.form.get('validFrom').value : null, validTo: this.hasValidTo ? this.form.get('validTo').value : null, } as IDossierTemplate; - if (this.data?.clone) { - const dossierTemplateId = this.dossierTemplate?.dossierTemplateId; - const nameOfClonedTemplate = this._getNameOfClonedTemplate(this.dossierTemplate.name); - await firstValueFrom(this._dossierTemplatesService.clone(dossierTemplate, dossierTemplateId, nameOfClonedTemplate)); - } else { - await firstValueFrom(this._dossierTemplatesService.createOrUpdate(dossierTemplate)); - } + await firstValueFrom(this._dossierTemplatesService.createOrUpdate(dossierTemplate)); this._dialogRef.close(true); } catch (error: any) { const message = error.status === HttpStatusCode.Conflict - ? _('add-edit-clone-dossier-template.error.conflict') - : _('add-edit-clone-dossier-template.error.generic'); + ? _('add-edit-dossier-template.error.conflict') + : _('add-edit-dossier-template.error.generic'); this._toaster.error(message, { error }); } this._loadingService.stop(); @@ -106,7 +95,7 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon private _getForm(): FormGroup { return this._formBuilder.group({ - name: [this._getTemplateName(), Validators.required], + name: [this.dossierTemplate?.name, Validators.required], description: [this.dossierTemplate?.description], validFrom: [ this.dossierTemplate?.validFrom ? dayjs(this.dossierTemplate?.validFrom) : null, @@ -120,37 +109,6 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon }); } - private _getTemplateName(): string | null { - if (this.dossierTemplate) { - const templateName = this.dossierTemplate.name.trim(); - if (this.data.clone) { - const nameOfClonedTemplate = this._getNameOfClonedTemplate(templateName); - const allTemplatesNames = this._dossierTemplatesService.all.map(t => t.name); - - let clonesCount = 0; - for (const name of allTemplatesNames) { - const splitName = name.split(nameOfClonedTemplate); - const suffixRegExp = new RegExp(/^\(\s*\d+\s*\)$/); - if (splitName[0] === 'Clone of ' && (splitName[1].trim().match(suffixRegExp) || splitName[1] === '')) { - clonesCount++; - } - } - - if (clonesCount >= 1) { - return `Clone of ${nameOfClonedTemplate} ${clonesCount === 1 ? '(1)' : `(${clonesCount})`}`; - } - return `Clone of ${nameOfClonedTemplate}`; - } - return templateName; - } - return null; - } - - private _getNameOfClonedTemplate(templateName: string): string { - const nameOfClonedTemplate = templateName.split('Clone of ').filter(n => n)[0]; - return nameOfClonedTemplate.split(/\(\s*\d+\s*\)$/)[0].trim(); - } - private _applyValidityIntervalConstraints(value): boolean { if (applyIntervalConstraints(value, this._previousValidFrom, this._previousValidTo, this.form, 'validFrom', 'validTo')) { return true; @@ -172,11 +130,4 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon return null; }; } - - get disabled(): boolean { - if (!this.data?.clone) { - return super.disabled; - } - return !this.valid; - } } diff --git a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.html new file mode 100644 index 000000000..6e31c1709 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + {{ 'clone-dossier-template.actions.save' | translate }} + + + + + diff --git a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts new file mode 100644 index 000000000..51437e070 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts @@ -0,0 +1,61 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { DossierTemplatesService } from '../../../../services/entity-services/dossier-templates.service'; +import { DossierTemplate, IDossierTemplate } from '../../../../../../../../libs/red-domain/src'; +import { LoadingService, Toaster } from '../../../../../../../../libs/common-ui/src'; +import { firstValueFrom } from 'rxjs'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; + +@Component({ + templateUrl: './clone-dossier-template-dialog.component.html', + styleUrls: ['./clone-dossier-template-dialog.component.scss'], +}) +export class CloneDossierTemplateDialogComponent { + private readonly _dossierTemplate: DossierTemplate; + nameOfClonedDossierTemplate: string; + + constructor( + private readonly _toaster: Toaster, + private readonly _loadingService: LoadingService, + private readonly _dossierTemplatesService: DossierTemplatesService, + protected readonly _dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) readonly dossierTemplateId: string, + ) { + this._dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId); + this.nameOfClonedDossierTemplate = this._getCloneName(); + } + + private _getCloneName(): string | null { + const templateName = this._dossierTemplate.name.trim(); + + let nameOfClonedTemplate: string = templateName.split('Clone of ').filter(n => n)[0]; + nameOfClonedTemplate = nameOfClonedTemplate.split(/\(\s*\d+\s*\)$/)[0].trim(); + + const allTemplatesNames = this._dossierTemplatesService.all.map(t => t.name); + + let clonesCount = 0; + for (const name of allTemplatesNames) { + const splitName = name.split(nameOfClonedTemplate); + const suffixRegExp = new RegExp(/^\(\s*\d+\s*\)$/); + if (splitName[0] === 'Clone of ' && (splitName[1].trim().match(suffixRegExp) || splitName[1] === '')) { + clonesCount++; + } + } + + if (clonesCount >= 1) { + return `Clone of ${nameOfClonedTemplate} ${clonesCount === 1 ? '(1)' : `(${clonesCount})`}`; + } + return `Clone of ${nameOfClonedTemplate}`; + } + + async save() { + this._loadingService.start(); + try { + await firstValueFrom(this._dossierTemplatesService.clone(this.dossierTemplateId, this.nameOfClonedDossierTemplate)); + this._dialogRef.close(true); + } catch (error: any) { + this._toaster.error(_('clone-dossier-template.error.generic'), { error }); + } + this._loadingService.stop(); + } +} diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts index e4dcda111..896cd6ed9 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts @@ -63,7 +63,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent d.dossierTemplateId)) { diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts index 848095ec5..e1cfc90a0 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts @@ -32,6 +32,6 @@ export class DossierTemplateInfoScreenComponent { } openEditDossierTemplateDialog($event: MouseEvent, dossierTemplate: DossierTemplate) { - this._dialogService.openDialog('addEditCloneDossierTemplate', $event, { dossierTemplateId: dossierTemplate.id }); + this._dialogService.openDialog('addEditDossierTemplate', $event, { dossierTemplateId: dossierTemplate.id }); } } diff --git a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts index fa5e70347..926a6cfff 100644 --- a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts +++ b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts @@ -2,7 +2,7 @@ import { Injectable, TemplateRef } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { AddEditFileAttributeDialogComponent } from '../dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component'; import { AddEntityDialogComponent } from '../dialogs/add-entity-dialog/add-entity-dialog.component'; -import { AddEditCloneDossierTemplateDialogComponent } from '../dialogs/add-edit-clone-dossier-template-dialog/add-edit-clone-dossier-template-dialog.component'; +import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component'; import { EditColorDialogComponent } from '../dialogs/edit-color-dialog/edit-color-dialog.component'; import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-dialog.component'; import { AddEditUserDialogComponent } from '../dialogs/add-edit-user-dialog/add-edit-user-dialog.component'; @@ -28,6 +28,7 @@ import { ActiveDossiersService } from '@services/dossiers/active-dossiers.servic import { UserService } from '@services/user.service'; import { IDossierAttributeConfig, IFileAttributeConfig, IReportTemplate } from '@red/domain'; import { ReportTemplateService } from '@services/report-template.service'; +import { CloneDossierTemplateDialogComponent } from '../dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component'; type DialogType = | 'confirm' @@ -38,7 +39,8 @@ type DialogType = | 'fileAttributesConfigurations' | 'addEditUser' | 'smtpAuthConfig' - | 'addEditCloneDossierTemplate' + | 'addEditDossierTemplate' + | 'cloneDossierTemplate' | 'addEditDossierAttribute' | 'uploadDictionary' | 'addEditDossierState' @@ -78,10 +80,14 @@ export class AdminDialogService extends DialogService { component: SmtpAuthDialogComponent, dialogConfig: { autoFocus: true }, }, - addEditCloneDossierTemplate: { - component: AddEditCloneDossierTemplateDialogComponent, + addEditDossierTemplate: { + component: AddEditDossierTemplateDialogComponent, dialogConfig: { width: '900px', autoFocus: true }, }, + cloneDossierTemplate: { + component: CloneDossierTemplateDialogComponent, + dialogConfig: { disableClose: false }, + }, addEditDossierAttribute: { component: AddEditDossierAttributeDialogComponent, dialogConfig: { autoFocus: true }, diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html index 100912920..3055e9041 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.html @@ -7,14 +7,14 @@ > from(this.pdfViewer.lockDocument()).pipe(map(() => blob))), withLatestFrom(this.stateService.file$), + tap(() => this._errorService.clear()), tap(([blob, file]) => this._loadDocument(blob, file)), ) .subscribe(); @@ -484,7 +488,6 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha } private _handleCustomActions() { - this.instance.UI.setToolMode('AnnotationEdit'); const textPopupsToToggle = [TextPopups.ADD_REDACTION, TextPopups.ADD_RECTANGLE, TextPopups.ADD_FALSE_POSITIVE]; const headerItemsToToggle = [ HeaderElements.SHAPE_TOOL_GROUP_BUTTON, @@ -550,7 +553,12 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha } private _loadDocument(blob: Blob, file: File) { - this.instance.UI.loadDocument(blob, { filename: file?.filename + '.pdf' ?? 'document.pdf' }); + const onError = () => { + this._loadingService.stop(); + this._errorService.set(DocLoadingError); + this.stateService.reloadBlob(); + }; + this.instance.UI.loadDocument(blob, { filename: file?.filename + '.pdf' ?? 'document.pdf', onError }); this._pageRotationService.clearRotationsHideActions(); } diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index 2758d5147..faa35213f 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -396,7 +396,7 @@ export class AnnotationActionsService { annotationWrapper.resizing = true; const viewerAnnotation = this._pdf.annotationManager.getAnnotationById(annotationWrapper.id); - if (annotationWrapper.rectangle || annotationWrapper.imported) { + if (annotationWrapper.rectangle || annotationWrapper.imported || annotationWrapper.isImage) { this._pdf.deleteAnnotations([annotationWrapper.id]); const rectangleAnnotation = this.#generateRectangle(annotationWrapper); this._pdf.annotationManager.addAnnotation(rectangleAnnotation, { imported: true }); @@ -446,12 +446,12 @@ export class AnnotationActionsService { $event?.stopPropagation(); const requests: List = annotations.map(annotation => ({ - reason: annotation.id, + sourceId: annotation.id, value: this._getFalsePositiveText(annotation), type: annotation.type, positions: annotation.positions, addToDictionary: true, - comment: { text: 'False Positive' }, + reason: 'False Positive', dictionaryEntryType: annotation.isRecommendation ? DictionaryEntryTypes.FALSE_RECOMMENDATION : DictionaryEntryTypes.FALSE_POSITIVE, diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts index 72562c3cf..668ec4252 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -1,14 +1,4 @@ -import { - ChangeType, - File, - IRedactionLog, - IRedactionLogEntry, - IViewedPage, - LogEntryStatus, - ManualRedactionType, - ViewMode, - ViewModes, -} from '@red/domain'; +import { ChangeType, File, IRedactionLog, IRedactionLogEntry, IViewedPage, ViewMode, ViewModes } from '@red/domain'; import { AnnotationWrapper } from '../../../models/file/annotation.wrapper'; import { BehaviorSubject, firstValueFrom, iif, Observable, Subject } from 'rxjs'; import { RedactionLogEntry } from '../../../models/file/redaction-log.entry'; @@ -179,7 +169,7 @@ export class FileDataService extends EntitiesService { #convertData(redactionLog: IRedactionLog, file: File): RedactionLogEntry[] { let result: RedactionLogEntry[] = []; - const reasonAnnotationIds: { [key: string]: RedactionLogEntry[] } = {}; + const sourceIdAnnotationIds: { [key: string]: RedactionLogEntry[] } = {}; const dictionaries = this._dictionariesMapService.get(this._state.dossierTemplateId); redactionLog.redactionLogEntry?.forEach(redactionLogEntry => { @@ -199,36 +189,18 @@ export class FileDataService extends EntitiesService { !!dictionary?.hint, ); - if ( - redactionLogEntry.manualChanges?.find( - mc => - mc.manualRedactionType === ManualRedactionType.ADD_TO_DICTIONARY && - (mc.annotationStatus === LogEntryStatus.APPROVED || mc.annotationStatus === LogEntryStatus.REQUESTED), - ) - ) { - // for dictionary entries -> I.E accepted recommendations or false positives, - // check reason - if (!reasonAnnotationIds[redactionLogEntry.reason]) { - reasonAnnotationIds[redactionLogEntry.reason] = [redactionLogEntryWrapper]; - } else { - reasonAnnotationIds[redactionLogEntry.reason].push(redactionLogEntryWrapper); + if (redactionLogEntry.sourceId) { + if (!sourceIdAnnotationIds[redactionLogEntry.sourceId]) { + sourceIdAnnotationIds[redactionLogEntry.sourceId] = []; } + sourceIdAnnotationIds[redactionLogEntry.sourceId].push(redactionLogEntryWrapper); } result.push(redactionLogEntryWrapper); }); - const reasonKeys = Object.keys(reasonAnnotationIds); - result = result.filter(r => { - const matched = reasonKeys.indexOf(r.id) >= 0; - if (matched) { - reasonAnnotationIds[r.id].forEach(value => { - value.reason = null; - }); - } - return !matched; - }); - + const sourceKeys = Object.keys(sourceIdAnnotationIds); + result = result.filter(r => !sourceKeys.includes(r.id)); result = result.filter(r => !r.hidden); return result; diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts index 10fc0c3f1..34e546838 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts @@ -1,11 +1,11 @@ import { Injectable, Injector } from '@angular/core'; -import { combineLatest, firstValueFrom, from, Observable, of, pairwise, switchMap } from 'rxjs'; +import { combineLatest, firstValueFrom, from, merge, Observable, of, pairwise, Subject, switchMap } from 'rxjs'; import { Dossier, File } from '@red/domain'; import { ActivatedRoute } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { PermissionsService } from '@services/permissions.service'; import { boolFactory } from '@iqser/common-ui'; -import { filter, startWith, tap } from 'rxjs/operators'; +import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators'; import { FileManagementService } from '@services/entity-services/file-management.service'; import { DOSSIER_ID, FILE_ID } from '@utils/constants'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; @@ -29,26 +29,28 @@ export class FilePreviewStateService { dossier: Dossier; file: File; - constructor( - private readonly _fileManagementService: FileManagementService, - private readonly _injector: Injector, - private readonly _route: ActivatedRoute, - private readonly _filesMapService: FilesMapService, - private readonly _dossiersService: DossiersService, - private readonly _filesService: FilesService, - private readonly _permissionsService: PermissionsService, - ) { - const dossiersService = dossiersServiceResolver(this._injector); + readonly #reloadBlob$ = new Subject(); - this.fileId = _route.snapshot.paramMap.get(FILE_ID); - this.dossierId = _route.snapshot.paramMap.get(DOSSIER_ID); + constructor( + route: ActivatedRoute, + filesMapService: FilesMapService, + private readonly _injector: Injector, + permissionsService: PermissionsService, + private readonly _filesService: FilesService, + private readonly _dossiersService: DossiersService, + private readonly _fileManagementService: FileManagementService, + ) { + const dossiersService = dossiersServiceResolver(_injector); + + this.fileId = route.snapshot.paramMap.get(FILE_ID); + this.dossierId = route.snapshot.paramMap.get(DOSSIER_ID); this.dossierTemplateId = dossiersService.find(this.dossierId).dossierTemplateId; this.dossier$ = dossiersService.getEntityChanged$(this.dossierId).pipe(tap(dossier => (this.dossier = dossier))); - this.file$ = _filesMapService.watch$(this.dossierId, this.fileId).pipe(tap(file => (this.file = file))); + this.file$ = filesMapService.watch$(this.dossierId, this.fileId).pipe(tap(file => (this.file = file))); [this.isReadonly$, this.isWritable$] = boolFactory( combineLatest([this.file$, this.dossier$]), - ([file, dossier]) => !_permissionsService.canPerformAnnotationActions(file, dossier), + ([file, dossier]) => !permissionsService.canPerformAnnotationActions(file, dossier), ); this.blob$ = this.#blob$; @@ -60,7 +62,11 @@ export class FilePreviewStateService { } get #blob$() { - return this.file$.pipe( + const reloadBlob$ = this.#reloadBlob$.pipe( + withLatestFrom(this.file$), + map(([, file]) => file), + ); + return merge(this.file$, reloadBlob$).pipe( startWith(undefined), pairwise(), filter(([oldFile, newFile]) => oldFile?.cacheIdentifier !== newFile.cacheIdentifier), @@ -68,6 +74,10 @@ export class FilePreviewStateService { ); } + reloadBlob(): void { + this.#reloadBlob$.next(true); + } + #dossierFilesChange$() { return this._dossiersService.dossierFileChanges$.pipe( filter(dossierId => dossierId === this.dossierId), diff --git a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts index 23d07b31b..d4421c017 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts @@ -66,8 +66,8 @@ export class ManualRedactionService extends GenericService { addRecommendation(annotations: AnnotationWrapper[], dossierId: string, fileId: string, comment = { text: 'Accepted Recommendation' }) { const recommendations: List = annotations.map(annotation => ({ addToDictionary: true, - // set the ID as reason, so we can hide the suggestion - reason: annotation.annotationId, + sourceId: annotation.annotationId, + reason: 'False Positive', value: annotation.value, positions: annotation.positions, type: annotation.recommendationType, diff --git a/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts b/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts index 5a28f77c3..a6479d814 100644 --- a/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts @@ -70,8 +70,8 @@ export class DossierTemplatesService extends EntitiesService this.loadAll())); } - clone(@RequiredParam() body: any, dossierTemplateId: string, name: string) { - return this._post(body, `${this._defaultModelPath}/${dossierTemplateId}/clone?nameOfClonedDossierTemplate=${name}`).pipe( + clone(dossierTemplateId: string, name: string) { + return this._post(null, `${this._defaultModelPath}/${dossierTemplateId}/clone?nameOfClonedDossierTemplate=${name}`).pipe( switchMap(() => this.loadAll()), ); } diff --git a/apps/red-ui/src/app/services/logger-rules.service.ts b/apps/red-ui/src/app/services/logger-rules.service.ts index d522b9ed5..e4aafbe98 100644 --- a/apps/red-ui/src/app/services/logger-rules.service.ts +++ b/apps/red-ui/src/app/services/logger-rules.service.ts @@ -6,10 +6,12 @@ import { ILoggerConfig } from '@red/domain'; export class LoggerRulesService extends NGXLoggerRulesService { shouldCallWriter(level: NgxLoggerLevel, config: ILoggerConfig, message?: unknown, additional?: unknown[]): boolean { if (message && typeof message === 'string') { - const matches = message.match('(?<=\\[)(.*?)(?=\\])'); + const matches = message.match('\\[(.*?)\\]'); - if (matches && matches.length > 0 && config.features[matches[0]]) { - const featureConfig = config.features[matches[0]]; + const firstMatch = matches[1]?.toUpperCase(); + + if (matches && matches.length > 0 && config.features[firstMatch]) { + const featureConfig = config.features[firstMatch]; if (!featureConfig.enabled || (featureConfig.level && featureConfig?.level < config.level)) { return false; diff --git a/apps/red-ui/src/assets/help-mode/links.json b/apps/red-ui/src/assets/help-mode/links.json index beba01977..6cd868047 100644 --- a/apps/red-ui/src/assets/help-mode/links.json +++ b/apps/red-ui/src/assets/help-mode/links.json @@ -150,7 +150,7 @@ "fr": "" }, "hint_remove_from_dictionary": { - "en": "/en/index-en.html?contextId=hints_remove_from_dictionary", + "en": "/en/index-en.html?contextId=hint_remove_from_dictionary", "de": "", "it": "", "fr": "" @@ -252,7 +252,7 @@ "fr": "" }, "redaction_resize": { - "en": "/en/index-en.html?contextId=redaction_resize_redaction", + "en": "/en/index-en.html?contextId=redaction_resize", "de": "", "it": "", "fr": "" @@ -263,6 +263,12 @@ "it": "", "fr": "" }, + "hint_resize": { + "en": "/en/index-en.html?contextId=hint_resize", + "de": "", + "it": "", + "fr": "" + }, "skipped_force_redaction": { "en": "/en/index-en.html?contextId=skipped_force_redaction", "de": "", @@ -358,5 +364,53 @@ "de": "", "it": "", "fr": "" + }, + "image_resize": { + "en": "/en/index-en.html?contextId=image_resize", + "de": "", + "it": "", + "fr": "" + }, + "image_recategorize": { + "en": "/en/index-en.html?contextId=image_recategorize", + "de": "", + "it": "", + "fr": "" + }, + "image_hide": { + "en": "/en/index-en.html?contextId=image_hide", + "de": "", + "it": "", + "fr": "" + }, + "image_remove_only_here": { + "en": "/en/index-en.html?contextId=image_remove_only_here", + "de": "", + "it": "", + "fr": "" + }, + "redaction_remove_from_dictionary": { + "en": "/en/index-en.html?contextId=redaction_remove_from_dictionary", + "de": "", + "it": "", + "fr": "" + }, + "skipped_resize": { + "en": "/en/index-en.html?contextId=skipped_resize_redaction", + "de": "", + "it": "", + "fr": "" + }, + "skipped_recategorize": { + "en": "/en/index-en.html?contextId=skipped_recategorize_redaction", + "de": "", + "it": "", + "fr": "" + }, + "skipped_hide": { + "en": "/en/index-en.html?contextId=skipped_hide", + "de": "", + "it": "", + "fr": "" } } diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index 6d9d53fc8..c1a3b4833 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -36,22 +36,6 @@ }, "header-new": "Dossier erstellen" }, - "add-edit-clone-dossier-template": { - "error": { - "conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen.", - "generic": "Fehler beim Erstellen der Dossiervorlage." - }, - "form": { - "description": "Beschreibung", - "description-placeholder": "Beschreibung eingeben", - "name": "Name der Dossier-Vorlage", - "name-placeholder": "Namen eingeben", - "valid-from": "Gültig ab", - "valid-to": "Gültig bis" - }, - "save": "Dossier-Vorlage speichern", - "title": "{type, select, edit{Dossier-Vorlage {name} bearbeiten} create{Dossier-Vorlage erstellen} clone{} other{}}" - }, "add-edit-dossier-attribute": { "error": { "generic": "Attribut konnte nicht gespeichert werden!" @@ -77,6 +61,22 @@ "success": "", "title": "" }, + "add-edit-dossier-template": { + "error": { + "conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen.", + "generic": "Fehler beim Erstellen der Dossiervorlage." + }, + "form": { + "description": "Beschreibung", + "description-placeholder": "Beschreibung eingeben", + "name": "Name der Dossier-Vorlage", + "name-placeholder": "Namen eingeben", + "valid-from": "Gültig ab", + "valid-to": "Gültig bis" + }, + "save": "Dossier-Vorlage speichern", + "title": "{type, select, edit{Dossier-Vorlage {name} bearbeiten} create{Dossier-Vorlage erstellen} other{}}" + }, "add-edit-entity": { "error": { "entity-already-exists": "", @@ -454,6 +454,19 @@ }, "header": "Begründung für die Schwärzung bearbeiten" }, + "clone-dossier-template": { + "actions": { + "save": "" + }, + "content": { + "name": "", + "name-placeholder": "" + }, + "error": { + "generic": "" + }, + "title": "" + }, "color": "", "comments": { "add-comment": "Kommentar eingeben", @@ -1124,6 +1137,10 @@ "label": "Diese Datei wurde gelöscht!" } }, + "file-preview": { + "action": "", + "label": "" + }, "http": { "generic": "Aktion mit Code {status} fehlgeschlagen" }, diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index cbd1a8491..a606856e6 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -36,22 +36,6 @@ }, "header-new": "Create Dossier" }, - "add-edit-clone-dossier-template": { - "error": { - "conflict": "Failed to create dossier template: a dossier template with the same name already exists.", - "generic": "Failed to create dossier template." - }, - "form": { - "description": "Description", - "description-placeholder": "Enter Description", - "name": "Dossier Template Name", - "name-placeholder": "Enter Name", - "valid-from": "Valid from", - "valid-to": "Valid to" - }, - "save": "Save Dossier Template", - "title": "{type, select, edit{Edit {name}} create{Create} clone{Clone} other{}} Dossier Template" - }, "add-edit-dossier-attribute": { "error": { "generic": "Failed to save attribute!" @@ -77,6 +61,22 @@ "success": "Successfully {type, select, edit{updated} create{created} other{}} the dossier state!", "title": "{type, select, edit{Edit {name}} create{Create} other{}} Dossier State" }, + "add-edit-dossier-template": { + "error": { + "conflict": "Failed to create dossier template: a dossier template with the same name already exists.", + "generic": "Failed to create dossier template." + }, + "form": { + "description": "Description", + "description-placeholder": "Enter Description", + "name": "Dossier Template Name", + "name-placeholder": "Enter Name", + "valid-from": "Valid from", + "valid-to": "Valid to" + }, + "save": "Save Dossier Template", + "title": "{type, select, edit{Edit {name}} create{Create} other{}} Dossier Template" + }, "add-edit-entity": { "error": { "entity-already-exists": "Entity with this name already exists!", @@ -454,6 +454,19 @@ }, "header": "Edit Redaction Reason" }, + "clone-dossier-template": { + "actions": { + "save": "Save Dossier Template" + }, + "content": { + "name": "Dossier Template Name", + "name-placeholder": "Enter Name" + }, + "error": { + "generic": "Failed to clone dossier template." + }, + "title": "Clone Dossier Template" + }, "color": "Color", "comments": { "add-comment": "Enter comment", @@ -1026,7 +1039,7 @@ "change-successful": "Dossier {dossierName} was updated.", "delete-successful": "Dossier {dossierName} was deleted.", "dictionary": { - "add-to-dictionary-action": "Available for add to dictionary", + "add-to-dictionary-action": "Enable 'Add to dictionary'", "display-name": { "cancel": "Cancel", "edit": "Edit Display Name", @@ -1124,6 +1137,10 @@ "label": "This file has been deleted!" } }, + "file-preview": { + "action": "Refresh", + "label": "An unknown error occurred. Please refresh the page" + }, "http": { "generic": "Action failed with code {status}" }, diff --git a/libs/red-domain/src/lib/redaction-log/redaction-log-entry.ts b/libs/red-domain/src/lib/redaction-log/redaction-log-entry.ts index 04774547b..24a55fdef 100644 --- a/libs/red-domain/src/lib/redaction-log/redaction-log-entry.ts +++ b/libs/red-domain/src/lib/redaction-log/redaction-log-entry.ts @@ -34,4 +34,5 @@ export interface IRedactionLogEntry { textBefore?: string; type?: string; value?: string; + sourceId?: string; } diff --git a/package.json b/package.json index 36afd87dc..2a159797d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redaction", - "version": "3.440.0", + "version": "3.451.0", "private": true, "license": "MIT", "scripts": { diff --git a/paligo-styles/homepage.scss b/paligo-styles/homepage.scss index 745c66503..7256c0b92 100644 --- a/paligo-styles/homepage.scss +++ b/paligo-styles/homepage.scss @@ -1,14 +1,6 @@ @use '../apps/red-ui/src/assets/styles/variables'; @use 'mixin'; -.featured-content-label { - display: none; -} - -.featured-content { - display: none; -} - .portal-single-publication { background-color: transparent; @@ -22,7 +14,7 @@ } .portal-contents { - margin-top: 100px; + margin-top: 24px; margin-bottom: 0; .inner { @@ -45,10 +37,6 @@ .portal-contents .inner { grid-template-columns: 1fr; } - - .publication-contents:first-child { - grid-column: auto; - } } // Icon Overwrites for sections - change these if sections change!!! diff --git a/paligo-styles/mixin.scss b/paligo-styles/mixin.scss index 93c4af988..299f4656e 100644 --- a/paligo-styles/mixin.scss +++ b/paligo-styles/mixin.scss @@ -86,13 +86,8 @@ background-color: variables.$white; border-radius: 4px; - &:first-child { - grid-column: 1 / span 2; - } - h4.featured-title, .section-toc-title { - @include heading-4; margin: 0; a { @@ -105,6 +100,10 @@ } } + .section-toc-title { + @include heading-4; + } + ul { margin: 0; padding: 0; diff --git a/paligo-theme.tar.gz b/paligo-theme.tar.gz index 425b102c5..279150e4a 100644 Binary files a/paligo-theme.tar.gz and b/paligo-theme.tar.gz differ diff --git a/paligo-theme/paligo-styles/redacto-theme.css b/paligo-theme/paligo-styles/redacto-theme.css index 76ac4602e..537362864 100644 --- a/paligo-theme/paligo-styles/redacto-theme.css +++ b/paligo-theme/paligo-styles/redacto-theme.css @@ -1,492 +1,479 @@ @charset "UTF-8"; -@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap'); .portal-header { - z-index: 1; - height: 450px; + z-index: 1; + height: 450px; } .portal-header::before { - background-color: #283241; + background-color: #283241; } .portal-header h1 { - font-size: 64px; - font-weight: 300; - line-height: 87px; - margin-top: 68px; - margin-bottom: 40px; + font-size: 64px; + font-weight: 300; + line-height: 87px; + margin-top: 68px; + margin-bottom: 40px; } .portal-header .portal-search { - max-width: 600px; - margin: auto; - position: relative; + max-width: 600px; + margin: auto; + position: relative; } .portal-header .portal-search .search-field { - width: 100%; - border: 1px solid #d3d5da; - border-radius: 8px; - background-color: #fff; + width: 100%; + border: 1px solid #d3d5da; + border-radius: 8px; + background-color: #fff; } .portal-header .portal-search .search-field::placeholder { - opacity: 0.7; + opacity: 0.7; } .portal-header .portal-search .search-field, .portal-header .portal-search .search-field::placeholder { - color: #283241; - font-size: 14px; - line-height: 18px; + color: #283241; + font-size: 14px; + line-height: 18px; } .portal-header .portal-search .search-field { - padding: 12px 17px; + padding: 12px 17px; } .portal-header .portal-search .btn { - position: absolute; - right: 0; - padding: 11px 18px; - background-color: transparent; - color: #283241; - cursor: pointer; - border-radius: 0 8px 8px 0; + position: absolute; + right: 0; + padding: 11px 18px; + background-color: transparent; + color: #283241; + cursor: pointer; + border-radius: 0 8px 8px 0; } .portal-header .portal-search .btn:hover { - background-color: #dd4d50; + background-color: #dd4d50; } @media only screen and (max-width: 768px) { - .portal-header h1 { - font-size: 42px; - font-weight: 300; - line-height: 57px; - } + .portal-header h1 { + font-size: 42px; + font-weight: 300; + line-height: 57px; + } } -.featured-content-label { - display: none; -} - -.featured-content { - display: none; -} - .portal-single-publication { - background-color: transparent; + background-color: transparent; } .portal-single-publication > a { - border-radius: 4px; + border-radius: 4px; } .portal-single-publication .publication-icon { - background-color: #dd4d50; + background-color: #dd4d50; } .portal-contents { - margin-top: 100px; - margin-bottom: 0; + margin-top: 24px; + margin-bottom: 0; } .portal-contents .inner { - margin: 0; - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 24px; + margin: 0; + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 24px; } .portal-contents .inner::before { - content: none; + content: none; } .publication-contents { - padding: 24px 40px; - border: 1px solid #e2e4e9; - width: 100%; - margin: 0; - background-color: #fff; - border-radius: 4px; -} -.publication-contents:first-child { - grid-column: 1/span 2; + padding: 24px 40px; + border: 1px solid #e2e4e9; + width: 100%; + margin: 0; + background-color: #fff; + border-radius: 4px; } .publication-contents h4.featured-title, .publication-contents .section-toc-title { - font-size: 28px; - font-weight: 300; - line-height: 36px; - margin: 0; + margin: 0; } .publication-contents h4.featured-title a, .publication-contents .section-toc-title a { - color: #283241; + color: #283241; } .publication-contents h4.featured-title a:hover, .publication-contents .section-toc-title a:hover { - color: #283241; - text-decoration: underline; + color: #283241; + text-decoration: underline; +} +.publication-contents .section-toc-title { + font-size: 28px; + font-weight: 300; + line-height: 36px; } .publication-contents ul { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } .publication-contents li { - margin: 4px 0; + margin: 4px 0; } .publication-contents li:first-child { - margin-top: 20px; + margin-top: 20px; } .publication-contents li:last-child { - margin-bottom: 40px; + margin-bottom: 40px; } .publication-contents li a { - color: #dd4d50; - font-size: 16px; - line-height: 24px; + color: #dd4d50; + font-size: 16px; + line-height: 24px; } .publication-contents li a:hover { - color: #dd4d50; - text-decoration: underline; + color: #dd4d50; + text-decoration: underline; } .publication-contents h4 span, .publication-contents li::before { - display: none; + display: none; } @media only screen and (max-width: 768px) { - .portal-contents .inner { - grid-template-columns: 1fr; - } - - .publication-contents:first-child { - grid-column: auto; - } + .portal-contents .inner { + grid-template-columns: 1fr; + } } /* Einleitung */ .cat-panel-1:before { - content: "\f277"; + content: '\f277'; } /* Workflow */ .cat-panel-2:before { - content: "\f0c1"; + content: '\f0c1'; } /* Voraussetzungen */ .cat-panel-3:before { - content: "\f109"; + content: '\f109'; } /* Benutzermenü und -profil */ .cat-panel-4:before { - content: "\f007"; + content: '\f007'; } /* Benachrichtigungen */ .cat-panel-5:before { - content: "\f0f3"; + content: '\f0f3'; } /* Suchfunktion */ .cat-panel-6:before { - content: "\f002"; + content: '\f002'; } /* Ebenen in der Benutzeroberfläche des RedactManagers */ .cat-panel-7:before { - content: "\f248"; + content: '\f248'; } /* Rollen und Berechtigungen */ .cat-panel-8:before { - content: "\f084"; + content: '\f084'; } /* Dossier erstellen und verwalten */ .cat-panel-9:before { - content: "\f07c"; + content: '\f07c'; } /* Dokumente bearbeiten im Editor */ .cat-panel-10:before { - content: "\f15c"; + content: '\f15c'; } /* Dossier abschließen und herunterladen */ .cat-panel-11:before { - content: "\f019"; + content: '\f019'; } /* Funktionsübersicht */ .cat-panel-12:before { - content: "\f03a"; + content: '\f03a'; } /* Glossar */ .cat-panel-13:before { - content: "\f02d"; + content: '\f02d'; } /* FAQ’s (häufige Fragen) */ .cat-panel-14:before { - content: "\f059"; + content: '\f059'; } .portal-search-result { - background-color: #f5f5f7; + background-color: #f5f5f7; } .search-container { - padding-bottom: 100px; + padding-bottom: 100px; } .portal-search-result { - padding: 80px 0 0 0; + padding: 80px 0 0 0; } ul.searchresults { - border: 1px solid #e2e4e9; - background-color: #fff; - border-radius: 4px; - margin-top: 32px; + border: 1px solid #e2e4e9; + background-color: #fff; + border-radius: 4px; + margin-top: 32px; } ul.searchresults .search-highlight { - font-style: normal; + font-style: normal; } li.searchresultitem { - margin: 0 32px; - border-bottom: 1px solid #e2e4e9; - padding: 32px 8px; + margin: 0 32px; + border-bottom: 1px solid #e2e4e9; + padding: 32px 8px; } .searchresultitem.selected-searchresultitem { - background-color: transparent; - border-radius: 0; + background-color: transparent; + border-radius: 0; } .searchresulttitle { - font-size: 28px; - font-weight: 300; - line-height: 36px; - color: #283241; + font-size: 28px; + font-weight: 300; + line-height: 36px; + color: #283241; } .searchresultsnippet { - margin: 16px 0; - color: #283241; + margin: 16px 0; + color: #283241; } .search-result-breadcrumbs { - color: #dd4d50; + color: #dd4d50; } .portal-footer, .site-footer { - border-top: 1px solid #e2e4e9; - padding: 0; + border-top: 1px solid #e2e4e9; + padding: 0; } .portal-footer.portal-footer, .site-footer.portal-footer { - margin-top: 100px; + margin-top: 100px; } .portal-footer .inner, .site-footer .inner { - margin: 0; - padding: 8px 0 64px 0; - font-size: 16px; - line-height: 24px; + margin: 0; + padding: 8px 0 64px 0; + font-size: 16px; + line-height: 24px; } .portal-footer .inner > *, .site-footer .inner > * { - padding: 0; + padding: 0; } .portal-footer .inner .copyright, .site-footer .inner .copyright { - width: 50%; + width: 50%; } :root { - --iqser-primary: lightblue; - --iqser-primary-rgb: 220, 230, 234; - --iqser-primary-2: orange; - --iqser-accent: blue; - --iqser-accent-rgb: 123, 234, 111; - --iqser-disabled: #9398a0; - --iqser-not-disabled-table-item: #f9fafb; - --iqser-btn-bg-hover: #e2e4e9; - --iqser-btn-bg: #f0f1f4; - --iqser-warn: #fdbd00; - --iqser-white: white; - --iqser-black: black; - --iqser-light: white; - --iqser-separator: rgba(226, 228, 233, 0.9); - --iqser-quick-filter-border: #d3d5da; - --iqser-grey-1: #283241; - --iqser-grey-2: #f4f5f7; - --iqser-grey-3: #aaacb3; - --iqser-grey-4: #e2e4e9; - --iqser-grey-5: #d3d5da; - --iqser-grey-6: #f0f1f4; - --iqser-grey-7: #9398a0; - --iqser-grey-8: #f9fafb; - --iqser-grey-9: #f5f5f7; - --iqser-grey-10: #313d4e; - --iqser-grey-11: #ecedf0; - --iqser-green-1: #00ff00; - --iqser-green-2: #5ce594; - --iqser-orange-1: #ff801a; - --iqser-yellow-1: #ffb83b; - --iqser-yellow-2: #fdbd00; - --iqser-yellow-rgb: 253, 189, 0; - --iqser-red-1: #dd4d50; - --iqser-red-2: #f16164; - --iqser-blue-1: #4875f7; - --iqser-blue-2: #48c9f7; - --iqser-blue-3: #5b97db; - --iqser-blue-4: #374c81; - --iqser-blue-5: #c5d3eb; - --iqser-pink-1: #f125de; - --iqser-helpmode-primary: green; + --iqser-primary: lightblue; + --iqser-primary-rgb: 220, 230, 234; + --iqser-primary-2: orange; + --iqser-accent: blue; + --iqser-accent-rgb: 123, 234, 111; + --iqser-disabled: #9398a0; + --iqser-not-disabled-table-item: #f9fafb; + --iqser-btn-bg-hover: #e2e4e9; + --iqser-btn-bg: #f0f1f4; + --iqser-warn: #fdbd00; + --iqser-white: white; + --iqser-black: black; + --iqser-light: white; + --iqser-separator: rgba(226, 228, 233, 0.9); + --iqser-quick-filter-border: #d3d5da; + --iqser-grey-1: #283241; + --iqser-grey-2: #f4f5f7; + --iqser-grey-3: #aaacb3; + --iqser-grey-4: #e2e4e9; + --iqser-grey-5: #d3d5da; + --iqser-grey-6: #f0f1f4; + --iqser-grey-7: #9398a0; + --iqser-grey-8: #f9fafb; + --iqser-grey-9: #f5f5f7; + --iqser-grey-10: #313d4e; + --iqser-grey-11: #ecedf0; + --iqser-green-1: #00ff00; + --iqser-green-2: #5ce594; + --iqser-orange-1: #ff801a; + --iqser-yellow-1: #ffb83b; + --iqser-yellow-2: #fdbd00; + --iqser-yellow-rgb: 253, 189, 0; + --iqser-red-1: #dd4d50; + --iqser-red-2: #f16164; + --iqser-blue-1: #4875f7; + --iqser-blue-2: #48c9f7; + --iqser-blue-3: #5b97db; + --iqser-blue-4: #374c81; + --iqser-blue-5: #c5d3eb; + --iqser-pink-1: #f125de; + --iqser-helpmode-primary: green; } .site-sidebar { - background-color: #283241; - scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-grey-2); - scrollbar-width: thin; - /* Track */ - /* Handle */ + background-color: #283241; + scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-grey-2); + scrollbar-width: thin; + /* Track */ + /* Handle */ } .site-sidebar .logo { - padding: 24px 0 30px 0 !important; + padding: 24px 0 30px 0 !important; } .site-sidebar::-webkit-scrollbar { - width: 11px; + width: 11px; } .site-sidebar::-webkit-scrollbar-track { - background: var(--iqser-grey-2); + background: var(--iqser-grey-2); } .site-sidebar::-webkit-scrollbar-thumb { - background: var(--iqser-quick-filter-border); + background: var(--iqser-quick-filter-border); } .site-sidebar-search { - padding: 0 24px; + padding: 0 24px; } .site-sidebar-search .search-field { - width: 100%; - border: 1px solid #d3d5da; - border-radius: 8px; - background-color: #fff; + width: 100%; + border: 1px solid #d3d5da; + border-radius: 8px; + background-color: #fff; } .site-sidebar-search .search-field::placeholder { - opacity: 0.7; + opacity: 0.7; } .site-sidebar-search .search-field, .site-sidebar-search .search-field::placeholder { - color: #283241; - font-size: 14px; - line-height: 18px; + color: #283241; + font-size: 14px; + line-height: 18px; } .site-sidebar-search .search-field { - padding: 7px 13px; + padding: 7px 13px; } .nav-site-sidebar { - margin-top: 16px; + margin-top: 16px; } .nav-site-sidebar .topic-link { - padding-top: 11px; - padding-bottom: 11px; - font-size: 14px; - line-height: 18px; - color: #d3d5da; + padding-top: 11px; + padding-bottom: 11px; + font-size: 14px; + line-height: 18px; + color: #d3d5da; } .nav-site-sidebar .topic-link:hover { - background-color: #313d4e; + background-color: #313d4e; } .nav-site-sidebar .active > .topic-link { - background-color: #313d4e; + background-color: #313d4e; } .nav-site-sidebar .active > a { - color: #fff; - font-weight: 600; + color: #fff; + font-weight: 600; } .nav-site-sidebar > li > a { - padding-left: 24px; + padding-left: 24px; } .nav-site-sidebar > li > ul > li > a { - padding-left: 32px; + padding-left: 32px; } .nav-site-sidebar > li > ul > li > ul > li > a { - padding-left: 40px; + padding-left: 40px; } .toc .glyphicon { - top: 5px; + top: 5px; } .toc > li > .topic-link > .glyphicon { - margin-top: 4px; + margin-top: 4px; } .toolbar { - box-shadow: none; - padding: 21px 24px; - margin-bottom: 50px; + box-shadow: none; + padding: 21px 24px; + margin-bottom: 50px; } .topic-content .breadcrumb-container { - margin-top: 40px; + margin-top: 40px; } .topic-content .breadcrumb { - font-size: 14px; - line-height: 18px; - font-weight: 600; + font-size: 14px; + line-height: 18px; + font-weight: 600; } .topic-content .breadcrumb a { - color: #283241; + color: #283241; } .topic-content .breadcrumb a:hover { - color: #dd4d50; - text-decoration: underline; + color: #dd4d50; + text-decoration: underline; } .topic-content .breadcrumb .breadcrumb-node { - color: #dd4d50; + color: #dd4d50; } main article { - margin-bottom: 0; - padding: 0; + margin-bottom: 0; + padding: 0; } section > .titlepage .title { - margin: 24px 0 16px 0; + margin: 24px 0 16px 0; } #topic-content > section > .titlepage h2.title { - margin: 0 0 24px; + margin: 0 0 24px; } .image-viewport { - margin: auto; + margin: auto; } .image-viewport img { - margin: 16px auto; + margin: 16px auto; } .pager { - margin-top: 30px; - margin-bottom: 30px; - padding: 0; + margin-top: 30px; + margin-bottom: 30px; + padding: 0; } .pager li > a, .pager li > span { - color: #dd4d50; - font-size: 14px; - font-weight: 600; - line-height: 19px; - text-transform: uppercase; - padding: 0; - background-color: transparent; - border: none; - border-radius: 0; + color: #dd4d50; + font-size: 14px; + font-weight: 600; + line-height: 19px; + text-transform: uppercase; + padding: 0; + background-color: transparent; + border: none; + border-radius: 0; } .pager li > a:hover, .pager li > span:hover { - text-decoration: underline; - background-color: transparent; - color: #dd4d50; + text-decoration: underline; + background-color: transparent; + color: #dd4d50; } .warning, @@ -494,230 +481,240 @@ section > .titlepage .title { .important, .caution, .tip { - margin-top: 32px; - margin-bottom: 32px; - padding: 16px 24px 16px 68px; - background-color: #fff; - border-left: 4px solid #dd4d50; - border-radius: 4px; + margin-top: 32px; + margin-bottom: 32px; + padding: 16px 24px 16px 68px; + background-color: #fff; + border-left: 4px solid #dd4d50; + border-radius: 4px; } .warning:before, .note:before, .important:before, .caution:before, .tip:before { - color: #dd4d50; - width: 20px; - height: 20px; - text-align: center; - left: 24px; - top: calc(50% - 15px); + color: #dd4d50; + width: 20px; + height: 20px; + text-align: center; + left: 24px; + top: calc(50% - 15px); } .warning h3, .note h3, .important h3, .caution h3, .tip h3 { - padding: 0; - font-size: 18px; - font-weight: 600; - line-height: 24px; - margin-bottom: 8px; + padding: 0; + font-size: 18px; + font-weight: 600; + line-height: 24px; + margin-bottom: 8px; } .warning p, .note p, .important p, .caution p, .tip p { - line-height: 20px; + line-height: 20px; } .topic-content > section > p { - margin: 12px 0; + margin: 12px 0; } .panel { - padding: 12px 0; - border-radius: 4px; - border: none; + padding: 12px 0; + border-radius: 4px; + border: none; } .panel .panel-body > p { - margin-bottom: 12px; + margin-bottom: 12px; } .panel .panel-body > p:not(:first-of-type) { - margin-top: 18px; + margin-top: 18px; } .mediaobject { - margin-top: 20px; + margin-top: 20px; } .mediaobject img { - border-radius: 4px; - margin: 0; - box-shadow: 0 3px 12px 5px rgba(40, 50, 65, 0.14); + border-radius: 4px; + margin: 0; + box-shadow: 0 3px 12px 5px rgba(40, 50, 65, 0.14); } .mediaobject .caption > p { - font-size: 14px; - text-align: center; - font-style: italic; - margin: 0; + font-size: 14px; + text-align: center; + font-style: italic; + margin: 0; } .inlinemediaobject { - vertical-align: unset; + vertical-align: unset; } main ol, main ul { - margin: 0 0 24px; + margin: 0 0 24px; } .section-toc { - padding: 24px 40px; - border: 1px solid #e2e4e9; - width: 100%; - margin: 0; - background-color: #fff; - border-radius: 4px; -} -.section-toc:first-child { - grid-column: 1/span 2; + padding: 24px 40px; + border: 1px solid #e2e4e9; + width: 100%; + margin: 0; + background-color: #fff; + border-radius: 4px; } .section-toc h4.featured-title, .section-toc .section-toc-title { - font-size: 28px; - font-weight: 300; - line-height: 36px; - margin: 0; + margin: 0; } .section-toc h4.featured-title a, .section-toc .section-toc-title a { - color: #283241; + color: #283241; } .section-toc h4.featured-title a:hover, .section-toc .section-toc-title a:hover { - color: #283241; - text-decoration: underline; + color: #283241; + text-decoration: underline; +} +.section-toc .section-toc-title { + font-size: 28px; + font-weight: 300; + line-height: 36px; } .section-toc ul { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } .section-toc li { - margin: 4px 0; + margin: 4px 0; } .section-toc li:first-child { - margin-top: 20px; + margin-top: 20px; } .section-toc li:last-child { - margin-bottom: 40px; + margin-bottom: 40px; } .section-toc li a { - color: #dd4d50; - font-size: 16px; - line-height: 24px; + color: #dd4d50; + font-size: 16px; + line-height: 24px; } .section-toc li a:hover { - color: #dd4d50; - text-decoration: underline; + color: #dd4d50; + text-decoration: underline; } .section-toc h4 span, .section-toc li::before { - display: none; + display: none; } .section-toc li:first-child { - margin-top: 16px; + margin-top: 16px; } .section-toc li:last-child { - margin-bottom: 8px; + margin-bottom: 8px; } .procedure > li.step::before { - background-color: transparent; - border: 1px solid #dd4d50; - color: #dd4d50; - line-height: 23px; + background-color: transparent; + border: 1px solid #dd4d50; + color: #dd4d50; + line-height: 23px; } .question { - font-weight: 600; + font-weight: 600; } .question > td > p { - margin: 32px 0 18px 0; + margin: 32px 0 18px 0; } .question > td:first-child { - padding-right: 4px; + padding-right: 4px; } .fixed-toolbar article.topic :target.question:before { - content: none; + content: none; } body { - color: #283241; - background-color: #f5f5f7; - font-family: "Open Sans", sans-serif; - scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-grey-2); - scrollbar-width: thin; - /* Track */ - /* Handle */ + color: #283241; + background-color: #f5f5f7; + font-family: 'Open Sans', sans-serif; + scrollbar-color: var(--iqser-quick-filter-border) var(--iqser-grey-2); + scrollbar-width: thin; + /* Track */ + /* Handle */ } -body h1, body .h1, -body h2, body .h2, -body h3, body .h3, -body h4, body .h4, -body h5, body .h5, -body h6, body .h6, +body h1, +body .h1, +body h2, +body .h2, +body h3, +body .h3, +body h4, +body .h4, +body h5, +body .h5, +body h6, +body .h6, body p, body pre { - margin: 0; - font-family: "Open Sans", sans-serif; + margin: 0; + font-family: 'Open Sans', sans-serif; } body::-webkit-scrollbar { - width: 11px; + width: 11px; } body::-webkit-scrollbar-track { - background: var(--iqser-grey-2); + background: var(--iqser-grey-2); } body::-webkit-scrollbar-thumb { - background: var(--iqser-quick-filter-border); + background: var(--iqser-quick-filter-border); } -body h1, body .h1 { - font-size: 64px; - font-weight: 300; - line-height: 87px; +body h1, +body .h1 { + font-size: 64px; + font-weight: 300; + line-height: 87px; } -body h2, body .h2 { - font-size: 42px; - font-weight: 300; - line-height: 57px; +body h2, +body .h2 { + font-size: 42px; + font-weight: 300; + line-height: 57px; } -body h3, body .h3 { - font-size: 32px; - font-weight: 300; - line-height: 43px; +body h3, +body .h3 { + font-size: 32px; + font-weight: 300; + line-height: 43px; } -body h4, body .h4 { - font-size: 28px; - font-weight: 300; - line-height: 36px; +body h4, +body .h4 { + font-size: 28px; + font-weight: 300; + line-height: 36px; } -body h5, body .h5 { - font-size: 18px; - font-weight: 600; - line-height: 24px; +body h5, +body .h5 { + font-size: 18px; + font-weight: 600; + line-height: 24px; } body p { - font-size: 16px; - line-height: 24px; + font-size: 16px; + line-height: 24px; } body a { - color: #dd4d50; + color: #dd4d50; } body a:hover { - text-decoration: underline; - color: #dd4d50; + text-decoration: underline; + color: #dd4d50; } body a:focus { - color: #dd4d50; + color: #dd4d50; }