diff --git a/apps/red-ui/src/app/modules/account/account-routing.module.ts b/apps/red-ui/src/app/modules/account/account-routing.module.ts index 2c3c7d4db..8e6dcc586 100644 --- a/apps/red-ui/src/app/modules/account/account-routing.module.ts +++ b/apps/red-ui/src/app/modules/account/account-routing.module.ts @@ -36,6 +36,22 @@ const routes: IqserRoutes = [ canActivate: [CompositeRouteGuard], data: { routeGuards: [IqserAuthGuard, RedRoleGuard], + screen: 'preferences', + }, + children: [ + { + path: '', + component: PreferencesComponent, + }, + ], + }, + { + path: 'warnings-preferences', + component: BaseAccountScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [IqserAuthGuard, RedRoleGuard], + screen: 'warnings-preferences', }, children: [ { diff --git a/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts b/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts index 360a7eca9..5a44887ad 100644 --- a/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts +++ b/apps/red-ui/src/app/modules/account/account-side-nav/account-side-nav.component.ts @@ -30,6 +30,10 @@ export class AccountSideNavComponent { screen: 'preferences', label: _('preferences-screen.label'), }, + { + screen: 'warnings-preferences', + label: _('preferences-screen.warnings-label'), + }, ]; constructor(private readonly _permissionsService: IqserPermissionsService) {} diff --git a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.html b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.html index a2dbe2f8b..5e3e2542a 100644 --- a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.html +++ b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.html @@ -1,16 +1,29 @@
+
-
- - {{ 'preferences-screen.form.auto-expand-filters-on-action' | translate }} - -
-
- - {{ 'preferences-screen.form.show-suggestions-in-preview' | translate }} - -
+ +
+ + {{ 'preferences-screen.form.auto-expand-filters-on-action' | translate }} + +
+
+ + {{ 'preferences-screen.form.show-suggestions-in-preview' | translate }} + +
+
+ +

{{ 'preferences-screen.warnings-subtitle' | translate }}

+

{{ 'preferences-screen.warnings-description' | translate }}

+ +
+ + {{ 'preferences-screen.form.unapproved-suggestions-warning' | translate }} + +
+
diff --git a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.scss b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.scss index e69de29bb..9fb4fef95 100644 --- a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.scss +++ b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.scss @@ -0,0 +1,16 @@ +@use 'variables'; + +.content-delimiter { + border-top: 1px solid var(--iqser-separator); + margin-bottom: 15px; +} + +.warnings-subtitle { + font-size: var(--iqser-font-size); + color: var(--iqser-text); + font-weight: 600; +} + +.warnings-description { + width: 105%; +} diff --git a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts index 4e23df42f..2911d605a 100644 --- a/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/preferences/preferences.component.ts @@ -1,17 +1,27 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core'; import { UserPreferenceService } from '@users/user-preference.service'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; import { BaseFormComponent, IqserPermissionsService } from '@iqser/common-ui'; import { ROLES } from '@users/roles'; interface PreferencesForm { + // preferences autoExpandFiltersOnActions: boolean; - showSuggestionsInPreview: boolean; + displaySuggestionsInPreview: boolean; + // warnings preferences + unapprovedSuggestionsWarning: boolean; [k: string]: any; } type AsControl = { [K in keyof T]: FormControl }; +type Screen = 'preferences' | 'warnings-preferences'; + +const Screens = { + PREFERENCES: 'preferences', + WARNING_PREFERENCES: 'warnings-preferences', +} as const; @Component({ selector: 'redaction-preferences', @@ -21,17 +31,24 @@ type AsControl = { [K in keyof T]: FormControl }; }) export class PreferencesComponent extends BaseFormComponent { readonly form: FormGroup>; + readonly currentScreen: Screen; + readonly screens = Screens; initialFormValue: PreferencesForm; constructor( readonly userPreferenceService: UserPreferenceService, private readonly _formBuilder: FormBuilder, private readonly _permissionsService: IqserPermissionsService, + private readonly _route: ActivatedRoute, + private readonly _changeRef: ChangeDetectorRef, ) { super(); this.form = this._formBuilder.group({ + // preferences autoExpandFiltersOnActions: [this.userPreferenceService.getAutoExpandFiltersOnActions()], - showSuggestionsInPreview: [this.userPreferenceService.getShowSuggestionsInPreview()], + displaySuggestionsInPreview: [this.userPreferenceService.getDisplaySuggestionsInPreview()], + // warnings preferences + unapprovedSuggestionsWarning: [this.userPreferenceService.getUnapprovedSuggestionsWarning()], }); if (!this._permissionsService.has(ROLES.managePreferences)) { @@ -39,17 +56,26 @@ export class PreferencesComponent extends BaseFormComponent { } this.initialFormValue = this.form.getRawValue(); + this.currentScreen = _route.snapshot.data.screen; } async save(): Promise { if (this.form.controls.autoExpandFiltersOnActions.value !== this.userPreferenceService.getAutoExpandFiltersOnActions()) { await this.userPreferenceService.toggleAutoExpandFiltersOnActions(); } - if (this.form.controls.showSuggestionsInPreview.value !== this.userPreferenceService.getShowSuggestionsInPreview()) { - await this.userPreferenceService.toggleShowSuggestionsInPreview(); + if (this.form.controls.displaySuggestionsInPreview.value !== this.userPreferenceService.getDisplaySuggestionsInPreview()) { + await this.userPreferenceService.toggleDisplaySuggestionsInPreview(); + } + if (this.form.controls.unapprovedSuggestionsWarning.value !== this.userPreferenceService.getUnapprovedSuggestionsWarning()) { + await this.userPreferenceService.toggleUnapprovedSuggestionsWarning(); } await this.userPreferenceService.reload(); - this.form.patchValue({ autoExpandFiltersOnActions: this.userPreferenceService.getAutoExpandFiltersOnActions() }); + this.form.patchValue({ + autoExpandFiltersOnActions: this.userPreferenceService.getAutoExpandFiltersOnActions(), + displaySuggestionsInPreview: this.userPreferenceService.getDisplaySuggestionsInPreview(), + unapprovedSuggestionsWarning: this.userPreferenceService.getUnapprovedSuggestionsWarning(), + }); this.initialFormValue = this.form.getRawValue(); + this._changeRef.markForCheck(); } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts index 317dfb29a..a39aaed3e 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts @@ -386,7 +386,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy if (this._viewModeService.isRedacted) { annotations = annotations.filter(a => !bool(a.isChangeLogRemoved)); - if (!this._userPreferencesService.getShowSuggestionsInPreview()) { + if (!this._userPreferencesService.getDisplaySuggestionsInPreview()) { annotations = annotations.filter(a => !a.isSuggestion); } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts index c782253de..4d8aa9f76 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/view-switch/view-switch.component.ts @@ -1,10 +1,14 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { ViewMode, ViewModes } from '@red/domain'; import { ViewModeService } from '../../services/view-mode.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { FileDataService } from '../../services/file-data.service'; +import { BASE_HREF, ConfirmationDialogInput, ConfirmOptions, Toaster } from '@iqser/common-ui'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { UserPreferenceService } from '@users/user-preference.service'; +import { FilePreviewDialogService } from '../../services/file-preview-dialog.service'; @Component({ selector: 'redaction-view-switch', @@ -19,9 +23,13 @@ export class ViewSwitchComponent { readonly canSwitchToEarmarksView$: Observable; constructor( + @Inject(BASE_HREF) private readonly _baseHref: string, readonly viewModeService: ViewModeService, private readonly _stateService: FilePreviewStateService, private readonly _fileDataService: FileDataService, + private readonly _userPreferenceService: UserPreferenceService, + private readonly _dialogService: FilePreviewDialogService, + private readonly _toaster: Toaster, ) { this.canSwitchToDeltaView$ = combineLatest([_fileDataService.hasChangeLog$, _stateService.file$]).pipe( map(([hasChangeLog, file]) => hasChangeLog && !file.isApproved), @@ -35,6 +43,48 @@ export class ViewSwitchComponent { } switchView(viewMode: ViewMode) { + if (viewMode === ViewModes.REDACTED) { + return this.#switchToRedactedView(); + } this.viewModeService.viewMode = viewMode; } + + async #switchToRedactedView() { + const unapprovedSuggestionsWarning = this._userPreferenceService.getUnapprovedSuggestionsWarning(); + if (unapprovedSuggestionsWarning) { + const suggestions = (await this._fileDataService.annotations).filter(a => a.isSuggestion); + if (suggestions.length) { + const displaySuggestionsInPreview = this._userPreferenceService.getDisplaySuggestionsInPreview(); + const question = displaySuggestionsInPreview + ? _('unapproved-suggestions.confirmation-dialog.displayed-question') + : _('unapproved-suggestions.confirmation-dialog.not-displayed-question'); + const data = new ConfirmationDialogInput({ + title: _('unapproved-suggestions.confirmation-dialog.title'), + question: question, + confirmationText: _('unapproved-suggestions.confirmation-dialog.confirmation-text'), + denyText: _('unapproved-suggestions.confirmation-dialog.deny-text'), + checkboxes: [ + { + label: _('unapproved-suggestions.confirmation-dialog.checkbox-text'), + value: false, + }, + ], + checkboxesValidation: false, + }); + + return this._dialogService.openDialog('confirm', null, data, result => { + if (result) { + if (result === ConfirmOptions.SECOND_CONFIRM) { + this._userPreferenceService.toggleUnapprovedSuggestionsWarning(); + this._toaster.success(_('unapproved-suggestions.confirmation-dialog.success-confirmation-text'), { + params: { settingsUrl: `${this._baseHref}/main/account/warnings-preferences` }, + }); + } + this.viewModeService.switchToRedacted(); + } + }); + } + } + return this.viewModeService.switchToRedacted(); + } } diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 4ac2cc153..f3a725067 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -17,6 +17,8 @@ import { AutoUnsubscribe, bool, CircleButtonTypes, + ConfirmationDialogInput, + ConfirmOptions, CustomError, Debounce, ErrorService, @@ -252,11 +254,8 @@ export class FilePreviewScreenComponent this._annotationManager.show(redactions); this._annotationManager.hide(nonRedactionEntries); + await this.#hideSuggestions(redactions); - if (!this.userPreferenceService.getShowSuggestionsInPreview()) { - const suggestions = redactions.filter(a => bool(a.getCustomData('suggestion'))); - this._annotationManager.hide(suggestions); - } break; } case ViewModes.TEXT_HIGHLIGHTS: { @@ -755,4 +754,11 @@ export class FilePreviewScreenComponent const annotations = this._annotationManager.get(selected); this._annotationManager.select(annotations); } + + async #hideSuggestions(redactions: Annotation[]): Promise { + if (!this.userPreferenceService.getDisplaySuggestionsInPreview()) { + const currentPageSuggestions = redactions.filter(a => bool(a.getCustomData('suggestion'))); + this._annotationManager.hide(currentPageSuggestions); + } + } } diff --git a/apps/red-ui/src/app/translations/account-translations.ts b/apps/red-ui/src/app/translations/account-translations.ts index 88b9efac4..77ca13811 100644 --- a/apps/red-ui/src/app/translations/account-translations.ts +++ b/apps/red-ui/src/app/translations/account-translations.ts @@ -4,4 +4,5 @@ export const accountTranslations: Record = { notifications: _('notifications-screen.title'), 'user-profile': _('user-profile-screen.title'), preferences: _('preferences-screen.title'), + 'warnings-preferences': _('preferences-screen.warnings-title'), }; diff --git a/apps/red-ui/src/app/users/user-preference.service.ts b/apps/red-ui/src/app/users/user-preference.service.ts index 8cd346f26..c27cf8a72 100644 --- a/apps/red-ui/src/app/users/user-preference.service.ts +++ b/apps/red-ui/src/app/users/user-preference.service.ts @@ -7,7 +7,8 @@ const KEYS = { lastDossierTemplate: 'Last-Dossier-Template', filesListingMode: 'Files-Listing-Mode', autoExpandFiltersOnActions: 'Auto-Expand-Filters-On-Actions', - showSuggestionsInPreview: 'Show-Suggestions-In-Preview', + displaySuggestionsInPreview: 'Display-Suggestions-In-Preview', + unapprovedSuggestionsWarning: 'Unapproved-Suggestions-Warning', } as const; @Injectable({ @@ -51,12 +52,21 @@ export class UserPreferenceService extends IqserUserPreferenceService { await this._save(KEYS.autoExpandFiltersOnActions, nextValue); } - getShowSuggestionsInPreview(): boolean { - return this._getAttribute(KEYS.showSuggestionsInPreview, 'false') === 'true'; + getDisplaySuggestionsInPreview(): boolean { + return this._getAttribute(KEYS.displaySuggestionsInPreview, 'false') === 'true'; } - async toggleShowSuggestionsInPreview(): Promise { - const nexValue = (!this.getShowSuggestionsInPreview()).toString(); - await this._save(KEYS.showSuggestionsInPreview, nexValue); + async toggleDisplaySuggestionsInPreview(): Promise { + const nextValue = (!this.getDisplaySuggestionsInPreview()).toString(); + await this._save(KEYS.displaySuggestionsInPreview, nextValue); + } + + getUnapprovedSuggestionsWarning(): boolean { + return this._getAttribute(KEYS.unapprovedSuggestionsWarning, 'false') === 'true'; + } + + async toggleUnapprovedSuggestionsWarning(): Promise { + const nextValue = (!this.getUnapprovedSuggestionsWarning()).toString(); + await this._save(KEYS.unapprovedSuggestionsWarning, nextValue); } getFilesListingMode(): ListingMode { diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index a9cce2132..9b420ce2f 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -753,6 +753,7 @@ "dossier-details": { "assign-members": "Mitglieder zuweisen", "collapse": "Details ausblenden", + "document-status": "", "edit-owner": "Eigentümer bearbeiten", "expand": "Details zeigen", "members": "Mitglieder", @@ -1799,10 +1800,15 @@ }, "form": { "auto-expand-filters-on-action": "", - "show-suggestions-in-preview": "" + "show-suggestions-in-preview": "", + "unapproved-suggestions-warning": "" }, "label": "", - "title": "" + "title": "", + "warnings-description": "", + "warnings-label": "", + "warnings-subtitle": "", + "warnings-title": "" }, "processing-status": { "ocr": "", @@ -2049,6 +2055,17 @@ } }, "type": "Typ", + "unapproved-suggestions": { + "confirmation-dialog": { + "checkbox-text": "", + "confirmation-text": "", + "deny-text": "", + "displayed-question": "", + "not-displayed-question": "", + "success-confirmation-text": "", + "title": "" + } + }, "unknown": "Unbekannt", "upload-dictionary-dialog": { "options": { diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index aa15ab0da..230841bcb 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -753,13 +753,13 @@ "dossier-details": { "assign-members": "Assign Members", "collapse": "Hide Details", + "document-status": "Document Status", "edit-owner": "Edit Owner", "expand": "Show Details", "members": "Members", "owner": "Owner", "see-less": "See less", - "title": "Dossier Details", - "document-status": "Document Status" + "title": "Dossier Details" }, "dossier-listing": { "add-new": "New Dossier", @@ -1800,10 +1800,15 @@ }, "form": { "auto-expand-filters-on-action": "Auto expand filters on my actions", - "show-suggestions-in-preview": "Show suggestions in preview" + "show-suggestions-in-preview": "Display suggestions in document preview", + "unapproved-suggestions-warning": "Warning regarding unapproved suggestions in document Preview mode" }, "label": "Preferences", - "title": "Edit preferences" + "title": "Edit preferences", + "warnings-description": "Selecting the \"Do not show this message again\" checkbox will skip the warning dialog the next time you trigger it.", + "warnings-label": "Prompts and Dialogs", + "warnings-subtitle": "Do not show again options", + "warnings-title": "Prompts and Dialogs Settings" }, "processing-status": { "ocr": "OCR", @@ -2050,6 +2055,17 @@ } }, "type": "Type", + "unapproved-suggestions": { + "confirmation-dialog": { + "checkbox-text": "Do not show this message again", + "confirmation-text": "Continue to Preview", + "deny-text": "Cancel", + "displayed-question": "The document contains unapproved suggestions, which are marked with their respective color.", + "not-displayed-question": "The document contains unapproved suggestions that are not included in the preview.", + "success-confirmation-text": "Prompts about unapproved suggestions were disabled. Change this preference in account settings.", + "title": "Document with unapproved suggestions" + } + }, "unknown": "Unknown", "upload-dictionary-dialog": { "options": { diff --git a/libs/common-ui b/libs/common-ui index 45627ed33..e94e4a02f 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 45627ed3338011c64d1b328e12bdcac107a19280 +Subproject commit e94e4a02f62bd0b2d55fedc81bbff3b9808c5584