diff --git a/packages/devextreme-scss/scss/widgets/base/scheduler/views/_index.scss b/packages/devextreme-scss/scss/widgets/base/scheduler/views/_index.scss index a8250d8f5fef..5344fd09c304 100644 --- a/packages/devextreme-scss/scss/widgets/base/scheduler/views/_index.scss +++ b/packages/devextreme-scss/scss/widgets/base/scheduler/views/_index.scss @@ -310,11 +310,6 @@ $scheduler-month-date-text-padding: 6px; flex: 0 0 auto; min-width: 0; - &:last-child .dx-scheduler-group-header { - border-right: $scheduler-base-border; - border-right-color: $scheduler-base-border-color; - } - .dx-scheduler-group-header { @include flex-container(row, nowrap); @@ -332,11 +327,30 @@ $scheduler-month-date-text-padding: 6px; border-top-color: $scheduler-base-border-color; } } + + &:not(.dx-scheduler-group-flex-container-hierarchical) .dx-scheduler-group-row:last-child .dx-scheduler-group-header { + border-right: $scheduler-base-border; + border-right-color: $scheduler-base-border-color; + } } .dx-scheduler-group-flex-container-hierarchical { flex-direction: column; + .dx-scheduler-group-flex-container .dx-scheduler-group-row:last-child .dx-scheduler-group-header { + border-right: none; + } + + .dx-scheduler-group-row > .dx-scheduler-group-header:not(.dx-scheduler-group-header-leaf) { + border-right: $scheduler-base-border; + border-right-color: $scheduler-base-border-color; + } + + .dx-scheduler-group-flex-container .dx-scheduler-group-row:last-child > .dx-scheduler-group-header { + border-right: $scheduler-base-border; + border-right-color: $scheduler-base-border-color; + } + .dx-scheduler-group-row { @include flex-container(row, nowrap); @@ -855,6 +869,19 @@ $scheduler-month-date-text-padding: 6px; } } + .dx-scheduler-group-flex-container-hierarchical { + .dx-scheduler-group-flex-container .dx-scheduler-group-row:last-child .dx-scheduler-group-header { + border-left: none; + } + + .dx-scheduler-group-row > .dx-scheduler-group-header:not(.dx-scheduler-group-header-leaf), + .dx-scheduler-group-flex-container .dx-scheduler-group-row:last-child > .dx-scheduler-group-header { + border-right: none; + border-left: $scheduler-base-border; + border-left-color: $scheduler-base-border-color; + } + } + .dx-scheduler-header-panel { left: 0; right: inherit; diff --git a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss index 991285a0deae..4f2995e2fd33 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss @@ -654,6 +654,11 @@ $fluent-scheduler-agenda-time-panel-cell-padding: 8px; .dx-scheduler-group-header { border-bottom: none; } + + .dx-scheduler-header-panel .dx-scheduler-group-row:has(+ .dx-scheduler-group-row) .dx-scheduler-group-header { + border-bottom: baseScheduler.$scheduler-base-border; + border-bottom-color: $scheduler-base-border-color; + } } &.dx-scheduler-agenda { diff --git a/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss index 2abce2057d9c..8c8238c8e7b0 100644 --- a/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss @@ -164,15 +164,16 @@ $generic-scheduler-agenda-group-header-padding: $generic-scheduler-agenda-time-c background-color: $scheduler-header-bg; } -.dx-scheduler-header-panel { // stylelint-disable-line no-duplicate-selectors +.dx-scheduler-group-table, +.dx-scheduler-header-panel { .dx-scheduler-group-row { - &:not(:first-child) { + .dx-scheduler-group-header { border-bottom: baseScheduler.$scheduler-base-border; border-bottom-color: $scheduler-base-border-color; + } - .dx-scheduler-group-header { - color: $scheduler-panel-text-color; - } + &:not(:first-child) .dx-scheduler-group-header { + color: $scheduler-panel-text-color; } } } @@ -198,6 +199,17 @@ $generic-scheduler-agenda-group-header-padding: $generic-scheduler-agenda-time-c border-top-color: $scheduler-base-border-color; } + &.dx-scheduler-work-space-all-day:not(.dx-scheduler-work-space-week):not(.dx-scheduler-work-space-work-week) { + .dx-scheduler-group-header { + border-bottom: none; + } + + .dx-scheduler-header-panel .dx-scheduler-group-row:has(+ .dx-scheduler-group-row) .dx-scheduler-group-header { + border-bottom: baseScheduler.$scheduler-base-border; + border-bottom-color: $scheduler-base-border-color; + } + } + &.dx-scheduler-agenda { .dx-scheduler-date-table-cell { border: none; diff --git a/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss index cc2da233bf69..a0569c62d83c 100644 --- a/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss @@ -594,6 +594,11 @@ $material-scheduler-agenda-time-panel-cell-padding: 8px; .dx-scheduler-group-header { border-bottom: none; } + + .dx-scheduler-header-panel .dx-scheduler-group-row:has(+ .dx-scheduler-group-row) .dx-scheduler-group-header { + border-bottom: baseScheduler.$scheduler-base-border; + border-bottom-color: $scheduler-base-border-color; + } } &.dx-scheduler-agenda { diff --git a/packages/devextreme/js/__internal/scheduler/classes.ts b/packages/devextreme/js/__internal/scheduler/classes.ts index 3e06d8bc1334..6f9245029857 100644 --- a/packages/devextreme/js/__internal/scheduler/classes.ts +++ b/packages/devextreme/js/__internal/scheduler/classes.ts @@ -43,9 +43,3 @@ export const GROUP_ROW_CLASS = 'dx-scheduler-group-row'; export const GROUP_HEADER_CONTENT_CLASS = 'dx-scheduler-group-header-content'; export const LAST_GROUP_CELL_CLASS = 'dx-scheduler-last-group-cell'; export const FIRST_GROUP_CELL_CLASS = 'dx-scheduler-first-group-cell'; - -export const VERTICAL_GROUP_COUNT_CLASSES = [ - 'dx-scheduler-group-column-count-one', - 'dx-scheduler-group-column-count-two', - 'dx-scheduler-group-column-count-three', -]; diff --git a/packages/devextreme/js/__internal/scheduler/r1/components/base/group_panel_vertical.tsx b/packages/devextreme/js/__internal/scheduler/r1/components/base/group_panel_vertical.tsx index 3ef844185a47..b5c2363d8d06 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/components/base/group_panel_vertical.tsx +++ b/packages/devextreme/js/__internal/scheduler/r1/components/base/group_panel_vertical.tsx @@ -17,7 +17,7 @@ const renderGroupPanelContent = ( isHierarchical: boolean, groupByDate: boolean, ): JSX.Element | JSX.Element[] => { - if (isTimelineGroupTable) { + if (isTimelineGroupTable && !isHierarchical) { return getTimelineGroupPanelRows(groupPanelData, groupByDate) .map((group) => { } = this.props; const style = normalizeStyles(renderUtils.addHeightToStyle(height, styles)); const isTimelineGroupTable = className === TIMELINE_GROUP_TABLE_CLASS; - const isHierarchical = !isTimelineGroupTable && groupPanelData.maxDepth > 1; + const useResourceHierarchyLayout = groupPanelData.hasHierarchy && groupPanelData.maxDepth > 1; + const isHierarchical = isTimelineGroupTable + ? useResourceHierarchyLayout + : groupPanelData.maxDepth > 1; const flexContainerClassName = isHierarchical ? `dx-scheduler-group-flex-container ${HIERARCHICAL_GROUP_FLEX_CONTAINER_CLASS}` : 'dx-scheduler-group-flex-container'; diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts index 4030bceddb9a..8833292877ce 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts @@ -3,7 +3,6 @@ import dateUtils from '@js/core/utils/date'; import { isDefined } from '@js/core/utils/type'; import { dateUtilsTs } from '@ts/core/utils/date'; -import { VERTICAL_GROUP_COUNT_CLASSES } from '../../classes'; import { HORIZONTAL_GROUP_ORIENTATION, VERTICAL_GROUP_ORIENTATION, } from '../../constants'; @@ -99,19 +98,6 @@ export const getOverflowIndicatorColor = (color: string, colors: string[]): stri : undefined ); -export const getVerticalGroupCountClass = (groups: unknown[]): string | undefined => { - switch (groups?.length) { - case 1: - return VERTICAL_GROUP_COUNT_CLASSES[0]; - case 2: - return VERTICAL_GROUP_COUNT_CLASSES[1]; - case 3: - return VERTICAL_GROUP_COUNT_CLASSES[2]; - default: - return undefined; - } -}; - export const setOptionHour = (date: Date, optionHour: number): Date => { const nextDate = new Date(date); diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/index.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/index.ts index c08e12029250..1856a323cfd2 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/index.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/index.ts @@ -62,7 +62,6 @@ export { getTotalCellCountByCompleteData, getTotalRowCountByCompleteData, getValidCellDateForLocalTimeFormat, - getVerticalGroupCountClass, getViewStartByOptions, isAppointmentTakesAllDay, isDateAndTimeView, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts b/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts index b007f58caa95..c7eac2219570 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts @@ -21,7 +21,7 @@ import { GROUP_ROW_CLASS, TIME_PANEL_CLASS, } from '../classes'; -import { agendaUtils, formatWeekday, getVerticalGroupCountClass } from '../r1/utils/index'; +import { agendaUtils, formatWeekday } from '../r1/utils/index'; import tableCreatorModule, { type GroupRows } from '../table_creator'; import type { ResourceId } from '../utils/loader/types'; import { VIEWS } from '../utils/options/constants_view'; @@ -102,7 +102,6 @@ class SchedulerAgenda extends WorkSpace { if (this.$groupTable) { this.$groupTable.remove(); this.$groupTable = null; - this.detachGroupCountClass(); } } else if (!this.$groupTable) { this.initGroupTable(); @@ -230,13 +229,6 @@ class SchedulerAgenda extends WorkSpace { return rows.every((groupRow) => groupRow.every((cell) => !cell)); } - protected override attachGroupCountClass(): void { - const className = getVerticalGroupCountClass(this.option().groups); - if (className) { - this.$element().addClass(className); - } - } - private removeEmptyRows(rows: number[][]): number[][] { const isEmpty = (data: number[]): boolean => !data.some((value) => value > 0); return rows.filter((row) => row.length && !isEmpty(row)); diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts index 7655a5a89327..9e1e1a2d81b1 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts @@ -78,7 +78,6 @@ import { GROUP_HEADER_CONTENT_CLASS, GROUP_ROW_CLASS, TIME_PANEL_CLASS, - VERTICAL_GROUP_COUNT_CLASSES, VIRTUAL_CELL_CLASS, } from '../classes'; import { APPOINTMENT_SETTINGS_KEY } from '../constants'; @@ -2394,7 +2393,6 @@ class SchedulerWorkSpace extends Widget { }; if (this.option().groups?.length) { - this.attachGroupCountClass(); const $groupHeaderContainer = this.getGroupHeaderContainer(); if ($groupHeaderContainer) { this.renderRenovatedComponent( @@ -2404,8 +2402,6 @@ class SchedulerWorkSpace extends Widget { options, ); } - } else { - this.detachGroupCountClass(); } } @@ -2478,12 +2474,6 @@ class SchedulerWorkSpace extends Widget { } renderRHeaderPanel(isRenderDateHeader = true): void { - if (this.option().groups?.length) { - this.attachGroupCountClass(); - } else { - this.detachGroupCountClass(); - } - this.renderRenovatedComponent( this.$thead, this.renovatedHeaderPanelComponent, @@ -3221,20 +3211,6 @@ class SchedulerWorkSpace extends Widget { protected setIndicationUpdateInterval(): void { return noop(); } - protected detachGroupCountClass(): void { - VERTICAL_GROUP_COUNT_CLASSES.forEach((className) => { - this.$element().removeClass(className); - }); - } - - protected attachGroupCountClass(): void { - const className = this.groupedStrategy.getGroupCountClass(this.option().groups); - - if (className) { - this.$element().addClass(className); - } - } - protected getDateHeaderTemplate(): TemplateBase | null | undefined { return this.option().dateCellTemplate; } @@ -3353,12 +3329,9 @@ class SchedulerWorkSpace extends Widget { let cellTemplates: (() => dxElementWrapper)[] = []; if (groupCount && $container) { const groupRows = this.makeGroupRows(this.option().groups, this.option().groupByDate); - this.attachGroupCountClass(); const { elements } = groupRows; $container.append(Array.isArray(elements) ? elements : elements.toArray()); cellTemplates = groupRows.cellTemplates; - } else { - this.detachGroupCountClass(); } return cellTemplates; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_horizontal.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_horizontal.ts index 6c7c18e41408..5e852d38e91a 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_horizontal.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_horizontal.ts @@ -8,7 +8,6 @@ import type { import { WORK_SPACE_BORDER_PX } from '@ts/scheduler/workspaces/const'; import { FIRST_GROUP_CELL_CLASS, LAST_GROUP_CELL_CLASS } from '../classes'; -import type { ResourceLoader } from '../utils/loader/resource_loader'; import type { GroupedStrategyConfig } from './work_space_grouped_strategy_config'; class HorizontalGroupedStrategy { @@ -77,11 +76,6 @@ class HorizontalGroupedStrategy { return this.config.getAllDayHeight(); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getGroupCountClass(groups: ResourceLoader[]): string | undefined { - return undefined; - } - getLeftOffset(): number { return this.config.getTimePanelWidth(); } diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.test.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.test.ts index 2913d192235d..73eb05320668 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.test.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.test.ts @@ -8,12 +8,10 @@ import VerticalGroupedStrategy from './work_space_grouped_strategy_vertical'; jest.mock('@ts/scheduler/r1/utils/index', (): { calculateDayDuration: (startDayHour: number, endDayHour: number) => number; - getVerticalGroupCountClass: () => undefined; } => ({ calculateDayDuration: (startDayHour: number, endDayHour: number): number => ( endDayHour - startDayHour ), - getVerticalGroupCountClass: (): undefined => undefined, })); const createElement = ({ diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts index 8018efecb51c..bf3146d9269d 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts @@ -1,12 +1,11 @@ import type { dxElementWrapper } from '@js/core/renderer'; import { getBoundingRect } from '@js/core/utils/position'; -import { calculateDayDuration, getVerticalGroupCountClass } from '@ts/scheduler/r1/utils/index'; +import { calculateDayDuration } from '@ts/scheduler/r1/utils/index'; import type { CellPositionData, GroupBoundsOffset } from '@ts/scheduler/types'; import { WORK_SPACE_BORDER_PX } from '@ts/scheduler/workspaces/const'; import { FIRST_GROUP_CELL_CLASS, LAST_GROUP_CELL_CLASS } from '../classes'; import { Cache } from '../global_cache'; -import type { ResourceLoader } from '../utils/loader/resource_loader'; import type { GroupedStrategyConfig } from './work_space_grouped_strategy_config'; class VerticalGroupedStrategy { @@ -77,10 +76,6 @@ class VerticalGroupedStrategy { return 0; } - getGroupCountClass(groups: ResourceLoader[]): string | undefined { - return getVerticalGroupCountClass(groups); - } - getLeftOffset(): number { return this.config.getTimePanelWidth() + this.config.getGroupTableWidth(); } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js index e9510824e838..28b70a3d09cd 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js @@ -39,7 +39,7 @@ QUnit.module('Integration: Resources', moduleConfig, () => { }, 'appointment2': { top: 202, - left: 430 + left: 411 } }, { 'appointment1': { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timeline.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timeline.markup.tests.js index 0f7affa43e3e..a010732318f0 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timeline.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timeline.markup.tests.js @@ -138,26 +138,6 @@ QUnit.module('Timeline markup', moduleConfig, () => { assert.equal($firstColumnCells.length, 2, 'Cell count is OK'); assert.equal($secondColumnCells.length, 4, 'Cell count is OK'); }); - - QUnit.test('Timeline should have correct group-count class depending on group count', async function(assert) { - const $element = this.instance.$element(); - - await applyWorkspaceGroups(this.instance, [{ - label: 'one', - fieldExpr: 'one', - dataSource: [{ id: 1, text: 'a' }, { id: 2, text: 'b' }] - }, { - label: 'two', - fieldExpr: 'two', - dataSource: [{ id: 1, text: '1' }, { id: 2, text: '2' }] - }]); - - assert.ok($element.hasClass('dx-scheduler-group-column-count-two'), 'Correct class'); - - await applyWorkspaceGroups(this.instance, []); - - assert.notOk($element.hasClass('dx-scheduler-group-column-count-two'), 'group-count class was not applied'); - }); }); let timelineDayModuleConfig = {