From a34404eac040c5b49492267b1ab184058462e745 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 14 Dec 2023 00:04:11 -0800 Subject: [PATCH] Resolve some change detection issues --- CONTRIBUTING.md | 2 +- docs/development.md | 16 +- .../admin/settings/settings.component.ts | 14 +- .../upload-file-widget.component.spec.ts | 49 ++- .../filter-editor/filter-editor.component.ts | 93 +++-- src-ui/src/app/services/settings.service.ts | 395 +++++++++--------- 6 files changed, 283 insertions(+), 286 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d87bd243b..953d19fb8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,7 +94,7 @@ The following files need to be changed: - src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key) - src/paperless/settings.py (in the _LANGUAGES_ array) -- src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method) +- src-ui/src/app/services/settings.service.ts (inside the _LANGUAGE_OPTIONS_ array) - src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_) Please add the language in the correct order, alphabetically by locale. diff --git a/docs/development.md b/docs/development.md index 16933a172..a87641ded 100644 --- a/docs/development.md +++ b/docs/development.md @@ -277,27 +277,17 @@ Adding new languages requires adding the translated files in the } ``` -2. Add the language to the available options in +2. Add the language to the `LANGUAGE_OPTIONS` array in `src-ui/src/app/services/settings.service.ts`: - ```typescript - getLanguageOptions(): LanguageOption[] { - return [ - {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, - {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, - {code: "de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, - {code: "nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, - {code: "fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, - {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"} - // Add your new language here - ] - } ``` `dateInputFormat` is a special string that defines the behavior of the date input fields and absolutely needs to contain "dd", "mm" and "yyyy". + ``` + 3. Import and register the Angular data for this locale in `src-ui/src/app/app.module.ts`: diff --git a/src-ui/src/app/components/admin/settings/settings.component.ts b/src-ui/src/app/components/admin/settings/settings.component.ts index 57d308969..90dd00dfd 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.ts @@ -48,6 +48,12 @@ enum SettingsNavIDs { SavedViews = 4, } +const systemLanguage = { code: '', name: $localize`Use system language` } +const systemDateFormat = { + code: '', + name: $localize`Use date format of display language`, +} + @Component({ selector: 'pngx-settings', templateUrl: './settings.component.html', @@ -512,15 +518,11 @@ export class SettingsComponent } get displayLanguageOptions(): LanguageOption[] { - return [{ code: '', name: $localize`Use system language` }].concat( - this.settings.getLanguageOptions() - ) + return [systemLanguage].concat(this.settings.getLanguageOptions()) } get dateLocaleOptions(): LanguageOption[] { - return [ - { code: '', name: $localize`Use date format of display language` }, - ].concat(this.settings.getDateLocaleOptions()) + return [systemDateFormat].concat(this.settings.getDateLocaleOptions()) } get today() { diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts index b0f600430..30215d542 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts @@ -27,6 +27,24 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component' import { UploadFileWidgetComponent } from './upload-file-widget.component' import { DragDropModule } from '@angular/cdk/drag-drop' +const FAILED_STATUSES = [new FileStatus()] +const WORKING_STATUSES = [new FileStatus(), new FileStatus()] +const STARTED_STATUSES = [new FileStatus(), new FileStatus(), new FileStatus()] +const SUCCESS_STATUSES = [ + new FileStatus(), + new FileStatus(), + new FileStatus(), + new FileStatus(), +] +const DEFAULT_STATUSES = [ + new FileStatus(), + new FileStatus(), + new FileStatus(), + new FileStatus(), + new FileStatus(), + new FileStatus(), +] + describe('UploadFileWidgetComponent', () => { let component: UploadFileWidgetComponent let fixture: ComponentFixture @@ -150,41 +168,22 @@ function mockConsumerStatuses(consumerStatusService) { .mockImplementation((phase) => { switch (phase) { case FileStatusPhase.FAILED: - return [new FileStatus()] + return FAILED_STATUSES case FileStatusPhase.WORKING: - return [new FileStatus(), new FileStatus()] + return WORKING_STATUSES case FileStatusPhase.STARTED: - return [new FileStatus(), new FileStatus(), new FileStatus()] + return STARTED_STATUSES case FileStatusPhase.SUCCESS: - return [ - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - ] + return SUCCESS_STATUSES case FileStatusPhase.UPLOADING: return [partialUpload1, partialUpload2] default: - return [ - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - ] + return DEFAULT_STATUSES } }) jest .spyOn(consumerStatusService, 'getConsumerStatusNotCompleted') .mockImplementation(() => { - return [ - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - new FileStatus(), - ] + return DEFAULT_STATUSES }) } diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts index 030f4ec07..432d28f47 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts @@ -104,6 +104,51 @@ const RELATIVE_DATE_QUERYSTRINGS = [ }, ] +const DEFAULT_TEXT_FILTER_TARGET_OPTIONS = [ + { id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title` }, + { + id: TEXT_FILTER_TARGET_TITLE_CONTENT, + name: $localize`Title & content`, + }, + { id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` }, + { + id: TEXT_FILTER_TARGET_CUSTOM_FIELDS, + name: $localize`Custom fields`, + }, + { + id: TEXT_FILTER_TARGET_FULLTEXT_QUERY, + name: $localize`Advanced search`, + }, +] + +const TEXT_FILTER_TARGET_MORELIKE_OPTION = { + id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE, + name: $localize`More like`, +} + +const DEFAULT_TEXT_FILTER_MODIFIER_OPTIONS = [ + { + id: TEXT_FILTER_MODIFIER_EQUALS, + label: $localize`equals`, + }, + { + id: TEXT_FILTER_MODIFIER_NULL, + label: $localize`is empty`, + }, + { + id: TEXT_FILTER_MODIFIER_NOTNULL, + label: $localize`is not empty`, + }, + { + id: TEXT_FILTER_MODIFIER_GT, + label: $localize`greater than`, + }, + { + id: TEXT_FILTER_MODIFIER_LT, + label: $localize`less than`, + }, +] + @Component({ selector: 'pngx-filter-editor', templateUrl: './filter-editor.component.html', @@ -199,29 +244,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy { _moreLikeDoc: PaperlessDocument get textFilterTargets() { - let targets = [ - { id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title` }, - { - id: TEXT_FILTER_TARGET_TITLE_CONTENT, - name: $localize`Title & content`, - }, - { id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` }, - { - id: TEXT_FILTER_TARGET_CUSTOM_FIELDS, - name: $localize`Custom fields`, - }, - { - id: TEXT_FILTER_TARGET_FULLTEXT_QUERY, - name: $localize`Advanced search`, - }, - ] if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) { - targets.push({ - id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE, - name: $localize`More like`, - }) + return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([ + TEXT_FILTER_TARGET_MORELIKE_OPTION, + ]) } - return targets + return DEFAULT_TEXT_FILTER_TARGET_OPTIONS } textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT @@ -234,28 +262,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { public textFilterModifier: string get textFilterModifiers() { - return [ - { - id: TEXT_FILTER_MODIFIER_EQUALS, - label: $localize`equals`, - }, - { - id: TEXT_FILTER_MODIFIER_NULL, - label: $localize`is empty`, - }, - { - id: TEXT_FILTER_MODIFIER_NOTNULL, - label: $localize`is not empty`, - }, - { - id: TEXT_FILTER_MODIFIER_GT, - label: $localize`greater than`, - }, - { - id: TEXT_FILTER_MODIFIER_LT, - label: $localize`less than`, - }, - ] + return DEFAULT_TEXT_FILTER_MODIFIER_OPTIONS } get textFilterModifierIsNull(): boolean { diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index 7b9428f9e..267a37b98 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -38,6 +38,201 @@ export interface LanguageOption { dateInputFormat?: string } +const LANGUAGE_OPTIONS = [ + { + code: 'en-us', + name: $localize`English (US)`, + englishName: 'English (US)', + dateInputFormat: 'mm/dd/yyyy', + }, + { + code: 'af-za', + name: $localize`Afrikaans`, + englishName: 'Afrikaans', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'ar-ar', + name: $localize`Arabic`, + englishName: 'Arabic', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'be-by', + name: $localize`Belarusian`, + englishName: 'Belarusian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'bg-bg', + name: $localize`Bulgarian`, + englishName: 'Bulgarian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'ca-es', + name: $localize`Catalan`, + englishName: 'Catalan', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'cs-cz', + name: $localize`Czech`, + englishName: 'Czech', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'da-dk', + name: $localize`Danish`, + englishName: 'Danish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'de-de', + name: $localize`German`, + englishName: 'German', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'el-gr', + name: $localize`Greek`, + englishName: 'Greek', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'en-gb', + name: $localize`English (GB)`, + englishName: 'English (GB)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'es-es', + name: $localize`Spanish`, + englishName: 'Spanish', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'fi-fi', + name: $localize`Finnish`, + englishName: 'Finnish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'fr-fr', + name: $localize`French`, + englishName: 'French', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'hu-hu', + name: $localize`Hungarian`, + englishName: 'Hungarian', + dateInputFormat: 'yyyy.mm.dd', + }, + { + code: 'it-it', + name: $localize`Italian`, + englishName: 'Italian', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'lb-lu', + name: $localize`Luxembourgish`, + englishName: 'Luxembourgish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'nl-nl', + name: $localize`Dutch`, + englishName: 'Dutch', + dateInputFormat: 'dd-mm-yyyy', + }, + { + code: 'no-no', + name: $localize`Norwegian`, + englishName: 'Norwegian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'pl-pl', + name: $localize`Polish`, + englishName: 'Polish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'pt-br', + name: $localize`Portuguese (Brazil)`, + englishName: 'Portuguese (Brazil)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'pt-pt', + name: $localize`Portuguese`, + englishName: 'Portuguese', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'ro-ro', + name: $localize`Romanian`, + englishName: 'Romanian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'ru-ru', + name: $localize`Russian`, + englishName: 'Russian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sk-sk', + name: $localize`Slovak`, + englishName: 'Slovak', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sl-si', + name: $localize`Slovenian`, + englishName: 'Slovenian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sr-cs', + name: $localize`Serbian`, + englishName: 'Serbian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sv-se', + name: $localize`Swedish`, + englishName: 'Swedish', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'tr-tr', + name: $localize`Turkish`, + englishName: 'Turkish', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'uk-ua', + name: $localize`Ukrainian`, + englishName: 'Ukrainian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'zh-cn', + name: $localize`Chinese Simplified`, + englishName: 'Chinese Simplified', + dateInputFormat: 'yyyy-mm-dd', + }, +] + +const ISO_LANGUAGE_OPTION: LanguageOption = { + code: 'iso-8601', + name: $localize`ISO 8601`, + dateInputFormat: 'yyyy-mm-dd', +} + @Injectable({ providedIn: 'root', }) @@ -151,210 +346,14 @@ export class SettingsService { } getLanguageOptions(): LanguageOption[] { - const languages = [ - { - code: 'en-us', - name: $localize`English (US)`, - englishName: 'English (US)', - dateInputFormat: 'mm/dd/yyyy', - }, - { - code: 'af-za', - name: $localize`Afrikaans`, - englishName: 'Afrikaans', - dateInputFormat: 'yyyy-mm-dd', - }, - { - code: 'ar-ar', - name: $localize`Arabic`, - englishName: 'Arabic', - dateInputFormat: 'yyyy-mm-dd', - }, - { - code: 'be-by', - name: $localize`Belarusian`, - englishName: 'Belarusian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'bg-bg', - name: $localize`Bulgarian`, - englishName: 'Bulgarian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'ca-es', - name: $localize`Catalan`, - englishName: 'Catalan', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'cs-cz', - name: $localize`Czech`, - englishName: 'Czech', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'da-dk', - name: $localize`Danish`, - englishName: 'Danish', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'de-de', - name: $localize`German`, - englishName: 'German', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'el-gr', - name: $localize`Greek`, - englishName: 'Greek', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'en-gb', - name: $localize`English (GB)`, - englishName: 'English (GB)', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'es-es', - name: $localize`Spanish`, - englishName: 'Spanish', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'fi-fi', - name: $localize`Finnish`, - englishName: 'Finnish', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'fr-fr', - name: $localize`French`, - englishName: 'French', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'hu-hu', - name: $localize`Hungarian`, - englishName: 'Hungarian', - dateInputFormat: 'yyyy.mm.dd', - }, - { - code: 'it-it', - name: $localize`Italian`, - englishName: 'Italian', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'lb-lu', - name: $localize`Luxembourgish`, - englishName: 'Luxembourgish', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'nl-nl', - name: $localize`Dutch`, - englishName: 'Dutch', - dateInputFormat: 'dd-mm-yyyy', - }, - { - code: 'no-no', - name: $localize`Norwegian`, - englishName: 'Norwegian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'pl-pl', - name: $localize`Polish`, - englishName: 'Polish', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'pt-br', - name: $localize`Portuguese (Brazil)`, - englishName: 'Portuguese (Brazil)', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'pt-pt', - name: $localize`Portuguese`, - englishName: 'Portuguese', - dateInputFormat: 'dd/mm/yyyy', - }, - { - code: 'ro-ro', - name: $localize`Romanian`, - englishName: 'Romanian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'ru-ru', - name: $localize`Russian`, - englishName: 'Russian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'sk-sk', - name: $localize`Slovak`, - englishName: 'Slovak', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'sl-si', - name: $localize`Slovenian`, - englishName: 'Slovenian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'sr-cs', - name: $localize`Serbian`, - englishName: 'Serbian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'sv-se', - name: $localize`Swedish`, - englishName: 'Swedish', - dateInputFormat: 'yyyy-mm-dd', - }, - { - code: 'tr-tr', - name: $localize`Turkish`, - englishName: 'Turkish', - dateInputFormat: 'yyyy-mm-dd', - }, - { - code: 'uk-ua', - name: $localize`Ukrainian`, - englishName: 'Ukrainian', - dateInputFormat: 'dd.mm.yyyy', - }, - { - code: 'zh-cn', - name: $localize`Chinese Simplified`, - englishName: 'Chinese Simplified', - dateInputFormat: 'yyyy-mm-dd', - }, - ] - // Sort languages by localized name at runtime - languages.sort((a, b) => { + return LANGUAGE_OPTIONS.sort((a, b) => { return a.name < b.name ? -1 : 1 }) - - return languages } getDateLocaleOptions(): LanguageOption[] { - let isoOption: LanguageOption = { - code: 'iso-8601', - name: $localize`ISO 8601`, - dateInputFormat: 'yyyy-mm-dd', - } - return [isoOption].concat(this.getLanguageOptions()) + return [ISO_LANGUAGE_OPTION].concat(this.getLanguageOptions()) } private getLanguageCookieName() {