-
Notifications
You must be signed in to change notification settings - Fork 4
[NAE-2425] Allowing using seconds in dateTime field #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/6.4.3
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 on lines
+31
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constrain step properties to positive integers before exposing them.
Proposed fix public get stepHour(): number {
- return AbstractBaseDataFieldComponent.resolveNumberProperty(
+ const value = AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_HOUR_PROPERTY],
1
);
+ return Number.isInteger(value) && value > 0 ? value : 1;
}
public get stepMinute(): number {
- return AbstractBaseDataFieldComponent.resolveNumberProperty(
+ const value = AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_MINUTE_PROPERTY],
5
);
+ return Number.isInteger(value) && value > 0 ? value : 5;
}
public get stepSecond(): number {
- return AbstractBaseDataFieldComponent.resolveNumberProperty(
+ const value = AbstractBaseDataFieldComponent.resolveNumberProperty(
this.component?.properties?.[DateTimeField.STEP_SECOND_PROPERTY],
1
);
+ return Number.isInteger(value) && value > 0 ? value : 1;
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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'; | ||
|
|
@@ -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
|
||
|
|
||
| constructor() { | ||
| } | ||
|
|
@@ -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, | ||
|
|
@@ -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) { | ||
|
|
@@ -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 = []; | ||
|
|
@@ -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 on lines
+317
to
+340
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle falsy-but-valid input and invalid parse output in Line 318 currently treats Proposed fix protected resolveDateTime(value: any): Moment | undefined {
- if (!value) {
+ if (value === undefined || value === null || value === '') {
return undefined;
}
+ let parsed: Moment;
if (moment.isMoment(value)) {
- return value;
+ parsed = value;
+ } else if (value instanceof Date) {
+ parsed = moment(value);
+ } else if (Array.isArray(value)) {
+ const [year, month, day, hour = 0, minute = 0, second = 0, millisecond = 0] = value;
+ parsed = moment({
+ year,
+ month: month - 1,
+ date: day,
+ hour,
+ minute,
+ second,
+ millisecond
+ });
+ } else {
+ parsed = moment(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);
+ return parsed.isValid() ? parsed : undefined;
}🤖 Prompt for AI Agents |
||
|
|
||
| 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
|
||
| } | ||
|
|
||
| protected resolveByteSize(bytesSize) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Decouple
DateTimeFieldmodel fromAbstractBaseDataFieldComponent.Importing a UI component class into a model for static parsing helpers couples layers unnecessarily. Move these parsers into a neutral utility (e.g., field-property parser util) and reuse from both model/component layers.
🤖 Prompt for AI Agents