Skip to content

Instantly share code, notes, and snippets.

@RyanJulyan
Created December 7, 2023 18:06
Show Gist options
  • Save RyanJulyan/1d8cee2c8d5a0660cad64b3be60041e7 to your computer and use it in GitHub Desktop.
Save RyanJulyan/1d8cee2c8d5a0660cad64b3be60041e7 to your computer and use it in GitHub Desktop.
Gantt Chart CRUD page leveraging frappe-gantt
<!DOCTYPE html>
<html>
<head>
<title>Gantt Chart</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/frappe-gantt/0.6.1/frappe-gantt.min.css" integrity="sha512-b6CPl1eORfMoZgwWGEYWNxYv79KG0dALXfVu4uReZJOXAfkINSK4UhA0ELwGcBBY7VJN7sykwrCGQnbS8qTKhQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/frappe-gantt/0.6.1/frappe-gantt.min.js" integrity="sha512-HyGTvFEibBWxuZkDsE2wmy0VQ0JRirYgGieHp0pUmmwyrcFkAbn55kZrSXzCgKga04SIti5jZQVjbTSzFpzMlg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style>
.details-container{
min-width: 200px;
padding: 5px;
}
</style>
</head>
<body>
<h1>Gantt Chart CRUD</h1>
<form id="task-form">
<input type="text" id="task-id" placeholder="Task ID" required>
<br/>
<input type="text" id="task-name" placeholder="Task Name" required>
<br/>
<input type="date" id="task-start" placeholder="Start Date" required>
<br/>
<input type="date" id="task-end" placeholder="End Date" required>
<br/>
<input type="number" id="task-progress" placeholder="Progress" required>
<br/>
<input type="text" id="task-dependencies" placeholder="Dependencies (comma-separated IDs)">
<br/>
<button type="submit">Add Task</button>
</form>
<div id="gantt"></div>
<script>
// Our data model
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
// Create a task
function createTask(task) {
if (!task.id || !task.name || !task.start || !task.end || typeof task.progress === 'undefined') {
console.error('All task properties (id, name, start, end, progress) must be defined');
return;
}
// Convert the task ID to a string
task.id = String(task.id);
// Convert the dependencies to a string
if (task.dependencies) {
task.dependencies = task.dependencies.map(String).join(',');
}
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
updateGanttChart();
}
// Read a task
function readTask(index) {
return tasks[index];
}
// Update a task
function updateTask(index, updatedTask) {
if (!updatedTask.id || !updatedTask.name || !updatedTask.start || !updatedTask.end || typeof updatedTask.progress === 'undefined') {
console.error('All task properties (id, name, start, end, progress) must be defined');
return;
}
// Convert the task ID to a string
updatedTask.id = String(updatedTask.id);
// Convert the dependencies to a string
if (updatedTask.dependencies) {
updatedTask.dependencies = updatedTask.dependencies.map(String).join(',');
}
tasks[index] = updatedTask;
localStorage.setItem('tasks', JSON.stringify(tasks));
updateGanttChart();
}
// Delete a task
function deleteTask(index) {
tasks.splice(index, 1);
localStorage.setItem('tasks', JSON.stringify(tasks));
updateGanttChart();
}
// Export tasks to JSON
function exportTasksToJSON() {
return JSON.stringify(tasks);
}
// Update the Gantt chart with the current tasks
function updateGanttChart() {
// Clear the SVG element
document.querySelector('#gantt').innerHTML = '';
let gantt = new Gantt("#gantt", tasks, {
on_click: function (task) {
// Do nothing on click, we'll handle updates in the popup
},
custom_popup_html: function(task) {
// Create a form in the popup for updating the task
return `
<div class="details-container">
<h4>Task ID: ${task.id}</h4>
<form id="popup-form" onsubmit="event.preventDefault(); updateTaskFromPopup(${task.id});" oninput="x.value=parseInt(progress.value)">
<label for="name">Name:</label>
<br/>
<input type="text" id="name" name="name" value="${task.name}" style="width: 96%">
<br/>
<label for="start">Start Date:</label>
<br/>
<input type="date" id="start" name="start" value="${task.start}" style="width: 96%">
<br/>
<label for="end">End Date:</label>
<br/>
<input type="date" id="end" name="end" value="${task.end}" style="width: 96%">
<br/>
<label for="progress">Progress: <output name="x" for="progress">${task.progress}</output>%</label>
<br/>
<input type="range" id="progress" min="1" max="100" value="${task.progress}" class="slider" style="width: 96%" >
<br/>
<br/>
<button type="submit" style="width: 100%">Update</button>
<br/>
<br/>
</form>
</div>
`;
},
on_date_change: function(task, start, end) {
console.log(task, start, end);
// Update the task in the data model
let index = tasks.findIndex(t => t.id === task.id);
if (index > -1) {
tasks[index].start = start;
tasks[index].end = end;
localStorage.setItem('tasks', JSON.stringify(tasks));
}
},
on_progress_change: function(task, progress) {
console.log(task, progress);
// Update the task in the data model
let index = tasks.findIndex(t => t.id === task.id);
if (index > -1) {
tasks[index].progress = progress;
localStorage.setItem('tasks', JSON.stringify(tasks));
}
},
on_view_change: function(mode) {
console.log(mode);
},
});
gantt.change_view_mode('Day') // Quarter Day, Half Day, Day, Week, Month
}
function updateTaskFromPopup(taskId) {
// Get the form data
let name = document.getElementById('name').value;
let start = document.getElementById('start').value;
let end = document.getElementById('end').value;
let progress = document.getElementById('progress').value;
// Update the task
let index = tasks.findIndex(t => t.id === String(taskId));
if (index > -1) {
updateTask(index, {
id: taskId,
name: name,
start: start,
end: end,
progress: parseInt(progress, 10),
dependencies: tasks[index].dependencies
});
}
}
// // Let's create, read, update, and delete some tasks
// createTask({ id: 1, name: 'Task 1', start: '2023-06-24', end: '2023-06-30', progress: 0 });
// console.log(readTask(0)); // { id: 1, name: 'Task 1', start: '2023-06-24', end: '2023-06-30' }
// updateTask(0, { id: 1, name: 'Updated Task 1', start: '2023-06-24', end: '2023-06-30', progress: 10 });
// console.log(readTask(0)); // { id: 1, name: 'Updated Task 1', start: '2023-06-24', end: '2023-06-30' }
// // deleteTask(0);
// console.log(tasks); // []
// // Let's create some tasks and export them to JSON
// createTask({ id: 2, name: 'Task 2', start: '2023-06-24', end: '2023-06-30', progress: 0, dependencies: [1] });
// createTask({ id: 3, name: 'Task 3', start: '2023-07-01', end: '2023-07-07', progress: 0 });
// console.log(exportTasksToJSON()); // [{"id":1,"name":"Task 1","start":"2023-06-24","end":"2023-06-30"},{"id":2,"name":"Task 2","start":"2023-07-01","end":"2023-07-07"}]
// // Initialize the Gantt chart
updateGanttChart();
document.getElementById('task-form').addEventListener('submit', function(event) {
event.preventDefault();
// Get the task details from the form
let id = document.getElementById('task-id').value;
let name = document.getElementById('task-name').value;
let start = document.getElementById('task-start').value;
let end = document.getElementById('task-end').value;
let progress = document.getElementById('task-progress').value;
let dependencies = document.getElementById('task-dependencies').value;
// Create the task
createTask({
id: id,
name: name,
start: start,
end: end,
progress: parseInt(progress, 10),
dependencies: dependencies ? dependencies.split(',').map(String) : []
});
// Clear the form
document.getElementById('task-form').reset();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment