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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ public override bool IsConverter(IPublishedPropertyType propertyType)

/// <inheritdoc/>
protected override object ConvertToObject(DateTimeDto dateTimeDto)
=> DateOnly.FromDateTime(dateTimeDto.Date.UtcDateTime);
=> DateOnly.FromDateTime(dateTimeDto.Date.DateTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,5 @@ public override bool IsConverter(IPublishedPropertyType propertyType)

/// <inheritdoc/>
protected override object ConvertToObject(DateTimeDto dateTimeDto)
=> DateTime.SpecifyKind(dateTimeDto.Date.UtcDateTime, DateTimeKind.Unspecified);

=> DateTime.SpecifyKind(dateTimeDto.Date.DateTime, DateTimeKind.Unspecified);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ public override bool IsConverter(IPublishedPropertyType propertyType)

/// <inheritdoc/>
protected override object ConvertToObject(DateTimeDto dateTimeDto)
=> TimeOnly.FromDateTime(dateTimeDto.Date.UtcDateTime);
=> TimeOnly.FromDateTime(dateTimeDto.Date.DateTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import type { UUIComboboxElement, UUIComboboxEvent } from '@umbraco-cms/backoffice/external/uui';

interface UmbDateTime {
date: string | undefined;
timeZone: string | undefined;
date: string | null;
timeZone: string | null;
}

interface UmbTimeZonePickerOption extends UmbTimeZone {
Expand All @@ -34,6 +34,7 @@
{
private _timeZoneOptions: Array<UmbTimeZonePickerOption> = [];
private _clientTimeZone: UmbTimeZone | undefined;
private _timeZoneMode: UmbTimeZonePickerValue['mode'] | undefined;

@property({ type: Boolean, reflect: true })
readonly = false;
Expand Down Expand Up @@ -104,6 +105,7 @@
() => {
return (
this._displayTimeZone &&
this._timeZoneMode !== 'local' &&

Check warning on line 108 in src/Umbraco.Web.UI.Client/src/packages/property-editors/date-time/property-editor-ui-date-time-picker-base.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (release/17.0)

❌ Getting worse: Complex Method

UmbPropertyEditorUiDateTimePickerElementBase.constructor increases in cyclomatic complexity from 13 to 14, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
!!this.value?.timeZone &&
!this._timeZoneOptions.some((opt) => opt.value === this.value?.timeZone && !opt.invalid)
);
Expand All @@ -120,8 +122,13 @@
if (this._displayTimeZone) {
timeZonePickerConfig = config.getValueByAlias<UmbTimeZonePickerValue>('timeZones');
}

this.#setTimeInputStep(timeFormat);
this.#prefillValue(timeZonePickerConfig);

// To ensure the expected value matches the prefilled value, we trigger an update.
// If the values match, no change event will be fired.
this.#updateValue(this._selectedDate?.toISO({ includeOffset: false }) ?? null);
}

#prefillValue(timeZonePickerConfig: UmbTimeZonePickerValue | undefined) {
Expand Down Expand Up @@ -158,8 +165,8 @@
#prefillTimeZones(config: UmbTimeZonePickerValue | undefined, selectedDate: DateTime | undefined) {
// Retrieve the time zones from the config
this._clientTimeZone = getClientTimeZone();
this._timeZoneMode = config?.mode;

Check warning on line 169 in src/Umbraco.Web.UI.Client/src/packages/property-editors/date-time/property-editor-ui-date-time-picker-base.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (release/17.0)

❌ New issue: Complex Method

UmbPropertyEditorUiDateTimePickerElementBase.prefillTimeZones has a cyclomatic complexity of 9, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
// Retrieve the time zones from the config
const dateToCalculateOffset = selectedDate ?? DateTime.now();
switch (config?.mode) {
case 'all':
Expand Down Expand Up @@ -219,7 +226,8 @@
return;
}
} else if (this.value?.date) {
return; // If there is a date but no time zone, we don't preselect anything
// If there is no time zone in the value, but there is a date, we leave the time zone unselected
return;
}

// Check if we can pre-select the client time zone
Expand Down Expand Up @@ -269,16 +277,8 @@
return;
}

if (!newPickerValue) {
this._datePickerValue = '';
this.value = undefined;
this._selectedDate = undefined;
this.dispatchEvent(new UmbChangeEvent());
return;
}

this._datePickerValue = newPickerValue;
this.#updateValue(value, true);
this.#updateValue(value);
}

#onTimeZoneChange(event: UUIComboboxEvent) {
Expand All @@ -291,7 +291,7 @@

if (!this._selectedTimeZone) {
if (this.value?.date) {
this.value = { date: this.value.date, timeZone: undefined };
this.value = { date: this.value.date, timeZone: null };
} else {
this.value = undefined;
}
Expand All @@ -303,46 +303,84 @@
return;
}

this.#updateValue(this._selectedDate.toISO({ includeOffset: false }) || '');
this.#updateValue(this._selectedDate.toISO({ includeOffset: false }));
}

#updateValue(date: string, updateOffsets = false) {
#updateValue(date: string | null) {
// Try to parse the date with the selected time zone
const newDate = DateTime.fromISO(date, { zone: this._selectedTimeZone ?? 'UTC' });
const newDate = date ? DateTime.fromISO(date, { zone: this._selectedTimeZone || 'UTC' }) : null;

