diff --git a/platform-annotation-processors-test/pom.xml b/platform-annotation-processors-test/pom.xml index f656769286a..025b96c7d5e 100644 --- a/platform-annotation-processors-test/pom.xml +++ b/platform-annotation-processors-test/pom.xml @@ -4,7 +4,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-annotation-processors-test diff --git a/platform-annotation-processors/pom.xml b/platform-annotation-processors/pom.xml index ccfbe15215f..e7eb9101730 100644 --- a/platform-annotation-processors/pom.xml +++ b/platform-annotation-processors/pom.xml @@ -4,7 +4,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-annotation-processors diff --git a/platform-annotations/pom.xml b/platform-annotations/pom.xml index 21c5c02523f..1339d9c3b71 100644 --- a/platform-annotations/pom.xml +++ b/platform-annotations/pom.xml @@ -3,7 +3,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-annotations diff --git a/platform-benchmark/pom.xml b/platform-benchmark/pom.xml index d6c448f540d..90bc14064b3 100644 --- a/platform-benchmark/pom.xml +++ b/platform-benchmark/pom.xml @@ -6,7 +6,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT Trident Genesis Platform Microbenckmarks diff --git a/platform-benchmark/src/main/java/ua/com/fielden/companion/BenchmarkIocModule.java b/platform-benchmark/src/main/java/ua/com/fielden/companion/BenchmarkIocModule.java index 23fac98897e..de2ea58db99 100644 --- a/platform-benchmark/src/main/java/ua/com/fielden/companion/BenchmarkIocModule.java +++ b/platform-benchmark/src/main/java/ua/com/fielden/companion/BenchmarkIocModule.java @@ -19,9 +19,9 @@ import ua.com.fielden.platform.serialisation.api.impl.IdOnlyProxiedEntityTypeCacheForTests; import ua.com.fielden.platform.web.annotations.AppUri; +import java.time.Duration; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import static java.lang.String.format; @@ -59,7 +59,7 @@ protected void configure() { @Provides @Singleton @SessionCache Cache provideSessionCache() { - return CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.MINUTES).build(); + return CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(2)).build(); } } diff --git a/platform-benchmark/src/main/java/ua/com/fielden/eql/BenchmarkIocModule.java b/platform-benchmark/src/main/java/ua/com/fielden/eql/BenchmarkIocModule.java index a6b5d01c134..e7825c097e1 100644 --- a/platform-benchmark/src/main/java/ua/com/fielden/eql/BenchmarkIocModule.java +++ b/platform-benchmark/src/main/java/ua/com/fielden/eql/BenchmarkIocModule.java @@ -19,9 +19,9 @@ import ua.com.fielden.platform.serialisation.api.impl.IdOnlyProxiedEntityTypeCacheForTests; import ua.com.fielden.platform.web.annotations.AppUri; +import java.time.Duration; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import static java.lang.String.format; @@ -59,7 +59,7 @@ protected void configure() { @Provides @Singleton @SessionCache Cache provideSessionCache() { - return CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.MINUTES).build(); + return CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(2)).build(); } } diff --git a/platform-dao/pom.xml b/platform-dao/pom.xml index 36acd584fc8..ddb9e8af1c8 100644 --- a/platform-dao/pom.xml +++ b/platform-dao/pom.xml @@ -3,7 +3,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-dao diff --git a/platform-dao/src/main/java/ua/com/fielden/platform/eql/dbschema/HibernateToJdbcSqlTypeCorrespondence.java b/platform-dao/src/main/java/ua/com/fielden/platform/eql/dbschema/HibernateToJdbcSqlTypeCorrespondence.java index 2a6a51578df..342835b88e3 100644 --- a/platform-dao/src/main/java/ua/com/fielden/platform/eql/dbschema/HibernateToJdbcSqlTypeCorrespondence.java +++ b/platform-dao/src/main/java/ua/com/fielden/platform/eql/dbschema/HibernateToJdbcSqlTypeCorrespondence.java @@ -10,8 +10,6 @@ import java.sql.Types; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import static org.apache.commons.lang3.StringUtils.substringBefore; import static ua.com.fielden.platform.utils.Pair.pair; @@ -40,11 +38,8 @@ public final class HibernateToJdbcSqlTypeCorrespondence { */ // funnily enough Hibernate itself performs such conversion in certain Dialect implementations public static String genericSqlTypeName(final int sqlType, final Dialect dialect) { - final var map = GENERIC_TYPE_NAMES.computeIfAbsent(dialect, $ -> new ConcurrentHashMap<>()); - return map.computeIfAbsent(sqlType, $ -> substringBefore(dialect.getTypeName(sqlType), '(')); + return substringBefore(dialect.getTypeName(sqlType), '('); } - // where - private static final Map> GENERIC_TYPE_NAMES = new ConcurrentHashMap<>(1); // expect at most 1 dialect /** * Infers the name of a Hibernate type to use in a {@code CAST} SQL expression. diff --git a/platform-dao/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDatesDao.java b/platform-dao/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDatesDao.java index f0d84e3c7ce..07dd2c74099 100644 --- a/platform-dao/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDatesDao.java +++ b/platform-dao/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDatesDao.java @@ -22,7 +22,14 @@ public TgEntityWithTimeZoneDatesDao(final IFilter filter) { @Override protected IFetchProvider createFetchProvider() { - return super.createFetchProvider().with("key", "dateProp", "datePropUtc"); + return super.createFetchProvider().with( + "key", + "dateProp", + "datePropUtc", + "datePropDependent", + "dateOnlyProp", + "dateOnlyPropUtc" + ); } } \ No newline at end of file diff --git a/platform-dao/src/test/java/ua/com/fielden/platform/test/ioc/PlatformTestServerIocModule.java b/platform-dao/src/test/java/ua/com/fielden/platform/test/ioc/PlatformTestServerIocModule.java index f51f658075b..1cb61e0d236 100644 --- a/platform-dao/src/test/java/ua/com/fielden/platform/test/ioc/PlatformTestServerIocModule.java +++ b/platform-dao/src/test/java/ua/com/fielden/platform/test/ioc/PlatformTestServerIocModule.java @@ -38,9 +38,9 @@ import ua.com.fielden.platform.utils.IUniversalConstants; import ua.com.fielden.platform.web.annotations.AppUri; +import java.time.Duration; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import static java.lang.String.format; @@ -230,7 +230,7 @@ protected void bindDomainCompanionObjects(final List fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-db-evolution diff --git a/platform-doc/claude/entity-model/quick-reference.md b/platform-doc/claude/entity-model/quick-reference.md index 7322141029c..34fe5ce7c83 100644 --- a/platform-doc/claude/entity-model/quick-reference.md +++ b/platform-doc/claude/entity-model/quick-reference.md @@ -96,6 +96,13 @@ protected static final EntityResultQueryModel model_ = select(Source.class) Use `models_` (plural `List`), inner `enum`, `@SupportsEntityExistsValidation`. See `entity-model/reference.md` § *Synthetic Grouping Property Entities*. +## Fixed Entity Instances + +Protect specific records of a user-maintained *persistent* entity that business logic references by key. +An inner `enum Fixed` lists the protected keys and is the single source of truth; the rows are created by migration/population, not by the enum. +Four parts: (1) the `Fixed` enum with `matches` / `fromValue` / `isOneOf`; (2) a key+desc `@BeforeChange` validator — **fail** on key rename, **warn** on desc change, guarded by `isPersisted() && Fixed.isOneOf(entity)`; (3) an `IRenderingCustomiser` that italicises fixed rows; (4) a `batchDelete` override rejecting fixed rows. +See `entity-model/reference.md` § *Fixed Entity Instances*. + ## Metamodel References Always use metamodel references instead of string literals: diff --git a/platform-doc/claude/entity-model/reference.md b/platform-doc/claude/entity-model/reference.md index 9c2edbfa130..5e259c04e1e 100644 --- a/platform-doc/claude/entity-model/reference.md +++ b/platform-doc/claude/entity-model/reference.md @@ -667,6 +667,204 @@ The distinguishing line is *what kind of data they present*, not the field shape Grouping property entities pair naturally with **generative entities** below — the latter typically host them as `@CritOnly(SINGLE)` selection criteria that drive the data generator. +## Fixed Entity Instances + +The **fixed entity instances** pattern protects a subset of records in an otherwise user-maintained reference (lookup) entity. +The table supports full CRUD through its Entity Centre and Master, but a few specific records are referenced by key from business logic, so they must not be renamed or deleted — and their descriptions must not silently drift. +The protected records are declared as an inner `enum` (named `Fixed`), which is the single source of truth for their keys. + +The enum **identifies** fixed records; it does not create them. +The records themselves are inserted by the usual means — a data-migration retriever, a release script, or test data population. +Each fixed record's key must equal the key value its enum member declares. +This is the value that the conventional enum method `matches` compares against. +It could be the enum member's name or one of its fields (e.g., `HIGH_PRIORITY("High Priority")` +carries the key `"High Priority"`.). +Unlike a *synthetic grouping property entity*, which synthesises its records from the enum at query time, a fixed-instance entity is an ordinary persistent entity whose records live in the database; the enum merely flags which of them are protected. + +The code blocks below are reproduced verbatim from a representative implementation; the pattern itself is independent of any particular entity. + +### The `Fixed` enum — conventional methods + +```java +public enum Fixed { + NONE("NONE", "No Meter"); + + public final String unit; + public final String desc; + + Fixed(final String unit, final String desc) { + this.unit = unit; + this.desc = desc; + } + + public boolean matches(final String unit) { + return this.unit.equalsIgnoreCase(unit); + } + + public boolean matches(final MeasurementUnit unit) { + return unit != null && matches(unit.getUnit()); + } + + public static Fixed fromValue(final MeasurementUnit unit) { + return unit != null ? fromValue(unit.getUnit()) : null; + } + + public static Fixed fromValue(final String unit) { + for (final var fixed : Fixed.values()) { + if (fixed.matches(unit)) { + return fixed; + } + } + return null; + } + + public static boolean isOneOf(final MeasurementUnit unit) { + return fromValue(unit) != null; + } + + public static boolean isOneOf(final String unit) { + return fromValue(unit) != null; + } +} +``` + +The contract every `Fixed` enum provides: +- A field per key-defining property — at minimum the natural key (`unit`), usually the description too. +- `matches(String)` — case-insensitive comparison against the key. + The `String` overload is the primitive; the entity overload is a null-safe convenience. +- `fromValue(...)` — resolve the enum constant from a key or entity, returning `null` when none matches (paired `String` and entity overloads). +- `isOneOf(...)` — membership test built on `fromValue`. + +Business logic consumes these directly — e.g. `Fixed.NONE.matches(unit)` to special-case a particular record, or `Fixed.isOneOf(unit)` to ask "is this a protected record?". + +### Validation of key and desc + +A single validator guards both the key and the description, attached to each via `@BeforeChange(@Handler(...))`: + +```java +@IsProperty +@MapTo +@CompositeKeyMember(1) +@BeforeChange(@Handler(MeasurementUnitKeyAndDescValidator.class)) +private String unit; + +@IsProperty +@MapTo +@BeforeChange(@Handler(MeasurementUnitKeyAndDescValidator.class)) +private String desc; +``` + +```java +public class MeasurementUnitKeyAndDescValidator implements IBeforeChangeEventHandler { + + public static final String + ERR_FIXED_MEASUREMENT_UNIT = MeasurementUnit.ENTITY_TITLE + " [%s] is used in the business logic and cannot be modified.", + WARN_FIXED_MEASUREMENT_UNIT = MeasurementUnit.ENTITY_TITLE + " [%s] is used in the business logic — please make sure that overall meaning remains the same if the description is changed."; + + @Override + public Result handle(final MetaProperty property, final String newValue, final Set mutatorAnnotations) { + final MeasurementUnit unit = property.getEntity(); + if (unit.isPersisted() && Fixed.isOneOf(unit)) { + if (property.getName().contentEquals(MeasurementUnit_.unit()) && fromValue(unit) != fromValue(newValue)) { + return failuref(ERR_FIXED_MEASUREMENT_UNIT, unit.getUnit()); + } + else if (property.getName().contentEquals(MeasurementUnit_.desc()) && !EntityUtils.equalsEx(property.getValue(), newValue)) { + return warningf(WARN_FIXED_MEASUREMENT_UNIT, unit.getUnit()); + } + } + return successful(); + } + +} +``` + +The rules encoded here: +- **Guard on `isPersisted() && Fixed.isOneOf(entity)`.** + Restrictions apply only to a persisted record that *is* one of the fixed instances. + New entities are unrestricted — which is what lets migration/population create the fixed records in the first place — and non-fixed records are never touched. +- **Key change is a hard failure.** + Renaming a fixed record to a different identity (`fromValue(current) != fromValue(newValue)`) returns `failuref(...)`, blocking the assignment. + Comparing fixed *identities* rather than raw strings means a case-only or no-op re-set of the same key is allowed. +- **Description change is a warning, not a failure.** + A genuine description change produces a warning — the edit is permitted but the user is warned that the record carries business meaning. + +**Deactivation (activatable reference entities).** +When the entity extends `ActivatableAbstractEntity`, protect the `active` flag too: add a separate validator on `active` that *warns* when a fixed record is deactivated, chained after `ActivePropertyValidator`. + +### Rendering in the Entity Centre + +Fixed records are rendered italic and in the "required" colour so users can distinguish protected records from their own. +Implement an `IRenderingCustomiser` whose `getCustomRenderingFor` returns value styles for the key column (keyed by `""`, which stands for "this") when the entity is a fixed record, and register it on the centre via `.setRenderingCustomiser(...)`. + +```java +private static class MeasurementUnitRenderingCustomiser implements IRenderingCustomiser> { + + @Override + public Optional> getCustomRenderingFor(final AbstractEntity entity) { + return RenderingCustomiserUtils.getCustomRenderingForFixedValue((MeasurementUnit) entity, MeasurementUnit.Fixed::isOneOf); + } + +} +``` + +The customiser delegates to a small shared helper that holds the two non-obvious details — the italic + required-colour styling, and a workaround for a platform bug that unwraps an empty `Optional` (so it returns an empty map, never `Optional.empty()`): + +```java +public static > Optional> getCustomRenderingForFixedValue(final T entity, final Predicate isFixed) { + if (isFixed.test(entity)) { + final Map valueStyles = new HashMap<>(); + valueStyles.put("font-style", "italic"); + valueStyles.put("color", REQUIRED_PROPERTY_COLOUR); + + final Map> keyStyles = new HashMap<>(); + keyStyles.put("valueStyles", valueStyles); + + final Map styles = mapOf(t2("" /* stands for "this" */, keyStyles)); + + return Optional.of(styles); + } + + return Optional.of(Map.of()); +} +``` + +Pass the membership predicate as a method reference (`Fixed::isOneOf`); `REQUIRED_PROPERTY_COLOUR` is `#03A9F4`. + +### Deletion rules + +Block deletion of fixed records in the DAO by overriding `batchDelete(Collection)` (see *Canonical `batchDelete` Pattern*): + +```java +public static final String ERR_FIXED_UNIT_CANNOT_BE_DELETED = MeasurementUnit.ENTITY_TITLE + " [%s] is used in the business logic and cannot be deleted."; + +@Override +@SessionRequired +@Authorise(MeasurementUnit_CanDelete_Token.class) +public int batchDelete(final Collection entitiesIds) { + validateDeletion(entitiesIds).ifFailure(Result::throwRuntime); + + return defaultBatchDelete(entitiesIds); +} + +private Result validateDeletion(final Collection entitiesIds) { + final var query = select(MeasurementUnit.class).where() + .prop(MeasurementUnit_.id()).in().values(entitiesIds) + .and().prop(MeasurementUnit_.unit()).in().values(Arrays.stream(MeasurementUnit.Fixed.values()).map(it -> it.unit).toList()) + .model(); + final var maybeUnit = first(co(MeasurementUnit.class).getFirstEntities(from(query).model(), 1)); + if (maybeUnit.isPresent()) { + return failuref(ERR_FIXED_UNIT_CANNOT_BE_DELETED, maybeUnit.get()); + } + + return successful(); +} +``` + +- The check is a single DB query intersecting the requested IDs with the set of fixed keys (`Fixed.values()` mapped to keys), asking for at most one hit (`getFirstEntities(..., 1)`). + This avoids loading every requested entity and short-circuits on the first protected record. +- This key comparison runs in the database, so its case sensitivity follows the column's collation — unlike method `matches`, which may be case-insensitive via `equalsIgnoreCase`. Store fixed keys in their canonical case so the two sites cannot diverge. +- Only override the `Collection` overload; leave `batchDelete(List)` delegating to `defaultBatchDelete`. + ## Generative Entities A **generative entity** is a persistent entity whose rows are computed ad hoc at Entity Centre `run` phase rather than maintained by normal CRUD. diff --git a/platform-eql-grammar/pom.xml b/platform-eql-grammar/pom.xml index 07c6d737e20..e011d8b6438 100644 --- a/platform-eql-grammar/pom.xml +++ b/platform-eql-grammar/pom.xml @@ -6,7 +6,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-eql-grammar diff --git a/platform-pojo-bl/pom.xml b/platform-pojo-bl/pom.xml index 21ef87a1a25..9bc256d7d58 100644 --- a/platform-pojo-bl/pom.xml +++ b/platform-pojo-bl/pom.xml @@ -3,7 +3,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-pojo-bl @@ -16,10 +16,10 @@ - 2.21.1 - 2.21 - 33.5.0-jre - 5.4.1 + 2.22.1 + 2.22 + 33.6.0-jre + 5.5.1 2.7.3 7.0.0 9.9.1 @@ -268,7 +268,7 @@ commons-io commons-io - 2.20.0 + 2.21.0 org.commonmark diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/CriteriaGenerator.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/CriteriaGenerator.java index b953600a19c..16656fd0d49 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/CriteriaGenerator.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/CriteriaGenerator.java @@ -215,15 +215,10 @@ private static List generateCriteriaProperties(final Class copyDateAnnotations(final Class managedType, final String propertyName) { - return of(DateOnly.class, TimeOnly.class, PersistentType.class) + return of(DateOnly.class, TimeOnly.class, PersistentType.class, DependentTimeZoneMode.class) .map(annotationType -> getPropertyAnnotationOptionally(annotationType, managedType, propertyName)) .flatMap(annotation -> annotation.isPresent() ? of(annotation.get()) : empty()) .map(annotation -> { @@ -231,8 +226,10 @@ private static List copyDateAnnotations(final Class managedType, return newDateOnlyAnnotation(); } else if (annotation instanceof TimeOnly) { return newTimeOnlyAnnotation(); - } else { + } else if (annotation instanceof PersistentType) { return newUtcAnnotation(); + } else { + return newDependentTimeZoneModeAnnotation(); } }) .collect(toList()); diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/TypeDiffSerialiser.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/TypeDiffSerialiser.java index 7f8b5e73e6f..d97cbd14e06 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/TypeDiffSerialiser.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/criteria/generator/impl/TypeDiffSerialiser.java @@ -34,7 +34,7 @@ private TypeDiffSerialiser() { */ public byte[] serialise(final Map diff) { try { - return writeValueAsBytes(diff); // default encoding is Charsets.UTF_8 + return writeValueAsBytes(diff); // default encoding is StandardCharsets.UTF_8 } catch (final JsonProcessingException ex) { throw new SerialisationException("Error during type diff serialisation.", ex); } diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/DependentTimeZoneMode.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/DependentTimeZoneMode.java new file mode 100644 index 00000000000..adf8d56d108 --- /dev/null +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/DependentTimeZoneMode.java @@ -0,0 +1,35 @@ +package ua.com.fielden.platform.entity.annotation; + +import ua.com.fielden.platform.utils.IDates; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Date; + +/// An annotation for properties of type [java.util.Date] to enforce dependent time-zone mode in Web UI logic. +/// +/// Please note, that appropriate [IDates#now()] and [IDates#zoned(Date)] method variations are required in server-side logic. +/// I.e. it may not be sufficient to annotate the properties with this annotation. +/// +/// ```java +///static DateTime now(final IDates dates) { +/// return new DateTime(getTimeZone(dates)); +///} +///static DateTime zoned(final Date date, fina IDates dates) { +/// return new DateTime(date, getTimeZone(dates)); +///} +///private static DateTimeZone getTimeZone(final IDates dates) { +/// if (dates.requestTimeZone().isEmpty()) { +/// throw failure(ERR_TIME_ZONE_IS_MISSING); +/// } +/// return dates.requestTimeZone().get(); +///} +/// ``` +/// +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.FIELD }) +public @interface DependentTimeZoneMode { + +} diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/factory/DateAnnotations.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/factory/DateAnnotations.java index 5aa37d51693..4396a9a2ea0 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/factory/DateAnnotations.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/entity/annotation/factory/DateAnnotations.java @@ -1,25 +1,19 @@ package ua.com.fielden.platform.entity.annotation.factory; -import java.lang.annotation.Annotation; - import ua.com.fielden.platform.entity.annotation.DateOnly; +import ua.com.fielden.platform.entity.annotation.DependentTimeZoneMode; import ua.com.fielden.platform.entity.annotation.PersistentType; import ua.com.fielden.platform.entity.annotation.TimeOnly; import ua.com.fielden.platform.types.markers.IUtcDateTimeType; -/** - * Factory for date annotations. - * - * @author TG Team - * - */ +import java.lang.annotation.Annotation; + +/// Factory for date annotations. +/// public class DateAnnotations { - /** - * Instantiates {@link DateOnly} annotation. - * - * @return - */ + /// Instantiates [DateOnly] annotation. + /// public static DateOnly newDateOnlyAnnotation() { return new DateOnly() { @Override @@ -29,11 +23,8 @@ public Class annotationType() { }; } - /** - * Instantiates {@link TimeOnly} annotation. - * - * @return - */ + /// Instantiates [TimeOnly] annotation. + /// public static TimeOnly newTimeOnlyAnnotation() { return new TimeOnly() { @Override @@ -43,11 +34,8 @@ public Class annotationType() { }; } - /** - * Instantiates marker annotation for UTC date properties. - * - * @return - */ + /// Instantiates marker annotation for UTC date properties. + /// public static PersistentType newUtcAnnotation() { return new PersistentType() { @Override @@ -66,5 +54,16 @@ public Class userType() { } }; } - + + /// Instantiates [DependentTimeZoneMode] annotation. + /// + public static DependentTimeZoneMode newDependentTimeZoneModeAnnotation() { + return new DependentTimeZoneMode() { + @Override + public Class annotationType() { + return DependentTimeZoneMode.class; + } + }; + } + } \ No newline at end of file diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDates.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDates.java index b9e1a2c7245..e2bfed8fe7f 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDates.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/sample/domain/TgEntityWithTimeZoneDates.java @@ -4,6 +4,8 @@ import ua.com.fielden.platform.entity.AbstractPersistentEntity; import ua.com.fielden.platform.entity.annotation.CompanionObject; +import ua.com.fielden.platform.entity.annotation.DateOnly; +import ua.com.fielden.platform.entity.annotation.DependentTimeZoneMode; import ua.com.fielden.platform.entity.annotation.IsProperty; import ua.com.fielden.platform.entity.annotation.KeyTitle; import ua.com.fielden.platform.entity.annotation.KeyType; @@ -41,6 +43,35 @@ public class TgEntityWithTimeZoneDates extends AbstractPersistentEntity @AfterChange(UtcDatesToLocalDefiner.class) private Date datePropUtc; + @IsProperty + @MapTo + @Title("Date Prop Dependent") + @DependentTimeZoneMode + private Date datePropDependent; + + @IsProperty + @MapTo + @Title("Date Only Prop") + @DateOnly + private Date dateOnlyProp; + + @IsProperty + @MapTo + @Title("Date Only Prop UTC") + @PersistentType(userType = IUtcDateTimeType.class) + @DateOnly + private Date dateOnlyPropUtc; + + @Observable + public TgEntityWithTimeZoneDates setDatePropDependent(final Date datePropDependent) { + this.datePropDependent = datePropDependent; + return this; + } + + public Date getDatePropDependent() { + return datePropDependent; + } + @Observable public TgEntityWithTimeZoneDates setDatePropUtc(final Date datePropUtc) { this.datePropUtc = datePropUtc; @@ -60,4 +91,24 @@ public TgEntityWithTimeZoneDates setDateProp(final Date dateProp) { public Date getDateProp() { return dateProp; } + + @Observable + public TgEntityWithTimeZoneDates setDateOnlyProp(final Date dateOnlyProp) { + this.dateOnlyProp = dateOnlyProp; + return this; + } + + public Date getDateOnlyProp() { + return dateOnlyProp; + } + + @Observable + public TgEntityWithTimeZoneDates setDateOnlyPropUtc(final Date dateOnlyPropUtc) { + this.dateOnlyPropUtc = dateOnlyPropUtc; + return this; + } + + public Date getDateOnlyPropUtc() { + return dateOnlyPropUtc; + } } \ No newline at end of file diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/api/impl/TgJackson.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/api/impl/TgJackson.java index 616413ee75f..1cf13350c88 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/api/impl/TgJackson.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/api/impl/TgJackson.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.google.common.base.Charsets; import jakarta.inject.Inject; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.Logger; @@ -34,6 +33,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -225,10 +225,10 @@ public byte[] serialise(final Object obj) { } try { - // logger.debug("Serialised pretty JSON = |" + new String(writerWithDefaultPrettyPrinter().writeValueAsBytes(obj), Charsets.UTF_8) + "|."); + // logger.debug("Serialised pretty JSON = |" + new String(writerWithDefaultPrettyPrinter().writeValueAsBytes(obj), StandardCharsets.UTF_8) + "|."); EntitySerialiser.getContext().reset(); - final byte[] bytes = writeValueAsBytes(obj); // default encoding is Charsets.UTF_8 - logger.debug("Serialised JSON = |" + new String(bytes, Charsets.UTF_8) + "|."); + final byte[] bytes = writeValueAsBytes(obj); // default encoding is StandardCharsets.UTF_8 + logger.debug("Serialised JSON = |" + new String(bytes, StandardCharsets.UTF_8) + "|."); return bytes; } catch (final JsonProcessingException e) { diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/DefaultValueContract.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/DefaultValueContract.java index edb5be8b8b1..2bbe8c7d794 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/DefaultValueContract.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/DefaultValueContract.java @@ -1,19 +1,5 @@ package ua.com.fielden.platform.serialisation.jackson; -import static java.lang.Boolean.FALSE; -import static java.util.Optional.empty; -import static java.util.Optional.of; -import static ua.com.fielden.platform.entity.annotation.IsProperty.DEFAULT_DISPLAY_AS; -import static ua.com.fielden.platform.entity.annotation.IsProperty.DEFAULT_LENGTH; -import static ua.com.fielden.platform.entity.annotation.IsProperty.DEFAULT_PRECISION; -import static ua.com.fielden.platform.entity.annotation.IsProperty.DEFAULT_SCALE; -import static ua.com.fielden.platform.entity.annotation.IsProperty.DEFAULT_TRAILING_ZEROS; -import static ua.com.fielden.platform.reflection.TitlesDescsGetter.getDefaultEntityTitleAndDesc; -import static ua.com.fielden.platform.types.tuples.T2.t2; -import static ua.com.fielden.platform.utils.EntityUtils.equalsEx; - -import java.util.Optional; - import ua.com.fielden.platform.entity.AbstractEntity; import ua.com.fielden.platform.entity.annotation.DateOnly; import ua.com.fielden.platform.entity.annotation.PersistentType; @@ -26,15 +12,24 @@ import ua.com.fielden.platform.types.markers.IUtcDateTimeType; import ua.com.fielden.platform.types.tuples.T2; -/** - * A set of utilities to determine if the value of some property or meta-info is default. It is used internally for Jackson entity serialiser to significantly reduce the amount of - * the information to be serialised. - * - * @author TG Team - * - */ +import java.util.Optional; + +import static java.lang.Boolean.FALSE; +import static java.util.Optional.empty; +import static java.util.Optional.of; +import static ua.com.fielden.platform.entity.annotation.IsProperty.*; +import static ua.com.fielden.platform.reflection.AnnotationReflector.isPropertyAnnotationPresent; +import static ua.com.fielden.platform.reflection.TitlesDescsGetter.getDefaultEntityTitleAndDesc; +import static ua.com.fielden.platform.types.tuples.T2.t2; +import static ua.com.fielden.platform.utils.EntityUtils.equalsEx; + +/// A set of utilities to determine if the value of some property or meta-info is default. +/// It is used internally for Jackson entity serialiser to significantly reduce the amount of the information to be serialised. +/// public class DefaultValueContract { private static final String UTC = "UTC"; + public static final String DATE_ONLY = "DATE"; + public static final String TIME_ONLY = "TIME"; private DefaultValueContract() { } @@ -134,18 +129,14 @@ public static boolean isUtc(final Class entityType, final String propertyName return UTC.equals(getTimeZone(entityType, propertyName)); } - /** - * Returns the value that indicates what portion of date property to display. - * - * @param entityType - * @param propertyName - * @return - */ + /// Returns the value that indicates which portion of date property to display. + /// public static String getTimePortionToDisplay(final Class entityType, final String propertyName) { - if (AnnotationReflector.isPropertyAnnotationPresent(DateOnly.class, entityType, propertyName)) { - return "DATE"; - } else if (AnnotationReflector.isPropertyAnnotationPresent(TimeOnly.class, entityType, propertyName)) { - return "TIME"; + if (isPropertyAnnotationPresent(DateOnly.class, entityType, propertyName)) { + return DATE_ONLY; + } + else if (isPropertyAnnotationPresent(TimeOnly.class, entityType, propertyName)) { + return TIME_ONLY; } return null; } diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntitySerialiser.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntitySerialiser.java index bc8ea007c92..c785258a104 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntitySerialiser.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntitySerialiser.java @@ -199,12 +199,16 @@ private static > EntityType createEntityTypeInfo(fin if (!isIgnoreDefault(ignore)) { entityTypeProp.set_ignore(ignore); } - if (isPropertyAnnotationPresent(DateOnly.class, type, name)) { + final var timePortion = getTimePortionToDisplay(type, name); + if (DATE_ONLY.equals(timePortion)) { entityTypeProp.set_date(TRUE); } - if (isPropertyAnnotationPresent(TimeOnly.class, type, name)) { + else if (TIME_ONLY.equals(timePortion)) { entityTypeProp.set_time(TRUE); } + if (isPropertyAnnotationPresent(DependentTimeZoneMode.class, type, name)) { + entityTypeProp.set_dependentTimeZoneMode(TRUE); + } final IsProperty isPropertyAnnotation = AnnotationReflector.getPropertyAnnotation(IsProperty.class, type, name); if (isPropertyAnnotation != null) { final Long length = Long.valueOf(isPropertyAnnotation.length()); diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntityTypeProp.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntityTypeProp.java index 9e882f50900..74f9dbf5c33 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntityTypeProp.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/EntityTypeProp.java @@ -58,6 +58,10 @@ public class EntityTypeProp extends AbstractEntity { @Title(value = "TimeZone", desc = "TimeZone of date-typed property.") private String _timeZone; + @IsProperty + @Title(value = "Dependent Time-zone Mode", desc = "Dependent Time-zone Mode of date-typed property.") + private Boolean _dependentTimeZoneMode; + @IsProperty @Title(value = "Is Date Only?", desc = "Should display only date portion?") private Boolean _date; @@ -156,6 +160,16 @@ public Boolean get_date() { return _date; } + @Observable + public EntityTypeProp set_dependentTimeZoneMode(final Boolean _dependentTimeZoneMode) { + this._dependentTimeZoneMode = _dependentTimeZoneMode; + return this; + } + + public Boolean get_dependentTimeZoneMode() { + return _dependentTimeZoneMode; + } + @Observable public EntityTypeProp set_timeZone(final String _timeZone) { this._timeZone = _timeZone; diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleDeserialisers.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleDeserialisers.java index 0a4dad2571b..383b1c62ff3 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleDeserialisers.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleDeserialisers.java @@ -4,8 +4,8 @@ import static org.apache.logging.log4j.LogManager.getLogger; import static ua.com.fielden.platform.reflection.PropertyTypeDeterminator.stripIfNeeded; +import java.time.Duration; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; @@ -27,7 +27,7 @@ public class TgSimpleDeserialisers extends SimpleDeserializers { private static final Logger LOGGER = getLogger(TgSimpleDeserialisers.class); private final transient TgJacksonModule module; - private final transient Cache,JsonDeserializer> genClassDeserialisers = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).initialCapacity(1000).build(); + private final transient Cache,JsonDeserializer> genClassDeserialisers = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofSeconds(10)).initialCapacity(1000).build(); public TgSimpleDeserialisers(final TgJacksonModule module) { this.module = module; diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleSerialisers.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleSerialisers.java index d2d3c31791a..bc8a12cc94d 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleSerialisers.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/serialisation/jackson/TgSimpleSerialisers.java @@ -4,8 +4,8 @@ import static org.apache.logging.log4j.LogManager.getLogger; import static ua.com.fielden.platform.reflection.PropertyTypeDeterminator.stripIfNeeded; +import java.time.Duration; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; @@ -26,7 +26,7 @@ public class TgSimpleSerialisers extends SimpleSerializers { private static final Logger LOGGER = getLogger(TgSimpleSerialisers.class); private final transient TgJacksonModule module; - public final transient Cache, JsonSerializer> genClassSerialisers = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).initialCapacity(1000).build(); + public final transient Cache, JsonSerializer> genClassSerialisers = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofSeconds(10)).initialCapacity(1000).build(); public TgSimpleSerialisers(final TgJacksonModule module) { this.module = module; diff --git a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/utils/EntityUtils.java b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/utils/EntityUtils.java index b8b6c0a1db2..9a05fb751a2 100644 --- a/platform-pojo-bl/src/main/java/ua/com/fielden/platform/utils/EntityUtils.java +++ b/platform-pojo-bl/src/main/java/ua/com/fielden/platform/utils/EntityUtils.java @@ -37,9 +37,9 @@ import java.math.MathContext; import java.math.RoundingMode; import java.text.NumberFormat; +import java.time.Duration; import java.util.*; import java.util.Optional; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -67,9 +67,9 @@ public class EntityUtils { private static final Logger logger = getLogger(); - private static final Cache, Boolean> persistentTypes = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).initialCapacity(512).build(); - private static final Cache, Boolean> syntheticTypes = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).initialCapacity(512).build(); - private static final Cache, Boolean> entityCriteriaTypes = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.SECONDS).initialCapacity(512).build(); + private static final Cache, Boolean> persistentTypes = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofSeconds(10)).initialCapacity(512).build(); + private static final Cache, Boolean> syntheticTypes = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofSeconds(10)).initialCapacity(512).build(); + private static final Cache, Boolean> entityCriteriaTypes = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofSeconds(10)).initialCapacity(512).build(); public static final String ERR_PERSISTENT_NATURE_OF_ENTITY_TYPE = "Could not determine persistent nature of entity type [%s]."; diff --git a/platform-web-resources/pom.xml b/platform-web-resources/pom.xml index 9c528ce0836..15f0064e7fe 100644 --- a/platform-web-resources/pom.xml +++ b/platform-web-resources/pom.xml @@ -5,7 +5,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-web-resources diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/ioc/WebResourceLoader.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/ioc/WebResourceLoader.java index fbb8bb2554e..9e73c4d9870 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/ioc/WebResourceLoader.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/ioc/WebResourceLoader.java @@ -28,8 +28,8 @@ import java.io.InputStream; import java.util.*; -import static com.google.common.base.Charsets.UTF_8; import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.sort; import static java.util.Optional.empty; import static java.util.Optional.ofNullable; diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/FileResource.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/FileResource.java index 350ef0282f4..c5d9a728316 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/FileResource.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/FileResource.java @@ -19,7 +19,7 @@ import java.util.Set; import java.util.function.Supplier; -import static com.google.common.base.Charsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Optional.empty; import static java.util.Optional.of; import static org.restlet.data.MediaType.*; diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/GraphiQLResource.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/GraphiQLResource.java index 76e1283ca4e..df96fd8dd56 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/GraphiQLResource.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/GraphiQLResource.java @@ -1,6 +1,6 @@ package ua.com.fielden.platform.web.resources.webui; -import static com.google.common.base.Charsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.restlet.data.MediaType.TEXT_HTML; import static ua.com.fielden.platform.web.resources.RestServerUtil.encodedRepresentation; diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/MasterTestsComponentResource.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/MasterTestsComponentResource.java index f70997d57f8..7bbde18de50 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/MasterTestsComponentResource.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/MasterTestsComponentResource.java @@ -12,7 +12,7 @@ import org.restlet.representation.Representation; import org.restlet.resource.Get; -import com.google.common.base.Charsets; +import java.nio.charset.StandardCharsets; import ua.com.fielden.platform.entity.AbstractEntity; import ua.com.fielden.platform.utils.IDates; @@ -51,6 +51,6 @@ public MasterTestsComponentResource( @Get @Override public Representation get() { - return new EncodeRepresentation(Encoding.GZIP, new InputRepresentation(new ByteArrayInputStream(master.render().toString().getBytes(Charsets.UTF_8)), MediaType.TEXT_HTML)); + return new EncodeRepresentation(Encoding.GZIP, new InputRepresentation(new ByteArrayInputStream(master.render().toString().getBytes(StandardCharsets.UTF_8)), MediaType.TEXT_HTML)); } } \ No newline at end of file diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/ServiceWorkerResource.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/ServiceWorkerResource.java index f2fc4c1ab12..ac23f748c8f 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/ServiceWorkerResource.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/resources/webui/ServiceWorkerResource.java @@ -1,6 +1,6 @@ package ua.com.fielden.platform.web.resources.webui; -import static com.google.common.base.Charsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.restlet.data.MediaType.TEXT_JAVASCRIPT; import static ua.com.fielden.platform.web.resources.RestServerUtil.encodedRepresentation; diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/TgTestApplicationServerIocModule.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/TgTestApplicationServerIocModule.java index f50bddb016f..1aa0dc9e988 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/TgTestApplicationServerIocModule.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/TgTestApplicationServerIocModule.java @@ -22,9 +22,9 @@ import ua.com.fielden.platform.web.annotations.AppUri; import ua.com.fielden.platform.web.interfaces.IUserPreferencesProvider; +import java.time.Duration; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import static java.lang.String.format; @@ -70,7 +70,7 @@ protected void configure() { @Singleton @SessionCache Cache provideSessionCache(final @UntrustedDeviceSessionDuration int untrustedDeviceSessionDurationMins) { return CacheBuilder.newBuilder() - .expireAfterWrite(untrustedDeviceSessionDurationMins / 2, TimeUnit.MINUTES) + .expireAfterWrite(Duration.ofMinutes(untrustedDeviceSessionDurationMins / 2)) .build(); } diff --git a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/config/TgEntityWithTimeZoneDatesWebUiConfig.java b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/config/TgEntityWithTimeZoneDatesWebUiConfig.java index f1815034424..d0dc9ec1033 100644 --- a/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/config/TgEntityWithTimeZoneDatesWebUiConfig.java +++ b/platform-web-resources/src/main/java/ua/com/fielden/platform/web/test/server/config/TgEntityWithTimeZoneDatesWebUiConfig.java @@ -68,7 +68,8 @@ private EntityCentre createCentre(final Injector inje .withSummary("total_count_", "COUNT(SELF)", "Count:The total number of matching TgEntityWithTimeZoneDates.") .withAction(standardEditAction).also() .addProp("dateProp").minWidth(100).also() - .addProp("datePropUtc").minWidth(100) + .addProp("datePropUtc").minWidth(100).also() + .addProp("datePropDependent").minWidth(100) .addPrimaryAction(standardEditAction) .build(); @@ -76,11 +77,14 @@ private EntityCentre createCentre(final Injector inje return entityCentre; } private EntityMaster createMaster(final Injector injector) { - final String layout = LayoutComposer.mkGridForMaster(640, 1, 2); + final String layout = LayoutComposer.mkGridForMaster(960, 1, 5); final IMaster masterConfig = new SimpleMasterBuilder().forEntity(TgEntityWithTimeZoneDates.class) .addProp("dateProp").asDateTimePicker().also() .addProp("datePropUtc").asDateTimePicker().also() + .addProp("datePropDependent").asDateTimePicker().also() + .addProp("dateOnlyProp").asDatePicker().also() + .addProp("dateOnlyPropUtc").asDatePicker().also() .addAction(MasterActions.REFRESH).shortDesc("Cancel").longDesc("Cancel action") .addAction(MasterActions.SAVE) .setActionBarLayoutFor(Device.DESKTOP, Optional.empty(), LayoutComposer.mkActionLayoutForMaster()) diff --git a/platform-web-ui/pom.xml b/platform-web-ui/pom.xml index a74a9cc78c2..6dd2a5f53ed 100644 --- a/platform-web-ui/pom.xml +++ b/platform-web-ui/pom.xml @@ -3,7 +3,7 @@ fielden platform-parent - 2.4.4-SNAPSHOT + 2.4.5-SNAPSHOT platform-web-ui diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/svg/combining/IronIconsetUtility.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/svg/combining/IronIconsetUtility.java index f5cd6f9b177..2840ddb0bb2 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/svg/combining/IronIconsetUtility.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/svg/combining/IronIconsetUtility.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.file.DirectoryIteratorException; +import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; @@ -18,8 +19,6 @@ import java.util.List; import java.util.Set; -import com.google.common.base.Charsets; - public class IronIconsetUtility { public static final String FILE_BEGIN_TEMPLATE = "import '/resources/polymer/@polymer/iron-icon/iron-icon.js';%n" + "import '/resources/polymer/@polymer/iron-iconset-svg/iron-iconset-svg.js';%n" + @@ -39,7 +38,7 @@ public IronIconsetUtility(final String iconsetId, final int svgWidth, final Stri public void createSvgIconset(final String outputFile) throws IOException { try (OutputStream outputStream = new FileOutputStream(outputFile)) { - outputStream.write(joinFilesContent().getBytes(Charsets.UTF_8)); + outputStream.write(joinFilesContent().getBytes(StandardCharsets.UTF_8)); } } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/CentreDiffSerialiser.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/CentreDiffSerialiser.java index 9ac4af743ca..80fa8c2b79c 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/CentreDiffSerialiser.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/CentreDiffSerialiser.java @@ -35,8 +35,8 @@ private CentreDiffSerialiser() { */ public byte[] serialise(final Map diff) { try { - // logger.error("Serialised pretty JSON = |" + new String(writerWithDefaultPrettyPrinter().writeValueAsBytes(diff), Charsets.UTF_8) + "|."); - final byte[] bytes = writeValueAsBytes(diff); // default encoding is Charsets.UTF_8 + // logger.error("Serialised pretty JSON = |" + new String(writerWithDefaultPrettyPrinter().writeValueAsBytes(diff), StandardCharsets.UTF_8) + "|."); + final byte[] bytes = writeValueAsBytes(diff); // default encoding is StandardCharsets.UTF_8 return bytes; } catch (final JsonProcessingException ex) { throw new SerialisationException("Error during centre diff serialisation.", ex); diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateCriterionWidget.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateCriterionWidget.java index 3e0bdb6174c..d7caad20f26 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateCriterionWidget.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateCriterionWidget.java @@ -1,41 +1,29 @@ package ua.com.fielden.platform.web.centre.api.crit.impl; -import java.util.Map; - import ua.com.fielden.platform.entity.AbstractEntity; -import ua.com.fielden.platform.serialisation.jackson.DefaultValueContract; import ua.com.fielden.platform.web.view.master.api.widgets.datetimepicker.impl.DateTimePickerWidget; -/** - * An implementation for date double-editor criterion. - * - * @author TG Team - * - */ +import java.util.Map; + +/// An implementation for date double-editor criterion. +/// public class DateCriterionWidget extends AbstractRangeCriterionWidget { - /** - * Creates an instance of {@link DateCriterionWidget} for specified entity type and property name. - * - * @param criteriaType - * @param propertyName - */ + /// Creates an instance of [DateCriterionWidget] for specified entity type and property name. + /// public DateCriterionWidget(final Class> root, final Class managedType, final String propertyName) { super(root, "centre/criterion/multi/range/tg-date-range-criterion", propertyName, - new DateTimePickerWidget( - AbstractCriterionWidget.generateTitleDesc(root, managedType, propertyName).getKey(), - AbstractCriterionWidget.generateNames(root, managedType, propertyName).getKey(), - false, - DefaultValueContract.getTimeZone(managedType, propertyName), - DefaultValueContract.getTimePortionToDisplay(managedType, propertyName) - ), - new DateTimePickerWidget( - AbstractCriterionWidget.generateTitleDesc(root, managedType, propertyName).getValue(), - AbstractCriterionWidget.generateNames(root, managedType, propertyName).getValue(), - true, - DefaultValueContract.getTimeZone(managedType, propertyName), - DefaultValueContract.getTimePortionToDisplay(managedType, propertyName) - )); + new DateTimePickerWidget( + generateTitleDesc(root, managedType, propertyName).getKey(), + generateNames(root, managedType, propertyName).getKey(), + false + ), + new DateTimePickerWidget( + generateTitleDesc(root, managedType, propertyName).getValue(), + generateNames(root, managedType, propertyName).getValue(), + true + ) + ); } @Override diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateSingleCriterionWidget.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateSingleCriterionWidget.java index 7a88e0a974d..30c62fe4892 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateSingleCriterionWidget.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/crit/impl/DateSingleCriterionWidget.java @@ -1,31 +1,19 @@ package ua.com.fielden.platform.web.centre.api.crit.impl; import ua.com.fielden.platform.entity.AbstractEntity; -import ua.com.fielden.platform.serialisation.jackson.DefaultValueContract; import ua.com.fielden.platform.web.view.master.api.widgets.datetimepicker.impl.DateTimePickerWidget; -/** - * An implementation for date single-editor criterion. - * - * @author TG Team - * - */ +/// An implementation for date single-editor criterion. +/// public class DateSingleCriterionWidget extends AbstractSingleCriterionWidget { - /** - * Creates an instance of {@link DateSingleCriterionWidget} for specified entity type and property name. - * - * @param criteriaType - * @param propertyName - */ + /// Creates an instance of [DateSingleCriterionWidget] for specified entity type and property name. + /// public DateSingleCriterionWidget(final Class> root, final Class managedType, final String propertyName) { - super(root, propertyName, - new DateTimePickerWidget( - AbstractCriterionWidget.generateSingleTitleDesc(root, managedType, propertyName), - AbstractCriterionWidget.generateSingleName(root, managedType, propertyName), - false, - DefaultValueContract.getTimeZone(managedType, propertyName), - DefaultValueContract.getTimePortionToDisplay(managedType, propertyName) - )); + super(root, propertyName, new DateTimePickerWidget( + generateSingleTitleDesc(root, managedType, propertyName), + generateSingleName(root, managedType, propertyName), + false + )); } } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/impl/ResultSetBuilder.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/impl/ResultSetBuilder.java index f46e88c4f37..2a3641afc4c 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/impl/ResultSetBuilder.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/centre/api/impl/ResultSetBuilder.java @@ -7,7 +7,6 @@ import ua.com.fielden.platform.entity.fetch.IFetchProvider; import ua.com.fielden.platform.reflection.PropertyTypeDeterminator; import ua.com.fielden.platform.reflection.TitlesDescsGetter; -import ua.com.fielden.platform.serialisation.jackson.DefaultValueContract; import ua.com.fielden.platform.types.Colour; import ua.com.fielden.platform.types.Hyperlink; import ua.com.fielden.platform.types.Money; @@ -161,9 +160,7 @@ private Optional createWidget(final String propName) { } else if (isBoolean(propertyType)) { return of(new CheckboxWidget(pair("", TitlesDescsGetter.getTitleAndDesc(propName, root).getValue()), propName)); } else if (isDate(propertyType)) { - return of(new DateTimePickerWidget(pair("", TitlesDescsGetter.getTitleAndDesc(propName, root).getValue()), propName, false, - DefaultValueContract.getTimeZone(root, propName), - DefaultValueContract.getTimePortionToDisplay(root, propName))); + return of(new DateTimePickerWidget(pair("", TitlesDescsGetter.getTitleAndDesc(propName, root).getValue()), propName, false)); } else if (isCollectional(propertyType)) { return of(new CollectionalRepresentorWidget(pair("", TitlesDescsGetter.getTitleAndDesc(propName, root).getValue()),propName)); } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/menu/iconset/SvgButtonsIconset.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/menu/iconset/SvgButtonsIconset.java index 175ca07a000..063fa223c72 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/menu/iconset/SvgButtonsIconset.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/menu/iconset/SvgButtonsIconset.java @@ -5,8 +5,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; - -import com.google.common.base.Charsets; +import java.nio.charset.StandardCharsets; import ua.com.fielden.platform.svg.combining.IronIconsetUtility; @@ -19,7 +18,7 @@ public static void main(final String[] args) throws IOException { ""; for (int index = 1; index <= 9; index++) { try (OutputStream outputStream = new FileOutputStream(format("src/main/resources/images/collapse-expand/number%s.svg", index))) { - outputStream.write(numberSvgTemplate.replace('@', (index + "").charAt(0)).getBytes(Charsets.UTF_8)); + outputStream.write(numberSvgTemplate.replace('@', (index + "").charAt(0)).getBytes(StandardCharsets.UTF_8)); } } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/helpers/impl/WidgetSelector.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/helpers/impl/WidgetSelector.java index 8044b2caa04..d17450a0057 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/helpers/impl/WidgetSelector.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/helpers/impl/WidgetSelector.java @@ -5,8 +5,6 @@ import ua.com.fielden.platform.entity.annotation.DateOnly; import ua.com.fielden.platform.entity.annotation.TimeOnly; import ua.com.fielden.platform.reflection.PropertyTypeDeterminator; -import ua.com.fielden.platform.reflection.TitlesDescsGetter; -import ua.com.fielden.platform.serialisation.jackson.DefaultValueContract; import ua.com.fielden.platform.web.view.master.api.helpers.IWidgetSelector; import ua.com.fielden.platform.web.view.master.api.impl.SimpleMasterBuilder; import ua.com.fielden.platform.web.view.master.api.widgets.*; @@ -29,7 +27,8 @@ import java.util.Optional; import static java.lang.String.format; -import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.getTimePortionToDisplay; +import static ua.com.fielden.platform.reflection.TitlesDescsGetter.getTitleAndDesc; +import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.*; public class WidgetSelector> implements IWidgetSelector { @@ -79,15 +78,15 @@ public static > EntityAutocompletionWidget createAut final var declaredPropType = StringUtils.isEmpty(propertyName) ? entityType : PropertyTypeDeterminator.determinePropertyType(entityType, propertyName); return optPropType.map(propType -> { if (String.class.isAssignableFrom(declaredPropType)) { - return new EntityAutocompletionWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, entityType), propertyName, propType, true); + return new EntityAutocompletionWidget(getTitleAndDesc(propertyName, entityType), propertyName, propType, true); } else if (propType.equals(declaredPropType)) { - return new EntityAutocompletionWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, entityType), propertyName, propType, false); + return new EntityAutocompletionWidget(getTitleAndDesc(propertyName, entityType), propertyName, propType, false); } else { throw new EntityMasterConfigurationException(format(ERR_INVALID_AUTOCOMPLETER_TYPE, propType.getTypeName(), entityType.getSimpleName(), propertyName, declaredPropType.getTypeName())); } }).orElseGet(() -> { if (AbstractEntity.class.isAssignableFrom(declaredPropType)) { - return new EntityAutocompletionWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, entityType), propertyName, (Class>) declaredPropType, false); + return new EntityAutocompletionWidget(getTitleAndDesc(propertyName, entityType), propertyName, (Class>) declaredPropType, false); } else { throw new EntityMasterConfigurationException(format(ERR_INVALID_PROPERTY_FOR_AUTOCOMPLETION, entityType.getSimpleName(), propertyName, declaredPropType.getTypeName())); } @@ -96,31 +95,31 @@ public static > EntityAutocompletionWidget createAut @Override public ISinglelineTextConfig asSinglelineText() { - widget = new SinglelineTextWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new SinglelineTextWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new SinglelineTextConfig<>((SinglelineTextWidget) widget, smBuilder); } @Override public ICollectionalRepresentorConfig asCollectionalRepresentor() { - widget = new CollectionalRepresentorWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new CollectionalRepresentorWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new CollectionalRepresentorConfig<>((CollectionalRepresentorWidget) widget, smBuilder); } @Override public ICollectionalEditorConfig asCollectionalEditor() { - widget = new CollectionalEditorWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new CollectionalEditorWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new CollectionalEditorConfig<>((CollectionalEditorWidget) widget, smBuilder); } @Override public IMultilineTextConfig asMultilineText() { - widget = new MultilineTextWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), smBuilder.getEntityType(), propertyName); + widget = new MultilineTextWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), smBuilder.getEntityType(), propertyName); return new MultilineTextConfig<>((MultilineTextWidget) widget, smBuilder); } @Override public IRichTextConfig asRichText() { - widget = new RichTextWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), smBuilder.getEntityType(), propertyName); + widget = new RichTextWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), smBuilder.getEntityType(), propertyName); return new RichTextConfig<>((RichTextWidget)widget, smBuilder); } @@ -138,13 +137,7 @@ public IFileConfig asFile() { public IDateTimePickerConfig asDateTimePicker() { final String timePortion = getTimePortionToDisplay(smBuilder.getEntityType(), propertyName); if (timePortion == null) { - widget = new DateTimePickerWidget( - TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), - propertyName, - false, - DefaultValueContract.getTimeZone(smBuilder.getEntityType(), propertyName), - null - ); + widget = new DateTimePickerWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName, false); return new DateTimePickerConfig<>((DateTimePickerWidget) widget, smBuilder); } throw new EntityMasterConfigurationException(format(ERR_INVALID_DATEPICKER_CHOICE, @@ -153,15 +146,8 @@ public IDateTimePickerConfig asDateTimePicker() { @Override public IDatePickerConfig asDatePicker() { - final String DATE_ONLY = "DATE"; if (DATE_ONLY.equals(getTimePortionToDisplay(smBuilder.getEntityType(), propertyName))) { - widget = new DateTimePickerWidget( - TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), - propertyName, - false, - DefaultValueContract.getTimeZone(smBuilder.getEntityType(), propertyName), - DATE_ONLY - ); + widget = new DateTimePickerWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName, false); return new DatePickerConfig<>((DateTimePickerWidget) widget, smBuilder); } throw new EntityMasterConfigurationException(format(ERR_INVALID_DATEPICKER_CHOICE, propertyName, smBuilder.getEntityType().getSimpleName(), DateOnly.class.getSimpleName())); @@ -169,15 +155,8 @@ public IDatePickerConfig asDatePicker() { @Override public ITimePickerConfig asTimePicker() { - final String TIME_ONLY = "TIME"; if (TIME_ONLY.equals(getTimePortionToDisplay(smBuilder.getEntityType(), propertyName))) { - widget = new DateTimePickerWidget( - TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), - propertyName, - false, - DefaultValueContract.getTimeZone(smBuilder.getEntityType(), propertyName), - TIME_ONLY - ); + widget = new DateTimePickerWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName, false); return new TimePickerConfig<>((DateTimePickerWidget) widget, smBuilder); } throw new EntityMasterConfigurationException(format(ERR_INVALID_DATEPICKER_CHOICE, propertyName, smBuilder.getEntityType().getSimpleName(), TimeOnly.class.getSimpleName())); @@ -185,13 +164,13 @@ public ITimePickerConfig asTimePicker() { @Override public IDecimalConfig asDecimal() { - widget = new DecimalWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new DecimalWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new DecimalConfig<>((DecimalWidget) widget, smBuilder); } @Override public ISpinnerConfig asSpinner() { - widget = new SpinnerWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new SpinnerWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new SpinnerConfig<>((SpinnerWidget) widget, smBuilder); } @@ -202,13 +181,13 @@ public ISpinnerConfig asInteger() { @Override public IMoneyConfig asMoney() { - widget = new MoneyWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new MoneyWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new MoneyConfig<>((MoneyWidget) widget, smBuilder); } @Override public ICheckboxConfig asCheckbox() { - widget = new CheckboxWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new CheckboxWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new CheckboxConfig<>((CheckboxWidget) widget, smBuilder); } @@ -224,13 +203,13 @@ public IEmailConfig asEmail() { @Override public IColourConfig asColour() { - widget = new ColourWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new ColourWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new ColourConfig<>((ColourWidget) widget, smBuilder); } @Override public IHyperlinkConfig asHyperlink() { - widget = new HyperlinkWidget(TitlesDescsGetter.getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); + widget = new HyperlinkWidget(getTitleAndDesc(propertyName, smBuilder.getEntityType()), propertyName); return new HyperlinkConfig<>((HyperlinkWidget) widget, smBuilder); } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/widgets/datetimepicker/impl/DateTimePickerWidget.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/widgets/datetimepicker/impl/DateTimePickerWidget.java index b4c405a9912..12122a2770c 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/widgets/datetimepicker/impl/DateTimePickerWidget.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/api/widgets/datetimepicker/impl/DateTimePickerWidget.java @@ -1,44 +1,26 @@ package ua.com.fielden.platform.web.view.master.api.widgets.datetimepicker.impl; -import java.util.Map; - import ua.com.fielden.platform.utils.Pair; import ua.com.fielden.platform.web.view.master.api.widgets.impl.AbstractWidget; -/** - * The implementation for web date-time picker widgets. - * - * @author TG Team - * - */ +import java.util.Map; + +/// The implementation for Web UI date-time picker widgets. +/// public class DateTimePickerWidget extends AbstractWidget { private final boolean timePortionToBecomeEndOfDay; - private final String timeZone; - private final String datePortion; - /** - * Creates an instance of {@link DateTimePickerWidget} for specified entity type and property name. - * - * @param titleDesc - * @param propertyName - */ - public DateTimePickerWidget(final Pair titleDesc, final String propertyName, final boolean timePortionToBecomeEndOfDay, final String timeZone, final String datePortion) { + /// Creates an instance of [DateTimePickerWidget] for specified entity type and property name. + /// + public DateTimePickerWidget(final Pair titleDesc, final String propertyName, final boolean timePortionToBecomeEndOfDay) { super("editors/tg-datetime-picker", titleDesc, propertyName); this.timePortionToBecomeEndOfDay = timePortionToBecomeEndOfDay; - this.timeZone = timeZone; - this.datePortion = datePortion; } @Override protected Map createCustomAttributes() { final Map customAttr = super.createCustomAttributes(); customAttr.put("time-portion-to-become-end-of-day", timePortionToBecomeEndOfDay); - if (timeZone != null) { - customAttr.put("time-zone", timeZone); - } - if (datePortion != null) { - customAttr.put("date-portion", datePortion); - } return customAttr; } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/chart/decker/api/impl/ChartDeckerMaster.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/chart/decker/api/impl/ChartDeckerMaster.java index ca901e70895..c58a9b5e03c 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/chart/decker/api/impl/ChartDeckerMaster.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/chart/decker/api/impl/ChartDeckerMaster.java @@ -21,11 +21,8 @@ import java.util.function.Function; import java.util.stream.Stream; -import static java.util.Optional.ofNullable; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.StringUtils.join; -import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.getTimePortionToDisplay; -import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.getTimeZone; import static ua.com.fielden.platform.web.centre.EntityCentre.IMPORTS; import static ua.com.fielden.platform.web.centre.api.resultset.impl.FunctionalActionKind.PRIMARY_RESULT_SET; import static ua.com.fielden.platform.web.view.master.EntityMaster.ENTITY_TYPE; @@ -119,9 +116,9 @@ private String readyCallback(final IChartDeckerConfig deckerConfig) { + " },\n" + " lines: " + generateListOfValues(deck.getLines(), l -> generateLine(l)) + ",\n" + " dataPropertyNames: {\n" - + " groupKeyProp: " + generateValueAccessor(deck.getEntityType(), deck.getPropertyType(), deck.getGroupKeyProp()) + ",\n" + + " groupKeyProp: " + generateValueAccessor(deck.getPropertyType(), deck.getGroupKeyProp()) + ",\n" + " groupDescProp: '" + deck.getGroupDescProperty() + "',\n" - + " valueProps: " + generateListOfValues(deck.getSeries(), s -> generateValueAccessor(s.getEntityType(), s.getPropertyType(), s.getPropertyName())) + "\n" + + " valueProps: " + generateListOfValues(deck.getSeries(), s -> generateValueAccessor(s.getPropertyType(), s.getPropertyName())) + "\n" + " },\n" + " colours: " + generateListOfValues(deck.getSeries(), s -> "'" + s.getColour().getColourValue() + "'") + ",\n" + " barColour: (d, i) => self.barOptions[" + deckIndex + "].colours[i],\n" @@ -129,8 +126,8 @@ private String readyCallback(final IChartDeckerConfig deckerConfig) { + " propertyTypes: " + generateListOfValues(deck.getSeries(), s -> "'" + s.getPropertyType().getSimpleName() + "'") + ",\n" + " barLabel: (d, i) => this._labelFormatter(d, i, self.barOptions[" + deckIndex + "].propertyNames, self.barOptions[" + deckIndex + "].propertyTypes, self.barOptions[" + deckIndex + "].mode),\n" + " tooltip: (d, i) => this._tooltip(d, " - + generateValueAccessor(deck.getEntityType(), deck.getPropertyType(), deck.getGroupKeyProp()) + ", " - + generateValueAccessor(deck.getEntityType(), String.class, deck.getGroupDescProperty()) + ", " + + generateValueAccessor(deck.getPropertyType(), deck.getGroupKeyProp()) + ", " + + generateValueAccessor(String.class, deck.getGroupDescProperty()) + ", " + "self.barOptions[" + deckIndex + "].propertyNames[i], " + "self.barOptions[" + deckIndex + "].propertyTypes[i], " + "self.legendItems[" + deckIndex + "][i].title, " + deckIndex + ", i),\n" @@ -147,7 +144,7 @@ private String generateLineLegendItem(final ChartLine line) { } private String generateLine(final ChartLine line) { - return "{property: " + generateValueAccessor(line.getEntityType(), line.getPropertyType(), line.getProperty()) + ", title: '" + line.getTitle() + "', colour: '" + line.getColour().getColourValue() + "'}"; + return "{property: " + generateValueAccessor(line.getPropertyType(), line.getProperty()) + ", title: '" + line.getTitle() + "', colour: '" + line.getColour().getColourValue() + "'}"; } private String generateListOfValues(final List series, final Function func) { @@ -167,14 +164,11 @@ private String generateLegendItem(final ChartSeries series) { return "{title: '" + (isEmpty(series.getTitle()) ? "" : series.getTitle()) + "', colour: '" + series.getColour().getColourValue() + "'}"; } - private String generateValueAccessor(final Class deckType, final Class propertyType, final String aggregationProperty) { + private String generateValueAccessor(final Class propertyType, final String aggregationProperty) { if (Money.class.isAssignableFrom(propertyType)) { return "this._moneyPropAccessor('" + aggregationProperty + "')"; } else if (EntityUtils.isDate(propertyType)) { - final Optional timeZone = ofNullable(getTimeZone(deckType, aggregationProperty)); - final Optional timePortion = ofNullable(getTimePortionToDisplay(deckType, aggregationProperty)); - final String typeSpec = "Date:" + timeZone.orElse(":") + timePortion.orElse(""); - return "this._datePropAccessor('" + aggregationProperty + "', '" + typeSpec + "')"; + return "this._datePropAccessor('" + aggregationProperty + "')"; } return "'" + aggregationProperty + "'"; } diff --git a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/scatterplot/api/implementation/ScatterPlotMaster.java b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/scatterplot/api/implementation/ScatterPlotMaster.java index b928407155f..5ab5730d51b 100644 --- a/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/scatterplot/api/implementation/ScatterPlotMaster.java +++ b/platform-web-ui/src/main/java/ua/com/fielden/platform/web/view/master/scatterplot/api/implementation/ScatterPlotMaster.java @@ -24,9 +24,8 @@ import static java.util.Optional.*; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.StringUtils.join; -import static ua.com.fielden.platform.reflection.TitlesDescsGetter.*; -import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.getTimePortionToDisplay; -import static ua.com.fielden.platform.serialisation.jackson.DefaultValueContract.getTimeZone; +import static ua.com.fielden.platform.reflection.TitlesDescsGetter.getEntityTitleAndDesc; +import static ua.com.fielden.platform.reflection.TitlesDescsGetter.getTitleAndDesc; import static ua.com.fielden.platform.web.centre.EntityCentre.IMPORTS; import static ua.com.fielden.platform.web.centre.api.resultset.impl.FunctionalActionKind.PRIMARY_RESULT_SET; import static ua.com.fielden.platform.web.view.master.EntityMaster.ENTITY_TYPE; @@ -154,10 +153,7 @@ private String generateValueAccessor(Class> entityTy if (Money.class.isAssignableFrom(propertyType)) { return "this._moneyPropAccessor('" + propertyName + "')"; } else if (EntityUtils.isDate(propertyType)) { - final Optional timeZone = ofNullable(getTimeZone(entityType, propertyName)); - final Optional timePortion = ofNullable(getTimePortionToDisplay(entityType, propertyName)); - final String typeSpec = "Date:" + timeZone.orElse(":") + timePortion.orElse(""); - return "this._datePropAccessor('" + propertyName + "', '" + typeSpec + "')"; + return "this._datePropAccessor('" + propertyName + "')"; } return "'" + propertyName + "'"; } diff --git a/platform-web-ui/src/main/resources/package-lock.json b/platform-web-ui/src/main/resources/package-lock.json index 19934ee3a7f..2507518388a 100644 --- a/platform-web-ui/src/main/resources/package-lock.json +++ b/platform-web-ui/src/main/resources/package-lock.json @@ -86,73 +86,73 @@ "optional": true }, "node_modules/@fullcalendar/core": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz", - "integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.21.tgz", + "integrity": "sha512-t3u/+sqh3Iq7TWtUnVLcGDUE6OWZh0UD3c04bI/l7lSLAgAKr3kngBmhHiQD1QXpwC8ZN5iNqG7a7gOVixhSKQ==", "license": "MIT", "dependencies": { "preact": "~10.12.1" } }, "node_modules/@fullcalendar/daygrid": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz", - "integrity": "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.21.tgz", + "integrity": "sha512-QYb1y40RGYLlOxKpYWg8O+7njEnKnFG8Tt7qjnubJGR35s1phQg67E+81y2TyAbbm59p2JFOCXGDk9t6KDujIA==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.20" + "@fullcalendar/core": "~6.1.21" } }, "node_modules/@fullcalendar/interaction": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.20.tgz", - "integrity": "sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.21.tgz", + "integrity": "sha512-WPYpqtljDWmU0Xm2cOtFrLlocgxv7cgkOppj34Q6OUUat8a6Cnd6kYo2JR+irP223PE5lBYHFNp1qh7SIpJc0w==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.20" + "@fullcalendar/core": "~6.1.21" } }, "node_modules/@fullcalendar/list": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.20.tgz", - "integrity": "sha512-7Hzkbb7uuSqrXwTyD0Ld/7SwWNxPD6SlU548vtkIpH55rZ4qquwtwYdMPgorHos5OynHA4OUrZNcH51CjrCf2g==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.21.tgz", + "integrity": "sha512-2rpIhs5pJmV7jyk4oX4bckNqurt6iHcsweE3FDYDdNpmRukPrARnyQYcaVFNVw2bnBFeR/jQW/St2MlauxF3GQ==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.20" + "@fullcalendar/core": "~6.1.21" } }, "node_modules/@fullcalendar/moment-timezone": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/moment-timezone/-/moment-timezone-6.1.20.tgz", - "integrity": "sha512-fGk3bQU4hf0rgw3Zd/PH6Ok0Db+s9/nsuALj3IG8GYFqInwLsHZI0Qc+ljN8jv9LrLS5sOBBOZHWDg2ncx1inw==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/moment-timezone/-/moment-timezone-6.1.21.tgz", + "integrity": "sha512-1H5voLR6PGiIf+JM6TCWq8oMTMOOqs+Am8lo/3GzHnBPo81RN72h87zm50YgGq9HjIsMdNs7RgdMVAUcXByerQ==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.20", + "@fullcalendar/core": "~6.1.21", "moment-timezone": "^0.5.40" } }, "node_modules/@fullcalendar/multimonth": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.20.tgz", - "integrity": "sha512-rMMiPBA71lUJ1DV/0ckPtN4/G4LozkkDKoG7/CbmTYqFJiMRskM/1WpilhtRn4iUdNe03V5K7ofFQRs0wo4ZtQ==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.21.tgz", + "integrity": "sha512-/5IZDDcdRzgO/h7V3RBEhzhrza5TIQ2T025IjA2Dfq3xbvxSnMAl2CMcy7VrSHsKaY1eWvxQXg/NZZm7hLmDYA==", "license": "MIT", "dependencies": { - "@fullcalendar/daygrid": "~6.1.20" + "@fullcalendar/daygrid": "~6.1.21" }, "peerDependencies": { - "@fullcalendar/core": "~6.1.20" + "@fullcalendar/core": "~6.1.21" } }, "node_modules/@fullcalendar/timegrid": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.20.tgz", - "integrity": "sha512-4H+/MWbz3ntA50lrPif+7TsvMeX3R1GSYjiLULz0+zEJ7/Yfd9pupZmAwUs/PBpA6aAcFmeRr0laWfcz1a9V1A==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.21.tgz", + "integrity": "sha512-2DnShx/jallGmb8QCkr6pAOu/zuPhJrP7+uTrAtSnbqsX7GF3lTxqSeNGkTQwsgF5g/ia8udhQ+JNYaE+TN1cQ==", "license": "MIT", "dependencies": { - "@fullcalendar/daygrid": "~6.1.20" + "@fullcalendar/daygrid": "~6.1.21" }, "peerDependencies": { - "@fullcalendar/core": "~6.1.20" + "@fullcalendar/core": "~6.1.21" } }, "node_modules/@google-web-components/google-chart": { @@ -1130,9 +1130,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.3.tgz", - "integrity": "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", + "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -1224,17 +1224,17 @@ } }, "node_modules/fullcalendar": { - "version": "6.1.20", - "resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.20.tgz", - "integrity": "sha512-7lz2P+0YdA86fBTwfr/ducajrM3zUw5o6uoiiYk9xMqcoTf003xBh3mpzW5om9slfAMwGgCBh0KsiYcU1JY1eQ==", + "version": "6.1.21", + "resolved": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.21.tgz", + "integrity": "sha512-yGZhflQmfCJKmmOlwJcQ0MPNAYABieaiJp9AaRgHBMRIUxNA+VFa6mkIbVNpjdSZIy9AY2HwteTt58tJ+3ktuQ==", "license": "MIT", "dependencies": { - "@fullcalendar/core": "~6.1.20", - "@fullcalendar/daygrid": "~6.1.20", - "@fullcalendar/interaction": "~6.1.20", - "@fullcalendar/list": "~6.1.20", - "@fullcalendar/multimonth": "~6.1.20", - "@fullcalendar/timegrid": "~6.1.20" + "@fullcalendar/core": "~6.1.21", + "@fullcalendar/daygrid": "~6.1.21", + "@fullcalendar/interaction": "~6.1.21", + "@fullcalendar/list": "~6.1.21", + "@fullcalendar/multimonth": "~6.1.21", + "@fullcalendar/timegrid": "~6.1.21" } }, "node_modules/get-caller-file": { @@ -1384,10 +1384,20 @@ } }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -1444,9 +1454,9 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", - "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -1523,9 +1533,9 @@ "license": "MIT" }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -1725,9 +1735,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.25.6", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.6.tgz", - "integrity": "sha512-RIm+e9BiqAaJ1mRECv3vR3C+VG8ELoTTI+47tVudGi82yLnFOx3G/p/iSPK1HmHQdKhkkrJ68NJqxh7S+FBVmQ==", + "version": "1.25.9", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.9.tgz", + "integrity": "sha512-pRTklkDDMMRopyoAcrr9wV/8g/RYgrLHBuJAb5hlEuYZRdm5yqmPjWId83fpBwPpSFqEdja0H7Dfd7z1X/npcA==", "license": "MIT", "dependencies": { "orderedmap": "^2.0.0" @@ -1754,12 +1764,12 @@ } }, "node_modules/prosemirror-view": { - "version": "1.41.8", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", - "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "version": "1.41.9", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.9.tgz", + "integrity": "sha512-clTunTX+eaLbr87L1V1QPheRlEQJyTlL3gXe9x3jQIk3rL0RVWxviDGz8tFaydwIVm+hKhYCyr+R/zBtWr9s6A==", "license": "MIT", "dependencies": { - "prosemirror-model": "^1.20.0", + "prosemirror-model": "^1.25.8", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } @@ -2008,9 +2018,9 @@ } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", "dev": true, "license": "MIT", "dependencies": { diff --git a/platform-web-ui/src/main/resources/package.json b/platform-web-ui/src/main/resources/package.json index bd9a18805dd..f6edfbd50b2 100644 --- a/platform-web-ui/src/main/resources/package.json +++ b/platform-web-ui/src/main/resources/package.json @@ -79,7 +79,7 @@ "//": "Do NOT nest overrides under a package that appears as $ elsewhere (npm/cli#5914 + #5730). Hoist such sub-rules to the root instead.", "overrides": { "@toast-ui/editor": { - "dompurify": "^3.4.3", + "dompurify": "^3.4.11", "@types/trusted-types": "../_EXCLUDED_" }, "wct-browser-legacy": { diff --git a/platform-web-ui/src/main/resources/polymer/dompurify/dist/purify.es.mjs.js b/platform-web-ui/src/main/resources/polymer/dompurify/dist/purify.es.mjs.js index fa15f56486f..3c6d3d19922 100644 --- a/platform-web-ui/src/main/resources/polymer/dompurify/dist/purify.es.mjs.js +++ b/platform-web-ui/src/main/resources/polymer/dompurify/dist/purify.es.mjs.js @@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.3/LICENSE */ +/*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); @@ -310,7 +310,7 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']); const text = freeze(['#text']); -const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']); +const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']); const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']); const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']); const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']); @@ -327,16 +327,31 @@ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205 ); const DOCTYPE_NAME = seal(/^html$/i); const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); +// Markup-significant character probes used by _sanitizeElements. +// Shared module-level instances are safe despite the sticky /g flags: +// unapply() resets lastIndex for RegExp receivers before every call. +const ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); +const COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); +const FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); +const SELF_CLOSING_TAG = seal(/\/>/i); -/* eslint-disable @typescript-eslint/indent */ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType const NODE_TYPE = { element: 1, + attribute: 2, text: 3, + cdataSection: 4, + entityReference: 5, // Deprecated - progressingInstruction: 7, + entityNode: 6, + // Deprecated + processingInstruction: 7, comment: 8, - document: 9}; + document: 9, + documentType: 10, + documentFragment: 11, + notation: 12 // Deprecated +}; const getGlobal = function getGlobal() { return typeof window === 'undefined' ? null : window; }; @@ -391,10 +406,25 @@ const _createHooksMap = function _createHooksMap() { uponSanitizeShadowNode: [] }; }; +/** + * Resolve a set-valued configuration option: a fresh set built from + * cfg[key] when it is an own array property (seeded with a clone of + * options.base when given, case-normalized via options.transform), + * the fallback set otherwise. + * + * @param cfg the cloned, prototype-free configuration object + * @param key the configuration property to read + * @param fallback the set to use when the option is absent or not an array + * @param options transform and optional base set to merge into + * @returns the resolved set + */ +const _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) { + return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback; +}; function createDOMPurify() { let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); const DOMPurify = root => createDOMPurify(root); - DOMPurify.version = '3.4.3'; + DOMPurify.version = '3.4.11'; DOMPurify.removed = []; if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { // Not running in a browser, provide a factory function @@ -405,15 +435,15 @@ function createDOMPurify() { let document = window.document; const originalDocument = document; const currentScript = originalDocument.currentScript; - const DocumentFragment = window.DocumentFragment, - HTMLTemplateElement = window.HTMLTemplateElement, + window.DocumentFragment; + const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, - _window$NamedNodeMap = window.NamedNodeMap, - NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, - HTMLFormElement = window.HTMLFormElement, - DOMParser = window.DOMParser, + _window$NamedNodeMap = window.NamedNodeMap; + _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap; + window.HTMLFormElement; + const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes; const ElementPrototype = Element.prototype; const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); @@ -421,6 +451,10 @@ function createDOMPurify() { const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); + const getAttributes = lookupGetter(ElementPrototype, 'attributes'); + const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; + const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; // As per issue #47, the web-components registry is inherited by a // new document created via createHTMLDocument. As per the spec // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) @@ -435,6 +469,54 @@ function createDOMPurify() { } let trustedTypesPolicy; let emptyHTML = ''; + // The instance's own internal Trusted Types policy. Unlike a caller-supplied + // `TRUSTED_TYPES_POLICY`, this is created at most once — Trusted Types throws + // on duplicate policy names — and is the only policy allowed to persist + // across configurations and survive `clearConfig()`. + let defaultTrustedTypesPolicy; + let defaultTrustedTypesPolicyResolved = false; + // Tracks whether we are already inside a call to the configured Trusted Types + // policy (`createHTML` or `createScriptURL`). If a supplied policy callback + // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would + // re-enter the policy and recurse until the stack overflows. We detect that + // re-entry and throw a clear, actionable error instead. The guard is shared + // across both callbacks, because either one re-entering `sanitize` triggers + // the same unbounded recursion. + let IN_TRUSTED_TYPES_POLICY = 0; + const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() { + if (IN_TRUSTED_TYPES_POLICY > 0) { + throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or ' + 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' + 'infinite recursion. Do not pass a policy whose callbacks wrap ' + 'DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted ' + 'Types" section of the README.'); + } + }; + const _createTrustedHTML = function _createTrustedHTML(html) { + _assertNotInTrustedTypesPolicy(); + IN_TRUSTED_TYPES_POLICY++; + try { + return trustedTypesPolicy.createHTML(html); + } finally { + IN_TRUSTED_TYPES_POLICY--; + } + }; + const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) { + _assertNotInTrustedTypesPolicy(); + IN_TRUSTED_TYPES_POLICY++; + try { + return trustedTypesPolicy.createScriptURL(scriptUrl); + } finally { + IN_TRUSTED_TYPES_POLICY--; + } + }; + // Lazily resolve (and cache) the instance's internal default policy. + // Resolution is attempted at most once: a successful `createPolicy` cannot be + // repeated (Trusted Types throws on duplicate names), and a failed or + // unsupported attempt must not be retried on every parse. + const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() { + if (!defaultTrustedTypesPolicyResolved) { + defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); + defaultTrustedTypesPolicyResolved = true; + } + return defaultTrustedTypesPolicy; + }; const _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, @@ -531,6 +613,13 @@ function createDOMPurify() { let WHOLE_DOCUMENT = false; /* Track whether config is already set on this instance of DOMPurify. */ let SET_CONFIG = false; + /* Pristine allowlist bindings captured at setConfig() time. On the + * persistent-config path sanitize() restores the sets from these before + * the per-walk hook clone-guard, so a hook's in-call widening cannot + * carry across calls. Null until setConfig() is called; reset by + * clearConfig(). */ + let SET_CONFIG_ALLOWED_TAGS = null; + let SET_CONFIG_ALLOWED_ATTR = null; /* Decide if all elements (e.g. style, script) must be children of * document.body. By default, browsers might move them to document.head */ let FORCE_BODY = false; @@ -573,7 +662,17 @@ function createDOMPurify() { let USE_PROFILES = {}; /* Tags to ignore content of when KEEP_CONTENT is true */ let FORBID_CONTENTS = null; - const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']); + const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', + // mirrors the selected