diff --git a/core/pom.xml b/core/pom.xml index 139bffc8..98d832f8 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -248,6 +248,12 @@ DynamicImport-Package: * com.fasterxml.jackson.core provided + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.17.2 + provided + com.day.cq cq-replication diff --git a/core/src/main/java/com/vml/es/aem/acm/core/code/ArgumentType.java b/core/src/main/java/com/vml/es/aem/acm/core/code/ArgumentType.java index eeb3badf..c160d469 100644 --- a/core/src/main/java/com/vml/es/aem/acm/core/code/ArgumentType.java +++ b/core/src/main/java/com/vml/es/aem/acm/core/code/ArgumentType.java @@ -2,6 +2,7 @@ public enum ArgumentType { BOOL, + DATETIME, INTEGER, DECIMAL, STRING, diff --git a/core/src/main/java/com/vml/es/aem/acm/core/code/Arguments.java b/core/src/main/java/com/vml/es/aem/acm/core/code/Arguments.java index f2d23b20..32564dd5 100644 --- a/core/src/main/java/com/vml/es/aem/acm/core/code/Arguments.java +++ b/core/src/main/java/com/vml/es/aem/acm/core/code/Arguments.java @@ -86,6 +86,16 @@ public void bool(String name, Closure options) { add(argument); } + public void dateTime(String name) { + dateTime(name, null); + } + + public void dateTime(String name, Closure options) { + DateTimeArgument argument = new DateTimeArgument(name); + GroovyUtils.with(argument, options); + add(argument); + } + public void string(String name) { string(name, null); } diff --git a/core/src/main/java/com/vml/es/aem/acm/core/code/arg/DateTimeArgument.java b/core/src/main/java/com/vml/es/aem/acm/core/code/arg/DateTimeArgument.java new file mode 100644 index 00000000..8f497575 --- /dev/null +++ b/core/src/main/java/com/vml/es/aem/acm/core/code/arg/DateTimeArgument.java @@ -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 { + 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 variant '%s' is not supported!", name))); + } + } +} diff --git a/core/src/main/java/com/vml/es/aem/acm/core/util/JsonUtils.java b/core/src/main/java/com/vml/es/aem/acm/core/util/JsonUtils.java index 37d6d133..0160f209 100644 --- a/core/src/main/java/com/vml/es/aem/acm/core/util/JsonUtils.java +++ b/core/src/main/java/com/vml/es/aem/acm/core/util/JsonUtils.java @@ -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; @@ -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) + .registerModule(new JavaTimeModule()); public static final ObjectWriter COMPACT_WRITER = MAPPER.writer(); diff --git a/pom.xml b/pom.xml index 97bfa5ff..a8b67ae1 100644 --- a/pom.xml +++ b/pom.xml @@ -233,6 +233,7 @@ Bundle-Category: acm Bundle-DocURL: -plugin org.apache.sling.caconfig.bndplugin.ConfigurationClassScannerPlugin -plugin org.apache.sling.bnd.models.ModelsScannerPlugin +Private-Package: com.fasterxml.jackson.datatype.jsr310 ]]> @@ -254,6 +255,11 @@ Bundle-DocURL: scriptingbundle-maven-plugin 0.5.0 + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.17.2 + diff --git a/ui.frontend/src/components/CodeArgumentInput.module.css b/ui.frontend/src/components/CodeArgumentInput.module.css index 15dfe7e1..4e1556a1 100644 --- a/ui.frontend/src/components/CodeArgumentInput.module.css +++ b/ui.frontend/src/components/CodeArgumentInput.module.css @@ -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; -} \ No newline at end of file + 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; +} diff --git a/ui.frontend/src/components/CodeArgumentInput.tsx b/ui.frontend/src/components/CodeArgumentInput.tsx index 226d8a4f..7324f858 100644 --- a/ui.frontend/src/components/CodeArgumentInput.tsx +++ b/ui.frontend/src/components/CodeArgumentInput.tsx @@ -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; @@ -63,6 +64,31 @@ const CodeArgumentInput: React.FC = ({ arg }) => { )} /> ); + } else if (isDateTimeArgument(arg)) { + return ( + ( + + 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%" + /> + + )} + /> + ); } else if (isStringArgument(arg)) { return ( ; @@ -43,6 +43,12 @@ export type BoolArgument = Argument & { display: 'SWITCHER' | 'CHECKBOX'; }; +export type DateTimeArgument = Argument & { + variant: 'DATE' | 'DATETIME'; + min: string; + max: string; +}; + export type TextArgument = Argument & { language?: string; }; @@ -70,6 +76,10 @@ export function isBoolArgument(arg: Argument): arg is BoolArgumen return arg.type === 'BOOL'; } +export function isDateTimeArgument(arg: Argument): arg is DateTimeArgument { + return arg.type === 'DATETIME'; +} + export function isTextArgument(arg: Argument): arg is TextArgument { return arg.type === 'TEXT'; }