mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-40136 Migrate locale settings to signals (#11361)
This commit is contained in:
@@ -8,6 +8,8 @@ runs:
|
|||||||
with:
|
with:
|
||||||
path: dist
|
path: dist
|
||||||
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
|
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
restore-keys: |
|
||||||
|
dist-${{ github.run_id }}-
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
|
||||||
- name: Restore nxcache from cache
|
- name: Restore nxcache from cache
|
||||||
@@ -15,6 +17,8 @@ runs:
|
|||||||
with:
|
with:
|
||||||
path: nxcache
|
path: nxcache
|
||||||
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
|
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
restore-keys: |
|
||||||
|
nxcache-${{ github.run_id }}-
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
|
||||||
- name: Restore node_modules from cache
|
- name: Restore node_modules from cache
|
||||||
@@ -22,6 +26,8 @@ runs:
|
|||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
|
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
restore-keys: |
|
||||||
|
node-modules-${{ github.run_id }}-
|
||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
|
||||||
- name: show files
|
- name: show files
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
Title: User Preferences Service
|
Title: User Preferences Service
|
||||||
Added: v2.0.0
|
Added: v2.0.0
|
||||||
Status: Active
|
Status: Active
|
||||||
Last reviewed: 2019-01-16
|
Last reviewed: 2025-11-20
|
||||||
---
|
---
|
||||||
|
|
||||||
# [User Preferences Service](../../../lib/core/src/lib/common/services/user-preferences.service.ts "Defined in user-preferences.service.ts")
|
# User Preferences Service
|
||||||
|
|
||||||
Stores preferences for the app and for individual components.
|
Stores preferences for the app and for individual components.
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@ Stores preferences for the app and for individual components.
|
|||||||
Check if an item is present in the storage
|
Check if an item is present in the storage
|
||||||
- _property:_ `string` - Name of the property
|
- _property:_ `string` - Name of the property
|
||||||
- **Returns** `boolean` - True if the item is present, false otherwise
|
- **Returns** `boolean` - True if the item is present, false otherwise
|
||||||
- **select**(property: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/>
|
- **select**(property: `string`): `Observable<any>`<br/>
|
||||||
Sets up a callback to notify when a property has changed.
|
Sets up a callback to notify when a property has changed.
|
||||||
- _property:_ `string` - The property to watch
|
- _property:_ `string` - The property to watch
|
||||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<any>` - Notification callback
|
- **Returns** `Observable<any>` - Notification callback
|
||||||
- **set**(property: `string`, value: `any`)<br/>
|
- **set**(property: `string`, value: `any`)<br/>
|
||||||
Sets a preference property.
|
Sets a preference property.
|
||||||
- _property:_ `string` - Name of the property
|
- _property:_ `string` - Name of the property
|
||||||
@@ -71,7 +71,7 @@ class AppComponent {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
As soon as you assign the storage prefix, all settings that you get or set via the [`UserPreferencesService`](../../core/services/user-preferences.service.md) will be saved to a dedicated profile.
|
As soon as you assign the storage prefix, all settings that you get or set via the `UserPreferencesService` will be saved to a dedicated profile.
|
||||||
|
|
||||||
You can import the service into your controller and use its APIs as shown below:
|
You can import the service into your controller and use its APIs as shown below:
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ The service also provides quick access to a set of the "known" properties used a
|
|||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| authType | `string` | Authorization type (can be "ECM", "BPM" or "ALL"). |
|
| authType | `string` | Authorization type (can be "ECM", "BPM" or "ALL"). |
|
||||||
| disableCSRF | `boolean` | Prevents the CSRF Token from being submitted if true. Only valid for Process Services. |
|
| disableCSRF | `boolean` | Prevents the CSRF Token from being submitted if true. Only valid for Process Services. |
|
||||||
| paginationSize | `number` | [`Pagination`](../../../lib/content-services/document-list/models/document-library.model.ts) size. |
|
| paginationSize | `number` | `Pagination` size. |
|
||||||
| locale | `string` | Current locale setting. |
|
| locale | `string` | Current locale setting. |
|
||||||
|
|
||||||
## User Preference onChange Stream
|
## User Preference onChange Stream
|
||||||
@@ -112,7 +112,13 @@ whole set of user properties. This is useful when a component needs to react to
|
|||||||
```
|
```
|
||||||
|
|
||||||
You can also use the `select` method to get notification when a particular property is changed.
|
You can also use the `select` method to get notification when a particular property is changed.
|
||||||
A set of basic properties is added into the enumeration [`UserPreferenceValues`](lib/core/src/lib/services/user-preferences.service.ts) which gives you the key value to access the standard user preference service properties : **PaginationSize**, **DisableCSRF**, **Locale**, **SupportedPageSizes** and **ExpandedSideNavStatus**.
|
A set of basic properties is added into the enumeration `UserPreferenceValues` which gives you the key value to access the standard user preference service properties:
|
||||||
|
|
||||||
|
- `PaginationSize`
|
||||||
|
- `DisableCSRF`
|
||||||
|
- `Locale`
|
||||||
|
- `SupportedPageSizes`
|
||||||
|
- `ExpandedSideNavStatus`
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
userPreferences.disableCSRF = true;
|
userPreferences.disableCSRF = true;
|
||||||
@@ -120,3 +126,58 @@ A set of basic properties is added into the enumeration [`UserPreferenceValues`]
|
|||||||
console.log(CSRFflag); //this will be true;
|
console.log(CSRFflag); //this will be true;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Convenience Observables and Signals
|
||||||
|
|
||||||
|
For commonly accessed preferences like `locale`, the service provides both observables and signals that simplify access patterns.
|
||||||
|
|
||||||
|
#### Using Signals (Recommended - No Subscription Needed!)
|
||||||
|
|
||||||
|
Signals automatically handle cleanup and don't require manual unsubscription:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export class MyComponent {
|
||||||
|
private userPreferences = inject(UserPreferencesService);
|
||||||
|
|
||||||
|
// Signal - automatically reactive, no subscription needed!
|
||||||
|
currentLocale = this.userPreferences.localeSignal;
|
||||||
|
|
||||||
|
// Use in template or computed values
|
||||||
|
displayText = computed(() => `Current locale: ${this.currentLocale()}`);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Available signals:
|
||||||
|
|
||||||
|
- `localeSignal` - Current locale value
|
||||||
|
- `paginationSizeSignal` - Current pagination size
|
||||||
|
- `supportedPageSizesSignal` - Supported page sizes array
|
||||||
|
|
||||||
|
**Benefits of signals:**
|
||||||
|
|
||||||
|
- ✅ No manual subscription/unsubscription needed
|
||||||
|
- ✅ Automatic cleanup when component is destroyed
|
||||||
|
- ✅ Better performance with fine-grained reactivity
|
||||||
|
- ✅ Simpler code - just read the value with `()`
|
||||||
|
|
||||||
|
#### Using Observables (For Advanced Cases)
|
||||||
|
|
||||||
|
If you need RxJS operators or imperative subscriptions:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
constructor(private userPreferences: UserPreferencesService) {
|
||||||
|
// Observable - requires takeUntilDestroyed() to prevent memory leaks
|
||||||
|
this.userPreferences.locale$
|
||||||
|
.pipe(takeUntilDestroyed())
|
||||||
|
.subscribe(locale => {
|
||||||
|
this.currentLocale = locale;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Available observables:
|
||||||
|
- `locale$` - Observable for locale changes
|
||||||
|
- `paginationSize$` - Observable for pagination size changes
|
||||||
|
- `supportedPageSizes$` - Observable for supported page sizes changes
|
||||||
|
|
||||||
|
**Note:** When subscribing to observables from a singleton service in a component, always use `takeUntilDestroyed()` or `takeUntil()` to prevent memory leaks.
|
||||||
|
|||||||
+9
-7
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, DestroyRef, EventEmitter, inject, Inject, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
import { Component, DestroyRef, effect, EventEmitter, inject, Inject, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||||
import { endOfDay, isAfter, isBefore, isValid, parse } from 'date-fns';
|
import { endOfDay, isAfter, isBefore, isValid, parse } from 'date-fns';
|
||||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core';
|
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core';
|
||||||
import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter';
|
import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter';
|
||||||
@@ -23,7 +23,7 @@ import { InLastDateType } from './in-last-date-type';
|
|||||||
import { DateRangeType } from './date-range-type';
|
import { DateRangeType } from './date-range-type';
|
||||||
import { SearchDateRange } from './search-date-range';
|
import { SearchDateRange } from './search-date-range';
|
||||||
import { FormBuilder, ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms';
|
||||||
import { DateFnsUtils, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
import { DateFnsUtils, UserPreferencesService } from '@alfresco/adf-core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
@@ -100,7 +100,13 @@ export class SearchDateRangeComponent implements OnInit {
|
|||||||
private userPreferencesService: UserPreferencesService,
|
private userPreferencesService: UserPreferencesService,
|
||||||
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
||||||
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats
|
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats
|
||||||
) {}
|
) {
|
||||||
|
// Use effect to react to locale signal changes (must be in injection context)
|
||||||
|
effect(() => {
|
||||||
|
const locale = this.userPreferencesService.localeSignal();
|
||||||
|
this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
readonly endDateValidator = (formControl: UntypedFormControl): { [key: string]: boolean } | null => {
|
readonly endDateValidator = (formControl: UntypedFormControl): { [key: string]: boolean } | null => {
|
||||||
if (isBefore(formControl.value, this.betweenStartDateFormControl.value) || isAfter(formControl.value, this.convertedMaxDate)) {
|
if (isBefore(formControl.value, this.betweenStartDateFormControl.value) || isAfter(formControl.value, this.convertedMaxDate)) {
|
||||||
@@ -114,10 +120,6 @@ export class SearchDateRangeComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.dateFormatConfig.display.dateInput = this.dateFormat;
|
this.dateFormatConfig.display.dateInput = this.dateFormat;
|
||||||
this.convertedMaxDate = endOfDay(this.maxDate && this.maxDate !== 'today' ? parse(this.maxDate, this.dateFormat, new Date()) : new Date());
|
this.convertedMaxDate = endOfDay(this.maxDate && this.maxDate !== 'today' ? parse(this.maxDate, this.dateFormat, new Date()) : new Date());
|
||||||
this.userPreferencesService
|
|
||||||
.select(UserPreferenceValues.Locale)
|
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
||||||
.subscribe((locale) => this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale)));
|
|
||||||
this.form.controls.dateRangeType.valueChanges
|
this.form.controls.dateRangeType.valueChanges
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe((dateRangeType) => this.updateValidators(dateRangeType));
|
.subscribe((dateRangeType) => this.updateValidators(dateRangeType));
|
||||||
|
|||||||
+6
-12
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, DestroyRef, inject, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
import { Component, effect, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
||||||
import {
|
import {
|
||||||
DatetimeAdapter,
|
DatetimeAdapter,
|
||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
MatDatetimepickerModule
|
MatDatetimepickerModule
|
||||||
} from '@mat-datetimepicker/core';
|
} from '@mat-datetimepicker/core';
|
||||||
import { CardViewDateItemModel } from '../../models/card-view-dateitem.model';
|
import { CardViewDateItemModel } from '../../models/card-view-dateitem.model';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../../../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../../../common/services/user-preferences.service';
|
||||||
import { BaseCardView } from '../base-card-view';
|
import { BaseCardView } from '../base-card-view';
|
||||||
import { ClipboardService } from '../../../clipboard/clipboard.service';
|
import { ClipboardService } from '../../../clipboard/clipboard.service';
|
||||||
import { TranslationService } from '../../../translation/translation.service';
|
import { TranslationService } from '../../../translation/translation.service';
|
||||||
@@ -40,7 +40,6 @@ import { MatChipsModule } from '@angular/material/chips';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
|
||||||
@@ -83,8 +82,6 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
|||||||
|
|
||||||
cardViewDateTimeControl: FormControl<Date> = new FormControl<Date>(null);
|
cardViewDateTimeControl: FormControl<Date> = new FormControl<Date>(null);
|
||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dateAdapter: DateAdapter<Date>,
|
private dateAdapter: DateAdapter<Date>,
|
||||||
private userPreferencesService: UserPreferencesService,
|
private userPreferencesService: UserPreferencesService,
|
||||||
@@ -92,16 +89,13 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
|||||||
private translateService: TranslationService
|
private translateService: TranslationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
// Use effect to react to locale signal changes (must be in injection context)
|
||||||
|
effect(() => {
|
||||||
|
this.property.locale = this.userPreferencesService.localeSignal();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.userPreferencesService
|
|
||||||
.select(UserPreferenceValues.Locale)
|
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
||||||
.subscribe((locale) => {
|
|
||||||
this.property.locale = locale;
|
|
||||||
});
|
|
||||||
|
|
||||||
(this.dateAdapter as AdfDateFnsAdapter).displayFormat = 'MMM DD';
|
(this.dateAdapter as AdfDateFnsAdapter).displayFormat = 'MMM DD';
|
||||||
|
|
||||||
if (this.property.multivalued) {
|
if (this.property.multivalued) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { inject, Injectable, RendererFactory2 } from '@angular/core';
|
import { inject, Injectable, RendererFactory2, Signal } from '@angular/core';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Observable, BehaviorSubject } from 'rxjs';
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
@@ -25,6 +25,7 @@ import { LanguageItem } from './language-item.interface';
|
|||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { Directionality, Direction } from '@angular/cdk/bidi';
|
import { Directionality, Direction } from '@angular/cdk/bidi';
|
||||||
import { DEFAULT_LANGUAGE_LIST } from '../models/default-languages.model';
|
import { DEFAULT_LANGUAGE_LIST } from '../models/default-languages.model';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
export enum UserPreferenceValues {
|
export enum UserPreferenceValues {
|
||||||
@@ -53,10 +54,78 @@ export class UserPreferencesService {
|
|||||||
private onChangeSubject: BehaviorSubject<any>;
|
private onChangeSubject: BehaviorSubject<any>;
|
||||||
onChange: Observable<any>;
|
onChange: Observable<any>;
|
||||||
|
|
||||||
constructor(public translate: TranslateService, private appConfig: AppConfigService, private storage: StorageService) {
|
/**
|
||||||
|
* Observable that emits the current locale whenever it changes.
|
||||||
|
* This is a convenience property that simplifies subscribing to locale changes.
|
||||||
|
*
|
||||||
|
* @example Observable usage (requires manual unsubscription):
|
||||||
|
* ```typescript
|
||||||
|
* constructor(private userPreferencesService: UserPreferencesService) {
|
||||||
|
* this.userPreferencesService.locale$
|
||||||
|
* .pipe(takeUntilDestroyed())
|
||||||
|
* .subscribe(locale => {
|
||||||
|
* this.currentLocale = locale;
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @example Signal usage (automatic cleanup, recommended):
|
||||||
|
* ```typescript
|
||||||
|
* export class MyComponent {
|
||||||
|
* private userPreferencesService = inject(UserPreferencesService);
|
||||||
|
* currentLocale = this.userPreferencesService.localeSignal; // Signal - no subscription needed!
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
readonly locale$: Observable<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that provides the current locale value.
|
||||||
|
* Automatically handles cleanup - no need for takeUntilDestroyed or manual unsubscription.
|
||||||
|
* This is the recommended way to access locale in components.
|
||||||
|
*/
|
||||||
|
readonly localeSignal: Signal<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable that emits the current pagination size whenever it changes.
|
||||||
|
*/
|
||||||
|
readonly paginationSize$: Observable<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that provides the current pagination size value.
|
||||||
|
*/
|
||||||
|
readonly paginationSizeSignal: Signal<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable that emits the supported page sizes whenever they change.
|
||||||
|
*/
|
||||||
|
readonly supportedPageSizes$: Observable<number[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that provides the supported page sizes array.
|
||||||
|
*/
|
||||||
|
readonly supportedPageSizesSignal: Signal<number[]>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public translate: TranslateService,
|
||||||
|
private appConfig: AppConfigService,
|
||||||
|
private storage: StorageService
|
||||||
|
) {
|
||||||
this.onChangeSubject = new BehaviorSubject(this.userPreferenceStatus);
|
this.onChangeSubject = new BehaviorSubject(this.userPreferenceStatus);
|
||||||
this.onChange = this.onChangeSubject.asObservable();
|
this.onChange = this.onChangeSubject.asObservable();
|
||||||
|
|
||||||
|
// Initialize convenience observables
|
||||||
|
this.locale$ = this.select<string>(UserPreferenceValues.Locale);
|
||||||
|
this.paginationSize$ = this.select<number>(UserPreferenceValues.PaginationSize);
|
||||||
|
this.supportedPageSizes$ = this.select<string>(UserPreferenceValues.SupportedPageSizes).pipe(
|
||||||
|
map((value) => (value ? JSON.parse(value) : this.defaults.supportedPageSizes))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize convenience signals (automatically handle cleanup)
|
||||||
|
this.localeSignal = toSignal(this.locale$, { initialValue: this.defaults.locale });
|
||||||
|
this.paginationSizeSignal = toSignal(this.paginationSize$, { initialValue: this.defaults.paginationSize });
|
||||||
|
this.supportedPageSizesSignal = toSignal(this.supportedPageSizes$, { initialValue: this.defaults.supportedPageSizes });
|
||||||
|
|
||||||
this.appConfig.onLoad.subscribe(() => {
|
this.appConfig.onLoad.subscribe(() => {
|
||||||
this.initUserPreferenceStatus();
|
this.initUserPreferenceStatus();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,10 +17,11 @@
|
|||||||
|
|
||||||
import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
|
||||||
import { DateFnsUtils } from './date-fns-utils';
|
import { DateFnsUtils } from './date-fns-utils';
|
||||||
import { Inject, Injectable, Optional } from '@angular/core';
|
import { effect, Inject, Injectable, Optional } from '@angular/core';
|
||||||
import { MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core';
|
import { MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core';
|
||||||
import { UserPreferenceValues, UserPreferencesService } from '../services/user-preferences.service';
|
import { UserPreferencesService } from '../services/user-preferences.service';
|
||||||
import { isValid, Locale, parse } from 'date-fns';
|
import { isValid, Locale, parse } from 'date-fns';
|
||||||
|
import { enUS } from 'date-fns/locale';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date-fns adapter with moment-to-date-fns conversion.
|
* Date-fns adapter with moment-to-date-fns conversion.
|
||||||
@@ -82,10 +83,24 @@ export class AdfDateFnsAdapter extends DateFnsAdapter {
|
|||||||
@Optional() @Inject(MAT_DATE_FORMATS) private formats: MatDateFormats,
|
@Optional() @Inject(MAT_DATE_FORMATS) private formats: MatDateFormats,
|
||||||
preferences: UserPreferencesService
|
preferences: UserPreferencesService
|
||||||
) {
|
) {
|
||||||
super(matDateLocale);
|
// Ensure we have a valid locale for the base class
|
||||||
|
// If matDateLocale is not provided, use enUS as default
|
||||||
|
super(matDateLocale || enUS);
|
||||||
|
|
||||||
preferences.select(UserPreferenceValues.Locale).subscribe((locale: string) => {
|
// Initialize locale synchronously from signal's initial value
|
||||||
this.setLocale(DateFnsUtils.getLocaleFromString(locale));
|
// This ensures locale is set before any format() calls
|
||||||
|
const initialLocale = preferences.localeSignal();
|
||||||
|
if (initialLocale) {
|
||||||
|
this.setLocale(DateFnsUtils.getLocaleFromString(initialLocale));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use effect to reactively update locale when signal changes
|
||||||
|
// Note: This adapter is a singleton service, so no cleanup needed
|
||||||
|
effect(() => {
|
||||||
|
const locale = preferences.localeSignal();
|
||||||
|
if (locale) {
|
||||||
|
this.setLocale(DateFnsUtils.getLocaleFromString(locale));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { effect, Injectable } from '@angular/core';
|
||||||
import { DateAdapter } from '@angular/material/core';
|
import { DateAdapter } from '@angular/material/core';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
|
import { UserPreferencesService } from '../services/user-preferences.service';
|
||||||
|
|
||||||
// Stub for the moment.js integration.
|
// Stub for the moment.js integration.
|
||||||
// While this dependency is no longer used by the libraries, the moment adapter can still discover the moment.js linked to the application
|
// While this dependency is no longer used by the libraries, the moment adapter can still discover the moment.js linked to the application
|
||||||
@@ -37,7 +37,10 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
|
|||||||
constructor(preferences: UserPreferencesService) {
|
constructor(preferences: UserPreferencesService) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
preferences.select(UserPreferenceValues.Locale).subscribe((locale: string) => {
|
// Use effect to reactively update locale when signal changes
|
||||||
|
// Note: This adapter is a singleton service, so no cleanup needed
|
||||||
|
effect(() => {
|
||||||
|
const locale = preferences.localeSignal();
|
||||||
this.setLocale(locale);
|
this.setLocale(locale);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, inject, ChangeDetectorRef } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation, inject, ChangeDetectorRef, effect } from '@angular/core';
|
||||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||||
import { AppConfigService } from '../../../app-config/app-config.service';
|
import { AppConfigService } from '../../../app-config/app-config.service';
|
||||||
import { DateConfig } from '../../data/data-column.model';
|
import { DateConfig } from '../../data/data-column.model';
|
||||||
import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
|
import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../../../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../../../common/services/user-preferences.service';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [LocalizedDatePipe, TimeAgoPipe, AsyncPipe],
|
imports: [LocalizedDatePipe, TimeAgoPipe, AsyncPipe],
|
||||||
@@ -52,19 +51,18 @@ export class DateCellComponent extends DataTableCellComponent implements OnInit
|
|||||||
locale: undefined
|
locale: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
ngOnInit(): void {
|
constructor() {
|
||||||
// Subscribe to locale changes
|
super();
|
||||||
this.userPreferencesService
|
// Use effect to react to locale signal changes (must be in injection context)
|
||||||
.select(UserPreferenceValues.Locale)
|
effect(() => {
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
this.userLocale = this.userPreferencesService.localeSignal() || 'en';
|
||||||
.subscribe((locale) => {
|
this.setConfig();
|
||||||
this.userLocale = locale || 'en';
|
this.updateValue(); // Recalculate computedTitle with new locale
|
||||||
this.setConfig();
|
this.cdr.markForCheck();
|
||||||
this.updateValue(); // Recalculate computedTitle with new locale
|
});
|
||||||
this.cdr.markForCheck();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.setConfig();
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,8 @@
|
|||||||
import { DecimalPipe } from '@angular/common';
|
import { DecimalPipe } from '@angular/common';
|
||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { AppConfigService } from '../app-config/app-config.service';
|
import { AppConfigService } from '../app-config/app-config.service';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../common/services/user-preferences.service';
|
||||||
import { DecimalNumberModel } from '../models/decimal-number.model';
|
import { DecimalNumberModel } from '../models/decimal-number.model';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'adfDecimalNumber',
|
name: 'adfDecimalNumber',
|
||||||
@@ -32,22 +31,14 @@ export class DecimalNumberPipe implements PipeTransform {
|
|||||||
static DEFAULT_MIN_FRACTION_DIGITS = 0;
|
static DEFAULT_MIN_FRACTION_DIGITS = 0;
|
||||||
static DEFAULT_MAX_FRACTION_DIGITS = 2;
|
static DEFAULT_MAX_FRACTION_DIGITS = 2;
|
||||||
|
|
||||||
defaultLocale: string = DecimalNumberPipe.DEFAULT_LOCALE;
|
|
||||||
defaultMinIntegerDigits: number = DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS;
|
defaultMinIntegerDigits: number = DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS;
|
||||||
defaultMinFractionDigits: number = DecimalNumberPipe.DEFAULT_MIN_FRACTION_DIGITS;
|
defaultMinFractionDigits: number = DecimalNumberPipe.DEFAULT_MIN_FRACTION_DIGITS;
|
||||||
defaultMaxFractionDigits: number = DecimalNumberPipe.DEFAULT_MAX_FRACTION_DIGITS;
|
defaultMaxFractionDigits: number = DecimalNumberPipe.DEFAULT_MAX_FRACTION_DIGITS;
|
||||||
constructor(public userPreferenceService?: UserPreferencesService, public appConfig?: AppConfigService) {
|
|
||||||
if (this.userPreferenceService) {
|
|
||||||
this.userPreferenceService
|
|
||||||
.select(UserPreferenceValues.Locale)
|
|
||||||
.pipe(takeUntilDestroyed())
|
|
||||||
.subscribe((locale) => {
|
|
||||||
if (locale) {
|
|
||||||
this.defaultLocale = locale;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public userPreferenceService?: UserPreferencesService,
|
||||||
|
public appConfig?: AppConfigService
|
||||||
|
) {
|
||||||
if (this.appConfig) {
|
if (this.appConfig) {
|
||||||
this.defaultMinIntegerDigits = this.appConfig.get<number>('decimalValues.minIntegerDigits', DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS);
|
this.defaultMinIntegerDigits = this.appConfig.get<number>('decimalValues.minIntegerDigits', DecimalNumberPipe.DEFAULT_MIN_INTEGER_DIGITS);
|
||||||
this.defaultMinFractionDigits = this.appConfig.get<number>(
|
this.defaultMinFractionDigits = this.appConfig.get<number>(
|
||||||
@@ -67,7 +58,9 @@ export class DecimalNumberPipe implements PipeTransform {
|
|||||||
const actualMaxFractionDigits: number = digitsInfo?.maxFractionDigits ? digitsInfo.maxFractionDigits : this.defaultMaxFractionDigits;
|
const actualMaxFractionDigits: number = digitsInfo?.maxFractionDigits ? digitsInfo.maxFractionDigits : this.defaultMaxFractionDigits;
|
||||||
|
|
||||||
const actualDigitsInfo = `${actualMinIntegerDigits}.${actualMinFractionDigits}-${actualMaxFractionDigits}`;
|
const actualDigitsInfo = `${actualMinIntegerDigits}.${actualMinFractionDigits}-${actualMaxFractionDigits}`;
|
||||||
const actualLocale = locale || this.defaultLocale;
|
// Use signal directly - no subscription needed!
|
||||||
|
const defaultLocale = this.userPreferenceService?.localeSignal() || DecimalNumberPipe.DEFAULT_LOCALE;
|
||||||
|
const actualLocale = locale || defaultLocale;
|
||||||
|
|
||||||
const decimalPipe: DecimalPipe = new DecimalPipe(actualLocale);
|
const decimalPipe: DecimalPipe = new DecimalPipe(actualLocale);
|
||||||
|
|
||||||
|
|||||||
@@ -16,38 +16,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { Pipe, PipeTransform, OnDestroy } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { AppConfigService } from '../app-config/app-config.service';
|
import { AppConfigService } from '../app-config/app-config.service';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../common/services/user-preferences.service';
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
name: 'adfLocalizedDate',
|
name: 'adfLocalizedDate',
|
||||||
pure: false
|
pure: false
|
||||||
})
|
})
|
||||||
export class LocalizedDatePipe implements PipeTransform, OnDestroy {
|
export class LocalizedDatePipe implements PipeTransform {
|
||||||
static DEFAULT_LOCALE = 'en-US';
|
static DEFAULT_LOCALE = 'en-US';
|
||||||
static DEFAULT_DATE_FORMAT = 'mediumDate';
|
static DEFAULT_DATE_FORMAT = 'mediumDate';
|
||||||
|
|
||||||
defaultLocale: string = LocalizedDatePipe.DEFAULT_LOCALE;
|
|
||||||
defaultFormat: string = LocalizedDatePipe.DEFAULT_DATE_FORMAT;
|
defaultFormat: string = LocalizedDatePipe.DEFAULT_DATE_FORMAT;
|
||||||
|
|
||||||
private onDestroy$ = new Subject<boolean>();
|
constructor(
|
||||||
|
public userPreferenceService?: UserPreferencesService,
|
||||||
constructor(public userPreferenceService?: UserPreferencesService, public appConfig?: AppConfigService) {
|
public appConfig?: AppConfigService
|
||||||
if (this.userPreferenceService) {
|
) {
|
||||||
this.userPreferenceService
|
|
||||||
.select(UserPreferenceValues.Locale)
|
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
|
||||||
.subscribe((locale) => {
|
|
||||||
if (locale) {
|
|
||||||
this.defaultLocale = locale;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.appConfig) {
|
if (this.appConfig) {
|
||||||
this.defaultFormat = this.appConfig.get<string>('dateValues.defaultDateFormat', LocalizedDatePipe.DEFAULT_DATE_FORMAT);
|
this.defaultFormat = this.appConfig.get<string>('dateValues.defaultDateFormat', LocalizedDatePipe.DEFAULT_DATE_FORMAT);
|
||||||
}
|
}
|
||||||
@@ -55,13 +42,10 @@ export class LocalizedDatePipe implements PipeTransform, OnDestroy {
|
|||||||
|
|
||||||
transform(value: Date | string | number, format?: string, locale?: string, timezone?: string): string {
|
transform(value: Date | string | number, format?: string, locale?: string, timezone?: string): string {
|
||||||
const actualFormat = format || this.defaultFormat;
|
const actualFormat = format || this.defaultFormat;
|
||||||
const actualLocale = locale || this.defaultLocale;
|
// Use signal directly - no subscription needed!
|
||||||
|
const defaultLocale = this.userPreferenceService?.localeSignal() || LocalizedDatePipe.DEFAULT_LOCALE;
|
||||||
|
const actualLocale = locale || defaultLocale;
|
||||||
const datePipe = timezone ? new DatePipe(actualLocale, timezone) : new DatePipe(actualLocale);
|
const datePipe = timezone ? new DatePipe(actualLocale, timezone) : new DatePipe(actualLocale);
|
||||||
return datePipe.transform(value, actualFormat);
|
return datePipe.transform(value, actualFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.onDestroy$.next(true);
|
|
||||||
this.onDestroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,9 @@
|
|||||||
|
|
||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { AppConfigService } from '../app-config/app-config.service';
|
import { AppConfigService } from '../app-config/app-config.service';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../common/services/user-preferences.service';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { differenceInDays, formatDistance } from 'date-fns';
|
import { differenceInDays, formatDistance } from 'date-fns';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
||||||
import { DateFnsUtils } from '../common/utils/date-fns-utils';
|
import { DateFnsUtils } from '../common/utils/date-fns-utils';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
@@ -32,25 +31,20 @@ export class TimeAgoPipe implements PipeTransform {
|
|||||||
static DEFAULT_LOCALE = 'en-US';
|
static DEFAULT_LOCALE = 'en-US';
|
||||||
static DEFAULT_DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm';
|
static DEFAULT_DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm';
|
||||||
|
|
||||||
defaultLocale: string;
|
|
||||||
defaultDateTimeFormat: string;
|
defaultDateTimeFormat: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public userPreferenceService: UserPreferencesService,
|
public userPreferenceService: UserPreferencesService,
|
||||||
public appConfig: AppConfigService
|
public appConfig: AppConfigService
|
||||||
) {
|
) {
|
||||||
this.userPreferenceService
|
|
||||||
.select(UserPreferenceValues.Locale)
|
|
||||||
.pipe(takeUntilDestroyed())
|
|
||||||
.subscribe((locale) => {
|
|
||||||
this.defaultLocale = locale || TimeAgoPipe.DEFAULT_LOCALE;
|
|
||||||
});
|
|
||||||
this.defaultDateTimeFormat = this.appConfig.get<string>('dateValues.defaultDateTimeFormat', TimeAgoPipe.DEFAULT_DATE_TIME_FORMAT);
|
this.defaultDateTimeFormat = this.appConfig.get<string>('dateValues.defaultDateTimeFormat', TimeAgoPipe.DEFAULT_DATE_TIME_FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
transform(value: Date, locale?: string) {
|
transform(value: Date, locale?: string) {
|
||||||
if (value !== null && value !== undefined) {
|
if (value !== null && value !== undefined) {
|
||||||
const actualLocale = locale || this.defaultLocale;
|
// Use signal directly - no subscription needed!
|
||||||
|
const defaultLocale = this.userPreferenceService.localeSignal() || TimeAgoPipe.DEFAULT_LOCALE;
|
||||||
|
const actualLocale = locale || defaultLocale;
|
||||||
const diff = differenceInDays(new Date(), new Date(value));
|
const diff = differenceInDays(new Date(), new Date(value));
|
||||||
if (diff > 7) {
|
if (diff > 7) {
|
||||||
const datePipe: DatePipe = new DatePipe(actualLocale);
|
const datePipe: DatePipe = new DatePipe(actualLocale);
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable, InjectionToken, Optional } from '@angular/core';
|
import { effect, Inject, Injectable, InjectionToken, Optional } from '@angular/core';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { TranslateLoaderService } from './translate-loader.service';
|
import { TranslateLoaderService } from './translate-loader.service';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../common/services/user-preferences.service';
|
import { UserPreferencesService } from '../common/services/user-preferences.service';
|
||||||
|
|
||||||
export const TRANSLATION_PROVIDER = new InjectionToken('Injection token for translation providers.');
|
export const TRANSLATION_PROVIDER = new InjectionToken('Injection token for translation providers.');
|
||||||
|
|
||||||
@@ -71,7 +71,10 @@ export class TranslationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => {
|
// Use effect to reactively update translations when locale signal changes
|
||||||
|
// Note: This is a singleton service, so no cleanup needed
|
||||||
|
effect(() => {
|
||||||
|
const locale = userPreferencesService.localeSignal();
|
||||||
if (locale) {
|
if (locale) {
|
||||||
this.userLang = locale;
|
this.userLang = locale;
|
||||||
this.use(this.userLang);
|
this.use(this.userLang);
|
||||||
|
|||||||
+4
-1
@@ -22,12 +22,14 @@ import { DateCloudFilterType } from '../../models/date-cloud-filter.model';
|
|||||||
import { DateRangeFilterService } from './date-range-filter.service';
|
import { DateRangeFilterService } from './date-range-filter.service';
|
||||||
import { mockFilterProperty } from '../mock/date-range-filter.mock';
|
import { mockFilterProperty } from '../mock/date-range-filter.mock';
|
||||||
import { add, endOfDay } from 'date-fns';
|
import { add, endOfDay } from 'date-fns';
|
||||||
|
import { enUS } from 'date-fns/locale';
|
||||||
import { HarnessLoader } from '@angular/cdk/testing';
|
import { HarnessLoader } from '@angular/cdk/testing';
|
||||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||||
import { MatSelectHarness } from '@angular/material/select/testing';
|
import { MatSelectHarness } from '@angular/material/select/testing';
|
||||||
import { MatFormFieldHarness } from '@angular/material/form-field/testing';
|
import { MatFormFieldHarness } from '@angular/material/form-field/testing';
|
||||||
import { MatDateRangeInputHarness } from '@angular/material/datepicker/testing';
|
import { MatDateRangeInputHarness } from '@angular/material/datepicker/testing';
|
||||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||||
|
import { MAT_DATE_LOCALE } from '@angular/material/core';
|
||||||
|
|
||||||
describe('DateRangeFilterComponent', () => {
|
describe('DateRangeFilterComponent', () => {
|
||||||
let component: DateRangeFilterComponent;
|
let component: DateRangeFilterComponent;
|
||||||
@@ -37,7 +39,8 @@ describe('DateRangeFilterComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [NoopTranslateModule, DateRangeFilterComponent]
|
imports: [NoopTranslateModule, DateRangeFilterComponent],
|
||||||
|
providers: [{ provide: MAT_DATE_LOCALE, useValue: enUS }]
|
||||||
});
|
});
|
||||||
fixture = TestBed.createComponent(DateRangeFilterComponent);
|
fixture = TestBed.createComponent(DateRangeFilterComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
+11
-10
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
import { Component, DestroyRef, effect, EventEmitter, inject, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { DateAdapter } from '@angular/material/core';
|
import { DateAdapter } from '@angular/material/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
ProcessFilterProperties,
|
ProcessFilterProperties,
|
||||||
ProcessSortFilterProperty
|
ProcessSortFilterProperty
|
||||||
} from '../../models/process-filter-cloud.model';
|
} from '../../models/process-filter-cloud.model';
|
||||||
import { DateFnsUtils, IconComponent, TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
import { DateFnsUtils, IconComponent, TranslationService, UserPreferencesService } from '@alfresco/adf-core';
|
||||||
import { ProcessFilterCloudService } from '../../services/process-filter-cloud.service';
|
import { ProcessFilterCloudService } from '../../services/process-filter-cloud.service';
|
||||||
import { ProcessFilterDialogCloudComponent } from '../process-filter-dialog/process-filter-dialog-cloud.component';
|
import { ProcessFilterDialogCloudComponent } from '../process-filter-dialog/process-filter-dialog-cloud.component';
|
||||||
import { ProcessCloudService } from '../../../services/process-cloud.service';
|
import { ProcessCloudService } from '../../../services/process-cloud.service';
|
||||||
@@ -101,7 +101,7 @@ interface ProcessFilterFormProps {
|
|||||||
styleUrls: ['./edit-process-filter-cloud.component.scss'],
|
styleUrls: ['./edit-process-filter-cloud.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class EditProcessFilterCloudComponent implements OnInit, OnChanges {
|
export class EditProcessFilterCloudComponent implements OnChanges {
|
||||||
/** The name of the application. */
|
/** The name of the application. */
|
||||||
@Input()
|
@Input()
|
||||||
appName: string = '';
|
appName: string = '';
|
||||||
@@ -228,13 +228,14 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges {
|
|||||||
private processFilterCloudService: ProcessFilterCloudService,
|
private processFilterCloudService: ProcessFilterCloudService,
|
||||||
private appsProcessCloudService: AppsProcessCloudService,
|
private appsProcessCloudService: AppsProcessCloudService,
|
||||||
private processCloudService: ProcessCloudService
|
private processCloudService: ProcessCloudService
|
||||||
) {}
|
) {
|
||||||
|
// Use effect to react to locale signal changes (must be in injection context)
|
||||||
ngOnInit() {
|
effect(() => {
|
||||||
this.userPreferencesService
|
const locale = this.userPreferencesService.localeSignal();
|
||||||
.select(UserPreferenceValues.Locale)
|
if (locale) {
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale));
|
||||||
.subscribe((locale) => this.dateAdapter.setLocale(locale));
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
|||||||
+11
-8
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DestroyRef, Directive, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
import { DestroyRef, Directive, effect, EventEmitter, inject, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||||
import { AssignmentType, FilterOptions, TaskFilterAction, TaskFilterProperties, TaskStatusFilter } from '../../models/filter-cloud.model';
|
import { AssignmentType, FilterOptions, TaskFilterAction, TaskFilterProperties, TaskStatusFilter } from '../../models/filter-cloud.model';
|
||||||
import { TaskCloudService } from './../../../services/task-cloud.service';
|
import { TaskCloudService } from './../../../services/task-cloud.service';
|
||||||
import { AppsProcessCloudService } from './../../../../app/services/apps-process-cloud.service';
|
import { AppsProcessCloudService } from './../../../../app/services/apps-process-cloud.service';
|
||||||
@@ -24,7 +24,7 @@ import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/
|
|||||||
import { debounceTime, filter, finalize, switchMap } from 'rxjs/operators';
|
import { debounceTime, filter, finalize, switchMap } from 'rxjs/operators';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { DateAdapter } from '@angular/material/core';
|
import { DateAdapter } from '@angular/material/core';
|
||||||
import { DateFnsUtils, TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
import { DateFnsUtils, TranslationService, UserPreferencesService } from '@alfresco/adf-core';
|
||||||
import { TaskFilterDialogCloudComponent } from '../task-filter-dialog/task-filter-dialog-cloud.component';
|
import { TaskFilterDialogCloudComponent } from '../task-filter-dialog/task-filter-dialog-cloud.component';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { IdentityUserModel } from '../../../../people/models/identity-user.model';
|
import { IdentityUserModel } from '../../../../people/models/identity-user.model';
|
||||||
@@ -55,7 +55,7 @@ const ORDER_PROPERTY = 'order';
|
|||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||||
export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnChanges {
|
export abstract class BaseEditTaskFilterCloudComponent<T> implements OnChanges {
|
||||||
public static ACTIONS_DISABLED_BY_DEFAULT = [ACTION_SAVE, ACTION_DELETE];
|
public static ACTIONS_DISABLED_BY_DEFAULT = [ACTION_SAVE, ACTION_DELETE];
|
||||||
|
|
||||||
/** (required) Name of the app. */
|
/** (required) Name of the app. */
|
||||||
@@ -145,11 +145,14 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
|
|||||||
protected formBuilder = inject(UntypedFormBuilder);
|
protected formBuilder = inject(UntypedFormBuilder);
|
||||||
protected dateAdapter = inject<DateAdapter<Date>>(DateAdapter);
|
protected dateAdapter = inject<DateAdapter<Date>>(DateAdapter);
|
||||||
|
|
||||||
ngOnInit() {
|
constructor() {
|
||||||
this.userPreferencesService
|
// Use effect to react to locale signal changes (must be in injection context)
|
||||||
.select(UserPreferenceValues.Locale)
|
effect(() => {
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
const locale = this.userPreferencesService.localeSignal();
|
||||||
.subscribe((locale) => this.dateAdapter.setLocale(locale));
|
if (locale) {
|
||||||
|
this.dateAdapter.setLocale(DateFnsUtils.getLocaleFromString(locale));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
|||||||
Reference in New Issue
Block a user