Resolve some change detection issues

This commit is contained in:
shamoon 2023-12-14 00:04:11 -08:00
parent 0d7474d4af
commit a34404eac0
6 changed files with 283 additions and 286 deletions

View File

@ -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-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key)
- src/paperless/settings.py (in the _LANGUAGES_ array) - 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_) - 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. Please add the language in the correct order, alphabetically by locale.

View File

@ -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`: `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 `dateInputFormat` is a special string that defines the behavior of
the date input fields and absolutely needs to contain "dd", "mm" the date input fields and absolutely needs to contain "dd", "mm"
and "yyyy". and "yyyy".
```
3. Import and register the Angular data for this locale in 3. Import and register the Angular data for this locale in
`src-ui/src/app/app.module.ts`: `src-ui/src/app/app.module.ts`:

View File

@ -48,6 +48,12 @@ enum SettingsNavIDs {
SavedViews = 4, SavedViews = 4,
} }
const systemLanguage = { code: '', name: $localize`Use system language` }
const systemDateFormat = {
code: '',
name: $localize`Use date format of display language`,
}
@Component({ @Component({
selector: 'pngx-settings', selector: 'pngx-settings',
templateUrl: './settings.component.html', templateUrl: './settings.component.html',
@ -512,15 +518,11 @@ export class SettingsComponent
} }
get displayLanguageOptions(): LanguageOption[] { get displayLanguageOptions(): LanguageOption[] {
return [{ code: '', name: $localize`Use system language` }].concat( return [systemLanguage].concat(this.settings.getLanguageOptions())
this.settings.getLanguageOptions()
)
} }
get dateLocaleOptions(): LanguageOption[] { get dateLocaleOptions(): LanguageOption[] {
return [ return [systemDateFormat].concat(this.settings.getDateLocaleOptions())
{ code: '', name: $localize`Use date format of display language` },
].concat(this.settings.getDateLocaleOptions())
} }
get today() { get today() {

View File

@ -27,6 +27,24 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
import { UploadFileWidgetComponent } from './upload-file-widget.component' import { UploadFileWidgetComponent } from './upload-file-widget.component'
import { DragDropModule } from '@angular/cdk/drag-drop' 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', () => { describe('UploadFileWidgetComponent', () => {
let component: UploadFileWidgetComponent let component: UploadFileWidgetComponent
let fixture: ComponentFixture<UploadFileWidgetComponent> let fixture: ComponentFixture<UploadFileWidgetComponent>
@ -150,41 +168,22 @@ function mockConsumerStatuses(consumerStatusService) {
.mockImplementation((phase) => { .mockImplementation((phase) => {
switch (phase) { switch (phase) {
case FileStatusPhase.FAILED: case FileStatusPhase.FAILED:
return [new FileStatus()] return FAILED_STATUSES
case FileStatusPhase.WORKING: case FileStatusPhase.WORKING:
return [new FileStatus(), new FileStatus()] return WORKING_STATUSES
case FileStatusPhase.STARTED: case FileStatusPhase.STARTED:
return [new FileStatus(), new FileStatus(), new FileStatus()] return STARTED_STATUSES
case FileStatusPhase.SUCCESS: case FileStatusPhase.SUCCESS:
return [ return SUCCESS_STATUSES
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
]
case FileStatusPhase.UPLOADING: case FileStatusPhase.UPLOADING:
return [partialUpload1, partialUpload2] return [partialUpload1, partialUpload2]
default: default:
return [ return DEFAULT_STATUSES
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
]
} }
}) })
jest jest
.spyOn(consumerStatusService, 'getConsumerStatusNotCompleted') .spyOn(consumerStatusService, 'getConsumerStatusNotCompleted')
.mockImplementation(() => { .mockImplementation(() => {
return [ return DEFAULT_STATUSES
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
new FileStatus(),
]
}) })
} }

View File

@ -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({ @Component({
selector: 'pngx-filter-editor', selector: 'pngx-filter-editor',
templateUrl: './filter-editor.component.html', templateUrl: './filter-editor.component.html',
@ -199,29 +244,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
_moreLikeDoc: PaperlessDocument _moreLikeDoc: PaperlessDocument
get textFilterTargets() { 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) { if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
targets.push({ return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([
id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE, TEXT_FILTER_TARGET_MORELIKE_OPTION,
name: $localize`More like`, ])
})
} }
return targets return DEFAULT_TEXT_FILTER_TARGET_OPTIONS
} }
textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT
@ -234,28 +262,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
public textFilterModifier: string public textFilterModifier: string
get textFilterModifiers() { get textFilterModifiers() {
return [ return 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`,
},
]
} }
get textFilterModifierIsNull(): boolean { get textFilterModifierIsNull(): boolean {

View File

@ -38,6 +38,201 @@ export interface LanguageOption {
dateInputFormat?: string 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({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
@ -151,210 +346,14 @@ export class SettingsService {
} }
getLanguageOptions(): LanguageOption[] { 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 // 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 a.name < b.name ? -1 : 1
}) })
return languages
} }
getDateLocaleOptions(): LanguageOption[] { getDateLocaleOptions(): LanguageOption[] {
let isoOption: LanguageOption = { return [ISO_LANGUAGE_OPTION].concat(this.getLanguageOptions())
code: 'iso-8601',
name: $localize`ISO 8601`,
dateInputFormat: 'yyyy-mm-dd',
}
return [isoOption].concat(this.getLanguageOptions())
} }
private getLanguageCookieName() { private getLanguageCookieName() {