Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {WrappedBoolean} from "../data-field-template/models/wrapped-boolean";
})
export abstract class AbstractBaseDataFieldComponent<T extends DataField<unknown>> implements OnDestroy {

private static readonly TRUE_VALUES = ['true', '1', 'yes', 'y', 'ano', 'áno', 'pravda'];
private static readonly FALSE_VALUES = ['false', '0', 'no', 'n', 'nie', 'nepravda'];

@Input() public dataField: T;
@Input() public formControlRef: FormControl;
@Input() public showLargeLayout: WrappedBoolean;
Expand All @@ -21,7 +24,7 @@ export abstract class AbstractBaseDataFieldComponent<T extends DataField<unknown
this.showLargeLayout = dataFieldPortalData.showLargeLayout;
if (!this.dataField.initialized) {
this.formControlRef = new FormControl('', {updateOn: this.dataField.getUpdateOnStrategy()});
this.dataField.registerFormControl(this.formControlRef)
this.dataField.registerFormControl(this.formControlRef);
}
}
}
Expand All @@ -35,6 +38,51 @@ export abstract class AbstractBaseDataFieldComponent<T extends DataField<unknown
&& property in this.dataField.component.properties;
}

public getBooleanComponentProperty(property: string, defaultValue = false): boolean {
return AbstractBaseDataFieldComponent.resolveBooleanProperty(
this.dataField?.component?.properties?.[property],
defaultValue
);
}

public getNumberComponentProperty(property: string, defaultValue: number): number {
return AbstractBaseDataFieldComponent.resolveNumberProperty(
this.dataField?.component?.properties?.[property],
defaultValue
);
}

public static resolveBooleanProperty(value: unknown, defaultValue = false): boolean {
if (value === undefined || value === null || value === '') {
return defaultValue;
}

if (typeof value === 'boolean') {
return value;
}

if (typeof value === 'string') {
const normalized = value.trim().toLowerCase();
if (AbstractBaseDataFieldComponent.TRUE_VALUES.includes(normalized)) {
return true;
}
if (AbstractBaseDataFieldComponent.FALSE_VALUES.includes(normalized)) {
return false;
}
return defaultValue;
}
return Boolean(value);
}

public static resolveNumberProperty(value: unknown, defaultValue: number): number {
if (value === undefined || value === null || value === '') {
return defaultValue;
}

const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : defaultValue;
}

public hasTitle(): boolean {
return this.dataField.title !== undefined && this.dataField.title !== '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,27 @@ export abstract class AbstractDateTimeDefaultFieldComponent extends AbstractTime
@Inject(MAT_DATE_LOCALE) protected _locale: string,
protected _languageService: LanguageService,
@Optional() @Inject(DATA_FIELD_PORTAL_DATA) dataFieldPortalData: DataFieldPortalData<DateTimeField>) {
super(_translate, _adapter, _locale, _languageService, dataFieldPortalData)
super(_translate, _adapter, _locale, _languageService, dataFieldPortalData);
}

public get showSeconds(): boolean {
return this.dataField?.showSeconds ?? false;
}

public get stepHour(): number {
return this.dataField?.stepHour ?? 1;
}

public get stepMinute(): number {
return this.dataField?.stepMinute ?? 5;
}

public get stepSecond(): number {
return this.dataField?.stepSecond ?? 1;
}

public get enableMeridian(): boolean {
return this.dataField?.enableMeridian ?? false;
}

getErrorMessage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,64 @@ import {AbstractTimeInstanceField} from '../../time-instance-abstract-field/mode
import {Layout} from '../../models/layout';
import {Validation} from '../../models/validation';
import {Component, ComponentPrefixes} from '../../models/component';
import {AbstractBaseDataFieldComponent} from '../../base-component/abstract-base-data-field.component';
Comment thread
machacjozef marked this conversation as resolved.

export class DateTimeField extends AbstractTimeInstanceField {

public static readonly SHOW_SECONDS_PROPERTY = 'showSeconds';

public static readonly ENABLE_MERIDIAN_PROPERTY = 'enableMeridian';

public static readonly STEP_HOUR_PROPERTY = 'stepHour';
public static readonly STEP_MINUTE_PROPERTY = 'stepMinute';
public static readonly STEP_SECOND_PROPERTY = 'stepSecond';

constructor(stringId: string, title: string, value: Moment, behavior: Behavior, placeholder?: string,
description?: string, layout?: Layout, validations?: Array<Validation>, component?: Component, parentTaskId?: string) {
super(stringId, title, value, behavior, placeholder, description, layout, validations, component, parentTaskId);
}

public get showSeconds(): boolean {
return AbstractBaseDataFieldComponent.resolveBooleanProperty(
this.component?.properties?.[DateTimeField.SHOW_SECONDS_PROPERTY],
false
);
}

public get stepHour(): number {
return AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_HOUR_PROPERTY],
1
);
}

