diff --git a/apps/red-ui/src/app/app.component.ts b/apps/red-ui/src/app/app.component.ts index 10eefc848..2c7c8b6f4 100644 --- a/apps/red-ui/src/app/app.component.ts +++ b/apps/red-ui/src/app/app.component.ts @@ -1,8 +1,10 @@ -import { Component, ViewContainerRef } from '@angular/core'; +import { Component, Inject, Renderer2, ViewContainerRef } from '@angular/core'; import { RouterHistoryService } from '@services/router-history.service'; import { UserService } from '@services/user.service'; import { REDDocumentViewer } from './modules/pdf-viewer/services/document-viewer.service'; import { DossiersChangesService } from '@services/dossiers/dossier-changes.service'; +import { DOCUMENT } from '@angular/common'; +import { UserPreferenceService } from '@services/user-preference.service'; @Component({ selector: 'redaction-root', @@ -16,9 +18,13 @@ export class AppComponent { readonly viewContainerRef: ViewContainerRef, private readonly _routerHistoryService: RouterHistoryService, private readonly _userService: UserService, + private readonly _userPreferenceService: UserPreferenceService, readonly documentViewer: REDDocumentViewer, private readonly _dossierChangesService: DossiersChangesService, + @Inject(DOCUMENT) private document: Document, + private renderer: Renderer2, ) { + this.renderer.addClass(this.document.body, _userPreferenceService.getTheme()); // TODO: Find a better place to initialize dossiers refresh if (_userService.currentUser?.isUser) { _dossierChangesService.initializeRefresh(); 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 006247efa..187f411d6 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 @@ -22,7 +22,7 @@ [placeholder]="'search.placeholder' | translate" iqserHelpMode="search_in_entire_application" > - + diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.scss b/apps/red-ui/src/app/components/notifications/notifications.component.scss index b0c2303ea..23a290b31 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.scss +++ b/apps/red-ui/src/app/components/notifications/notifications.component.scss @@ -41,7 +41,7 @@ white-space: normal; a { - color: var(--iqser-accent); + color: var(--iqser-text); font-weight: bold; } } @@ -55,7 +55,7 @@ } &:hover { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-tab-hover); .dot { background-color: var(--iqser-grey-5); diff --git a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss index d725c9d04..1f1e8b80c 100644 --- a/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss +++ b/apps/red-ui/src/app/components/spotlight-search/spotlight-search.component.scss @@ -7,13 +7,13 @@ font-size: 13px; border: none; outline: none; - color: var(--iqser-accent); - background-color: var(--iqser-white); + color: var(--iqser-text); + background-color: transparent; } .highlight { border-radius: 4px; - background-color: var(--iqser-grey-2); + background-color: var(--iqser-side-nav); } .wrapper { 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 25196da0e..198f90aaa 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -88,7 +88,7 @@ export class AnnotationWrapper implements IListable, Record { } get isSuperTypeBasedColor() { - return this.isSkipped || this.isSuggestion || this.isDeclinedSuggestion || this.isIgnoredHint; + return this.isSuggestion || this.isDeclinedSuggestion || this.isIgnoredHint; } get isSkipped() { @@ -359,8 +359,16 @@ export class AnnotationWrapper implements IListable, Record { content += 'Legal basis: ' + annotationWrapper.legalBasis + '\n\n'; } + if (annotationWrapper.hasBeenRemovedByManualOverride) { + content += 'Removed by manual override'; + } + if (entry.section) { - content += 'In section: "' + entry.section + '"'; + let prefix = 'In section: '; + if (content.length) { + prefix = ` ${prefix.toLowerCase()}`; + } + content += `${prefix} "${entry.section}"`; } annotationWrapper.shortContent = this._getShortContent(annotationWrapper, entry) || content; @@ -429,7 +437,7 @@ export class AnnotationWrapper implements IListable, Record { case LogEntryStatus.APPROVED: return SuperTypes.Redaction; case LogEntryStatus.DECLINED: - return SuperTypes.Skipped; + return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped; case LogEntryStatus.REQUESTED: return SuperTypes.SuggestionRemoveDictionary; } diff --git a/apps/red-ui/src/app/modules/account/base-account-screen/base-account-screen-component.scss b/apps/red-ui/src/app/modules/account/base-account-screen/base-account-screen-component.scss index b8778a2b1..d94a3f70d 100644 --- a/apps/red-ui/src/app/modules/account/base-account-screen/base-account-screen-component.scss +++ b/apps/red-ui/src/app/modules/account/base-account-screen/base-account-screen-component.scss @@ -1,7 +1,7 @@ @use 'common-mixins'; .content-container { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); justify-content: center; @include common-mixins.scroll-bar; overflow: auto; diff --git a/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.scss b/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.scss index 5bfd95db4..9f7f3fbe9 100644 --- a/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.scss +++ b/apps/red-ui/src/app/modules/account/screens/notifications/notifications-screen/notifications-screen.component.scss @@ -16,7 +16,7 @@ .statement { opacity: 0.7; - color: var(--iqser-grey-1); + color: var(--iqser-text); font-weight: 500; padding: 10px 0; } @@ -40,7 +40,7 @@ padding: 10px 0; .group-title { - color: var(--iqser-grey-1); + color: var(--iqser-text); font-weight: 600; } diff --git a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.html b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.html index e984688de..250f76949 100644 --- a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.html +++ b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.html @@ -15,7 +15,8 @@ -
+ +
@@ -23,14 +24,26 @@
+ + +
+ + {{ 'user-profile-screen.form.dark-theme' | translate }} + +
-
diff --git a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.scss b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.scss index e1573c569..0c1bd8a5f 100644 --- a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.scss +++ b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.scss @@ -1,3 +1,3 @@ a { - color: black; + color: var(--iqser-text); } diff --git a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts index 6d904d8e0..af9648942 100644 --- a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts @@ -10,6 +10,7 @@ import { UserService } from '@services/user.service'; import { ConfigService } from '@services/config.service'; import { LanguageService } from '../../../../../i18n/language.service'; import { firstValueFrom } from 'rxjs'; +import { UserPreferenceService } from '@services/user-preference.service'; @Component({ selector: 'redaction-user-profile-screen', @@ -18,38 +19,44 @@ import { firstValueFrom } from 'rxjs'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class UserProfileScreenComponent extends BaseFormComponent implements OnInit { - changePasswordUrl: SafeResourceUrl; - translations = languagesTranslations; + readonly translations = languagesTranslations; + readonly devMode = this._userPreferenceService.areDevFeaturesEnabled; + readonly changePasswordUrl: SafeResourceUrl; - private _profileModel: IProfile; + #profileModel: IProfile; constructor( - readonly permissionsService: PermissionsService, - private readonly _formBuilder: UntypedFormBuilder, + domSanitizer: DomSanitizer, + configService: ConfigService, private readonly _userService: UserService, - private readonly _configService: ConfigService, - private readonly _languageService: LanguageService, - private readonly _domSanitizer: DomSanitizer, + readonly permissionsService: PermissionsService, + readonly userPreferences: UserPreferenceService, private readonly _loadingService: LoadingService, + private readonly _formBuilder: UntypedFormBuilder, + private readonly _languageService: LanguageService, protected readonly _translateService: TranslateService, + protected readonly _userPreferenceService: UserPreferenceService, ) { super(); this._loadingService.start(); - this.changePasswordUrl = this._domSanitizer.bypassSecurityTrustResourceUrl( - `${this._configService.values.OAUTH_URL}/account/password`, - ); + this.changePasswordUrl = domSanitizer.bypassSecurityTrustResourceUrl(`${configService.values.OAUTH_URL}/account/password`); } get languageChanged(): boolean { - return this._profileModel['language'] !== this.form.get('language').value; + return this.#profileModel['language'] !== this.form.get('language').value; + } + + get themeChanged(): boolean { + return this.#profileModel['darkTheme'] !== this.form.get('darkTheme').value; } get profileChanged(): boolean { const keys = Object.keys(this.form.getRawValue()); keys.splice(keys.indexOf('language'), 1); + keys.splice(keys.indexOf('darkTheme'), 1); for (const key of keys) { - if (this._profileModel[key] !== this.form.get(key).value) { + if (this.#profileModel[key] !== this.form.get(key).value) { return true; } } @@ -86,6 +93,10 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI await firstValueFrom(this._userService.loadAll()); } + if (this.themeChanged) { + await this._userPreferenceService.saveTheme(this.form.get('darkTheme').value ? 'dark' : 'light'); + } + this._initializeForm(); } @@ -95,23 +106,25 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI firstName: [undefined], lastName: [undefined], language: [undefined], + darkTheme: [false], }); } private _initializeForm(): void { try { this.form = this._getForm(); - this._profileModel = { + this.#profileModel = { email: this._userService.currentUser.email, firstName: this._userService.currentUser.firstName, lastName: this._userService.currentUser.lastName, language: this._languageService.currentLanguage, + darkTheme: this._userPreferenceService.getTheme() === 'dark', }; if (this._userService.currentUser.email) { // disable email if it's already set this.form.get('email').disable(); } - this.form.patchValue(this._profileModel, { emitEvent: false }); + this.form.patchValue(this.#profileModel, { emitEvent: false }); this.initialFormValue = this.form.getRawValue(); } catch (e) { } finally { diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss index 2e6df1245..79ddc9f17 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss @@ -54,7 +54,7 @@ .csv-part-header { min-height: 50px; box-sizing: border-box; - background: var(--iqser-white); + background: var(--iqser-background); border-top: 1px solid var(--iqser-separator); border-bottom: 1px solid var(--iqser-separator); display: flex; @@ -82,7 +82,7 @@ } .search-input-container { - background-color: var(--iqser-white); + background-color: var(--iqser-background); border-bottom: 1px solid var(--iqser-separator); padding: 8px 16px; } @@ -100,7 +100,7 @@ align-items: center; justify-content: center; text-align: center; - color: var(--iqser-grey-7); + color: var(--iqser-btn-bg); line-height: 15px; font-weight: 500; } @@ -116,14 +116,14 @@ > .left { width: 375px; min-width: 375px; - background: var(--iqser-grey-2); + background: var(--iqser-alt-background); display: flex; flex-direction: column; .csv-header-pill-content { overflow: auto; padding: 7px 0; - background: var(--iqser-grey-2); + background: var(--iqser-alt-background); @include common-mixins.no-scroll-bar; .csv-header-pill-wrapper { @@ -133,7 +133,7 @@ min-height: 32px; border-radius: 8px; padding: 10px; - background: var(--iqser-white); + background: var(--iqser-background); cursor: pointer; display: flex; flex-direction: column; @@ -169,7 +169,7 @@ min-width: 150px; display: flex; flex-direction: column; - background: var(--iqser-grey-2); + background: var(--iqser-alt-background); border-right: 1px solid var(--iqser-separator); &:not(.collapsed) iqser-circle-button { diff --git a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html index 50380cbea..25e652fcc 100644 --- a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html @@ -102,8 +102,8 @@ {{ log.message }} -
- {{ log.recordDate | date: 'd MMM yyyy, hh:mm a' }} +
+ {{ log.recordDate | date: 'd MMM yyyy, hh:mm a' }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html index 166bf5f5e..1340ee764 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html @@ -77,12 +77,12 @@ {{ attribute.label }}
-
- {{ attribute.placeholder }} +
+ {{ attribute.placeholder }}
-
- {{ translations[attribute.type] | translate }} +
+ {{ translations[attribute.type] | translate }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.html index 8fc488463..7b1e32582 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.html @@ -70,12 +70,12 @@
-
- {{ state.rank }} +
+ {{ state.rank }}
-
- {{ state.dossierCount }} +
+ {{ state.dossierCount }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.scss index 1c40bf617..8e05e5883 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.scss @@ -9,7 +9,7 @@ font-size: 16px; font-weight: 600; line-height: 20px; - color: var(--iqser-grey-1); + color: var(--iqser-text); } .right-container { diff --git a/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.html index e72abf4cf..985cde3c9 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/entities-listing/entities-listing-screen.component.html @@ -78,8 +78,8 @@
-
- {{ dict.rank }} +
+ {{ dict.rank }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/info/info.component.scss b/apps/red-ui/src/app/modules/admin/screens/entities/screens/info/info.component.scss index 6e7689711..5226a6f9e 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/info/info.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/info/info.component.scss @@ -18,7 +18,7 @@ padding: 30px; overflow: auto; @include common-mixins.scroll-bar; - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); justify-content: center; .dialog { diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html index 355f56117..c592ddb1a 100644 --- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html @@ -96,7 +96,9 @@ {{ attribute.label }}
-
+
+ +
-
- {{ attribute.csvColumnHeader }} +
+ {{ attribute.csvColumnHeader }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.scss index fc571e7bc..3a1c27dab 100644 --- a/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/general-config/general-config-screen.component.scss @@ -1,7 +1,7 @@ @use 'common-mixins'; .content-container { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); display: flex; flex-direction: column; align-items: center; diff --git a/apps/red-ui/src/app/modules/admin/screens/license/combo-chart/combo-chart.component.scss b/apps/red-ui/src/app/modules/admin/screens/license/combo-chart/combo-chart.component.scss index 7ee754487..c2ef9aba1 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/combo-chart/combo-chart.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/license/combo-chart/combo-chart.component.scss @@ -66,7 +66,7 @@ } .tooltip-anchor { - fill: rgb(0, 0, 0); + fill: var(--iqser-text); } .gridline-path { @@ -86,4 +86,18 @@ } } } + + fill: var(--iqser-text); +} + +.chart-legend .legend-labels { + background: var(--iqser-alt-background) !important; + + .legend-label .legend-label-text { + color: var(--iqser-text) !important; + + &:hover { + color: rgba(var(--iqser-text-rgb), 0.8) !important; + } + } } diff --git a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.scss index 5302874b3..9912f1c10 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.scss @@ -27,7 +27,7 @@ &:hover { > div { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); } } } diff --git a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.scss index f73496ca2..ee5df8933 100644 --- a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.scss @@ -24,7 +24,7 @@ .template { padding: 8px 10px; - background-color: var(--iqser-grey-6); + background-color: var(--iqser-btn-bg); border-radius: 4px; transition: background-color 0.2s; position: relative; @@ -51,7 +51,7 @@ } &:hover { - background-color: var(--iqser-grey-4); + background-color: var(--iqser-btn-bg-hover); .actions { display: flex; diff --git a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts index 24ffb9c9b..5e810dc17 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/rules/rules-screen/rules-screen.component.ts @@ -7,6 +7,7 @@ import { RulesService } from '../../../services/rules.service'; import { firstValueFrom } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; import { DOSSIER_TEMPLATE_ID } from '@red/domain'; +import { EditorThemeService } from '@services/editor-theme.service'; import ICodeEditor = monaco.editor.ICodeEditor; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions; @@ -44,6 +45,7 @@ export class RulesScreenComponent implements OnInit { private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _toaster: Toaster, private readonly _loadingService: LoadingService, + private readonly _editorThemeService: EditorThemeService, route: ActivatedRoute, ) { this.#dossierTemplateId = route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID); @@ -73,15 +75,10 @@ export class RulesScreenComponent implements OnInit { onCodeEditorInit(editor: ICodeEditor) { this._codeEditor = editor; - (window as any).monaco.editor.defineTheme('redaction', { - base: 'vs', - inherit: true, - rules: [], - colors: { - 'editor.lineHighlightBackground': '#f4f5f7', - }, - }); - (window as any).monaco.editor.setTheme('redaction'); + for (const theme of this._editorThemeService.themes) { + (window as any).monaco.editor.defineTheme(theme, this._editorThemeService.configurations[theme]); + } + (window as any).monaco.editor.setTheme(this._editorThemeService.getTheme(true)); this._changeDetectorRef.detectChanges(); } diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html index 2ad031f25..fa2b709a3 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html @@ -74,7 +74,9 @@
-
{{ user.email || '-' }}
+
+ {{ user.email || '-' }} +
-
{{ getDisplayRoles(user) }}
+
+ {{ getDisplayRoles(user) }} +
diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.scss index bbdca01c2..18550f5ed 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.scss @@ -39,7 +39,7 @@ width: 60px; height: 60px; border-radius: 8px; - background-color: var(--iqser-grey-6); + background-color: var(--iqser-btn-bg); color: var(--iqser-grey-7); align-items: center; justify-content: center; @@ -53,7 +53,7 @@ } &:not(.disabled):not(.active):hover { - background-color: darken(variables.$grey-6, 2); + background-color: var(--iqser-btn-bg-hover); } &:not(:last-child) { diff --git a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts index ca4aa8714..164ca9f7b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/watermark/watermark-screen/watermark-screen.component.ts @@ -11,8 +11,9 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { WatermarkService } from '@services/entity-services/watermark.service'; import { firstValueFrom, Observable, of } from 'rxjs'; import { catchError, tap } from 'rxjs/operators'; +import { LicenseService } from '@services/license.service'; +import { UserPreferenceService } from '@services/user-preference.service'; import { ActivatedRoute, Router } from '@angular/router'; -import { LicenseService } from '../../../../../services/license.service'; export const DEFAULT_WATERMARK: IWatermark = { id: null, @@ -56,6 +57,7 @@ export class WatermarkScreenComponent implements OnInit { @Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn, private readonly _watermarkService: WatermarkService, private readonly _changeDetectorRef: ChangeDetectorRef, + private readonly _userPreferenceService: UserPreferenceService, private readonly _router: Router, ) { this._loadingService.start(); @@ -154,6 +156,8 @@ export class WatermarkScreenComponent implements OnInit { ).then(instance => { this._instance = instance; + instance.UI.setTheme(this._userPreferenceService.getTheme()); + instance.Core.documentViewer.on('documentLoaded', async () => { this._loadingService.stop(); await this._drawWatermark(); diff --git a/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.html b/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.html index 4803ea9b6..29236f29d 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.html +++ b/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.html @@ -1,4 +1,4 @@ -
+
@@ -12,45 +12,24 @@
-
- +
+
- -
-
- -
- - -
- +
diff --git a/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.ts index 88e8bdd58..8f1e3277c 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/add-edit-entity/add-edit-entity.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { Dictionary, IDictionary } from '@red/domain'; -import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormGroup, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { map, startWith } from 'rxjs/operators'; import { firstValueFrom, Observable } from 'rxjs'; import { toSnakeCase } from '@utils/functions'; @@ -10,7 +10,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui'; -const REDACTION_FIELDS = ['defaultReason', 'addToDictionaryAction']; +const REDACTION_FIELDS = ['defaultReason']; @Component({ selector: 'redaction-add-edit-entity [entity] [dossierTemplateId]', @@ -22,10 +22,10 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit @Input() dossierTemplateId: string; @Input() entity: Dictionary; - hasHexColor$: Observable; - hasRecommendationHexColor$: Observable; technicalName$: Observable; + colors: { label: string; placeholder: string; controlName: string; hasColor$: Observable }[]; + constructor( private readonly _dictionariesMapService: DictionariesMapService, private readonly _permissionsService: PermissionsService, @@ -77,6 +77,29 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit } } + #initializeColors(form: FormGroup): void { + this.colors = [ + { + label: _('add-edit-entity.form.color'), + placeholder: _('add-edit-entity.form.color-placeholder'), + controlName: 'hexColor', + hasColor$: this._colorEmpty$(form, 'hexColor'), + }, + { + label: _('add-edit-entity.form.recommendation-color'), + placeholder: _('add-edit-entity.form.recommendation-color-placeholder'), + controlName: 'recommendationHexColor', + hasColor$: this._colorEmpty$(form, 'recommendationHexColor'), + }, + { + label: _('add-edit-entity.form.skipped-color'), + placeholder: _('add-edit-entity.form.skipped-color-placeholder'), + controlName: 'skippedHexColor', + hasColor$: this._colorEmpty$(form, 'skippedHexColor'), + }, + ]; + } + private _initializeForm(): void { const controlsConfig = { type: [this.entity?.type], @@ -85,6 +108,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit rank: [{ value: this.entity?.rank, disabled: this.#isSystemManaged }, Validators.required], hexColor: [this.entity?.hexColor, [Validators.required, Validators.minLength(7)]], recommendationHexColor: [this.entity?.recommendationHexColor, [Validators.required, Validators.minLength(7)]], + skippedHexColor: [this.entity?.skippedHexColor, [Validators.required, Validators.minLength(7)]], hint: [{ value: !!this.entity?.hint, disabled: this.#isSystemManaged }], hasDictionary: [{ value: !!this.entity?.hasDictionary, disabled: this.#isSystemManaged }], caseSensitive: [{ value: this.entity ? !this.entity.caseInsensitive : false, disabled: this.#isSystemManaged }], @@ -94,17 +118,17 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit Object.assign(controlsConfig, { defaultReason: [{ value: null, disabled: true }], }); - - if (this.entity?.hasDictionary) { - Object.assign(controlsConfig, { - addToDictionaryAction: [this.#addToDictionaryActionControl], - }); - } } + + if (this.entity?.hasDictionary) { + Object.assign(controlsConfig, { + addToDictionaryAction: [this.#addToDictionaryActionControl], + }); + } + const form = this._formBuilder.group(controlsConfig); - this.hasHexColor$ = this._colorEmpty$(form, 'hexColor'); - this.hasRecommendationHexColor$ = this._colorEmpty$(form, 'recommendationHexColor'); + this.#initializeColors(form); this.technicalName$ = form.get('label').valueChanges.pipe(map((value: string) => this._toTechnicalName(value))); form.get('hint').valueChanges.subscribe(isHint => { @@ -112,15 +136,11 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit REDACTION_FIELDS.forEach(field => form.removeControl(field)); } else { form.addControl('defaultReason', new UntypedFormControl({ value: null, disabled: true })); - - if (form.get('hasDictionary').value) { - form.addControl('addToDictionaryAction', new UntypedFormControl(this.#addToDictionaryActionControl)); - } } }); form.get('hasDictionary').valueChanges.subscribe(hasDictionary => { - if (hasDictionary && !form.get('hint').value) { + if (hasDictionary) { form.addControl('addToDictionaryAction', new UntypedFormControl(this.#addToDictionaryActionControl)); } else { form.removeControl('addToDictionaryAction'); @@ -171,6 +191,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit description: this.form.get('description').value, hexColor: this.form.get('hexColor').value, recommendationHexColor: this.form.get('recommendationHexColor').value, + skippedHexColor: this.form.get('skippedHexColor').value, hint: this.form.get('hint').value, rank: this.form.get('rank').value, dossierTemplateId: this.dossierTemplateId, diff --git a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.html index d94dbc95f..ee66ff76b 100644 --- a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.html +++ b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.html @@ -2,7 +2,9 @@
-
{{ dossier.archivedTime | date: 'd MMM yyyy' }}
+
+ {{ dossier.archivedTime | date: 'd MMM yyyy' }} +
diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 4160bf43b..e544be4f2 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -17,7 +17,7 @@ &:not(.empty) { &:hover { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-side-nav); .heading { text-decoration: underline; diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss index f646df137..b782d561c 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss @@ -1,6 +1,6 @@ :host { align-items: center; - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); .container { padding: 32px; diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss index aa6d3e1a6..42741d8ec 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss @@ -21,7 +21,7 @@ transition: background-color 0.2s; &:hover { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-btn-bg); } } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.scss b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.scss index 73039cfb8..e415ad1bc 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.scss +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.scss @@ -29,7 +29,7 @@ padding: 3px 8px; &:hover { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-tab-hover); } &.active { diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss index b5a1b4580..522416718 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss @@ -31,5 +31,5 @@ } .right-chart { - border-left: 1px solid rgba(226, 228, 233, 0.9); + border-left: 1px solid var(--iqser-separator); } diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss index a3b6a8184..1110e38ca 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-details/annotation-details.component.scss @@ -28,7 +28,7 @@ height: 24px; &:hover { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-tab-hover); border-radius: 12px; mat-icon { diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.scss b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.scss index a6653f9b5..6817bb6ea 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.scss @@ -52,7 +52,7 @@ } &:hover { - background-color: var(--iqser-grey-4); + background-color: var(--iqser-annotation-comments-hover); } } } @@ -60,7 +60,7 @@ &:hover, &.help-mode { - background-color: var(--iqser-grey-8); + background-color: var(--iqser-annotation-hover); ::ng-deep .annotation-actions { display: flex; diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.scss b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.scss index c7ddef779..855230586 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.scss @@ -78,7 +78,7 @@ outline: none; &.active-panel { - background-color: #fafafa; + background-color: var(--iqser-workload-pages-bg); } } @@ -98,7 +98,7 @@ transition: background-color 0.25s; &:not(.disabled):hover { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-tab-hover); } mat-icon { diff --git a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.scss b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.scss index 818da8a29..e248fd1fa 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.scss @@ -1,12 +1,12 @@ .page-wrapper { - color: var(--iqser-accent); + color: var(--iqser-text); position: relative; padding: 12px 14px 12px 8px; cursor: pointer; border-left: 4px solid transparent; &:hover { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); } &.active { @@ -33,10 +33,10 @@ } &.read { - color: var(--iqser-grey-5); + color: var(--iqser-inputs-outline); .text { - color: var(--iqser-accent); + color: var(--iqser-text); } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/type-annotation-icon/type-annotation-icon.component.ts b/apps/red-ui/src/app/modules/file-preview/components/type-annotation-icon/type-annotation-icon.component.ts index 0bc6e7af0..e81375668 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/type-annotation-icon/type-annotation-icon.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/type-annotation-icon/type-annotation-icon.component.ts @@ -32,7 +32,12 @@ export class TypeAnnotationIconComponent implements OnChanges { this.color = this.annotation.color; } else { const type = this.annotation.isSuperTypeBasedColor ? this.annotation.superType : this.annotation.type; - this.color = this._dictionariesMapService.getDictionaryColor(type, this._dossierTemplateId, this.annotation.isRecommendation); + this.color = this._dictionariesMapService.getDictionaryColor( + type, + this._dossierTemplateId, + this.annotation.isRecommendation, + this.annotation.isSkipped, + ); } this.type = diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss index f149bcbab..e658d2b05 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.scss @@ -1,7 +1,7 @@ .vertical-line { width: 1px; height: 30px; - background-color: var(--iqser-grey-4); + background-color: var(--iqser-separator); margin: 0 16px; } 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 cf8b02fd6..61d85c707 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 @@ -6,7 +6,6 @@ import { bool, CircleButtonTypes, CustomError, - Debounce, ErrorService, FilterService, List, @@ -92,7 +91,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private readonly _router: Router, private readonly _ngZone: NgZone, private readonly _logger: NGXLogger, - private readonly _filesService: FilesService, private readonly _annotationManager: REDAnnotationManager, private readonly _errorService: ErrorService, private readonly _filterService: FilterService, @@ -307,14 +305,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } } - viewerPageChanged(page: number) { - // this.multiSelectService.deactivate(); - return this.#updateQueryParamsPage(page); - } - - @Debounce(100) async viewerReady() { - // Go to initial page from query params const pageNumber: string = this._activatedRoute.snapshot.queryParams.page; if (pageNumber) { const file = this.state.file; @@ -327,7 +318,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni page = file.numberOfPages; } - this.pdf.navigateTo(page); + setTimeout(() => { + this.pdf.navigateTo(page); + }, 300); } this._loadingService.stop(); @@ -347,7 +340,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) { const fileManagementService = this._injector.get(FileManagementService); - const originalFile = fileManagementService.downloadOriginalFile(dossierId, fileId, 'response', cacheIdentifier); + const originalFile = fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier); download(await firstValueFrom(originalFile), filename); } @@ -368,21 +361,24 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni pairwise(), tap(annotations => this.deleteAnnotations(...annotations)), ); - const currentPageAnnotations$ = combineLatest([this.pdf.currentPage$, annotations$]).pipe( + + const currentPageIfNotHighlightsView$ = combineLatest([this.pdf.currentPage$, this._viewModeService.viewMode$]).pipe( + filter(([, viewMode]) => viewMode !== ViewModes.TEXT_HIGHLIGHTS), + map(([page]) => page), + ); + + const currentPageAnnotations$ = combineLatest([currentPageIfNotHighlightsView$, annotations$]).pipe( map( ([page, [oldAnnotations, newAnnotations]]) => [oldAnnotations.filter(byPage(page)), newAnnotations.filter(byPage(page))] as const, ), ); - let start; return combineLatest([currentPageAnnotations$, documentLoaded$]).pipe( filter(([, loaded]) => loaded), - tap(() => (start = new Date().getTime())), map(([annotations]) => annotations), switchMap(annotations => this.drawChangedAnnotations(...annotations)), tap(([, newAnnotations]) => this.#highlightSelectedAnnotations(newAnnotations)), - tap(() => this._logger.info(`[ANNOTATIONS] Processing time: ${new Date().getTime() - start}`)), tap(() => this.updateViewMode()), ); } @@ -430,7 +426,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni #rebuildFilters() { const startTime = new Date().getTime(); - const annotationFilters = this._annotationProcessingService.getAnnotationFilter(this._fileDataService.all); + const annotationFilters = this._annotationProcessingService.getAnnotationFilter(); const primaryFilters = this._filterService.getGroup('primaryFilters')?.filters; this._filterService.addFilterGroup({ slug: 'primaryFilters', @@ -451,6 +447,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } async #updateQueryParamsPage(page: number): Promise { + console.log('updateQueryParamsPage: ', page); const extras: NavigationExtras = { queryParams: { page }, queryParamsHandling: 'merge', @@ -549,7 +546,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni .pipe( switchMap(blob => from(this._documentViewer.lock()).pipe(map(() => blob))), tap(() => this._errorService.clear()), - tap(blob => this.pdf.loadDocument(blob, this.state.file)), + tap(blob => this.pdf.loadDocument(blob, this.state.file, () => this.state.reloadBlob())), ) .subscribe(); @@ -558,7 +555,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni }); this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page => - this._ngZone.run(() => this.viewerPageChanged(page)), + this._ngZone.run(() => { + console.log('viewerPageChanged', page); + return this.#updateQueryParamsPage(page); + }), ); this.addActiveScreenSubscription = this.pdfProxyService.annotationSelected$.subscribe(); } @@ -587,30 +587,28 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (!newAnnotations.length) { return; } + const currentFilters = this._filterService.getGroup('primaryFilters')?.filters || []; this.#rebuildFilters(); - const startTime = new Date().getTime(); - if (currentFilters) { - this._handleDeltaAnnotationFilters(currentFilters, this._fileDataService.all); + this._handleDeltaAnnotationFilters(currentFilters); } await this._annotationDrawService.draw(newAnnotations, this.state.dossierTemplateId, this._skippedService.hideSkipped); - this._logger.info(`[ANNOTATIONS] Redraw time: ${new Date().getTime() - startTime} ms for ${newAnnotations.length} annotations`); } - private _handleDeltaAnnotationFilters(currentFilters: NestedFilter[], newAnnotations: AnnotationWrapper[]) { + private _handleDeltaAnnotationFilters(currentFilters: NestedFilter[]) { const primaryFilterGroup = this._filterService.getGroup('primaryFilters'); const primaryFilters = primaryFilterGroup.filters; const secondaryFilters = this._filterService.getGroup('secondaryFilters').filters; - const hasAnyFilterSet = [...primaryFilters, ...secondaryFilters].find(f => f.checked || f.indeterminate); + const hasAnyFilterSet = [...primaryFilters, ...secondaryFilters].some(f => f.checked || f.indeterminate); if (!hasAnyFilterSet) { return; } - const newPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(newAnnotations); + const newPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(); handleFilterDelta(currentFilters, newPageSpecificFilters, primaryFilters); this._filterService.addFilterGroup({ @@ -626,7 +624,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } } - private _setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal: boolean = false) { + private _setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal = false) { annotations.forEach(annotation => { annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 1; }); diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts index 4bda12b80..4850ad44d 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { SuperTypeSorter } from '../../../utils'; import { Filter, handleCheckedValue, IFilter, INestedFilter, NestedFilter } from '@iqser/common-ui'; @@ -7,10 +7,13 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { IViewedPage } from '@red/domain'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { FilePreviewStateService } from './file-preview-state.service'; +import { FileDataService } from './file-data.service'; @Injectable() export class AnnotationProcessingService { - constructor(private readonly _state: FilePreviewStateService, private readonly _dictionariesMapService: DictionariesMapService) {} + readonly #fileDataService = inject(FileDataService); + readonly #state = inject(FilePreviewStateService); + readonly #dictionariesMapService = inject(DictionariesMapService); static secondaryAnnotationFilters(viewedPages?: IViewedPage[]): INestedFilter[] { const _viewedPages = viewedPages ? viewedPages.map(page => page.page) : []; @@ -50,11 +53,11 @@ export class AnnotationProcessingService { ].map(item => new NestedFilter(item)); } - getAnnotationFilter(annotations: AnnotationWrapper[]): INestedFilter[] { + getAnnotationFilter(): INestedFilter[] { const filterMap = new Map(); const filters: INestedFilter[] = []; - annotations?.forEach(a => { + this.#fileDataService.all?.forEach(a => { const topLevelFilter = a.topLevelFilter; const filter = filterMap.get(a.filterKey); if (filter) { @@ -76,8 +79,8 @@ export class AnnotationProcessingService { } const dictionary = a.type === 'dossier_redaction' - ? this._state.dossierDictionary - : this._dictionariesMapService.getDictionary(a.type, this._state.dossierTemplateId); + ? this.#state.dossierDictionary + : this.#dictionariesMapService.getDictionary(a.type, this.#state.dossierTemplateId); const childFilter: IFilter = { id: a.filterKey, label: dictionary.label, @@ -212,11 +215,13 @@ export class AnnotationProcessingService { if (first.pageNumber === second.pageNumber) { if (first.y > second.y) { return -1; - } else if (first.y < second.y) { - return 1; - } else { - return first.x < second.x ? -1 : 1; } + + if (first.y < second.y) { + return 1; + } + + return first.x < second.x ? -1 : 1; } return first.pageNumber < second.pageNumber ? -1 : 1; }); 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 2f0e883c9..4cc249c90 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 @@ -4,7 +4,7 @@ import { Dictionary, Dossier, DOSSIER_ID, File, FILE_ID } from '@red/domain'; import { ActivatedRoute, Router } from '@angular/router'; import { FilesMapService } from '@services/files/files-map.service'; import { PermissionsService } from '@services/permissions.service'; -import { boolFactory } from '@iqser/common-ui'; +import { boolFactory, LoadingService } from '@iqser/common-ui'; import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators'; import { FileManagementService } from '@services/files/file-management.service'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; @@ -12,6 +12,21 @@ import { wipeFilesCache } from '@red/cache'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { FilesService } from '@services/files/files.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; +import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angular/common/http'; +import { TranslateService } from '@ngx-translate/core'; + +const ONE_MEGABYTE = 1024 * 1024; + +function getRemainingTime(event: HttpProgressEvent, startTime: number) { + const currTime = new Date().getTime(); + const remaining = event.total - event.loaded; + const speed = event.loaded / ((currTime - startTime) / 1000); + return Math.round(remaining / speed); +} + +function isDownload(event: HttpEvent): event is HttpProgressEvent { + return event.type === HttpEventType.DownloadProgress && event.total > ONE_MEGABYTE; +} @Injectable() export class FilePreviewStateService { @@ -40,6 +55,8 @@ export class FilePreviewStateService { private readonly _dossiersService: DossiersService, private readonly _fileManagementService: FileManagementService, private readonly _dictionaryService: DictionaryService, + private readonly _translateService: TranslateService, + private readonly _loadingService: LoadingService, ) { const dossiersService = dossiersServiceResolver(_injector, router); @@ -89,6 +106,16 @@ export class FilePreviewStateService { this.#reloadBlob$.next(true); } + #getRemainingTimeVerbose(event: HttpProgressEvent, startTime: number) { + const remainingTime = getRemainingTime(event, startTime); + if (remainingTime > 60) { + const minutes: string = this._translateService.instant('minutes'); + return `${Math.round(remainingTime / 60)} ${minutes}`; + } + const seconds: string = this._translateService.instant('seconds'); + return `${remainingTime} ${seconds}`; + } + #dossierFilesChange$() { return this._dossiersService.dossierFileChanges$.pipe( filter(dossierId => dossierId === this.dossierId), @@ -97,8 +124,36 @@ export class FilePreviewStateService { } #downloadOriginalFile(cacheIdentifier: string, wipeCaches = true): Observable { - const downloadFile = this._fileManagementService.downloadOriginalFile(this.dossierId, this.fileId, 'body', cacheIdentifier); + const downloadFile$ = this.#getFileToDownload(cacheIdentifier); const obs = wipeCaches ? from(wipeFilesCache()) : of({}); - return obs.pipe(switchMap(() => downloadFile)); + return obs.pipe(switchMap(() => downloadFile$)); + } + + #getFileToDownload(cacheIdentifier: string): Observable { + const downloadFile$ = this._fileManagementService.downloadOriginal(this.dossierId, this.fileId, 'events', cacheIdentifier); + let start; + return downloadFile$.pipe( + tap(() => (start ? undefined : (start = new Date().getTime()))), + tap(event => this.#showLoadingIfIsDownloadEvent(event, start)), + filter(event => event.type === HttpEventType.Response), + map((event: HttpResponse) => event.body), + ); + } + + #showLoadingIfIsDownloadEvent(event: HttpEvent, start) { + if (isDownload(event)) { + this.#updateDownloadProgress(event, start); + } + } + + #updateDownloadProgress(event: HttpProgressEvent, startTime: number) { + const progress = Math.round((event.loaded / event.total) * 100); + const loading: string = this._translateService.instant('loading'); + this._loadingService.update({ + title: loading + ' ' + this.file.filename, + type: 'progress-bar', + value: progress, + remainingTime: this.#getRemainingTimeVerbose(event, startTime), + }); } } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/components/paginator/paginator.component.scss b/apps/red-ui/src/app/modules/pdf-viewer/components/paginator/paginator.component.scss index 21be9c450..7a34c7e8e 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/components/paginator/paginator.component.scss +++ b/apps/red-ui/src/app/modules/pdf-viewer/components/paginator/paginator.component.scss @@ -4,7 +4,7 @@ bottom: 20px; left: calc(50% - (var(--workload-width) / 2)); transform: translate(-50%); - background: var(--iqser-white); + background: var(--iqser-background); color: var(--iqser-grey-7); border: 1px solid var(--iqser-grey-7); border-radius: 8px; @@ -32,6 +32,7 @@ margin: 0; } + background-color: var(--iqser-background); color: var(--iqser-grey-7); text-decoration: none; outline: none; @@ -55,7 +56,7 @@ padding-right: 4px; &:hover { - color: var(--iqser-accent); + color: var(--iqser-text); } } } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts index a27bb65b0..ee998df83 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts @@ -75,7 +75,7 @@ export class AnnotationDrawService { color = this._dictionariesMapService.getDictionaryColor(dictionary, dossierTemplateId, true); break; case SuperTypes.Skipped: - color = this._dictionariesMapService.getDictionaryColor(superType, dossierTemplateId); + color = this._dictionariesMapService.getDictionaryColor(dictionary, dossierTemplateId, false, true); break; default: color = this._dictionariesMapService.getDictionaryColor(superType, dossierTemplateId); @@ -85,9 +85,14 @@ export class AnnotationDrawService { } private async _draw(annotationWrappers: List, dossierTemplateId: string, hideSkipped: boolean) { + const totalPages = await firstValueFrom(this._pdf.totalPages$); const annotations = annotationWrappers - .map(annotation => this._computeAnnotation(annotation, dossierTemplateId, hideSkipped)) - .filter(a => !!a); + .map(annotation => this._computeAnnotation(annotation, dossierTemplateId, hideSkipped, totalPages)) + .filterTruthy(); + const documentLoaded = await firstValueFrom(this._documentViewer.loaded$); + if (!documentLoaded) { + return; + } await this._annotationManager.add(annotations); if (this._userPreferenceService.areDevFeaturesEnabled) { @@ -130,9 +135,9 @@ export class AnnotationDrawService { return rectangleAnnot; } - private _computeAnnotation(annotationWrapper: AnnotationWrapper, dossierTemplateId: string, hideSkipped: boolean) { + private _computeAnnotation(annotationWrapper: AnnotationWrapper, dossierTemplateId: string, hideSkipped: boolean, totalPages: number) { const pageNumber = this._pdf.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber; - if (pageNumber > this._pdf.pageCount) { + if (pageNumber > totalPages) { // skip imported annotations from files that have more pages than the current one return; } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts index 75b09d978..22042bfe0 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { Core } from '@pdftron/webviewer'; import { NGXLogger } from 'ngx-logger'; import { fromEvent, merge, Observable } from 'rxjs'; @@ -22,12 +22,10 @@ export class REDDocumentViewer { selectedText = ''; #document: DocumentViewer; - constructor( - private readonly _logger: NGXLogger, - private readonly _userPreferenceService: UserPreferenceService, - private readonly _pdf: PdfViewer, - private readonly _activatedRoute: ActivatedRoute, - ) {} + readonly #logger = inject(NGXLogger); + readonly #userPreferenceService = inject(UserPreferenceService); + readonly #pdf = inject(PdfViewer); + readonly #activatedRoute = inject(ActivatedRoute); get PDFDoc() { return this.document?.getPDFDoc(); @@ -41,7 +39,7 @@ export class REDDocumentViewer { const event$ = fromEvent(this.#document, 'documentUnloaded'); const toBool$ = event$.pipe(map(() => false)); - return toBool$.pipe(tap(() => this._logger.info('[PDF] Document unloaded'))); + return toBool$.pipe(tap(() => this.#logger.info('[PDF] Document unloaded'))); } get #documentLoaded$() { @@ -52,7 +50,7 @@ export class REDDocumentViewer { tap(() => this.#setCurrentPage()), tap(() => this.#setInitialDisplayMode()), tap(() => this.updateTooltipsVisibility()), - tap(() => this._logger.info('[PDF] Document loaded')), + tap(() => this.#logger.info('[PDF] Document loaded')), ); } @@ -73,13 +71,7 @@ export class REDDocumentViewer { get #textSelected$(): Observable { return fromEvent<[Quad, string, number]>(this.#document, 'textSelected').pipe( tap(([, selectedText]) => (this.selectedText = selectedText)), - tap(([, , pageNumber]) => { - if (this._pdf.isCompare && pageNumber % 2 === 0) { - this._pdf.disable('textPopup'); - } else { - this._pdf.enable('textPopup'); - } - }), + tap(([, , pageNumber]) => this.#disableTextPopupIfCompareMode(pageNumber)), map(([, selectedText]) => selectedText), ); } @@ -89,14 +81,14 @@ export class REDDocumentViewer { } close() { - this._logger.info('[PDF] Closing document'); + this.#logger.info('[PDF] Closing document'); this.#document.closeDocument(); - this._pdf.closeCompareMode(); + this.#pdf.closeCompareMode(); } updateTooltipsVisibility(): void { - const current = this._userPreferenceService.getFilePreviewTooltipsPreference(); - this._pdf.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false)); + const current = this.#userPreferenceService.getFilePreviewTooltipsPreference(); + this.#pdf.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false)); } init(document: DocumentViewer) { @@ -114,7 +106,7 @@ export class REDDocumentViewer { } await document.lock(); - this._logger.info('[PDF] Locked'); + this.#logger.info('[PDF] Locked'); return true; } @@ -156,7 +148,7 @@ export class REDDocumentViewer { pages.forEach(page => this.#document.setRotation(0, Number(page))); } - rotate(rotation: RotationType, page = this._pdf.currentPage) { + rotate(rotation: RotationType, page = this.#pdf.currentPage) { if (rotation === RotationTypes.LEFT) { this.#document.rotateCounterClockwise(page); } else { @@ -164,16 +156,24 @@ export class REDDocumentViewer { } } + #disableTextPopupIfCompareMode(pageNumber) { + if (this.#pdf.isCompare && pageNumber % 2 === 0) { + return this.#pdf.disable('textPopup'); + } + + this.#pdf.enable('textPopup'); + } + #setCurrentPage() { - const currentDocPage = this._activatedRoute.snapshot.queryParamMap.get('page'); - this.#document.setCurrentPage(Number(currentDocPage ?? '1'), false); + const currentDocPage = this.#activatedRoute.snapshot.queryParamMap.get('page'); + this.#pdf.navigateTo(currentDocPage ?? 1); } #setInitialDisplayMode() { - this._pdf.instance.UI.setFitMode('FitPage'); + this.#pdf.instance.UI.setFitMode('FitPage'); const displayModeManager = this.#document.getDisplayModeManager(); const instanceDisplayMode = displayModeManager.getDisplayMode(); - instanceDisplayMode.mode = this._pdf.isCompare ? 'Facing' : 'Single'; + instanceDisplayMode.mode = this.#pdf.isCompare ? 'Facing' : 'Single'; displayModeManager.setDisplayMode(instanceDisplayMode); } } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts index 8f4e2d850..6adad4f0a 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts @@ -13,6 +13,7 @@ import { Rgb } from '../utils/types'; import { asList } from '../utils/functions'; import { TranslateService } from '@ngx-translate/core'; import { LicenseService } from '@services/license.service'; +import { UserPreferenceService } from '@services/user-preference.service'; import TextTool = Core.Tools.TextTool; import Annotation = Core.Annotations.Annotation; import TextHighlightAnnotation = Core.Annotations.TextHighlightAnnotation; @@ -53,6 +54,7 @@ export class PdfViewer { private readonly _activatedRoute: ActivatedRoute, private readonly _licenseService: LicenseService, private readonly _translateService: TranslateService, + private readonly _userPreferenceService: UserPreferenceService, @Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn, ) {} @@ -133,6 +135,7 @@ export class PdfViewer { this.#instance = await this.#getInstance(htmlElement); await this.PDFNet.initialize(this._licenseService.activeLicenseKey); + this.#instance.UI.setTheme(this._userPreferenceService.getTheme()); this._logger.info('[PDF] Initialized'); this.documentViewer = this.#instance.Core.documentViewer; @@ -166,11 +169,11 @@ export class PdfViewer { this.#compareMode$.next(false); } - async loadDocument(blob: Blob, file: File) { + async loadDocument(blob: Blob, file: File, actionOnError: () => void = () => {}) { const onError = () => { this._injector.get(ErrorService).set(DOCUMENT_LOADING_ERROR); this._logger.error('[PDF] Error while loading document'); - // this.stateService.reloadBlob(); + actionOnError(); }; const document = await this.PDFNet.PDFDoc.createFromBuffer(await blob.arrayBuffer()); diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.scss b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.scss index 593f3c7ae..091142726 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.scss +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.scss @@ -1,8 +1,8 @@ -@use 'libs/common-ui/src/assets/styles/common-mixins'; +@use 'common-mixins'; .file-actions { display: flex; - color: var(--iqser-grey-1); + color: var(--iqser-text); > *:not(:last-child) { margin-right: 2px; diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts index de8bee50e..de12143e1 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts @@ -10,7 +10,7 @@ import { ViewChild, } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { Action, ActionTypes, Dossier, File } from '@red/domain'; +import { Action, ActionTypes, Dossier, File, User } from '@red/domain'; import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { CircleButtonType, @@ -46,7 +46,7 @@ import { ROTATION_ACTION_BUTTONS } from '../../../pdf-viewer/utils/constants'; }) export class FileActionsComponent implements OnChanges { readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser; + readonly currentUser: User; @Input() file: File; @Input() dossier: Dossier; diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html index c446cf066..a2faa635d 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html @@ -24,19 +24,18 @@ > - -
- -
+
+ +
{{ 'assign-dossier-owner.dialog.no-reviewers' | translate }}
diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.scss b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.scss index 0d427a120..51ce0bbb6 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.scss +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.scss @@ -54,7 +54,7 @@ redaction-team-members { &.selected, &:hover { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); .actions { display: flex; diff --git a/apps/red-ui/src/app/modules/shared/components/donut-chart/donut-chart.component.scss b/apps/red-ui/src/app/modules/shared/components/donut-chart/donut-chart.component.scss index 773493760..1bfd8851a 100644 --- a/apps/red-ui/src/app/modules/shared/components/donut-chart/donut-chart.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/donut-chart/donut-chart.component.scss @@ -62,7 +62,7 @@ } &:hover:not(.active):not(.filter-disabled) { - background-color: var(--iqser-grey-6); + background-color: var(--iqser-btn-bg); } &.active { diff --git a/apps/red-ui/src/app/modules/shared/components/dossier-state/dossier-state.component.scss b/apps/red-ui/src/app/modules/shared/components/dossier-state/dossier-state.component.scss index ce8a15efc..9290cb1ca 100644 --- a/apps/red-ui/src/app/modules/shared/components/dossier-state/dossier-state.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/dossier-state/dossier-state.component.scss @@ -10,5 +10,5 @@ redaction-small-chip { .dossier-state-text { font-size: 13px; line-height: 16px; - color: var(--iqser-grey-1); + color: var(--iqser-text); } diff --git a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.scss b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.scss index 862b53102..9afd86ac7 100644 --- a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.scss @@ -6,7 +6,7 @@ ngx-monaco-editor { } %arrow { - border: solid var(--iqser-grey-1); + border: solid var(--iqser-text); border-width: 2px 0 0 2px; height: 4px !important; width: 4px !important; diff --git a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts index f2cdbe2f2..f70b83f7b 100644 --- a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts @@ -1,5 +1,7 @@ import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { Debounce, List, OnChange } from '@iqser/common-ui'; +import { UserPreferenceService } from '@services/user-preference.service'; +import { EditorThemeService } from '@services/editor-theme.service'; import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions; import ICodeEditor = monaco.editor.ICodeEditor; import IDiffEditor = monaco.editor.IDiffEditor; @@ -41,6 +43,8 @@ export class EditorComponent implements OnInit, OnChanges { private _diffEditor: IDiffEditor; private _decorations: string[] = []; + constructor(private readonly _userPreferenceService: UserPreferenceService, private readonly _editorThemeService: EditorThemeService) {} + get currentEntries(): string[] { return this.value.split('\n'); } @@ -102,31 +106,14 @@ export class EditorComponent implements OnInit, OnChanges { } private _defineThemes(): void { - (window as any).monaco.editor.defineTheme('redaction', { - base: 'vs', - inherit: true, - rules: [], - colors: { - 'editor.lineHighlightBackground': '#f4f5f7', - }, - }); - (window as any).monaco.editor.defineTheme('redaction-disabled', { - base: 'vs', - inherit: true, - rules: [], - colors: { - 'editor.background': '#f4f5f7', - 'editor.foreground': '#9398a0', - 'editor.lineHighlightBackground': '#f4f5f7', - 'editorLineNumber.foreground': '#9398a0', - 'editorActiveLineNumber.foreground': '#9398a0', - }, - }); + for (const theme of this._editorThemeService.themes) { + (window as any).monaco.editor.defineTheme(theme, this._editorThemeService.configurations[theme]); + } } private _setTheme(): void { this._defineThemes(); - (window as any).monaco.editor.setTheme(this.canEdit ? 'redaction' : 'redaction-disabled'); + (window as any).monaco.editor.setTheme(this._editorThemeService.getTheme(this.canEdit)); } private _handleMarginButtonClick(event: IEditorMouseEvent) { diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss index 822b7dc96..aec40dc04 100644 --- a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss @@ -18,6 +18,6 @@ mat-slide-toggle { } &[disabled] { - color: rgba(var(--iqser-accent-rgb), 0.3); + color: rgba(var(--iqser-text-rgb), 0.3); } } diff --git a/apps/red-ui/src/app/modules/shared/components/select/select.component.scss b/apps/red-ui/src/app/modules/shared/components/select/select.component.scss index afcada18e..97bfc982c 100644 --- a/apps/red-ui/src/app/modules/shared/components/select/select.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/select/select.component.scss @@ -12,7 +12,6 @@ } } -// https://stackoverflow.com/questions/34641281/how-to-add-class-to-host-element :host(.fixed-height) { height: var(--height); overflow: hidden; @@ -65,23 +64,23 @@ mat-chip { } .mat-chip.mat-standard-chip.mat-chip-selected.mat-primary { - background-color: var(--iqser-grey-6); - color: var(--iqser-accent); + background-color: var(--iqser-btn-bg); + color: var(--iqser-text); } .mat-chip.mat-standard-chip { - background-color: var(--iqser-white); - color: var(--iqser-accent); + background-color: var(--iqser-background); + color: var(--iqser-text); margin: 0 0 2px 0; transition: background-color 0.2s; &:hover { - background-color: var(--iqser-grey-8); + background-color: var(--iqser-not-disabled-table-item); } } .mat-chip.mat-standard-chip::after { - background: var(--iqser-grey-8); + background: transparent; } .mat-standard-chip:focus::after { diff --git a/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts b/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts index 242c54047..f3ca4fbac 100644 --- a/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts +++ b/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts @@ -215,8 +215,8 @@ export class FileUploadService extends GenericService impleme private _createSubscription(uploadFile: FileUploadModel) { this.activeUploads++; const obs = this.uploadFileForm(uploadFile.dossierId, uploadFile.keepManualRedactions, uploadFile.file); - return obs.subscribe( - event => { + return obs.subscribe({ + next: event => { if (event.type === HttpEventType.UploadProgress) { uploadFile.progress = Math.round((event.loaded / (event.total || event.loaded)) * 100); this._applicationRef.tick(); @@ -234,7 +234,7 @@ export class FileUploadService extends GenericService impleme this._removeUpload(uploadFile); } }, - (err: HttpErrorResponse) => { + error: (err: HttpErrorResponse) => { uploadFile.completed = true; uploadFile.error = { // Extract error message @@ -246,7 +246,7 @@ export class FileUploadService extends GenericService impleme this.scheduleUpload(uploadFile); } }, - ); + }); } private _removeUpload(fileUploadModel: FileUploadModel) { diff --git a/apps/red-ui/src/app/modules/upload-download/upload-status-overlay/upload-status-overlay.component.scss b/apps/red-ui/src/app/modules/upload-download/upload-status-overlay/upload-status-overlay.component.scss index c2569c204..02647eb80 100644 --- a/apps/red-ui/src/app/modules/upload-download/upload-status-overlay/upload-status-overlay.component.scss +++ b/apps/red-ui/src/app/modules/upload-download/upload-status-overlay/upload-status-overlay.component.scss @@ -1,15 +1,14 @@ @use 'common-mixins'; -@use 'variables'; .red-upload-download-overlay { - background: var(--iqser-white); + background: var(--iqser-background); position: fixed; bottom: 20px; right: 20px; - box-shadow: 0 3px 12px 5px rgba(40, 50, 65, 0.14); border-radius: 8px; overflow: hidden; width: 400px; + @include common-mixins.drop-shadow; .red-upload-download-header { display: flex; @@ -19,14 +18,14 @@ padding: 16px 14px 16px 16px; cursor: pointer; - color: var(--iqser-accent); + color: var(--iqser-text); font-size: 13px; font-weight: 600; line-height: 16px; mat-icon { height: 13px; - color: var(--iqser-accent); + color: var(--iqser-text); &.collapse-icon { height: 15px; @@ -52,7 +51,7 @@ .dossier-name-wrapper { display: flex; padding: 4px 16px; - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); > span { @include common-mixins.line-clamp(1); @@ -90,7 +89,7 @@ } &.error { - background-color: rgba(variables.$primary, 0.1); + background-color: rgba(var(--iqser-primary-rgb), 0.1); padding-right: 100px; .error-message { @@ -113,13 +112,13 @@ } &:not(.error) { - background: linear-gradient(to right, rgba(244, 245, 247, 0) 0%, variables.$grey-2 35%); + background: linear-gradient(to right, rgba(244, 245, 247, 0) 0%, var(--iqser-alt-background) 35%); padding-left: 60px; } } &:not(.error):hover { - background-color: var(--iqser-grey-2); + background-color: var(--iqser-alt-background); .actions { display: flex; diff --git a/apps/red-ui/src/app/services/editor-theme.service.ts b/apps/red-ui/src/app/services/editor-theme.service.ts new file mode 100644 index 000000000..8033eeef0 --- /dev/null +++ b/apps/red-ui/src/app/services/editor-theme.service.ts @@ -0,0 +1,62 @@ +import { Injectable } from '@angular/core'; +import { UserPreferenceService } from './user-preference.service'; +import { editor } from 'monaco-editor'; +import IStandaloneThemeData = editor.IStandaloneThemeData; + +@Injectable({ + providedIn: 'root', +}) +export class EditorThemeService { + readonly themes = ['redaction', 'redaction-disabled', 'redaction-dark', 'redaction-disabled-dark']; + readonly configurations: Record = { + redaction: { + base: 'vs', + inherit: true, + rules: [], + colors: { + 'editor.lineHighlightBackground': '#f4f5f7', + }, + }, + 'redaction-disabled': { + base: 'vs', + inherit: true, + rules: [], + colors: { + 'editor.background': '#f4f5f7', + 'editor.foreground': '#9398a0', + 'editor.lineHighlightBackground': '#f4f5f7', + 'editorLineNumber.foreground': '#9398a0', + 'editorActiveLineNumber.foreground': '#9398a0', + }, + }, + 'redaction-dark': { + base: 'vs-dark', + inherit: true, + rules: [], + colors: { + 'editor.background': '#151a21', + 'editor.lineHighlightBackground': '#283241', + }, + }, + 'redaction-disabled-dark': { + base: 'vs-dark', + inherit: true, + rules: [], + colors: { + 'editor.background': '#151a21', + 'editor.foreground': '#9398a0', + 'editor.lineHighlightBackground': '#283241', + 'editorLineNumber.foreground': '#9398a0', + 'editorActiveLineNumber.foreground': '#9398a0', + }, + }, + }; + + constructor(private readonly _userPreferenceService: UserPreferenceService) {} + + getTheme(canEdit: boolean): string { + const isDarkTheme = this._userPreferenceService.getTheme() === 'dark'; + const editorTheme = canEdit ? 'redaction' : 'redaction-disabled'; + return `${editorTheme}${isDarkTheme ? '-dark' : ''}`; + } +} diff --git a/apps/red-ui/src/app/services/entity-services/dictionaries-map.service.ts b/apps/red-ui/src/app/services/entity-services/dictionaries-map.service.ts index 248ee722d..a7f3aa9dc 100644 --- a/apps/red-ui/src/app/services/entity-services/dictionaries-map.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dictionaries-map.service.ts @@ -13,14 +13,14 @@ export class DictionariesMapService extends EntitiesMapService { - constructor( - protected readonly _injector: Injector, - private readonly _filesService: FilesService, - private readonly _dossierStatsService: DossierStatsService, - ) { + constructor(protected readonly _injector: Injector, private readonly _filesService: FilesService) { super(_injector, ''); } @@ -30,13 +25,13 @@ export class FileManagementService extends GenericService { return this._post(body, `rotate/${dossierId}/${fileId}`); } - downloadOriginalFile(dossierId: string, fileId: string, observe?: 'body', indicator?: string): Observable; - downloadOriginalFile(dossierId: string, fileId: string, observe?: 'response', indicator?: string): Observable>; + downloadOriginal(dossierId: string, fileId: string, observe?: 'events', indicator?: string): Observable>; + downloadOriginal(dossierId: string, fileId: string, observe?: 'response', indicator?: string): Observable>; @Validate() - downloadOriginalFile( + downloadOriginal( @RequiredParam() dossierId: string, @RequiredParam() fileId: string, - observe: 'body' | 'response' = 'body', + observe: 'events' | 'response' = 'events', indicator?: string, ) { const queryParams: QueryParam[] = [{ key: 'inline', value: true }]; @@ -56,6 +51,7 @@ export class FileManagementService extends GenericService { params: this._queryParams(queryParams), headers: headers, observe: observe, + reportProgress: observe === 'events', }); } } diff --git a/apps/red-ui/src/app/services/user-preference.service.ts b/apps/red-ui/src/app/services/user-preference.service.ts index 5df934cac..d426b3349 100644 --- a/apps/red-ui/src/app/services/user-preference.service.ts +++ b/apps/red-ui/src/app/services/user-preference.service.ts @@ -9,6 +9,7 @@ const KEYS = { dossierRecent: 'Dossier-Recent', filePreviewTooltips: 'File-Preview-Tooltips', lastDossierTemplate: 'Last-Dossier-Template', + theme: 'Theme', } as const; @Injectable({ @@ -46,6 +47,15 @@ export class UserPreferenceService extends GenericService { await this._save(KEYS.lastDossierTemplate, dossierTemplateId); } + getTheme(): string { + return this._getAttribute(KEYS.theme, 'light'); + } + + async saveTheme(theme: 'light' | 'dark'): Promise { + await this._save(KEYS.theme, theme); + window.location.reload(); + } + getLanguage(): string { return this._getAttribute(KEYS.language); } @@ -64,7 +74,7 @@ export class UserPreferenceService extends GenericService { } toggleDevFeatures(): void { - sessionStorage.setItem('redaction.enable-dev-features', `${!this.areDevFeaturesEnabled}`); + sessionStorage.setItem('redaction.enable-dev-features', String(!this.areDevFeaturesEnabled)); window.location.reload(); } diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index aac659a62..d849c4ea0 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -100,6 +100,8 @@ "recommendation-color": "", "recommendation-color-placeholder": "", "redaction": "", + "skipped-color": "", + "skipped-color-placeholder": "", "technical-name": "", "technical-name-hint": "" }, @@ -1595,6 +1597,7 @@ "usage-details": "Nutzungsdetails" }, "license-information": "Lizenzinformationen", + "loading": "", "manual-annotation": { "dialog": { "actions": { @@ -1628,6 +1631,7 @@ } } }, + "minutes": "", "notification": { "assign-approver": "Sie wurden dem Dokument {fileHref, select, null{{fileName}} other{{fileName}}} im Dossier {dossierHref, select, null{{dossierName}} other{{dossierName}}} als Genehmiger zugewiesen!", "assign-reviewer": "Sie wurden dem Dokument {fileHref, select, null{{fileName}} other{{fileName}}} im Dossier {dossierHref, select, null{{dossierName}} other{{dossierName}}} als Reviewer zugewiesen!", @@ -1922,6 +1926,7 @@ "placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen", "this-dossier": "in diesem Dossier" }, + "seconds": "", "size": "", "smtp-auth-config": { "actions": { @@ -2050,6 +2055,7 @@ "save": "Änderungen speichern" }, "form": { + "dark-theme": "", "email": "Email", "first-name": "Vorname", "last-name": "Nachname" diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index dc8a98b29..58dff7e5d 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -100,6 +100,8 @@ "recommendation-color": "Recommendation Hex Color", "recommendation-color-placeholder": "#", "redaction": "Redaction", + "skipped-color": "Skipped Hex Color", + "skipped-color-placeholder": "#", "technical-name": "Technical Name", "technical-name-hint": "{type, select, edit{Autogenerated based on the initial display name.} create{Autogenerates based on the display name and cannot be edited after saving.} other{}}" }, @@ -1595,6 +1597,7 @@ "usage-details": "Usage Details" }, "license-information": "License Information", + "loading": "Loading", "manual-annotation": { "dialog": { "actions": { @@ -1628,6 +1631,7 @@ } } }, + "minutes": "minutes", "notification": { "assign-approver": "You have been assigned as approver for {fileHref, select, null{{fileName}} other{{fileName}}} in dossier: {dossierHref, select, null{{dossierName}} other{{dossierName}}}!", "assign-reviewer": "You have been assigned as reviewer for {fileHref, select, null{{fileName}} other{{fileName}}} in dossier: {dossierHref, select, null{{dossierName}} other{{dossierName}}}!", @@ -1922,6 +1926,7 @@ "placeholder": "Search documents...", "this-dossier": "in this dossier" }, + "seconds": "seconds", "size": "Size", "smtp-auth-config": { "actions": { @@ -2050,6 +2055,7 @@ "save": "Save Changes" }, "form": { + "dark-theme": "Dark Theme", "email": "Email", "first-name": "First name", "last-name": "Last name" diff --git a/apps/red-ui/src/assets/icons/general/reference.svg b/apps/red-ui/src/assets/icons/general/reference.svg index 77e985170..1b88e7b29 100644 --- a/apps/red-ui/src/assets/icons/general/reference.svg +++ b/apps/red-ui/src/assets/icons/general/reference.svg @@ -1,10 +1,12 @@ - - - + + + - + diff --git a/apps/red-ui/src/assets/pdftron/stylesheet.css b/apps/red-ui/src/assets/pdftron/stylesheet.css index 65408fd9a..1003f8cc9 100644 --- a/apps/red-ui/src/assets/pdftron/stylesheet.css +++ b/apps/red-ui/src/assets/pdftron/stylesheet.css @@ -37,3 +37,8 @@ .excluded-page { border: 2px solid #dd4d5080; } + +.AnnotationPopup { + --component-background: white; + --popup-button-hover: #e7edf3; +} diff --git a/apps/red-ui/src/assets/styles/_variables.scss b/apps/red-ui/src/assets/styles/_variables.scss index be6a0f8ce..41fec2923 100644 --- a/apps/red-ui/src/assets/styles/_variables.scss +++ b/apps/red-ui/src/assets/styles/_variables.scss @@ -9,9 +9,7 @@ $grey-5: #d3d5da; $grey-6: #f0f1f4; $grey-7: #9398a0; $grey-8: #f9fafb; -$grey-9: #f5f5f7; $grey-10: #313d4e; -$grey-11: #ecedf0; $blue-1: #4875f7; $blue-2: #48c9f7; @@ -33,9 +31,3 @@ $accent: $grey-1; $warn: $yellow-2; $light: $white; $dark: $black; - -$btn-bg-hover: $grey-4; -$btn-bg: $grey-6; -$quick-filter-border: $grey-5; - -$separator: rgba(226, 228, 233, 0.9); diff --git a/apps/red-ui/src/assets/styles/red-components.scss b/apps/red-ui/src/assets/styles/red-components.scss index 78d3c5e9e..e4155f00d 100644 --- a/apps/red-ui/src/assets/styles/red-components.scss +++ b/apps/red-ui/src/assets/styles/red-components.scss @@ -88,7 +88,7 @@ display: flex; align-items: center; justify-content: space-between; - background-color: var(--iqser-grey-6); + background-color: var(--iqser-btn-bg); > div { display: flex; diff --git a/apps/red-ui/src/assets/styles/red-editor.scss b/apps/red-ui/src/assets/styles/red-editor.scss index 4f1a692d1..5c8c49ba6 100644 --- a/apps/red-ui/src/assets/styles/red-editor.scss +++ b/apps/red-ui/src/assets/styles/red-editor.scss @@ -1,4 +1,5 @@ @use 'variables'; +@use 'common-mixins'; .monaco-diff-editor { .editor.original { @@ -60,9 +61,9 @@ right: 40px; border-radius: 8px; padding: 16px 32px 16px 16px; - background-color: var(--iqser-white); - box-shadow: 0 2px 6px 0 rgba(40, 50, 65, 0.3); + background-color: var(--iqser-background); z-index: 5000; + @include common-mixins.drop-shadow; > *:not(:last-child) { margin-right: 24px; diff --git a/apps/red-ui/src/styles.scss b/apps/red-ui/src/styles.scss index 4b83d585b..83465af66 100644 --- a/apps/red-ui/src/styles.scss +++ b/apps/red-ui/src/styles.scss @@ -4,22 +4,23 @@ @use 'common-variables'; @use 'assets/styles/red-theme'; -@include common-variables.configure( +@include common-variables.configureLight( $iqser-primary: vars.$primary, $iqser-primary-rgb: common-functions.hexToRgb(vars.$primary), $iqser-primary-2: vars.$primary-2, $iqser-accent: vars.$accent, $iqser-accent-rgb: common-functions.hexToRgb(vars.$accent), + $iqser-background: vars.$white, + $iqser-alt-background: vars.$grey-2, + $iqser-text: vars.$accent, + $iqser-text-rgb: common-functions.hexToRgb(vars.$accent), $iqser-disabled: vars.$grey-7, $iqser-not-disabled-table-item: vars.$grey-8, - $iqser-btn-bg-hover: vars.$btn-bg-hover, - $iqser-btn-bg: vars.$btn-bg, + $iqser-btn-bg-hover: vars.$grey-4, + $iqser-btn-bg: vars.$grey-6, + $iqser-side-nav: vars.$grey-2, $iqser-warn: vars.$warn, - $iqser-white: vars.$white, - $iqser-black: vars.$black, - $iqser-light: vars.$light, - $iqser-separator: vars.$separator, - $iqser-quick-filter-border: vars.$quick-filter-border, + $iqser-separator: rgba(vars.$grey-4, 0.9), $iqser-grey-2: vars.$grey-2, $iqser-grey-3: vars.$grey-3, $iqser-grey-4: vars.$grey-4, @@ -30,5 +31,66 @@ $iqser-green-2: vars.$green-2, $iqser-yellow-1: vars.$yellow-1, $iqser-yellow-2: vars.$yellow-2, - $iqser-helpmode-primary: vars.$green-2 + $iqser-helpmode-primary: vars.$green-2, + $iqser-inputs-outline: vars.$grey-5, + $iqser-popup-background: vars.$white, + $iqser-shadow: vars.$grey-4, + $iqser-toggle-bg: vars.$grey-4, + $iqser-file-drop-drag-over: #e2eefd, + $iqser-user-avatar-1: vars.$grey-6, + $iqser-user-avatar-2: vars.$grey-4, + $iqser-annotation-hover: vars.$grey-8, + $iqser-annotation-comments-hover: vars.$grey-4, + $iqser-workload-pages-bg: vars.$grey-8, + $iqser-tab-hover: vars.$grey-6, + $iqser-loading-progress: vars.$grey-7 +); + +$light-accent-5: lighten(vars.$accent, 5%); +$light-accent-10: lighten(vars.$accent, 10%); + +$dark-accent-5: darken(vars.$accent, 5%); +$dark-accent-8: darken(vars.$accent, 8%); +$dark-accent-10: darken(vars.$accent, 10%); + +@include common-variables.configureDark( + $iqser-primary: vars.$primary, + $iqser-primary-rgb: common-functions.hexToRgb(vars.$primary), + $iqser-primary-2: vars.$primary-2, + $iqser-accent: vars.$accent, + $iqser-accent-rgb: common-functions.hexToRgb(vars.$accent), + $iqser-background: $dark-accent-10, + $iqser-alt-background: $dark-accent-5, + $iqser-text: vars.$white, + $iqser-text-rgb: common-functions.hexToRgb(vars.$white), + $iqser-disabled: vars.$grey-7, + $iqser-not-disabled-table-item: $dark-accent-5, + $iqser-btn-bg-hover: vars.$accent, + $iqser-btn-bg: $dark-accent-5, + $iqser-side-nav: $dark-accent-8, + $iqser-warn: vars.$warn, + $iqser-separator: vars.$accent, + $iqser-grey-2: vars.$grey-2, + $iqser-grey-3: vars.$grey-3, + $iqser-grey-4: vars.$grey-4, + $iqser-grey-5: vars.$grey-5, + $iqser-grey-6: vars.$grey-6, + $iqser-grey-7: vars.$grey-7, + $iqser-green-1: vars.$green-1, + $iqser-green-2: vars.$green-2, + $iqser-yellow-1: vars.$yellow-1, + $iqser-yellow-2: vars.$yellow-2, + $iqser-helpmode-primary: vars.$green-2, + $iqser-inputs-outline: $light-accent-10, + $iqser-popup-background: $dark-accent-5, + $iqser-shadow: rgba(0, 0, 0, 0.4), + $iqser-toggle-bg: $light-accent-5, + $iqser-file-drop-drag-over: $light-accent-10, + $iqser-user-avatar-1: $light-accent-5, + $iqser-user-avatar-2: $light-accent-10, + $iqser-annotation-hover: $dark-accent-5, + $iqser-annotation-comments-hover: $light-accent-5, + $iqser-workload-pages-bg: $dark-accent-8, + $iqser-tab-hover: vars.$accent, + $iqser-loading-progress: $light-accent-10 ); diff --git a/libs/common-ui b/libs/common-ui index d892f174f..f12e9a209 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit d892f174f534fa794f30204ff9e855fc36dcfa8e +Subproject commit f12e9a20943a8c6cffd1b5c1c2e1ed38e0ab022a diff --git a/libs/red-domain/src/lib/dictionaries/dictionary.model.ts b/libs/red-domain/src/lib/dictionaries/dictionary.model.ts index e428db993..821bbf702 100644 --- a/libs/red-domain/src/lib/dictionaries/dictionary.model.ts +++ b/libs/red-domain/src/lib/dictionaries/dictionary.model.ts @@ -9,6 +9,7 @@ export class Dictionary extends Entity implements IDictionary { readonly dossierTemplateId?: string; readonly hexColor?: string; readonly recommendationHexColor?: string; + readonly skippedHexColor?: string; readonly hint: boolean; readonly label: string; readonly rank?: number; @@ -33,6 +34,7 @@ export class Dictionary extends Entity implements IDictionary { this.falseRecommendationEntries = entity.falseRecommendationEntries ?? []; this.hexColor = entity.hexColor; this.recommendationHexColor = entity.recommendationHexColor; + this.skippedHexColor = entity.skippedHexColor; this.hint = !!entity.hint; this.label = entity.label ?? entity.type; this.rank = entity.rank; diff --git a/libs/red-domain/src/lib/dictionaries/dictionary.ts b/libs/red-domain/src/lib/dictionaries/dictionary.ts index 899216bb2..8cf003a69 100644 --- a/libs/red-domain/src/lib/dictionaries/dictionary.ts +++ b/libs/red-domain/src/lib/dictionaries/dictionary.ts @@ -54,6 +54,8 @@ export interface IDictionary { readonly recommendationHexColor?: string; + readonly skippedHexColor?: string; + readonly hasDictionary?: boolean; readonly systemManaged?: boolean; diff --git a/libs/red-domain/src/lib/files/file.model.ts b/libs/red-domain/src/lib/files/file.model.ts index 54f4ad208..7d3886e83 100644 --- a/libs/red-domain/src/lib/files/file.model.ts +++ b/libs/red-domain/src/lib/files/file.model.ts @@ -31,6 +31,7 @@ export class File extends Entity implements IFile { readonly fileAttributes: FileAttributes; readonly fileId: string; readonly filename: string; + readonly fileSize: number; readonly hasAnnotationComments: boolean; readonly hasHints: boolean; readonly hasImages: boolean; @@ -94,6 +95,7 @@ export class File extends Entity implements IFile { this.excludedFromAutomaticAnalysis = !!file.excludedFromAutomaticAnalysis; this.fileId = file.fileId; this.filename = file.filename; + this.fileSize = file.fileSize; this.hasAnnotationComments = !!file.hasAnnotationComments; this.hasHints = !!file.hasHints; this.hasImages = !!file.hasImages; diff --git a/libs/red-domain/src/lib/files/file.ts b/libs/red-domain/src/lib/files/file.ts index 59ba00cd8..b7a2efcec 100644 --- a/libs/red-domain/src/lib/files/file.ts +++ b/libs/red-domain/src/lib/files/file.ts @@ -13,17 +13,8 @@ export interface IFile { * Shows if all manual changes have been applied by a reanalysis. */ readonly allManualRedactionsApplied?: boolean; - /** - * Shows how long the last analysis took - */ readonly analysisDuration?: number; - /** - * Shows if the file requires reanalysis. - */ readonly analysisRequired?: boolean; - /** - * Shows the date of approval, if approved. - */ readonly approvalDate?: string; /** * The current reviewer's (if any) user id. @@ -37,34 +28,17 @@ export interface IFile { * Shows which dossier dictionary versions was used during the analysis. */ readonly dossierDictionaryVersion?: number; - /** - * The ID of the dossier the file belongs to. - */ readonly dossierId: string; /** * Shows if the file was excluded from analysis. */ readonly excluded?: boolean; - /** - * Shows if the file was excluded from automatic analysis. - */ readonly excludedFromAutomaticAnalysis?: boolean; - /** - * Set of excluded pages for this file. - */ - readonly excludedPages?: Array; + readonly excludedPages?: number[]; fileAttributes?: FileAttributes; - /** - * The ID of the file. - */ readonly fileId: string; - /** - * The file's name. - */ readonly filename: string; - /** - * Shows if this file has comments on annotations. - */ + readonly fileSize: number; readonly hasAnnotationComments?: boolean; /** * Shows if any hints were found during the analysis. @@ -82,9 +56,6 @@ export interface IFile { * Shows if any requests were found during the analysis. */ readonly hasRequests?: boolean; - /** - * Shows if there are any Suggestions in this file. - */ readonly hasSuggestions?: boolean; /** * Shows if there is any change between the previous and current analysis. diff --git a/libs/red-domain/src/lib/users/profile.ts b/libs/red-domain/src/lib/users/profile.ts index d45a837bd..e53543392 100644 --- a/libs/red-domain/src/lib/users/profile.ts +++ b/libs/red-domain/src/lib/users/profile.ts @@ -4,4 +4,5 @@ export interface IProfile { firstName: string; lastName: string; language: string; + darkTheme: boolean; } diff --git a/package.json b/package.json index 08b5253a5..46a941e4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redaction", - "version": "3.570.0", + "version": "3.581.0", "private": true, "license": "MIT", "scripts": { diff --git a/paligo-styles/search.scss b/paligo-styles/search.scss index a6789b7f3..920690119 100644 --- a/paligo-styles/search.scss +++ b/paligo-styles/search.scss @@ -2,7 +2,7 @@ @use 'mixin'; .portal-search-result { - background-color: variables.$grey-9; + background-color: variables.$grey-2; } .search-container { diff --git a/paligo-styles/style.scss b/paligo-styles/style.scss index 60bf3b494..f71b6d57f 100644 --- a/paligo-styles/style.scss +++ b/paligo-styles/style.scss @@ -11,15 +11,21 @@ body { color: variables.$accent; - background-color: variables.$grey-9; + background-color: variables.$grey-2; font-family: 'Open Sans', sans-serif; - h1, .h1, - h2, .h2, - h3, .h3, - h4, .h4, - h5, .h5, - h6, .h6, + h1, + .h1, + h2, + .h2, + h3, + .h3, + h4, + .h4, + h5, + .h5, + h6, + .h6, p, pre { margin: 0; @@ -28,23 +34,28 @@ body { @include common-mixins.scroll-bar; - h1, .h1 { + h1, + .h1 { @include mixin.heading-1; } - h2, .h2 { + h2, + .h2 { @include mixin.heading-2; } - h3, .h3 { + h3, + .h3 { @include mixin.heading-3; } - h4, .h4 { + h4, + .h4 { @include mixin.heading-4; } - h5, .h5 { + h5, + .h5 { @include mixin.heading-5; } diff --git a/paligo-theme.tar.gz b/paligo-theme.tar.gz index 89a9974b1..0e6920eb3 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 7356127bf..dd85e8525 100644 --- a/paligo-theme/paligo-styles/redacto-theme.css +++ b/paligo-theme/paligo-styles/redacto-theme.css @@ -1,492 +1,494 @@ @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; + } } .portal-single-publication { - background-color: transparent; - width: 280px; + background-color: transparent; + width: 280px; } .portal-single-publication > a { - border-radius: 4px; + border-radius: 4px; } .portal-single-publication .publication-icon { - background-color: #dd4d50; + background-color: #dd4d50; } .featured-content-label { - margin-top: 24px; - text-align: center; + margin-top: 24px; + text-align: center; } .featured-content { - margin-top: 24px; - margin-bottom: 0; + margin-top: 24px; + margin-bottom: 0; } .featured-content .inner { - margin: 0; - justify-content: center; + margin: 0; + justify-content: center; } .featured-content .publication-contents { - padding: 24px 40px; - border: 1px solid #e2e4e9; - width: 100%; - margin: 0; - background-color: #fff; - border-radius: 4px; - border: none; - background-color: transparent; - width: 250px; - margin: 0 15px !important; + padding: 24px 40px; + border: 1px solid #e2e4e9; + width: 100%; + margin: 0; + background-color: #fff; + border-radius: 4px; + border: none; + background-color: transparent; + width: 250px; + margin: 0 15px !important; } .featured-content .publication-contents h4.featured-title, .featured-content .publication-contents .section-toc-title { - margin: 0; + margin: 0; } .featured-content .publication-contents h4.featured-title a, .featured-content .publication-contents .section-toc-title a { - color: #283241; + color: #283241; } .featured-content .publication-contents h4.featured-title a:hover, .featured-content .publication-contents .section-toc-title a:hover { - color: #283241; - text-decoration: underline; + color: #283241; + text-decoration: underline; } .featured-content .publication-contents .section-toc-title { - font-size: 28px; - font-weight: 300; - line-height: 36px; + font-size: 28px; + font-weight: 300; + line-height: 36px; } .featured-content .publication-contents ul { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } .featured-content .publication-contents li { - margin: 4px 0; + margin: 4px 0; } .featured-content .publication-contents li:first-child { - margin-top: 20px; + margin-top: 20px; } .featured-content .publication-contents li:last-child { - margin-bottom: 40px; + margin-bottom: 40px; } .featured-content .publication-contents li a { - color: #dd4d50; - font-size: 16px; - line-height: 24px; + color: #dd4d50; + font-size: 16px; + line-height: 24px; } .featured-content .publication-contents li a:hover { - color: #dd4d50; - text-decoration: underline; + color: #dd4d50; + text-decoration: underline; } .featured-content .publication-contents h4 span, .featured-content .publication-contents li::before { - display: none; + display: none; } .featured-content .publication-contents li a { - font-size: inherit; - line-height: inherit; + font-size: inherit; + line-height: inherit; } /* Einleitung */ .cat-panel-1:before { - content: "\f007"; + content: '\f007'; } /* Workflow */ .cat-panel-2:before { - content: "\f085"; + content: '\f085'; } /* 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: #f4f5f7; } .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; +body { + --iqser-primary: lightblue; + --iqser-primary-rgb: 220, 230, 234; + --iqser-primary-2: orange; + --iqser-accent: blue; + --iqser-accent-rgb: 123, 234, 111; + --iqser-background: white; + --iqser-text: black; + --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-grey-1: #283241; + --iqser-grey-10: #313d4e; + --iqser-grey-7: #9398a0; + --iqser-grey-3: #aaacb3; + --iqser-grey-5: #d3d5da; + --iqser-grey-4: #e2e4e9; + --iqser-grey-6: #f0f1f4; + --iqser-grey-2: #f4f5f7; + --iqser-grey-8: #f9fafb; + --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-inputs-outline) var(--iqser-alt-background); + scrollbar-width: thin; + /* Track */ + /* Handle */ } .site-sidebar .logo { - padding: 24px 0 30px 0 !important; + padding: 24px 0 30px 0 !important; +} +.site-sidebar ::-webkit-scrollbar-corner { + background: var(--iqser-alt-background); } .site-sidebar::-webkit-scrollbar { - width: 11px; + width: 11px; } .site-sidebar::-webkit-scrollbar-track { - background: var(--iqser-grey-2); + background: var(--iqser-alt-background); } .site-sidebar::-webkit-scrollbar-thumb { - background: var(--iqser-quick-filter-border); + background: var(--iqser-inputs-outline); } .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 { - position: relative; + position: relative; } 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; } .checklist-reset-wrapper { - position: absolute; - right: 0; - top: 0; + position: absolute; + right: 0; + top: 0; } .warning, @@ -494,229 +496,243 @@ 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; + 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 { - 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; + 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: #f4f5f7; + font-family: 'Open Sans', sans-serif; + scrollbar-color: var(--iqser-inputs-outline) var(--iqser-alt-background); + 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-corner { + background: var(--iqser-alt-background); } body::-webkit-scrollbar { - width: 11px; + width: 11px; } body::-webkit-scrollbar-track { - background: var(--iqser-grey-2); + background: var(--iqser-alt-background); } body::-webkit-scrollbar-thumb { - background: var(--iqser-quick-filter-border); + background: var(--iqser-inputs-outline); } -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; }