diff --git a/src/bonsai/bonsai/bim/data/webui/sioserver.py b/src/bonsai/bonsai/bim/data/webui/sioserver.py
index 37dcc81741..117505d2c0 100644
--- a/src/bonsai/bonsai/bim/data/webui/sioserver.py
+++ b/src/bonsai/bonsai/bim/data/webui/sioserver.py
@@ -121,6 +121,11 @@ class BlenderNamespace(socketio.AsyncNamespace):
blender_messages[sid]["demo_data"] = data
await sio.emit("demo_data", {"blenderId": sid, "data": data}, namespace="/web")
+ async def on_work_schedule_info(self, sid, data):
+ print(f"Work schedule info from Blender client {sid}")
+ blender_messages[sid]["work_schedule_info"] = data
+ await sio.emit("work_schedule_info", {"blenderId": sid, "data": data}, namespace="/web")
+
async def on_cost_items(self, sid, data):
print(f"Cost items data from Blender client {sid}")
blender_messages[sid]["cost_items"] = data
diff --git a/src/bonsai/bonsai/bim/data/webui/static/css/gantt.css b/src/bonsai/bonsai/bim/data/webui/static/css/gantt.css
index 9f97eb6b82..cd575af2bb 100644
--- a/src/bonsai/bonsai/bim/data/webui/static/css/gantt.css
+++ b/src/bonsai/bonsai/bim/data/webui/static/css/gantt.css
@@ -1,3 +1,5 @@
+@import url("./components/card.css");
+
:root {
--font-family: Arial, sans-serif;
--base-font-size: 16px;
diff --git a/src/bonsai/bonsai/bim/data/webui/static/js/gantt.js b/src/bonsai/bonsai/bim/data/webui/static/js/gantt.js
index 9531aa5ecb..5942765dfd 100644
--- a/src/bonsai/bonsai/bim/data/webui/static/js/gantt.js
+++ b/src/bonsai/bonsai/bim/data/webui/static/js/gantt.js
@@ -1,3 +1,5 @@
+import { CostUI } from './utilities/costui.js';
+
// keeps track of blenders connected in form of
// shown:bool, workSchedule: {}, ganttTasks: {}, warning: bool
const connectedClients = {};
@@ -36,9 +38,16 @@ function connectSocket() {
socket.on("blender_connect", handleBlenderConnect);
socket.on("blender_disconnect", handleBlenderDisconnect);
socket.on("connected_clients", handleConnectedClients);
+ socket.on("connect", handleWebConnect);
socket.on("theme_data", handleThemeData);
socket.on("gantt_data", handleGanttData);
socket.on("default_data", handleDefaultData);
+ socket.on("work_schedule_info", handleWorkScheduleData);
+}
+
+// function used to get drawings data from Bonsai
+function handleWebConnect() {
+ getWorkScheduleData();
}
// Function to handle 'blender_connect' event
@@ -62,6 +71,7 @@ function handleBlenderDisconnect(blenderId) {
console.log("blender disconnected: ", blenderId);
if (connectedClients.hasOwnProperty(blenderId)) {
delete connectedClients[blenderId];
+ removeWorkScheduleInfo(blenderId);
removeGanttElement(blenderId);
}
@@ -114,8 +124,25 @@ function handleThemeData(themeData) {
}
}
-// Function to handle 'gantt_data' event
+function handleWorkScheduleData(data) {
+ const blenderId = data["blenderId"];
+ const workSchedulesMainDiv = $("#work_schedules");
+ const workSchedulesDiv = $("
").attr("id", "work_schedules-" + blenderId);
+ workSchedulesMainDiv.append(workSchedulesDiv);
+
+ const workSchedules = data["data"]["work_schedule_info"];
+
+ workSchedules.forEach((workSchedule) => {
+ console.log(workSchedule);
+ const mainContainer = CostUI.text(new Date(workSchedule.CreationDate).toLocaleDateString());
+ const callback = () => loadWorkSchedule(workSchedule.id);
+ const card = CostUI.createCard(workSchedule.Name,mainContainer, callback);
+ workSchedulesDiv.append(card);
+ });
+}
+
function handleGanttData(data) {
+ console.log("running handleGanttData");
const blenderId = data["blenderId"];
console.log(data);
@@ -156,7 +183,7 @@ function handleDefaultData(data) {
const blenderId = data["blenderId"];
const isDirty = data["data"]["is_dirty"];
showWarning(blenderId, isDirty);
- console.log(data);
+ console.log('default data',data);
}
// Function to add a new gantt with data and filename
@@ -551,3 +578,33 @@ function toggleClientList() {
clientList.addClass("show");
}
+
+function loadWorkSchedule(workScheduleId) {
+ const msg = {
+ sourcePage: "gantt",
+ operator: {
+ type: "loadWorkSchedule",
+ workScheduleId: workScheduleId,
+ },
+ };
+ socket.emit("web_operator", msg);
+}
+
+function removeWorkScheduleInfo(blenderId) {
+ $("#work_schedules-"+ blenderId).empty();
+}
+
+function getWorkScheduleData(blenderId) {
+ const msg = {
+ sourcePage: "gantt",
+ operator: {
+ type: "getWorkSchedules",
+ },
+ };
+
+ if (blenderId !== undefined) {
+ msg.BlenderId = blenderId;
+ }
+
+ socket.emit("web_operator", msg);
+}
diff --git a/src/bonsai/bonsai/tool/web.py b/src/bonsai/bonsai/tool/web.py
index 3485b1b3fe..099e61c136 100644
--- a/src/bonsai/bonsai/tool/web.py
+++ b/src/bonsai/bonsai/tool/web.py
@@ -383,34 +383,36 @@ class Web(bonsai.core.tool.Web):
operator_data (dict): A dictionary containing the operator data.
"""
ifc_file = tool.Ifc.get()
+ if operator_data["type"] == "getWorkSchedules":
+ work_schedules = ifc_file.by_type("IfcWorkSchedule")
+ work_schedules_json = [ws.get_info(recursive=True) for ws in work_schedules]
+ cls.send_webui_data(data=work_schedules_json, data_key="work_schedule_info", event="work_schedule_info")
+ if operator_data["type"] == "loadWorkSchedule":
+ work_schedule = ifc_file.by_id(operator_data["workScheduleId"])
+ print("Generating Gantt chart")
+ bonsai.core.sequence.enable_editing_work_schedule_tasks(tool.Sequence, work_schedule=work_schedule)
+ bonsai.core.sequence.generate_gantt_chart(tool.Sequence, work_schedule=work_schedule)
if operator_data["type"] == "editTask":
task_id = int(operator_data["taskId"])
task = ifc_file.by_id(task_id)
task_time = task.TaskTime
column = operator_data["column"]
new_value = operator_data["value"]
+ if task_time is None:
+ ifcopenshell.api.sequence.add_task_time(ifc_file, task)
+ task_time = task.TaskTime
+ ifcopenshell.api.sequence.edit_task_time(
+ ifc_file, task_time=task_time, attributes={IFC_TASK_ATTRIBUTE_MAP[column]: str(new_value)}
+ )
- try:
- ifcopenshell.api.sequence.edit_task(
- ifc_file, task, attributes={IFC_TASK_ATTRIBUTE_MAP[column]: str(new_value)}
- )
- except AttributeError:
- if task_time is None:
- ifcopenshell.api.sequence.add_task_time(ifc_file, task)
- task_time = task.TaskTime
- ifcopenshell.api.sequence.edit_task_time(
- ifc_file, task_time=task_time, attributes={IFC_TASK_ATTRIBUTE_MAP[column]: str(new_value)}
- )
-
- bpy.ops.bim.load_task_properties()
-
- # after updating, send new gantt data to handle the case where
- # changing a task cascades and changes other tasks. as this wouldn't
- # be reflected in the web ui
- work_schedule = ifc_file.by_id(operator_data["workScheduleId"])
- task_json = tool.Sequence.create_tasks_json(work_schedule)
- gantt_data = {"tasks": task_json, "work_schedule": work_schedule.get_info(recursive=True)}
- cls.send_webui_data(data=gantt_data, data_key="gantt_data", event="gantt_data")
+ bpy.ops.bim.load_task_properties()
+ # after updating, send new gantt data to handle the case where
+ # changing a task cascades and changes other tasks. as this wouldn't
+ # be reflected in the web ui
+ work_schedule = ifc_file.by_id(operator_data["workScheduleId"])
+ task_json = tool.Sequence.create_tasks_json(work_schedule)
+ gantt_data = {"tasks": task_json, "work_schedule": work_schedule.get_info(recursive=True)}
+ cls.send_webui_data(data=gantt_data, data_key="gantt_data", event="gantt_data")
@classmethod
def handle_drawings_operator(cls, operator_data: dict) -> None: