Skip to content

Commit 3c87fd5

Browse files
fix the second case of two-template-roots regression (T1311798) (#31591) (#31609)
1 parent e5e6d15 commit 3c87fd5

File tree

5 files changed

+282
-5
lines changed

5 files changed

+282
-5
lines changed

e2e/wrappers/builders/react19/src/utils/componentFinder.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const COMPONENTS = [
2323
path: 'chat-template-rerender',
2424
name: 'ChatTemplateRerender',
2525
component: () => import('@examples/chat-template-rerender/react19/index.jsx')
26+
},
27+
{
28+
path: 'gantt-template-state-update',
29+
name: 'GanttTemplateStateUpdate',
30+
component: () => import('@examples/gantt-template-state-update/react19/index.jsx')
2631
}
2732
];
2833

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
export const currentDate = new Date(Date.now());
2+
const month = currentDate.getMonth();
3+
const year = currentDate.getFullYear();
4+
5+
export const tasks = [{
6+
id: 1,
7+
parentId: 0,
8+
title: 'Analysis/Software Requirements',
9+
start: new Date(year, month, 1),
10+
end: new Date(year, month, 28),
11+
progress: 31,
12+
}, {
13+
id: 2,
14+
parentId: 1,
15+
title: 'Conduct needs analysis',
16+
start: new Date(year, month, 1),
17+
end: new Date(year, month, 3),
18+
progress: 15,
19+
}, {
20+
id: 3,
21+
parentId: 1,
22+
title: 'Draft preliminary software specifications',
23+
start: new Date(year, month, 3),
24+
end: new Date(year, month, 5),
25+
progress: 30,
26+
}, {
27+
id: 4,
28+
parentId: 1,
29+
title: 'Review software specifications/budget with team',
30+
start: new Date(year, month, 4),
31+
end: new Date(year, month, 6),
32+
progress: 60,
33+
}, {
34+
id: 5,
35+
parentId: 1,
36+
title: 'Incorporate feedback on software specifications',
37+
start: new Date(year, month, 6),
38+
end: new Date(year, month, 8),
39+
progress: 45,
40+
}, {
41+
id: 6,
42+
parentId: 1,
43+
title: 'Develop delivery timeline',
44+
start: new Date(year, month, 8),
45+
end: new Date(year, month, 14),
46+
progress: 15,
47+
}, {
48+
id: 7,
49+
parentId: 1,
50+
title: 'Obtain approvals to proceed (concept, timeline, budget)',
51+
start: new Date(year, month, 14),
52+
end: new Date(year, month, 20),
53+
progress: 15,
54+
}, {
55+
id: 8,
56+
parentId: 1,
57+
title: 'Draft preliminary software specifications',
58+
start: new Date(year, month, 20),
59+
end: new Date(year, month, 25),
60+
progress: 0,
61+
}, {
62+
id: 9,
63+
parentId: 1,
64+
title: 'Secure required resources',
65+
start: new Date(year, month, 25),
66+
end: new Date(year, month, 28),
67+
progress: 0,
68+
}];
69+
70+
export const dependencies = [{
71+
id: 1,
72+
predecessorId: 2,
73+
successorId: 3,
74+
type: 0,
75+
}, {
76+
id: 2,
77+
predecessorId: 3,
78+
successorId: 4,
79+
type: 0,
80+
}, {
81+
id: 3,
82+
predecessorId: 4,
83+
successorId: 5,
84+
type: 0,
85+
}, {
86+
id: 4,
87+
predecessorId: 5,
88+
successorId: 6,
89+
type: 0,
90+
}, {
91+
id: 5,
92+
predecessorId: 6,
93+
successorId: 7,
94+
type: 0,
95+
}, {
96+
id: 6,
97+
predecessorId: 7,
98+
successorId: 8,
99+
type: 0,
100+
}, {
101+
id: 7,
102+
predecessorId: 8,
103+
successorId: 9,
104+
type: 0,
105+
}];
106+
107+
export const resources = [{
108+
id: 1,
109+
text: 'John Heart',
110+
}, {
111+
id: 2,
112+
text: 'Paul Peyton',
113+
}, {
114+
id: 3,
115+
text: 'Robert Reagan',
116+
}, {
117+
id: 4,
118+
text: 'Greta Sims',
119+
}, {
120+
id: 5,
121+
text: 'Brett Wade',
122+
}, {
123+
id: 6,
124+
text: 'Sandra Johnson',
125+
}, {
126+
id: 7,
127+
text: 'Kevin Carter',
128+
}, {
129+
id: 8,
130+
text: 'Cynthia Stanwick',
131+
}, {
132+
id: 9,
133+
text: 'Olivia Samuelson',
134+
}];
135+
136+
export const resourceAssignments = [{
137+
id: 0,
138+
taskId: 1,
139+
resourceId: 1,
140+
}, {
141+
id: 1,
142+
taskId: 2,
143+
resourceId: 2,
144+
}, {
145+
id: 2,
146+
taskId: 3,
147+
resourceId: 3,
148+
}, {
149+
id: 3,
150+
taskId: 4,
151+
resourceId: 4,
152+
}, {
153+
id: 4,
154+
taskId: 5,
155+
resourceId: 5,
156+
}, {
157+
id: 5,
158+
taskId: 6,
159+
resourceId: 6,
160+
}, {
161+
id: 6,
162+
taskId: 7,
163+
resourceId: 7,
164+
}, {
165+
id: 7,
166+
taskId: 8,
167+
resourceId: 8,
168+
}, {
169+
id: 8,
170+
taskId: 9,
171+
resourceId: 9,
172+
}];
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React, { useState } from "react";
2+
import Gantt, {
3+
Tasks,
4+
Dependencies,
5+
Resources,
6+
ResourceAssignments,
7+
Column,
8+
Editing,
9+
} from "devextreme-react/gantt";
10+
import { tasks, dependencies, resources, resourceAssignments } from "./data";
11+
12+
function App() {
13+
const [showData, setShowData] = useState(true);
14+
15+
const toggleData = () => setShowData(!showData);
16+
17+
const taskContentRender = ({ taskData, taskSize, taskResources }) => {
18+
const getImagePath = (taskId) => {
19+
const imgPath =
20+
"https://js.devexpress.com/React/Demos/WidgetsGallery/JSDemos/images/employees";
21+
const img = taskId < 10 ? `0${taskId}` : taskId;
22+
return `${imgPath}/${img}.png`;
23+
};
24+
25+
const getTaskColor = (taskId) => {
26+
const color = taskId % 6;
27+
return `custom-task-color-${color}`;
28+
};
29+
30+
return (
31+
<div
32+
className={`custom-task ${getTaskColor(taskData.id)}`}
33+
style={{ width: `${taskSize.width}px` }}
34+
>
35+
<div className="custom-task-img-wrapper">
36+
<img
37+
className="custom-task-img"
38+
src={getImagePath(taskData.id)}
39+
alt={taskData.title}
40+
/>
41+
</div>
42+
<div className="custom-task-wrapper">
43+
<div className="custom-task-title">{taskData.title}</div>
44+
{taskResources?.length > 0 && (
45+
<div className="custom-task-row">{taskResources[0].text}</div>
46+
)}
47+
</div>
48+
<div
49+
className="custom-task-progress"
50+
style={{ width: `${taskData.progress}%` }}
51+
/>
52+
</div>
53+
);
54+
};
55+
56+
return (
57+
<div id="form-demo">
58+
<div className="widget-container">
59+
<button onClick={toggleData}>
60+
{showData ? "Hide Data" : "Show Data"}
61+
</button>
62+
63+
<Gantt
64+
taskListWidth={500}
65+
height={700}
66+
scaleType="days"
67+
taskContentRender={taskContentRender}
68+
>
69+
<Tasks dataSource={showData ? tasks : []} />
70+
<Dependencies dataSource={showData ? dependencies : []} />
71+
<Resources dataSource={showData ? resources : []} />
72+
<ResourceAssignments
73+
dataSource={showData ? resourceAssignments : []}
74+
/>
75+
76+
<Column dataField="title" caption="Subject" width={300} />
77+
<Column dataField="start" caption="Start Date" />
78+
<Column dataField="end" caption="End Date" />
79+
80+
<Editing enabled />
81+
</Gantt>
82+
</div>
83+
</div>
84+
);
85+
}
86+
87+
export default App;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Selector } from 'testcafe';
2+
import { testInFramework } from '../test-helpers';
3+
4+
if(process.env.FRAMEWORK === 'react') {
5+
testInFramework('Gantt template state update', 'gantt-template-state-update', [
6+
'Gantt should be able to ummount its template when a parent component\'s state update happens',
7+
async (t) => {
8+
const hideButton = Selector('button').withText('Hide Data');
9+
const noDataPlaceholder = Selector('.dx-treelist-nodata');
10+
11+
await t
12+
.click(hideButton)
13+
.expect(noDataPlaceholder.visible).ok()
14+
.expect(noDataPlaceholder.textContent).eql('No data');
15+
}
16+
]);
17+
}

packages/devextreme-react/src/core/template-wrapper.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ const TemplateWrapperComponent: FC<TemplateWrapperProps> = ({
6767
removalListenerElement.current,
6868
].forEach((el) => el && events.off(el, DX_REMOVE_EVENT, onTemplateRemoved));
6969

70-
// In case of multiple root elements, letting the widget remove them all sync
71-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
72-
Promise.resolve().then(() => {
73-
onRemoved(componentKey);
74-
});
70+
onRemoved(componentKey);
7571
}, [onRemoved]);
7672

7773
useLayoutEffect(() => {

0 commit comments

Comments
 (0)