Skip to content

Date/datetime argument #74

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ DynamicImport-Package: *
<groupId>com.fasterxml.jackson.core</groupId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.day.cq</groupId>
<artifactId>cq-replication</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public enum ArgumentType {
BOOL,
DATETIME,
INTEGER,
DECIMAL,
STRING,
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/com/vml/es/aem/acm/core/code/Arguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ public void bool(String name, Closure<BoolArgument> options) {
add(argument);
}

public void dateTime(String name) {
dateTime(name, null);
}

public void dateTime(String name, Closure<DateTimeArgument> options) {
DateTimeArgument argument = new DateTimeArgument(name);
GroovyUtils.with(argument, options);
add(argument);
}

public void string(String name) {
string(name, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.vml.es.aem.acm.core.code.arg;

import com.vml.es.aem.acm.core.code.Argument;
import com.vml.es.aem.acm.core.code.ArgumentType;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;

public class DateTimeArgument extends Argument<LocalDateTime> {
private DateTimeArgument.Variant variant = DateTimeArgument.Variant.DATETIME;

private LocalDateTime min;

private LocalDateTime max;

public DateTimeArgument(String name) {
super(name, ArgumentType.DATETIME);
}

public LocalDateTime getMin() {
return min;
}

public void setMin(LocalDateTime min) {
this.min = min;
}

public void setMin(LocalDate min) {
this.min = min.atStartOfDay();
}

public LocalDateTime getMax() {
return max;
}

public void setMax(LocalDateTime max) {
this.max = max;
}

public void setMax(LocalDate max) {
this.max = max.atStartOfDay();
}

public DateTimeArgument.Variant getVariant() {
return variant;
}

public void setVariant(String variant) {
this.variant = DateTimeArgument.Variant.of(variant);
}

public void setVariant(DateTimeArgument.Variant render) {
this.variant = render;
}

// Cast LocalDate to LocalDateTime in case of DATE variant
public void setValue(LocalDate value) {
setValue(value.atStartOfDay());
}

public void date() {
this.variant = DateTimeArgument.Variant.DATE;
}

public void dateTime() {
this.variant = DateTimeArgument.Variant.DATETIME;
}

public enum Variant {
DATE,
DATETIME;

public static DateTimeArgument.Variant of(String name) {
return Arrays.stream(DateTimeArgument.Variant.values())
.filter(r -> r.name().equalsIgnoreCase(name))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
String.format("Datetime argument cannot be displayed as '%s'!", name)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -17,7 +18,8 @@ public final class JsonUtils {

public static final ObjectMapper MAPPER = new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to write dates as iso format as it's human readable but timestamps are not

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see only two options in this configuration: timestamps or with zone id. Should I change it?

.registerModule(new JavaTimeModule());

public static final ObjectWriter COMPACT_WRITER = MAPPER.writer();

Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ Bundle-DocURL:
<artifactId>scriptingbundle-maven-plugin</artifactId>
<version>0.5.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.2</version>
</dependency>
</dependencies>
</plugin>
<plugin>
Expand Down
14 changes: 7 additions & 7 deletions ui.frontend/src/components/CodeArgumentInput.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*Custom error state since react spectrum doesn't provide one for switch and checkbox component*/
.error {
color: var(--spectrum-red-900);
font-size: var(--spectrum-global-dimension-font-size-75);
line-height: var(--spectrum-global-font-line-height-small);
letter-spacing: var(--spectrum-global-font-letter-spacing-none);
margin-inline-end: var(--spectrum-global-dimension-size-100);
font-family: var(--spectrum-global-font-family-base), sans-serif;
}
color: var(--spectrum-red-900);
font-size: var(--spectrum-global-dimension-font-size-75);
line-height: var(--spectrum-global-font-line-height-small);
letter-spacing: var(--spectrum-global-font-letter-spacing-none);
margin-inline-end: var(--spectrum-global-dimension-size-100);
font-family: var(--spectrum-global-font-family-base), sans-serif;
}
32 changes: 29 additions & 3 deletions ui.frontend/src/components/CodeArgumentInput.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Checkbox, CheckboxGroup, Flex, Item, ListView, NumberField, Picker, Radio, RadioGroup, Switch, TextArea, TextField, View } from '@adobe/react-spectrum';
import { Checkbox, CheckboxGroup, DatePicker, Flex, Item, ListView, NumberField, Picker, Radio, RadioGroup, Switch, TextArea, TextField, View } from '@adobe/react-spectrum';
import { Editor } from '@monaco-editor/react';
import { Field } from '@react-spectrum/label';
import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import useFormCrossFieldValidation from '../hooks/form.ts';
import { Argument, ArgumentValue, isBoolArgument, isMultiSelectArgument, isNumberArgument, isSelectArgument, isStringArgument, isTextArgument } from '../utils/api.types.ts';
import { Argument, ArgumentValue, isBoolArgument, isDateTimeArgument, isMultiSelectArgument, isNumberArgument, isSelectArgument, isStringArgument, isTextArgument } from '../utils/api.types.ts';
import { Dates } from '../utils/dates.ts';
import { Strings } from '../utils/strings.ts';
import styles from "./CodeArgumentInput.module.css"
import styles from './CodeArgumentInput.module.css';

interface CodeArgumentInputProps {
arg: Argument<ArgumentValue>;
Expand Down Expand Up @@ -63,6 +64,31 @@ const CodeArgumentInput: React.FC<CodeArgumentInputProps> = ({ arg }) => {
)}
/>
);
} else if (isDateTimeArgument(arg)) {
return (
<Controller
name={arg.name}
control={control}
rules={controllerRules(arg)}
render={({ field, fieldState }) => (
<View key={arg.name} marginBottom="size-200">
<DatePicker
{...field}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since spectrum picker supports min/max then in the backend we could as well, fine

minValue={arg.min !== null ? Dates.toCalendarOrNull(arg.min) : undefined}
maxValue={arg.max !== null ? Dates.toCalendarOrNull(arg.max) : undefined}
value={Dates.toCalendarOrNull(field.value)}
onChange={(dateValue) => field.onChange(dateValue?.toString())}
granularity={arg.variant === 'DATETIME' ? 'second' : 'day'}
label={argLabel(arg)}
errorMessage={fieldState.error ? fieldState.error.message : undefined}
validationState={fieldState.error ? 'invalid' : 'valid'}
aria-label={`Argument '${arg.name}'`}
width="100%"
/>
</View>
)}
/>
);
} else if (isStringArgument(arg)) {
return (
<Controller
Expand Down
12 changes: 11 additions & 1 deletion ui.frontend/src/utils/api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export type Description = {
};
};

export type ArgumentType = 'BOOL' | 'STRING' | 'TEXT' | 'SELECT' | 'MULTISELECT' | 'INTEGER' | 'DECIMAL';
export type ArgumentType = 'BOOL' | 'STRING' | 'TEXT' | 'SELECT' | 'MULTISELECT' | 'INTEGER' | 'DECIMAL' | 'DATETIME';
export type ArgumentValue = string | string[] | number | number[] | boolean | null | undefined;
export type ArgumentValues = Record<string, ArgumentValue>;

Expand All @@ -43,6 +43,12 @@ export type BoolArgument = Argument<boolean> & {
display: 'SWITCHER' | 'CHECKBOX';
};

export type DateTimeArgument = Argument<string> & {
variant: 'DATE' | 'DATETIME';
min: string;
max: string;
};

export type TextArgument = Argument<string> & {
language?: string;
};
Expand Down Expand Up @@ -70,6 +76,10 @@ export function isBoolArgument(arg: Argument<ArgumentValue>): arg is BoolArgumen
return arg.type === 'BOOL';
}

export function isDateTimeArgument(arg: Argument<ArgumentValue>): arg is DateTimeArgument {
return arg.type === 'DATETIME';
}

export function isTextArgument(arg: Argument<ArgumentValue>): arg is TextArgument {
return arg.type === 'TEXT';
}
Expand Down