public get stepMinute(): number {
return AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_MINUTE_PROPERTY],
5
);
}


public get stepSecond(): number {
return AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_SECOND_PROPERTY],
1
);
}
Comment thread
machacjozef marked this conversation as resolved.

public get enableMeridian(): boolean {
return AbstractBaseDataFieldComponent.resolveBooleanProperty(
this.component?.properties?.[DateTimeField.ENABLE_MERIDIAN_PROPERTY],
false
);
}

public getTypedComponentType(): string {
return ComponentPrefixes.DATE_TIME + this.getComponentType();
}

protected valueEquality(a: Moment, b: Moment): boolean {
return AbstractTimeInstanceField.isEqual(a, b, 'minute');
return AbstractTimeInstanceField.isEqual(a, b, 'second');
}
}
16 changes: 16 additions & 0 deletions projects/netgrif-components-core/src/lib/moment/time-formats.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const DATE_FORMAT_STRING = 'DD.MM.YYYY';
export const DATE_TIME_FORMAT_STRING = 'DD.MM.YYYY HH:mm';
export const DATE_TIME_SECONDS_FORMAT_STRING = 'DD.MM.YYYY HH:mm:ss';

// https://momentjs.com/docs/#/displaying/format/
export const DATE_FORMAT = {
Expand All @@ -25,3 +26,18 @@ export const DATE_TIME_FORMAT = {
monthYearA11yLabel: 'MMMM YYYY',
},
};