// If the date is invalid, we reset the value
if (!newDate.isValid) {
if (!newDate || !newDate.isValid) {
if (!this.value) {
return; // No change
}
this.value = undefined;
this._selectedDate = undefined;
this.dispatchEvent(new UmbChangeEvent());
this.#updateOffsets(DateTime.now());
return;
}

const previousDate = this._selectedDate;
this._selectedDate = newDate;
this.value = {
date: this.#getCurrentDateValue(),
timeZone: this._selectedTimeZone,

let timeZoneToStore = null;
if (!this._displayTimeZone || !this._timeZoneMode) {
timeZoneToStore = null;
} else if (this._timeZoneMode === 'local') {
timeZoneToStore = 'UTC';
} else {
timeZoneToStore = this._selectedTimeZone ?? null;
}

const dateToStore =
timeZoneToStore && this._selectedTimeZone !== timeZoneToStore ? newDate.setZone(timeZoneToStore) : newDate;

const newValue = {
date: this.#formatDateValue(dateToStore),
timeZone: timeZoneToStore,
};

if (updateOffsets) {
this._timeZoneOptions.forEach((opt) => {
opt.offset = getTimeZoneOffset(opt.value, newDate);
});
// Update the time zone options (mostly for the offset)
this._filteredTimeZoneOptions = this._timeZoneOptions;
// Only update the stored data if it has actually changed to avoid firing unnecessary change events
const previousValue = this.value;
if (previousValue?.date === newValue.date && previousValue?.timeZone === newValue.timeZone) {
return;
}

this.value = newValue;
this.dispatchEvent(new UmbChangeEvent());

// Only update offsets if the date timestamp has changed
if (previousDate?.toUnixInteger() !== newDate.toUnixInteger()) {
this.#updateOffsets(newDate);
}

Check warning on line 357 in src/Umbraco.Web.UI.Client/src/packages/property-editors/date-time/property-editor-ui-date-time-picker-base.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (release/17.0)

❌ New issue: Complex Method

UmbPropertyEditorUiDateTimePickerElementBase.updateValue has a cyclomatic complexity of 17, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}

#getCurrentDateValue(): string | undefined {
#updateOffsets(date: DateTime) {
if (!this._displayTimeZone) return;
this._timeZoneOptions.forEach((opt) => {
opt.offset = getTimeZoneOffset(opt.value, date);
});
// Update the time zone options (mostly for the offset)
this._filteredTimeZoneOptions = this._timeZoneOptions;
}

#formatDateValue(date: DateTime): string | null {
let formattedDate: string | undefined;
switch (this._dateInputType) {
case 'date':
return this._selectedDate?.toISODate() ?? undefined;
formattedDate = date.toFormat('yyyy-MM-dd');
break;
case 'time':
return this._selectedDate?.toISOTime({ includeOffset: false }) ?? undefined;
formattedDate = date.toFormat('HH:mm:ss');
break;
default:
return this._selectedDate?.toISO({ includeOffset: !!this._selectedTimeZone }) ?? undefined;
formattedDate = date.toFormat(`yyyy-MM-dd'T'HH:mm:ss${this._timeZoneMode ? 'ZZ' : ''}`);
break;
}

return formattedDate ?? null;
}

#onTimeZoneSearch(event: UUIComboboxEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ protected override void CustomTestSetup(IUmbracoBuilder builder)

private static readonly object[] _sourceList1 =
[
new object[] { Constants.PropertyEditors.Aliases.DateOnly, false, new DateOnly(2025, 1, 22) },
new object[] { Constants.PropertyEditors.Aliases.DateOnly, false, new DateOnly(2025, 6, 22) },
new object[] { Constants.PropertyEditors.Aliases.TimeOnly, false, new TimeOnly(18, 33, 1) },
new object[] { Constants.PropertyEditors.Aliases.DateTimeUnspecified, false, new DateTime(2025, 1, 22, 18, 33, 1) },
new object[] { Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, true, new DateTimeOffset(2025, 1, 22, 18, 33, 1, TimeSpan.Zero) },
new object[] { Constants.PropertyEditors.Aliases.DateTimeUnspecified, false, new DateTime(2025, 6, 22, 18, 33, 1) },
new object[] { Constants.PropertyEditors.Aliases.DateTimeWithTimeZone, true, new DateTimeOffset(2025, 6, 22, 18, 33, 1, TimeSpan.FromHours(2)) },
];

[TestCaseSource(nameof(_sourceList1))]
Expand Down Expand Up @@ -105,7 +105,7 @@ public async Task Returns_Correct_Type_Based_On_Configuration(
.WithValue(
new JsonObject
{
["date"] = "2025-01-22T18:33:01.0000000+00:00",
["date"] = "2025-06-22T18:33:01.0000000+02:00",
["timeZone"] = "Europe/Copenhagen",
})
.Done()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
private static object[] _dateTimeUnspecifiedConvertToObjectCases =
[
new object[] { null, null },
new object[] { _convertToObjectInputDate, DateTime.Parse("2025-08-20T17:30:00") },
new object[] { _convertToObjectInputDate, DateTime.Parse("2025-08-20T16:30:00") },
];

[TestCaseSource(nameof(_dateTimeUnspecifiedConvertToObjectCases))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void Can_Convert_To_Intermediate_Value(string? input, object? expected)
private static object[] _timeOnlyConvertToObjectCases =
[
new object[] { null, null },
new object[] { _convertToObjectInputDate, TimeOnly.Parse("17:30") },
new object[] { _convertToObjectInputDate, TimeOnly.Parse("16:30") },
];

[TestCaseSource(nameof(_timeOnlyConvertToObjectCases))]
Expand Down
Loading