Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
import React from 'react';
import Scheduler, { Resource, View, Scrolling } from 'devextreme-react/scheduler';
import { resources, generateAppointments } from './data.ts';
const currentDate = new Date(2021, 1, 2);
const groups = ['humanId'];
const startDay = new Date(2021, 1, 1);
const endDay = new Date(2021, 1, 28);
const startDayHour = 8;
const endDayHour = 20;
const appointments = generateAppointments(startDay, endDay, startDayHour, endDayHour);
const App = () => (
<Scheduler
dataSource={appointments}
height={730}
defaultCurrentView={'Timeline'}
defaultCurrentDate={currentDate}
startDayHour={startDayHour}
endDayHour={endDayHour}
cellDuration={60}
showAllDayPanel={false}
groups={groups}>
<View
type='timelineWorkWeek'
name='Timeline'
groupOrientation='vertical'
/>
<View
type='workWeek'
groupOrientation='vertical'
/>
<View
type='month'
groupOrientation='horizontal'
/>
<Resource
fieldExpr='humanId'
dataSource={resources}
label='Employee'
/>
<Scrolling
mode='virtual'
/>
</Scheduler>
);
export default App;
import React from 'react';
import Scheduler, { Resource, View, Scrolling } from 'devextreme-react/scheduler';
import { resources, generateAppointments } from './data.js';
const currentDate = new Date(2021, 1, 2);
const groups = ['humanId'];
const startDay = new Date(2021, 1, 1);
const endDay = new Date(2021, 1, 28);
const startDayHour = 8;
const endDayHour = 20;
const appointments = generateAppointments(startDay, endDay, startDayHour, endDayHour);
const App = () => (
<Scheduler
dataSource={appointments}
height={730}
defaultCurrentView="Timeline"
defaultCurrentDate={currentDate}
startDayHour={startDayHour}
endDayHour={endDayHour}
cellDuration={60}
showAllDayPanel={false}
groups={groups}
>
<View
type="timelineWorkWeek"
name="Timeline"
groupOrientation="vertical"
/>
<View
type="workWeek"
groupOrientation="vertical"
/>
<View
type="month"
groupOrientation="horizontal"
/>
<Resource
fieldExpr="humanId"
dataSource={resources}
label="Employee"
/>
<Scrolling mode="virtual" />
</Scheduler>
);
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(
<App />,
document.getElementById('scheduler'),
);
import { SchedulerTypes } from 'devextreme-react/scheduler';
type Appointment = SchedulerTypes.Appointment & { humanId: number; };
type Resource = {
text: string;
id: number;
color: string;
};
export const resources: Resource[] = [{
id: 0,
text: 'David Carter',
color: '#74d57b',
}, {
id: 1,
text: 'Emma Lewis',
color: '#1db2f5',
}, {
id: 2,
text: 'Noah Hill',
color: '#f5564a',
}, {
id: 3,
text: 'William Bell',
color: '#97c95c',
}, {
id: 4,
text: 'Jane Jones',
color: '#ffc720',
}, {
id: 5,
text: 'Violet Young',
color: '#eb3573',
}, {
id: 6,
text: 'Samuel Perry',
color: '#a63db8',
}, {
id: 7,
text: 'Luther Murphy',
color: '#ffaa66',
}, {
id: 8,
text: 'Craig Morris',
color: '#2dcdc4',
}, {
id: 9,
text: 'Sandy Wood',
color: '#c34cb9',
}, {
id: 10,
text: 'Susan Bennett',
color: '#3d44ec',
}, {
id: 11,
text: 'Lilly Barnes',
color: '#4ddcca',
}, {
id: 12,
text: 'Marcus Price',
color: '#2ec98d',
}, {
id: 13,
text: 'David Stewart',
color: '#3ff6ca',
}, {
id: 14,
text: 'Joseph Smith',
color: '#f665aa',
}, {
id: 15,
text: 'Carter Wilson',
color: '#d1c974',
}, {
id: 16,
text: 'Wyatt Lopez',
color: '#ff6741',
}, {
id: 17,
text: 'John Long',
color: '#ee53dc',
}, {
id: 18,
text: 'Jack Rivera',
color: '#795ac3',
}, {
id: 19,
text: 'Victoria Adams',
color: '#ff7d8a',
}, {
id: 20,
text: 'Madison Anderson',
color: '#4cd482',
}, {
id: 21,
text: 'Luna Moore',
color: '#9d67cc',
}, {
id: 22,
text: 'Michael Bailey',
color: '#5ab1ef',
}, {
id: 23,
text: 'Jenny Powell',
color: '#68e18f',
}, {
id: 24,
text: 'Daniel Peterson',
color: '#4dd155',
}, {
id: 25,
text: 'Gabriel Gray',
color: '#ef9e44',
}, {
id: 26,
text: 'Anthony Robinson',
color: '#45a5cc',
}, {
id: 27,
text: 'Ellie Tomson',
color: '#a067bd',
}, {
id: 28,
text: 'Natalie Adams',
color: '#3d44ec',
}, {
id: 29,
text: 'Sofia Green',
color: '#4ddcca',
}];
const appointmentsText = [
'Google AdWords Strategy',
'New Brochures',
'Brochure Design Review',
'Website Re-Design Plan',
'Rollout of New Website and Marketing Brochures',
'Update Sales Strategy Documents',
'Non-Compete Agreements',
'Approve Hiring of John Jeffers',
'Update NDA Agreement',
'Update Employee Files with New NDA',
'Submit Questions Regarding New NDA',
'Submit Signed NDA',
'Review Revenue Projections',
'Comment on Revenue Projections',
'Provide New Health Insurance Docs',
'Review Changes to Health Insurance Coverage',
'Review Training Course for any Ommissions',
'Recall Rebate Form',
'Create Report on Customer Feedback',
'Review Customer Feedback Report',
'Customer Feedback Report Analysis',
'Prepare Shipping Cost Analysis Report',
'Provide Feedback on Shippers',
'Select Preferred Shipper',
'Complete Shipper Selection Form',
'Upgrade Server Hardware',
'Upgrade Personal Computers',
'Upgrade Apps to Windows RT or stay with WinForms',
'Estimate Time Required to Touch-Enable Apps',
'Report on Tranistion to Touch-Based Apps',
'Submit New Website Design',
'Create Icons for Website',
'Create New Product Pages',
'Approve Website Launch',
'Update Customer Shipping Profiles',
'Create New Shipping Return Labels',
'Get Design for Shipping Return Labels',
'PSD needed for Shipping Return Labels',
'Contact ISP and Discuss Payment Options',
'Prepare Year-End Support Summary Report',
'Review New Training Material',
'Distribute Training Material to Support Staff',
'Training Material Distribution Schedule',
'Approval on Converting to New HDMI Specification',
'Create New Spike for Automation Server',
'Code Review - New Automation Server',
'Confirm Availability for Sales Meeting',
'Reschedule Sales Team Meeting',
'Send 2 Remotes for Giveaways',
'Discuss Product Giveaways with Management',
'Replace Desktops on the 3rd Floor',
'Update Database with New Leads',
'Mail New Leads for Follow Up',
'Send Territory Sales Breakdown',
'Territory Sales Breakdown Report',
'Report on the State of Engineering Dept',
'Staff Productivity Report',
];
function getRandomDuration(durationState: number) {
const durationMin = Math.floor((durationState % 23) / 3 + 5) * 15;
return durationMin * 60 * 1000;
}
function getRandomText(textIndex: number) {
return appointmentsText[textIndex % appointmentsText.length];
}
function filterAppointmentsByTime(appointments: string | any[], startDayHour: number, endDayHour: number) {
const result: any[] = [];
for (let i = 0; i < appointments.length; i += 1) {
const { startDate } = appointments[i];
const { endDate } = appointments[i];
if (startDate.getDay() === endDate.getDay()
&& startDate.getHours() >= startDayHour - 1
&& endDate.getHours() <= endDayHour - 1) {
result.push(appointments[i]);
}
}
return result;
}
export function generateAppointments(startDay: Date, endDay: Date, startDayHour: number, endDayHour: number) {
const appointments: Appointment[] = [];
let textIndex = 0;
let durationState = 1;
const durationIncrement = 19;
for (let i = 0; i < resources.length; i += 1) {
let startDate = startDay;
while (startDate.getTime() < endDay.getTime()) {
durationState += durationIncrement;
const endDate = new Date(startDate.getTime() + getRandomDuration(durationState));
appointments.push({
text: getRandomText(textIndex),
startDate,
endDate,
humanId: resources[i].id,
});
textIndex += 1;
durationState += durationIncrement;
startDate = new Date(endDate.getTime() + getRandomDuration(durationState));
}
}
return filterAppointmentsByTime(appointments, startDayHour, endDayHour);
}
window.exports = window.exports || {};
window.config = {
transpiler: 'ts',
typescriptOptions: {
module: 'system',
emitDecoratorMetadata: true,
experimentalDecorators: true,
jsx: 'react',
},
meta: {
'react': {
'esModule': true,
},
'typescript': {
'exports': 'ts',
},
'devextreme/time_zone_utils.js': {
'esModule': true,
},
'devextreme/localization.js': {
'esModule': true,
},
'devextreme/viz/palette.js': {
'esModule': true,
},
'openai': {
'esModule': true,
},
},
paths: {
'npm:': 'https://unpkg.com/',
'bundles:': '../../../../bundles/',
'externals:': '../../../../bundles/externals/',
},
defaultExtension: 'js',
map: {
'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js',
'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js',
'react': 'npm:react@17.0.2/umd/react.development.js',
'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js',
'prop-types': 'npm:prop-types/prop-types.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign',
'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs',
'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12',
'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js',
'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js',
'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js',
'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3',
// SystemJS plugins
'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
// Prettier
'prettier/standalone': 'npm:prettier@2.8.8/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
},
packages: {
'devextreme': {
defaultExtension: 'js',
},
'devextreme-react': {
main: 'index.js',
},
'devextreme/events/utils': {
main: 'index',
},
'devextreme/localization/messages': {
format: 'json',
defaultExtension: 'json',
},
'devextreme/events': {
main: 'index',
},
'es6-object-assign': {
main: './index.js',
defaultExtension: 'js',
},
},
packageConfigPaths: [
'npm:@devextreme/*/package.json',
'npm:@devextreme/runtime@3.0.12/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
react: true,
},
};
System.config(window.config);
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('scheduler'));
export const resources = [
{
id: 0,
text: 'David Carter',
color: '#74d57b',
},
{
id: 1,
text: 'Emma Lewis',
color: '#1db2f5',
},
{
id: 2,
text: 'Noah Hill',
color: '#f5564a',
},
{
id: 3,
text: 'William Bell',
color: '#97c95c',
},
{
id: 4,
text: 'Jane Jones',
color: '#ffc720',
},
{
id: 5,
text: 'Violet Young',
color: '#eb3573',
},
{
id: 6,
text: 'Samuel Perry',
color: '#a63db8',
},
{
id: 7,
text: 'Luther Murphy',
color: '#ffaa66',
},
{
id: 8,
text: 'Craig Morris',
color: '#2dcdc4',
},
{
id: 9,
text: 'Sandy Wood',
color: '#c34cb9',
},
{
id: 10,
text: 'Susan Bennett',
color: '#3d44ec',
},
{
id: 11,
text: 'Lilly Barnes',
color: '#4ddcca',
},
{
id: 12,
text: 'Marcus Price',
color: '#2ec98d',
},
{
id: 13,
text: 'David Stewart',
color: '#3ff6ca',
},
{
id: 14,
text: 'Joseph Smith',
color: '#f665aa',
},
{
id: 15,
text: 'Carter Wilson',
color: '#d1c974',
},
{
id: 16,
text: 'Wyatt Lopez',
color: '#ff6741',
},
{
id: 17,
text: 'John Long',
color: '#ee53dc',
},
{
id: 18,
text: 'Jack Rivera',
color: '#795ac3',
},
{
id: 19,
text: 'Victoria Adams',
color: '#ff7d8a',
},
{
id: 20,
text: 'Madison Anderson',
color: '#4cd482',
},
{
id: 21,
text: 'Luna Moore',
color: '#9d67cc',
},
{
id: 22,
text: 'Michael Bailey',
color: '#5ab1ef',
},
{
id: 23,
text: 'Jenny Powell',
color: '#68e18f',
},
{
id: 24,
text: 'Daniel Peterson',
color: '#4dd155',
},
{
id: 25,
text: 'Gabriel Gray',
color: '#ef9e44',
},
{
id: 26,
text: 'Anthony Robinson',
color: '#45a5cc',
},
{
id: 27,
text: 'Ellie Tomson',
color: '#a067bd',
},
{
id: 28,
text: 'Natalie Adams',
color: '#3d44ec',
},
{
id: 29,
text: 'Sofia Green',
color: '#4ddcca',
},
];
const appointmentsText = [
'Google AdWords Strategy',
'New Brochures',
'Brochure Design Review',
'Website Re-Design Plan',
'Rollout of New Website and Marketing Brochures',
'Update Sales Strategy Documents',
'Non-Compete Agreements',
'Approve Hiring of John Jeffers',
'Update NDA Agreement',
'Update Employee Files with New NDA',
'Submit Questions Regarding New NDA',
'Submit Signed NDA',
'Review Revenue Projections',
'Comment on Revenue Projections',
'Provide New Health Insurance Docs',
'Review Changes to Health Insurance Coverage',
'Review Training Course for any Ommissions',
'Recall Rebate Form',
'Create Report on Customer Feedback',
'Review Customer Feedback Report',
'Customer Feedback Report Analysis',
'Prepare Shipping Cost Analysis Report',
'Provide Feedback on Shippers',
'Select Preferred Shipper',
'Complete Shipper Selection Form',
'Upgrade Server Hardware',
'Upgrade Personal Computers',
'Upgrade Apps to Windows RT or stay with WinForms',
'Estimate Time Required to Touch-Enable Apps',
'Report on Tranistion to Touch-Based Apps',
'Submit New Website Design',
'Create Icons for Website',
'Create New Product Pages',
'Approve Website Launch',
'Update Customer Shipping Profiles',
'Create New Shipping Return Labels',
'Get Design for Shipping Return Labels',
'PSD needed for Shipping Return Labels',
'Contact ISP and Discuss Payment Options',
'Prepare Year-End Support Summary Report',
'Review New Training Material',
'Distribute Training Material to Support Staff',
'Training Material Distribution Schedule',
'Approval on Converting to New HDMI Specification',
'Create New Spike for Automation Server',
'Code Review - New Automation Server',
'Confirm Availability for Sales Meeting',
'Reschedule Sales Team Meeting',
'Send 2 Remotes for Giveaways',
'Discuss Product Giveaways with Management',
'Replace Desktops on the 3rd Floor',
'Update Database with New Leads',
'Mail New Leads for Follow Up',
'Send Territory Sales Breakdown',
'Territory Sales Breakdown Report',
'Report on the State of Engineering Dept',
'Staff Productivity Report',
];
function getRandomDuration(durationState) {
const durationMin = Math.floor((durationState % 23) / 3 + 5) * 15;
return durationMin * 60 * 1000;
}
function getRandomText(textIndex) {
return appointmentsText[textIndex % appointmentsText.length];
}
function filterAppointmentsByTime(appointments, startDayHour, endDayHour) {
const result = [];
for (let i = 0; i < appointments.length; i += 1) {
const { startDate } = appointments[i];
const { endDate } = appointments[i];
if (
startDate.getDay() === endDate.getDay()
&& startDate.getHours() >= startDayHour - 1
&& endDate.getHours() <= endDayHour - 1
) {
result.push(appointments[i]);
}
}
return result;
}
export function generateAppointments(startDay, endDay, startDayHour, endDayHour) {
const appointments = [];
let textIndex = 0;
let durationState = 1;
const durationIncrement = 19;
for (let i = 0; i < resources.length; i += 1) {
let startDate = startDay;
while (startDate.getTime() < endDay.getTime()) {
durationState += durationIncrement;
const endDate = new Date(startDate.getTime() + getRandomDuration(durationState));
appointments.push({
text: getRandomText(textIndex),
startDate,
endDate,
humanId: resources[i].id,
});
textIndex += 1;
durationState += durationIncrement;
startDate = new Date(endDate.getTime() + getRandomDuration(durationState));
}
}
return filterAppointmentsByTime(appointments, startDayHour, endDayHour);
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script>
<script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
System.import("./index.tsx");
</script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<div id="scheduler"></div>
</div>
</body>
</html>
#scheduler .dx-scheduler-cell-sizes-vertical {
height: 100px;
}
#scheduler .dx-scheduler-cell-sizes-horizontal {
width: 150px;
}