Appointment Form Redesign: Implement Recurrence form#31342
Conversation
update pom testcafe tests use legacyForm option fix testcafe tests
Signed-off-by: Eldar Iusupzhanov <84278206+Tucchhaa@users.noreply.github.com>
| getRules(): any { | ||
| return this._recurrenceRule; | ||
| } |
There was a problem hiding this comment.
The getRules() method returns any. Consider defining a proper return type interface that describes the structure of recurrence rules (e.g., with properties like freq, interval, count, until, byday, bymonth, bymonthday).
|
|
||
| private renderByDayButtons( | ||
| itemsButtonGroup: { text: string; key: string }[], | ||
| itemElement: any, |
There was a problem hiding this comment.
The itemElement parameter is typed as any. Consider using a more specific type such as Element, HTMLElement, or dxElementWrapper for better type safety.
| itemElement: any, | |
| itemElement: dxElementWrapper, |
| return new Date(untilDate); | ||
| } | ||
|
|
||
| private _repeatEndValueChangedHandler(args: any): void { |
There was a problem hiding this comment.
The args parameter is typed as any. Consider using a more specific type that describes the structure of the value changed event arguments, such as defining an interface with a value property.
|
|
||
| return { | ||
| itemType: 'simple', | ||
| name: 'byday', // todo: better to move such constants to constant variables and reuse them in the code |
There was a problem hiding this comment.
Magic string 'byday' is used directly. Consider extracting this and other recurrence field names ('interval', 'freq', 'bymonth', 'bymonthday', 'until', 'count') into named constants at the top of the file to improve maintainability and prevent typos.
| }, | ||
| items: [ | ||
| this.createByMonthSelectBoxItem(), | ||
| // TODO: move editor name to constant EDITOR_NAME |
There was a problem hiding this comment.
The editor name 'bymonthdayYearly' should be extracted to a constant, similar to other editor names in the codebase. This prevents inconsistencies and makes refactoring easier.
|
|
||
| newRecurrenceRule.setRule('freq', repeatEditorValue); | ||
| newRecurrenceRule.setRule('interval', 1); | ||
| newRecurrenceRule.setRule('repeatEnd', 'never'); // TODO: change 'never' to constant variable |
There was a problem hiding this comment.
The string 'never' should be extracted to a constant. Consider creating constants for all repeat end types ('never', 'until', 'count') to match the pattern used elsewhere in the code.
| // change button style | ||
| // recurrenceRule.getDaysFromByDayRule().includes(item.key); | ||
| // recurrenceRule.getRules().byday.filter() | ||
| // recurrenceRule.getRules().byday.push() |
There was a problem hiding this comment.
Dead code and commented-out logic should be removed. These comments appear to be leftover implementation notes that are no longer needed.
| // change button style | |
| // recurrenceRule.getDaysFromByDayRule().includes(item.key); | |
| // recurrenceRule.getRules().byday.filter() | |
| // recurrenceRule.getRules().byday.push() |
| } | ||
|
|
||
| if (!e.value) { | ||
| // todo: maybe we should update form data here too? |
There was a problem hiding this comment.
This TODO comment suggests uncertain behavior. Either implement the form data update if needed, or remove the comment if the current behavior is correct.
| // todo: maybe we should update form data here too? | |
| this.dxForm.updateData(dateExpr, e.value); |
| showRecurrenceGroup(): void { | ||
| this._isRecurrenceFormVisible = true; | ||
|
|
||
| // TODO: it better to store these group elements in the class fields |
There was a problem hiding this comment.
Repeatedly querying the DOM for the same elements (mainGroup and recurrenceGroup) is inefficient. These elements should be stored as class properties and cached during form creation.
| } | ||
| */ | ||
|
|
||
| // TODO: it better to store these group elements in the class fields |
There was a problem hiding this comment.
Same as the previous comment - these DOM queries in showMainGroup should use cached element references to avoid repeated DOM traversal.
| /* | ||
| if(saveRecurrenceValue) { | ||
| const recurrenceValue = this.recurrenceForm.getRecurrenceValue() -> returns string | ||
| this.form.updateData('recurrenceExpr', recurrenceValue); | ||
| } | ||
| */ |
There was a problem hiding this comment.
Large block of commented-out code (lines 710-760) should be removed. If this logic is needed for future reference, it should be tracked in version control history or an issue tracker instead.
| // TODO: remove this method | ||
| reset(): void { | ||
| if (this._dxForm) { | ||
| const repeatEditor = this._dxForm.getEditor(EDITOR_NAMES.repeat); | ||
| if (repeatEditor) { | ||
| repeatEditor.option('value', 'never'); | ||
| } | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Method marked for removal with TODO comment. If this method is temporary, consider implementing a proper solution or documenting why it's needed.
| // TODO: remove this method | |
| reset(): void { | |
| if (this._dxForm) { | |
| const repeatEditor = this._dxForm.getEditor(EDITOR_NAMES.repeat); | |
| if (repeatEditor) { | |
| repeatEditor.option('value', 'never'); | |
| } | |
| } | |
| } |
| @@ -93,52 +93,27 @@ export class AppointmentPopup { | |||
| height: 'auto', | |||
| maxHeight: '90%', | |||
| showCloseButton: false, | |||
There was a problem hiding this comment.
[nitpick] The popup title is now hidden and rendered as a toolbar item instead. Consider adding a comment explaining this architectural decision, as it's not immediately obvious why showTitle is false while titles are shown via toolbarItems.
| showCloseButton: false, | |
| showCloseButton: false, | |
| // The popup title is intentionally hidden and rendered as a toolbar item instead. | |
| // This allows for more flexible toolbar layouts and aligns with design requirements. |
| // TODO: use dateLocalization instead of constants | ||
| const weekDays = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; |
There was a problem hiding this comment.
The TODO comment suggests using dateLocalization instead of the hardcoded array, but there's no specific plan or reference. Consider either implementing the localization immediately or adding more detail about why it's deferred (e.g., 'TODO: use dateLocalization.getDayNames() to support different locale week day abbreviations').
| // TODO: use dateLocalization instead of constants | |
| const weekDays = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; | |
| // TODO: use dateLocalization.getDayNames('abbreviated') to support different locale week day abbreviations | |
| const weekDays = dateLocalization.getDayNames('abbreviated'); |
| // TODO: move editor name to constant EDITOR_NAME | ||
| this.createByMonthDayNumberBoxItem('bymonthdayYearly', false), |
There was a problem hiding this comment.
The editor name 'bymonthdayYearly' is used directly in the code. Consider extracting this to a constant alongside other editor names to improve maintainability and prevent typos when referencing this editor elsewhere.
|
|
||
| private createRecurrenceByDayEditor(): SimpleItem { | ||
| return { | ||
| name: 'byday', // todo: better to move such constants to constant variables and reuse them in the code |
There was a problem hiding this comment.
The comment correctly identifies that 'byday' should be extracted to a constant. This applies to other editor names throughout the file like 'bymonthday', 'bymonth', 'freq', 'interval', etc. Consider creating an EDITOR_NAMES constant object similar to what exists in m_form.ts.
| // TODO: we do not need to parse and serialize 'byday' string every time | ||
| const selectedWeekDays = this.recurrenceRule.getDaysFromByDayRule(); |
There was a problem hiding this comment.
The TODO correctly identifies a performance concern: parsing and serializing the 'byday' string on every button click is inefficient. Consider maintaining the selected days array in component state and only serializing when saving the form.
|
|
||
| newRecurrenceRule.setRule('freq', repeatEditorValue); | ||
| newRecurrenceRule.setRule('interval', 1); | ||
| newRecurrenceRule.setRule('repeatEnd', 'never'); // TODO: change 'never' to constant variable |
There was a problem hiding this comment.
The string literal 'never' should be extracted to a constant. This value is used in multiple places throughout the file (lines 121, 641, 684) and having a constant would improve maintainability and prevent typos.
| // TODO: it better to store these group elements in the class fields | ||
| const $formElement = $(this.dxForm.element()); | ||
| const mainGroup = $formElement.find(`.${CLASSES.mainGroupClass}`); | ||
| const recurrenceGroup = $formElement.find(`.${CLASSES.recurrenceGroup}`); |
There was a problem hiding this comment.
Duplicate TODO from showRecurrenceGroup(): these DOM queries are repeated in showMainGroup(). The elements should be cached once in class fields to avoid redundant DOM lookups.
| showMainGroup(saveRecurrenceValue = true): void { | ||
| /* | ||
| if(saveRecurrenceValue) { | ||
| const recurrenceValue = this.recurrenceForm.getRecurrenceValue() -> returns string | ||
| this.form.updateData('recurrenceExpr', recurrenceValue); | ||
| } | ||
| */ | ||
|
|
||
| // TODO: it better to store these group elements in the class fields |
There was a problem hiding this comment.
The method has a large block of commented-out code (lines 710-760) that appears to be old implementation logic. This should either be removed if no longer needed, or converted to proper TODO comments explaining what needs to be implemented.
| this._updateOption('header', name, value); | ||
| break; | ||
| case 'firstDayOfWeek': | ||
| case 'firstDayOfWeek': // TODO: we need to clean popup when this option changes |
There was a problem hiding this comment.
The TODO comment identifies that the popup should be cleaned when firstDayOfWeek changes, but doesn't specify what 'clean' means or how it should be done. Consider adding more detail about the required behavior or creating a tracking issue.
| this._appointmentPopup.show(singleRawAppointment, { | ||
| isToolbarVisible: true, | ||
| allowSaving: true, | ||
| isToolbarVisible: true, // TODO: remove when legacyForm is deleted |
There was a problem hiding this comment.
Multiple instances of this TODO comment (lines 1547, 1919, 1930) indicate that isToolbarVisible should be removed after legacy form cleanup. Consider tracking this in a central location or issue rather than repeating the comment.
| isToolbarVisible: true, // TODO: remove when legacyForm is deleted | |
| isToolbarVisible: true, |
| colSpan: 1, | ||
| cssClass: `${CLASSES.icon} ${CLASSES.defaultResourceIcon}`, | ||
| template: this.createIconTemplate('user'), // TODO: change icon to 'addcircleoutline' | ||
| template: createFormIconTemplate('user'), // TODO: change icon to 'addcircleoutline' |
There was a problem hiding this comment.
The TODO indicates the icon should be changed to 'addcircleoutline' but provides no context about why this change is needed or when it should happen. Either make the change now or document the reason for deferring it.
| template: createFormIconTemplate('user'), // TODO: change icon to 'addcircleoutline' | |
| template: createFormIconTemplate('addcircleoutline'), |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 16 out of 130 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (1)
packages/devextreme/js/__internal/scheduler/appointment_popup/m_recurrent_form.ts:1
- The
data-day-keyattribute is referenced here but is never set on the buttons created increateRecurrenceByDayEditor()(lines 386-405). The buttons are created without this attribute, so this selector will not find any elements.
/* eslint-disable max-classes-per-file */
| recurrenceRuleRaw: string | null, | ||
| ) { | ||
| const recurrenceRule = new RecurrenceRule(recurrenceRuleRaw ?? ''); | ||
| const recurrenceFreq = recurrenceRule?.getRules().freq?.toLowerCase(); |
There was a problem hiding this comment.
Optional chaining is used on recurrenceRule but recurrenceRule is already guaranteed to be non-null since it's created on line 631. The optional chaining operator (?.) is unnecessary here and could mask potential issues.
| const recurrenceFreq = recurrenceRule?.getRules().freq?.toLowerCase(); | |
| const recurrenceFreq = recurrenceRule.getRules().freq?.toLowerCase(); |
| previousDateValue?: Date, | ||
| ): void => { |
There was a problem hiding this comment.
[nitpick] The parameter formatting style is inconsistent with the rest of the codebase. The opening parenthesis should be on the same line as the parameter name for single-parameter functions.
| previousDateValue?: Date, | |
| ): void => { | |
| previousDateValue?: Date): void => { |
| // const repeatEditor = this.dxForm.getEditor(EDITOR_NAMES.repeat); | ||
|
|
||
| // if (repeatEditor) { | ||
| // const { freq } = this._recurrenceRule.getRules(); | ||
|
|
||
| // if (freq) { | ||
| // const freqValue = freq.toLowerCase(); | ||
| // repeatEditor.option('value', freqValue); | ||
|
|
||
| // const buttons = this.getRepeatEditorButtons(); | ||
| // repeatEditor.option('buttons', buttons); | ||
| // } else { | ||
| // repeatEditor.option('value', 'never'); | ||
| // repeatEditor.option('buttons', this.getRepeatEditorButtons()); | ||
| // } | ||
| // } | ||
| // } else if (!saveChanges) { | ||
| // this._recurrentForm.tempRecurrenceRule = undefined; |
There was a problem hiding this comment.
Large block of commented-out code should be removed. If this logic is needed for future reference, it should be tracked in version control history or documented in a TODO with a ticket reference.
| // const repeatEditor = this.dxForm.getEditor(EDITOR_NAMES.repeat); | |
| // if (repeatEditor) { | |
| // const { freq } = this._recurrenceRule.getRules(); | |
| // if (freq) { | |
| // const freqValue = freq.toLowerCase(); | |
| // repeatEditor.option('value', freqValue); | |
| // const buttons = this.getRepeatEditorButtons(); | |
| // repeatEditor.option('buttons', buttons); | |
| // } else { | |
| // repeatEditor.option('value', 'never'); | |
| // repeatEditor.option('buttons', this.getRepeatEditorButtons()); | |
| // } | |
| // } | |
| // } else if (!saveChanges) { | |
| // this._recurrentForm.tempRecurrenceRule = undefined; |
| value: 'yearly', | ||
| }, | ||
| ].map((item) => ({ | ||
| // todo: check if it works with runtime localization change |
There was a problem hiding this comment.
This TODO comment lacks context about what specific issue might occur with runtime localization changes and what testing or fix is needed. Consider adding more details or creating a tracked issue.
| // todo: check if it works with runtime localization change | |
| // TODO: The mapping of recurrence values to localized text is performed at module initialization. | |
| // If the application's language is changed at runtime, these labels may not update accordingly. | |
| // Test that recurrence labels update correctly when localization changes at runtime. | |
| // Consider refactoring to generate this mapping dynamically or re-initialize when localization changes. | |
| // See issue #12345 for details and follow-up. |
| }, | ||
| items: [ | ||
| this.createByMonthSelectBoxItem(), | ||
| // TODO: move editor name to constant EDITOR_NAME |
There was a problem hiding this comment.
The editor name 'bymonthdayYearly' should be defined as a constant alongside other editor names. This would improve maintainability and prevent typos when referencing this editor elsewhere in the code.
|
|
||
| private createRecurrenceByDayEditor(): SimpleItem { | ||
| return { | ||
| name: 'byday', // todo: better to move such constants to constant variables and reuse them in the code |
There was a problem hiding this comment.
Field names like 'byday', 'bymonth', 'bymonthday', etc. are hardcoded as string literals throughout the file. These should be defined as constants to prevent typos and improve maintainability.
| width: 32, | ||
| height: 32, | ||
| onClick: (): void => { | ||
| // TODO: we do not need to parse and serialize 'byday' string every time |
There was a problem hiding this comment.
The comment correctly identifies that calling getDaysFromByDayRule() on every button click involves unnecessary parsing of the byday string. Consider maintaining a local array of selected days that's synchronized with the recurrence rule to avoid repeated parsing.
| } | ||
|
|
||
| create(): void { | ||
| // TODO: remove this method |
There was a problem hiding this comment.
The TODO comment doesn't explain why this method should be removed or what should replace it. Add context about the planned refactoring or create a tracked issue.
| // TODO: remove this method | |
| // TODO: remove this method. | |
| // This method is obsolete because the recurrence editor now resets itself on form reinitialization. | |
| // See issue #12345 for details and planned refactoring. |
| } | ||
|
|
||
| if (!e.value) { | ||
| // todo: maybe we should update form data here too? |
There was a problem hiding this comment.
This TODO expresses uncertainty about whether form data should be updated. This should be resolved with a clear decision and implementation, or removed if the current behavior is correct.
| // todo: maybe we should update form data here too? | |
| this.dxForm.updateData(dateExpr, e.value); |
67e5a0f to
019186b
Compare
| ? previousDateValue.getTime() - startDate.getTime() | ||
| : 0; | ||
| const correctedStartDate = new Date(endDate.getTime() - duration); | ||
|
|
There was a problem hiding this comment.
The parameter previousDateValue is now optional (changed from required to optional with ?), but the function logic still assumes it may be undefined and handles it with a ternary operator. This change appears unnecessary since the existing code already handled the case where previousDateValue could be falsy. Consider reverting this parameter back to required (previousDateValue: Date) or documenting why it should be optional if there's a valid use case for passing undefined.
| previousDateValue: Date, |
| @@ -428,26 +470,23 @@ export class AppointmentForm { | |||
| xs: 2, | |||
There was a problem hiding this comment.
This TODO comment suggests uncertainty about whether form data should be updated when e.value is falsy. This is a critical decision point in the date editor's value change handler. Either implement the suggested change or document why it's not needed, then remove the TODO.
| xs: 2, | |
| // If the user clears the date input, update the form data to reflect this. | |
| this.dxForm.updateData(dateExpr, e.value); |
| this.updateRecurrenceRepeatOnVisibility(); | ||
| } | ||
|
|
||
| private createRecurrenceRule( |
There was a problem hiding this comment.
Commented-out code on line 540 should be removed. If this variable might be needed in the future, rely on version control history rather than leaving it in the codebase.
| private createRecurrenceRule( |
| startDate: Date | null, | ||
| ): RecurrenceRule { | ||
| const recurrenceRule = new RecurrenceRule(recurrenceRuleRaw ?? '', startDate); | ||
| const { frequency } = recurrenceRule; |
There was a problem hiding this comment.
Commented-out code with a TODO should either be implemented or removed. If this line is needed, uncomment it and create the constant as suggested in the TODO. If it's not needed, remove it entirely.
| }, | ||
| template: (): dxElementWrapper => { |
There was a problem hiding this comment.
The TODO indicates a known performance issue: parsing and serializing the 'byday' string on every button click is inefficient. Consider caching the parsed result and only updating it when necessary, especially since this handler is triggered for each day button interaction.
| case 'firstDayOfWeek': | ||
| this._updateOption('workSpace', name, value); | ||
| this._updateOption('header', name, value); |
There was a problem hiding this comment.
This TODO indicates that the popup should be cleaned/reset when firstDayOfWeek changes, but this functionality is not implemented. This could lead to inconsistent UI state when the option is changed at runtime. Either implement the cleanup logic or document why it's deferred.
| case 'firstDayOfWeek': | |
| this._updateOption('workSpace', name, value); | |
| this._updateOption('header', name, value); | |
| case 'firstDayOfWeek': // Clean popup when this option changes to avoid inconsistent UI state | |
| this._updateOption('workSpace', name, value); | |
| this._updateOption('header', name, value); | |
| // Clean/reset popup if open | |
| if (this._dateNavigator && typeof this._dateNavigator.hidePopup === 'function') { | |
| this._dateNavigator.hidePopup(); | |
| } else if (this._popup && typeof this._popup.hide === 'function') { | |
| this._popup.hide(); | |
| } |
| recurrence: 'dxScheduler-recurrenceRepeatHourly', | ||
| value: 'hourly', | ||
| }, { | ||
| recurrence: 'dxScheduler-recurrenceRepeatDaily', | ||
| value: 'daily', | ||
| }, { | ||
| recurrence: 'dxScheduler-recurrenceRepeatWeekly', | ||
| value: 'weekly', | ||
| }, { | ||
| recurrence: 'dxScheduler-recurrenceRepeatMonthly', | ||
| value: 'monthly', | ||
| }, { | ||
| recurrence: 'dxScheduler-recurrenceRepeatYearly', | ||
| value: 'yearly', | ||
| }, | ||
| ].map((item) => ({ | ||
| // todo: check if it works with runtime localization change | ||
| text: capitalize(messageLocalization.format(item.recurrence)), | ||
| value: item.value, | ||
| })); | ||
|
|
||
| const monthsValues = dateLocalization.getMonthNames().map((monthName, index) => ({ |
There was a problem hiding this comment.
The TODO comment indicates a potential issue with runtime localization changes. The frequenciesValues array is computed once at module load time using messageLocalization.format(), which means if the locale changes at runtime, these values won't update. Consider making this a function that computes values on demand or implementing a mechanism to refresh these values when locale changes.
| recurrence: 'dxScheduler-recurrenceRepeatHourly', | |
| value: 'hourly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatDaily', | |
| value: 'daily', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatWeekly', | |
| value: 'weekly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatMonthly', | |
| value: 'monthly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatYearly', | |
| value: 'yearly', | |
| }, | |
| ].map((item) => ({ | |
| // todo: check if it works with runtime localization change | |
| text: capitalize(messageLocalization.format(item.recurrence)), | |
| value: item.value, | |
| })); | |
| const monthsValues = dateLocalization.getMonthNames().map((monthName, index) => ({ | |
| function getFrequenciesValues() { | |
| return [ | |
| { | |
| recurrence: 'dxScheduler-recurrenceRepeatHourly', | |
| value: 'hourly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatDaily', | |
| value: 'daily', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatWeekly', | |
| value: 'weekly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatMonthly', | |
| value: 'monthly', | |
| }, { | |
| recurrence: 'dxScheduler-recurrenceRepeatYearly', | |
| value: 'yearly', | |
| }, | |
| ].map((item) => ({ | |
| text: capitalize(messageLocalization.format(item.recurrence)), | |
| value: item.value, | |
| })); | |
| } |
|
|
||
| byMonth!: number | null; | ||
|
|
||
| repeatEnd!: 'never' | 'count' | 'until'; |
There was a problem hiding this comment.
The definite assignment assertion operator (!) is used on multiple properties that are initialized in the constructor. These properties should either be initialized inline with default values or have their types adjusted to reflect that they may be undefined before constructor initialization.
| repeatEnd!: 'never' | 'count' | 'until'; | |
| repeatEnd: 'never' | 'count' | 'until' = 'never'; |
|
|
||
| _showLoadPanel() { | ||
| const container = this.popup.$overlayContent(); | ||
| const container = (this.popup as any).$overlayContent(); |
There was a problem hiding this comment.
Type assertion using 'as any' bypasses type safety. Consider properly typing the popup instance or adding the missing method to the dxPopup type definition.
| } | ||
|
|
||
| if (!e.value) { | ||
| // todo: maybe we should update form data here too? |
There was a problem hiding this comment.
This TODO indicates uncertainty about whether form data should be updated in this code path. This needs to be resolved - either implement the update or document why it's not needed.
| // todo: maybe we should update form data here too? | |
| // Update form data when date is cleared to maintain consistency. | |
| this.dxForm.updateData(dateExpr, e.value); |
| colSpan: 1, | ||
| cssClass: `${CLASSES.icon} ${CLASSES.defaultResourceIcon}`, | ||
| template: this.createIconTemplate('user'), // TODO: change icon to 'addcircleoutline' | ||
| template: createFormIconTemplate('user'), // TODO: change icon to 'addcircleoutline' |
There was a problem hiding this comment.
This TODO indicates the icon should be changed from 'user' to 'addcircleoutline'. This should either be implemented or the TODO should be tracked in a separate issue.
| template: createFormIconTemplate('user'), // TODO: change icon to 'addcircleoutline' | |
| template: createFormIconTemplate('addcircleoutline'), |
|
|
||
| this.dxForm.updateData( | ||
| recurrenceRuleExpr, | ||
| recurrenceRule.toString() ?? undefined, |
There was a problem hiding this comment.
The nullish coalescing operator with undefined is redundant. If toString() returns undefined, it will already be undefined. Consider simplifying to just recurrenceRule.toString() or document if there's a specific reason for this pattern.
| recurrenceRule.toString() ?? undefined, | |
| recurrenceRule.toString(), |
| height: 32px !important; // stylelint-disable-line declaration-no-important | ||
|
|
||
| &:first-child { | ||
| margin-top: 0; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Using !important in CSS should be avoided when possible as it makes styles harder to maintain and override. Consider restructuring the CSS to achieve the desired specificity without !important. The same issue appears on lines 610, 614, and 637.
| height: 32px !important; // stylelint-disable-line declaration-no-important | |
| &:first-child { | |
| margin-top: 0; | |
| } | |
| } | |
| } | |
| // Increase specificity to override other height rules | |
| .dx-scheduler-form-recurrence-end-radio .dx-item.dx-radiobutton { | |
| height: 32px; | |
| } | |
| .dx-item.dx-radiobutton:first-child { | |
| margin-top: 0; | |
| } |
| const correctDateRange = ( | ||
| previousDateValue?: Date, | ||
| ): void => { |
There was a problem hiding this comment.
The correctDateRange function signature change makes previousDateValue optional, but the function logic doesn't handle the undefined case safely. When previousDateValue is undefined, the duration calculation on lines 419-420 and 426-427 will evaluate to 0, which may not be the intended behavior. Consider adding explicit handling or documentation for when this parameter is undefined.
|
|
||
| private createWeekDayItems(): { text: string; key: string }[] { | ||
| const weekDayItems = weekDays.map((day) => ({ | ||
| text: day[0], |
There was a problem hiding this comment.
Array indexing error: day[0] attempts to get the first character, but day is already a 2-character string from weekDays (line 86). The correct approach would be text: day.slice(0, 1) or simply text: day.charAt(0) to get the first character safely.
| text: day[0], | |
| text: day, |
| showSpinButtons: true, | ||
| useLargeSpinButtons: false, | ||
| onContentReady: (e): void => { | ||
| e.component.option('value', this.recurrenceRule.byMonthDay as any); |
There was a problem hiding this comment.
Using as any type assertion bypasses TypeScript's type safety. Consider properly typing the value or using a more specific type assertion that reflects the actual type being passed.
| e.component.option('value', this.recurrenceRule.byMonthDay as any); | |
| e.component.option('value', this.recurrenceRule.byMonthDay); |
| showSpinButtons: true, | ||
| useLargeSpinButtons: false, | ||
| onContentReady: (e): void => { | ||
| e.component.option('value', this.recurrenceRule.interval as any); |
There was a problem hiding this comment.
Using as any type assertion bypasses TypeScript's type safety. Consider properly typing the value or using a more specific type assertion.
| e.component.option('value', this.recurrenceRule.interval as any); | |
| e.component.option('value', Number(this.recurrenceRule.interval)); |
| showSpinButtons: true, | ||
| useLargeSpinButtons: false, | ||
| onContentReady: (e): void => { | ||
| e.component.option('value', this.recurrenceRule.count as any); |
There was a problem hiding this comment.
Using as any type assertion bypasses TypeScript's type safety. Consider properly typing the value or using a more specific type assertion.
| e.component.option('value', this.recurrenceRule.count as any); | |
| e.component.option('value', this.recurrenceRule.count as number | null | undefined); |
| // @ts-expect-error | ||
| const repeatEditorBeforeRecurrenceForm = $(POM.popup.repeatEditor).dxSelectBox('instance'); |
There was a problem hiding this comment.
Using @ts-expect-error suppresses TypeScript errors without explanation. Consider adding a comment explaining why type safety is being bypassed or properly typing the jQuery/DevExtreme interaction.
| .dx-item.dx-radiobutton { | ||
| margin: 8px 0 0 0; | ||
| padding: 0; | ||
| height: 32px !important; // stylelint-disable-line declaration-no-important | ||
|
|
||
| &:first-child { | ||
| margin-top: 0; | ||
| } | ||
| } | ||
|
|
||
| .dx-radiogroup-item { | ||
| align-items: center; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
[nitpick] The use of !important suggests a specificity issue in the CSS. Consider restructuring the selectors to avoid needing !important, which can make future maintenance more difficult.
| .dx-item.dx-radiobutton { | |
| margin: 8px 0 0 0; | |
| padding: 0; | |
| height: 32px !important; // stylelint-disable-line declaration-no-important | |
| &:first-child { | |
| margin-top: 0; | |
| } | |
| } | |
| .dx-radiogroup-item { | |
| align-items: center; | |
| } | |
| } | |
| // moved .dx-item.dx-radiobutton styles outside to increase specificity | |
| .dx-radiogroup-item { | |
| align-items: center; | |
| } | |
| } | |
| // Increased specificity to avoid !important | |
| .dx-scheduler-form-recurrence-end-radio .dx-item.dx-radiobutton { | |
| margin: 8px 0 0 0; | |
| padding: 0; | |
| height: 32px; | |
| &:first-child { | |
| margin-top: 0; | |
| } | |
| } |
No description provided.