From 864e421cd36ed20c520e2e7a9d5f8180dc560cf7 Mon Sep 17 00:00:00 2001 From: jonaswinkler <jonas.winkler@jpwinkler.de> Date: Sun, 17 Jan 2021 00:15:45 +0100 Subject: [PATCH] add configuration option for changing date display in paperless #325 --- src-ui/src/app/app.module.ts | 14 ++++++- .../saved-view-widget.component.html | 2 +- .../saved-view-widget.component.ts | 4 +- .../document-detail.component.html | 4 +- .../document-card-large.component.html | 2 +- .../document-card-small.component.html | 2 +- .../document-list.component.html | 4 +- .../correspondent-list.component.html | 2 +- .../manage/logs/logs.component.html | 2 +- .../manage/settings/settings.component.html | 37 ++++++++++++++++++- .../manage/settings/settings.component.ts | 20 ++++++++-- src-ui/src/app/pipes/custom-date.pipe.spec.ts | 8 ++++ src-ui/src/app/pipes/custom-date.pipe.ts | 19 ++++++++++ src-ui/src/app/services/settings.service.ts | 25 +++++++++---- 14 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 src-ui/src/app/pipes/custom-date.pipe.spec.ts create mode 100644 src-ui/src/app/pipes/custom-date.pipe.ts diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index 30411c980..49e937c0b 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -13,7 +13,7 @@ import { DocumentTypeListComponent } from './components/manage/document-type-lis import { LogsComponent } from './components/manage/logs/logs.component'; import { SettingsComponent } from './components/manage/settings/settings.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { DatePipe } from '@angular/common'; +import { DatePipe, registerLocaleData } from '@angular/common'; import { NotFoundComponent } from './components/not-found/not-found.component'; import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component'; @@ -59,6 +59,15 @@ import { SelectDialogComponent } from './components/common/select-dialog/select- import { NgSelectModule } from '@ng-select/ng-select'; import { NumberComponent } from './components/common/input/number/number.component'; import { SafePipe } from './pipes/safe.pipe'; +import { CustomDatePipe } from './pipes/custom-date.pipe'; + +import localeFr from '@angular/common/locales/fr'; +import localeNl from '@angular/common/locales/nl'; +import localeDe from '@angular/common/locales/de'; + +registerLocaleData(localeFr) +registerLocaleData(localeNl) +registerLocaleData(localeDe) @NgModule({ declarations: [ @@ -108,7 +117,8 @@ import { SafePipe } from './pipes/safe.pipe'; MetadataCollapseComponent, SelectDialogComponent, NumberComponent, - SafePipe + SafePipe, + CustomDatePipe ], imports: [ BrowserModule, diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html index 1bf06b60f..d907c59d6 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html @@ -12,7 +12,7 @@ </thead> <tbody> <tr *ngFor="let doc of documents" routerLink="/documents/{{doc.id}}"> - <td>{{doc.created | date}}</td> + <td>{{doc.created | customDate}}</td> <td>{{doc.title | documentTitle}}<app-tag [tag]="t" *ngFor="let t of doc.tags$ | async" class="ml-1"></app-tag> </tr> </tbody> diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts index f200d8db9..7405c2848 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts @@ -16,7 +16,7 @@ export class SavedViewWidgetComponent implements OnInit { private documentService: DocumentService, private router: Router, private list: DocumentListViewService) { } - + @Input() savedView: PaperlessSavedView @@ -34,7 +34,7 @@ export class SavedViewWidgetComponent implements OnInit { } else { this.list.load(this.savedView) this.router.navigate(["documents"]) - } + } } } diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html index 7d5e93fbe..253d5b167 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.html +++ b/src-ui/src/app/components/document-detail/document-detail.component.html @@ -85,11 +85,11 @@ <tbody> <tr> <td i18n>Date modified</td> - <td>{{document.modified | date:'medium'}}</td> + <td>{{document.modified | customDate}}</td> </tr> <tr> <td i18n>Date added</td> - <td>{{document.added | date:'medium'}}</td> + <td>{{document.added | customDate}}</td> </tr> <tr> <td i18n>Media filename</td> diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html index c2ea9980b..85964f528 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html @@ -64,7 +64,7 @@ <ngb-progressbar [type]="searchScoreClass" [value]="searchScore" class="search-score-bar mx-2" [max]="1"></ngb-progressbar> </div> - <small class="text-muted" [class.ml-auto]="!searchScore" i18n>Created: {{document.created | date}}</small> + <small class="text-muted" [class.ml-auto]="!searchScore" i18n>Created: {{document.created | customDate}}</small> </div> </div> diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html index 4f11b2a98..a0d0299a5 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html @@ -50,7 +50,7 @@ </svg> </a> </div> - <small class="text-muted pl-1">{{document.created | date}}</small> + <small class="text-muted pl-1">{{document.created | customDate:'shortDate'}}</small> </div> </div> diff --git a/src-ui/src/app/components/document-list/document-list.component.html b/src-ui/src/app/components/document-list/document-list.component.html index 18f39bfb5..a29e146bf 100644 --- a/src-ui/src/app/components/document-list/document-list.component.html +++ b/src-ui/src/app/components/document-list/document-list.component.html @@ -160,10 +160,10 @@ </ng-container> </td> <td> - {{d.created | date}} + {{d.created | customDate}} </td> <td class="d-none d-xl-table-cell"> - {{d.added | date}} + {{d.added | customDate}} </td> </tr> </tbody> diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.html b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.html index 08704190e..ffe260d73 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.html +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.html @@ -21,7 +21,7 @@ <td scope="row">{{ correspondent.name }}</td> <td scope="row">{{ getMatching(correspondent) }}</td> <td scope="row">{{ correspondent.document_count }}</td> - <td scope="row">{{ correspondent.last_correspondence | date }}</td> + <td scope="row">{{ correspondent.last_correspondence | customDate }}</td> <td scope="row"> <div class="btn-group"> <button class="btn btn-sm btn-outline-secondary" (click)="filterDocuments(correspondent)"> diff --git a/src-ui/src/app/components/manage/logs/logs.component.html b/src-ui/src/app/components/manage/logs/logs.component.html index d21cea60d..be14faf1d 100644 --- a/src-ui/src/app/components/manage/logs/logs.component.html +++ b/src-ui/src/app/components/manage/logs/logs.component.html @@ -20,7 +20,7 @@ <p class="m-0 p-0 log-entry-{{log.level}}" *ngFor="let log of logs"> - {{log.created | date:'short'}} + {{log.created | customDate:'short'}} {{getLevelText(log.level)}} {{log.message}} </p> diff --git a/src-ui/src/app/components/manage/settings/settings.component.html b/src-ui/src/app/components/manage/settings/settings.component.html index e7fac646f..d5acfb149 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.html +++ b/src-ui/src/app/components/manage/settings/settings.component.html @@ -19,7 +19,7 @@ <div class="col"> <select class="form-control" formControlName="displayLanguage"> - <option *ngFor="let lang of languages" [ngValue]="lang.code">{{lang.name}}</option> + <option *ngFor="let lang of displayLanguageOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> ({{lang.englishName}})</span></option> </select> <small class="form-text text-muted" i18n>You need to reload the page after applying a new language.</small> @@ -27,6 +27,41 @@ </div> </div> + <div class="form-row form-group"> + <div class="col-md-3 col-form-label"> + <span i18n>Date display</span> + </div> + <div class="col"> + + <select class="form-control" formControlName="dateLocale"> + <option *ngFor="let lang of dateLocaleOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> ({{today | date:'shortDate':null:lang.code}})</span></option> + </select> + + </div> + </div> + + <div class="form-row form-group"> + <div class="col-md-3 col-form-label"> + <span i18n>Date format</span> + </div> + <div class="col"> + + <div class="custom-control custom-radio"> + <input type="radio" id="dateFormatShort" name="dateFormat" class="custom-control-input" formControlName="dateFormat" value="shortDate"> + <label class="custom-control-label" for="dateFormatShort" i18n>Short: {{today | customDate:'shortDate'}}</label> + </div> + <div class="custom-control custom-radio"> + <input type="radio" id="dateFormatMedium" name="dateFormat" class="custom-control-input" formControlName="dateFormat" value="mediumDate"> + <label class="custom-control-label" for="dateFormatMedium" i18n>Medium: {{today | customDate:'mediumDate'}}</label> + </div> + <div class="custom-control custom-radio"> + <input type="radio" id="dateFormatLong" name="dateFormat" class="custom-control-input" formControlName="dateFormat" value="longDate"> + <label class="custom-control-label" for="dateFormatLong" i18n>Long: {{today | customDate:'longDate'}}</label> + </div> + + </div> + </div> + <div class="form-row form-group"> <div class="col-md-3 col-form-label"> <span i18n>Items per page</span> diff --git a/src-ui/src/app/components/manage/settings/settings.component.ts b/src-ui/src/app/components/manage/settings/settings.component.ts index f0d83a15f..8c1517800 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.ts +++ b/src-ui/src/app/components/manage/settings/settings.component.ts @@ -3,7 +3,7 @@ import { FormControl, FormGroup } from '@angular/forms'; import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; import { DocumentListViewService } from 'src/app/services/document-list-view.service'; import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; +import { LanguageOption, SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; import { ToastService } from 'src/app/services/toast.service'; @Component({ @@ -23,7 +23,9 @@ export class SettingsComponent implements OnInit { 'darkModeEnabled': new FormControl(this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED)), 'useNativePdfViewer': new FormControl(this.settings.get(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER)), 'savedViews': this.savedViewGroup, - 'displayLanguage': new FormControl(this.settings.getLanguage()) + 'displayLanguage': new FormControl(this.settings.getLanguage()), + 'dateLocale': new FormControl(this.settings.get(SETTINGS_KEYS.DATE_LOCALE)), + 'dateFormat': new FormControl(this.settings.get(SETTINGS_KEYS.DATE_FORMAT)), }) savedViews: PaperlessSavedView[] @@ -64,14 +66,24 @@ export class SettingsComponent implements OnInit { this.settings.set(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem) this.settings.set(SETTINGS_KEYS.DARK_MODE_ENABLED, (this.settingsForm.value.darkModeEnabled == true).toString()) this.settings.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, this.settingsForm.value.useNativePdfViewer) + this.settings.set(SETTINGS_KEYS.DATE_LOCALE, this.settingsForm.value.dateLocale) + this.settings.set(SETTINGS_KEYS.DATE_FORMAT, this.settingsForm.value.dateFormat) this.settings.setLanguage(this.settingsForm.value.displayLanguage) this.documentListViewService.updatePageSize() this.settings.updateDarkModeSettings() this.toastService.showInfo($localize`Settings saved successfully.`) } - get languages() { - return this.settings.getLanguageOptions() + get displayLanguageOptions(): LanguageOption[] { + return [{code: "", name: $localize`Use system language`}].concat(this.settings.getLanguageOptions()) + } + + get dateLocaleOptions(): LanguageOption[] { + return [{code: "", name: $localize`Use same as display language`}].concat(this.settings.getLanguageOptions()) + } + + get today() { + return new Date() } saveSettings() { diff --git a/src-ui/src/app/pipes/custom-date.pipe.spec.ts b/src-ui/src/app/pipes/custom-date.pipe.spec.ts new file mode 100644 index 000000000..822966baf --- /dev/null +++ b/src-ui/src/app/pipes/custom-date.pipe.spec.ts @@ -0,0 +1,8 @@ +import { CustomDatePipe } from './custom-date.pipe'; + +describe('CustomDatePipe', () => { + it('create an instance', () => { + const pipe = new CustomDatePipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src-ui/src/app/pipes/custom-date.pipe.ts b/src-ui/src/app/pipes/custom-date.pipe.ts new file mode 100644 index 000000000..19989fbdd --- /dev/null +++ b/src-ui/src/app/pipes/custom-date.pipe.ts @@ -0,0 +1,19 @@ +import { DatePipe } from '@angular/common'; +import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; +import { SettingsService, SETTINGS_KEYS } from '../services/settings.service'; + +@Pipe({ + name: 'customDate' +}) +export class CustomDatePipe extends DatePipe implements PipeTransform { + + constructor(@Inject(LOCALE_ID) locale: string, private settings: SettingsService) { + super(settings.get(SETTINGS_KEYS.DATE_LOCALE) || locale) + + } + + transform(value: any, format?: string, timezone?: string, locale?: string): string | null { + return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, locale) + } + +} diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index 50adcf5a7..04918d835 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -9,13 +9,21 @@ export interface PaperlessSettings { default: any } +export interface LanguageOption { + code: string, + name: string, + englishName?: string +} + export const SETTINGS_KEYS = { BULK_EDIT_CONFIRMATION_DIALOGS: 'general-settings:bulk-edit:confirmation-dialogs', BULK_EDIT_APPLY_ON_CLOSE: 'general-settings:bulk-edit:apply-on-close', DOCUMENT_LIST_SIZE: 'general-settings:documentListSize', DARK_MODE_USE_SYSTEM: 'general-settings:dark-mode:use-system', DARK_MODE_ENABLED: 'general-settings:dark-mode:enabled', - USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer' + USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer', + DATE_LOCALE: 'general-settings:date-display:date-locale', + DATE_FORMAT: 'general-settings:date-display:date-format' } const SETTINGS: PaperlessSettings[] = [ @@ -24,7 +32,9 @@ const SETTINGS: PaperlessSettings[] = [ {key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: "number", default: 50}, {key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: "boolean", default: true}, {key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: "boolean", default: false}, - {key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: "boolean", default: false} + {key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: "boolean", default: false}, + {key: SETTINGS_KEYS.DATE_LOCALE, type: "string", default: "de"}, + {key: SETTINGS_KEYS.DATE_FORMAT, type: "string", default: "mediumDate"} ] @Injectable({ @@ -59,13 +69,12 @@ export class SettingsService { } - getLanguageOptions() { + getLanguageOptions(): LanguageOption[] { return [ - {code: "", name: $localize`Use system language`}, - {code: "en-us", name: `${$localize`English`} (English)`}, - {code: "de", name: `${$localize`German`} (German)`}, - {code: "nl", name: `${$localize`Dutch`} (Dutch)`}, - {code: "fr", name: `${$localize`French`} (French)`} + {code: "en-us", name: $localize`English`, englishName: "English"}, + {code: "de", name: $localize`German`, englishName: "German"}, + {code: "nl", name: $localize`Dutch`, englishName: "Dutch"}, + {code: "fr", name: $localize`French`, englishName: "French"} ] }