export const DATE_TIME_SECONDS_FORMAT = {
parse: {
dateInput: [
DATE_TIME_SECONDS_FORMAT_STRING,
DATE_TIME_FORMAT_STRING
],
},
display: {
dateInput: DATE_TIME_SECONDS_FORMAT_STRING,
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'Do MMMM YYYY HH:mm:ss',
monthYearA11yLabel: 'MMMM YYYY',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import {UserField} from '../../data-fields/user-field/models/user-field';
import {ButtonField} from '../../data-fields/button-field/models/button-field';
import {FileField, FileUploadMIMEType} from '../../data-fields/file-field/models/file-field';
import moment from 'moment';
import moment, {Moment} from 'moment';
import {UserValue} from '../../data-fields/user-field/models/user-value';
import {FieldTypeResource} from '../model/field-type-resource';
import {FileListField} from '../../data-fields/file-list-field/models/file-list-field';
Expand All @@ -23,15 +23,16 @@
import {I18nField} from '../../data-fields/i18n-field/models/i18n-field';
import {UserListField} from '../../data-fields/user-list-field/models/user-list-field';
import {UserListValue} from '../../data-fields/user-list-field/models/user-list-value';
import {decodeBase64, encodeBase64} from "../../utility/base64";
import {decodeBase64, encodeBase64} from '../../utility/base64';
import {CaseRefField} from '../../data-fields/case-ref-field/model/case-ref-field';
import {StringCollectionField} from '../../data-fields/string-collection-field/models/string-collection-field';

@Injectable({
providedIn: 'root'
})
export class FieldConverterService {
private textFieldNames = [ 'richtextarea', 'htmltextarea', 'editor', 'htmlEditor' ]

private textFieldNames = ['richtextarea', 'htmltextarea', 'editor', 'htmlEditor'];

Check warning on line 35 in projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Member 'textFieldNames' is never reassigned; mark it as `readonly`.

See more on https://sonarcloud.io/project/issues?id=netgrif_components&issues=AZ343vdcuLVDl_1VWNQ1&open=AZ343vdcuLVDl_1VWNQ1&pullRequest=327

constructor() {
}
Expand All @@ -41,6 +42,7 @@
case FieldTypeResource.BOOLEAN:
return new BooleanField(item.stringId, item.name, item.value as boolean, item.behavior,
item.placeholder, item.description, item.layout, item.validations, item.component, item.parentTaskId);

case FieldTypeResource.TEXT:
if (this.textFieldNames.includes(item.component?.name)) {
return new TextAreaField(item.stringId, item.name, this.resolveTextValue(item, item.value), item.behavior,
Expand Down Expand Up @@ -70,12 +72,7 @@
return new DateField(item.stringId, item.name, date, item.behavior, item.placeholder,
item.description, item.layout, item.validations, item.component, item.parentTaskId);
case FieldTypeResource.DATE_TIME:
let dateTime;
if (item.value) {
dateTime = moment(new Date(item.value[0], item.value[1] - 1, item.value[2], item.value[3], item.value[4]));
}
return new DateTimeField(item.stringId, item.name, dateTime, item.behavior,
item.placeholder, item.description, item.layout, item.validations, item.component, item.parentTaskId);
return new DateTimeField(item.stringId, item.name, this.resolveDateTime(item.value), item.behavior, item.placeholder, item.description, item.layout, item.validations, item.component, item.parentTaskId);
case FieldTypeResource.USER:
let user;
if (item.value) {
Expand Down Expand Up @@ -291,7 +288,7 @@
return new UserValue(value.id, value.name, value.surname, value.email);
}
if (this.resolveType(field) === FieldTypeResource.DATE_TIME) {
return moment(new Date(value[0], value[1] - 1, value[2], value[3], value[4]));
return this.resolveDateTime(value);
}
if (this.resolveType(field) === FieldTypeResource.MULTICHOICE) {
const array = [];
Expand All @@ -317,8 +314,33 @@
return value;
}

protected resolveDateTime(value: any): Moment | undefined {
if (!value) {
return undefined;
}
if (moment.isMoment(value)) {
return value;
}
if (value instanceof Date) {
return moment(value);
}
if (Array.isArray(value)) {
const [year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0] = value;
return moment({
year,
month: month - 1,
date: day,
hour,
minute,
second,
millisecond
});
}
return moment(value);
}
Comment thread
machacjozef marked this conversation as resolved.

protected resolveAllowedTypes(allowTypes: string[]) {
return allowTypes?.length > 0 ? (allowTypes.length > 1 ? allowTypes as FileUploadMIMEType[] : allowTypes[0]) : null
return allowTypes?.length > 0 ? (allowTypes.length > 1 ? allowTypes as FileUploadMIMEType[] : allowTypes[0]) : null;

Check warning on line 343 in projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=netgrif_components&issues=AZ343vdcuLVDl_1VWNQ2&open=AZ343vdcuLVDl_1VWNQ2&pullRequest=327
}

protected resolveByteSize(bytesSize) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
<mat-datepicker-toggle matPrefix [for]="picker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #picker
[showSpinners]="true"
[showSeconds]="false"
[stepHour]="1"
[stepMinute]="5"
[showSeconds]="showSeconds"
[stepHour]="stepHour"
[stepMinute]="stepMinute"
[stepSecond]="stepSecond"
[color]="'primary'"
[enableMeridian]="false">
[enableMeridian]="enableMeridian">
</ngx-mat-datetime-picker>
<mat-hint [ngClass]="{'mat-hint-disabled': formControlRef.disabled}">{{dataField.description}}</mat-hint>
<mat-error *ngIf="dataField.isInvalid(formControlRef)">{{getErrorMessage()}}</mat-error>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,38 @@ import {
DataFieldPortalData,
DateTimeField,
DATE_TIME_FORMAT,
DATE_TIME_SECONDS_FORMAT,
LanguageService
} from '@netgrif/components-core'
import {TranslateService} from "@ngx-translate/core";
import {NGX_MAT_DATE_FORMATS, NgxMatDateAdapter} from "@angular-material-components/datetime-picker";
import {MAT_DATE_LOCALE} from "@angular/material/core";
} from '@netgrif/components-core';
import {TranslateService} from '@ngx-translate/core';
import {NGX_MAT_DATE_FORMATS, NgxMatDateAdapter} from '@angular-material-components/datetime-picker';
import {MAT_DATE_LOCALE} from '@angular/material/core';

export function dateTimeDefaultFormatsFactory(dataFieldPortalData?: DataFieldPortalData<DateTimeField>) {
return dataFieldPortalData?.dataField?.showSeconds
? DATE_TIME_SECONDS_FORMAT
: DATE_TIME_FORMAT;
}

@Component({
selector: 'nc-date-time-default-field',
templateUrl: './date-time-default-field.component.html',
styleUrls: ['./date-time-default-field.component.scss'],
selector: 'nc-date-time-default-field',
templateUrl: './date-time-default-field.component.html',
styleUrls: ['./date-time-default-field.component.scss'],
providers: [
{provide: NGX_MAT_DATE_FORMATS, useValue: DATE_TIME_FORMAT}
{
provide: NGX_MAT_DATE_FORMATS,
useFactory: dateTimeDefaultFormatsFactory,
deps: [[new Optional(), DATA_FIELD_PORTAL_DATA]]
}
]
})
export class DateTimeDefaultFieldComponent extends AbstractDateTimeDefaultFieldComponent {

constructor(_translate: TranslateService,
_adapter: NgxMatDateAdapter<any>,
@Inject(MAT_DATE_LOCALE) protected _locale: string,
_languageService: LanguageService,
@Optional() @Inject(DATA_FIELD_PORTAL_DATA) dataFieldPortalData: DataFieldPortalData<DateTimeField>) {
super(_translate, _adapter, _locale, _languageService, dataFieldPortalData);
}

constructor(_translate: TranslateService,
_adapter: NgxMatDateAdapter<any>,
@Inject(MAT_DATE_LOCALE) protected _locale: string,
_languageService: LanguageService,
@Optional() @Inject(DATA_FIELD_PORTAL_DATA) dataFieldPortalData: DataFieldPortalData<DateTimeField>) {
super(_translate, _adapter, _locale, _languageService, dataFieldPortalData);
}
}
Loading