From 91e236c42c18587bf5ff3a1421073bc4d67a3cdf Mon Sep 17 00:00:00 2001 From: Yassine Oualid Date: Wed, 28 Aug 2024 18:57:40 +0100 Subject: [PATCH] Display and Load Work Schedules from webUI --- src/bonsai/bonsai/bim/data/webui/sioserver.py | 5 ++ .../bim/data/webui/static/css/gantt.css | 2 + .../bonsai/bim/data/webui/static/js/gantt.js | 61 ++++++++++++++++++- src/bonsai/bonsai/tool/web.py | 44 ++++++------- 4 files changed, 89 insertions(+), 23 deletions(-) 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: