RED-5406 - Warning message for preview mode in case of unapproved suggestions

This commit is contained in:
Valentin Mihai 2022-11-15 17:15:54 +02:00
parent 24e47410ee
commit dd9fa76bc5
13 changed files with 210 additions and 35 deletions

View File

@ -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: [
{

View File

@ -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) {}

View File

@ -1,16 +1,29 @@
<form (submit)="save()" [formGroup]="form">
<div class="dialog-content">
<div class="content-delimiter" *ngIf="currentScreen === screens.WARNING_PREFERENCES"></div>
<div class="dialog-content-left">
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="autoExpandFiltersOnActions">
{{ 'preferences-screen.form.auto-expand-filters-on-action' | translate }}
</mat-slide-toggle>
</div>
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="showSuggestionsInPreview">
{{ 'preferences-screen.form.show-suggestions-in-preview' | translate }}
</mat-slide-toggle>
</div>
<ng-container *ngIf="currentScreen === screens.PREFERENCES">
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="autoExpandFiltersOnActions">
{{ 'preferences-screen.form.auto-expand-filters-on-action' | translate }}
</mat-slide-toggle>
</div>
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="displaySuggestionsInPreview">
{{ 'preferences-screen.form.show-suggestions-in-preview' | translate }}
</mat-slide-toggle>
</div>
</ng-container>
<ng-container *ngIf="currentScreen === screens.WARNING_PREFERENCES">
<p class="warnings-subtitle">{{ 'preferences-screen.warnings-subtitle' | translate }}</p>
<p class="warnings-description">{{ 'preferences-screen.warnings-description' | translate }}</p>
<div class="iqser-input-group">
<mat-checkbox color="primary" formControlName="unapprovedSuggestionsWarning">
{{ 'preferences-screen.form.unapproved-suggestions-warning' | translate }}
</mat-checkbox>
</div>
</ng-container>
</div>
</div>

View File

@ -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%;
}

View File

@ -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<T> = { [K in keyof T]: FormControl<T[K]> };
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<T> = { [K in keyof T]: FormControl<T[K]> };
})
export class PreferencesComponent extends BaseFormComponent {
readonly form: FormGroup<AsControl<PreferencesForm>>;
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<any> {
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();
}
}

View File

@ -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);
}
}

View File

@ -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<boolean>;
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();
}
}

View File

@ -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<void> {
if (!this.userPreferenceService.getDisplaySuggestionsInPreview()) {
const currentPageSuggestions = redactions.filter(a => bool(a.getCustomData('suggestion')));
this._annotationManager.hide(currentPageSuggestions);
}
}
}

View File

@ -4,4 +4,5 @@ export const accountTranslations: Record<string, string> = {
notifications: _('notifications-screen.title'),
'user-profile': _('user-profile-screen.title'),
preferences: _('preferences-screen.title'),
'warnings-preferences': _('preferences-screen.warnings-title'),
};

View File

@ -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<void> {
const nexValue = (!this.getShowSuggestionsInPreview()).toString();
await this._save(KEYS.showSuggestionsInPreview, nexValue);
async toggleDisplaySuggestionsInPreview(): Promise<void> {
const nextValue = (!this.getDisplaySuggestionsInPreview()).toString();
await this._save(KEYS.displaySuggestionsInPreview, nextValue);
}
getUnapprovedSuggestionsWarning(): boolean {
return this._getAttribute(KEYS.unapprovedSuggestionsWarning, 'false') === 'true';
}
async toggleUnapprovedSuggestionsWarning(): Promise<void> {
const nextValue = (!this.getUnapprovedSuggestionsWarning()).toString();
await this._save(KEYS.unapprovedSuggestionsWarning, nextValue);
}
getFilesListingMode(): ListingMode {

View File

@ -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": {

View File

@ -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 <a href={settingsUrl} target=_self >account settings</a>.",
"title": "Document with unapproved suggestions"
}
},
"unknown": "Unknown",
"upload-dictionary-dialog": {
"options": {

@ -1 +1 @@
Subproject commit 45627ed3338011c64d1b328e12bdcac107a19280
Subproject commit e94e4a02f62bd0b2d55fedc81bbff3b9808c5584