- web ui features to add a new cost schedules, and root cost items

- improved ui for cost schedules
- sharing more css across files
- refactor get_predefined_types(cost_schedule)
This commit is contained in:
`myoualid`
2024-09-06 08:55:10 +01:00
parent 541a6e18e6
commit d6098a0b6d
11 changed files with 1456 additions and 1307 deletions
@@ -176,6 +176,11 @@ class BlenderNamespace(socketio.AsyncNamespace):
blender_messages[sid]["cost_value"] = data blender_messages[sid]["cost_value"] = data
await sio.emit("cost_value", {"blenderId": sid, "data": data}, namespace="/web") await sio.emit("cost_value", {"blenderId": sid, "data": data}, namespace="/web")
async def on_predefined_types(self, sid, data):
print(f"Predefined types from Blender client {sid}")
blender_messages[sid]["predefined_types"] = data
await sio.emit("predefined_types", {"blenderId": sid, "data": data}, namespace="/web")
async def schedules(request): async def schedules(request):
with open("templates/index.html", "r") as f: with open("templates/index.html", "r") as f:
template = f.read() template = f.read()
@@ -5,24 +5,19 @@
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
/* prevent text from being selceted */
user-select: none; user-select: none;
} }
td:not(:first-child) { td:not(:first-child) {
text-align: center; text-align: center;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
td { td {
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
padding-left: 0.5em; padding-left: 0.5em;
padding-right: 0.5em; padding-right: 0.5em;
} }
.nested { .nested {
@@ -39,22 +34,15 @@ td {
padding: 0; padding: 0;
} }
.flex-container { input, select {
display: flex; background-color: var(--blender-button-background, var(--bg-color));
justify-content: space-between; color: var(--blender-button-text, var(--text-color));
align-items: center; border-color: var(--blender-button-border, var(--border-color));
width: 100%; transition: filter 0.2s ease;
}
input {
width: 100%;
border: 1px solid #e1e4e8;
border-radius: 6px; border-radius: 6px;
background-color:inherit;
padding: 6px 8px; padding: 6px 8px;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
color:inherit;
transition: border-color 0.2s cubic-bezier(0.3, 0, 0.5, 1); transition: border-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);
height: inherit; height: inherit;
margin-left: 0.5em; margin-left: 0.5em;
@@ -62,12 +50,11 @@ input {
} }
input:focus { input:focus {
border-color: #0366d6; border-color: #28a745;
outline: none; outline: none;
box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.3); box-shadow: 0 0 0 3px #28a745;
} }
#cost-items tr:hover, .highlighted { #cost-items tr:hover, .highlighted {
background-color: #ffb936; background-color: #ffb936;
color : black; color : black;
@@ -87,13 +74,17 @@ input:focus {
padding: 10px; padding: 10px;
} }
.cost-values-form { .floating-form {
min-width: 40%;
height: auto;
position: absolute; position: absolute;
background-color: white; background-color: #363636;
border: 1px solid black; border: 1px solid black;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 9999; z-index: 9999;
cursor: move; cursor: move;
padding: 20px;
user-select: none;
} }
.cost-values-table { .cost-values-table {
@@ -120,18 +111,20 @@ input:focus {
} }
.action-button { .action-button {
background-color: #28a745; /* GitHub green color */ background-color: #28a745;
border: none; border: none;
color: #fff; /* White text color */ color: #fff;
padding: 0.5em 1em; /* Adjust padding as needed */ padding: 0.5em 1em;
cursor: pointer; cursor: pointer;
border-radius: 6px; /* Slightly rounded corners */ border-radius: 6px;
font-weight: bold; /* Make the text bold */ font-weight: bold;
text-decoration: none; /* Remove underline */ text-decoration: none;
display: inline-block; /* Make the button inline */ display: inline-block;
transition: background-color 0.3s ease; /* Add a smooth transition */ transition: background-color 0.3s ease;
width: fit-content;
margin-left: 0.5em;
} }
.action-button:hover { .action-button:hover {
background-color: #218838; /* Darker green color on hover */ background-color: #218838;
} }
@@ -1,288 +1,166 @@
@import url("./components/card.css"); @import url("./components/card.css");
@import url("./shared.css");
:root {
--font-family: Arial, sans-serif;
--base-font-size: 16px;
--margin-tiny: 0.125rem;
--margin-small: 0.625rem;
--margin-medium: 1.25rem;
--margin-large: 2.5rem;
--padding-tiny: 0.125rem;
--padding-small: 0.625rem;
--padding-medium: 1rem;
--font-size-small: 1rem;
--font-size-large: 1.2rem;
--logo-height: 1.5rem;
--nav-height: 0.625rem;
--border-radius: 0.3rem;
--folder-collapse-font-size: 0.75rem;
--folder-collapse-font-family: Courier, "Courier New", monospace;
--box-shadow: 0 0 0.7rem #5f5f5f66;
}
:root.dark {
color-scheme: dark;
--bg-color: #252525;
--primary-text-color: #e0e0e0;
--secondary-text-color: #c7c7c7;
--nav-bg-color: #121212;
--nav-border-color: #25682a;
--nav-link-color: #fff;
--nav-link-hover-color: #3fb449;
--warning-color: #FFDB8F;
--border-color: #464444;
--hover-bg-color: #3a3a3a;
--highlight-color: #009136;
--task-complete-bg-color: #777777;
--milestone-border-color: #ffffff;
--group-item-bg-color: #4b4b4b;
--input-bg-color: #3b3b3b;
--input-border-color: #000;
--border-color: #464444;
}
:root.light {
color-scheme: light;
--bg-color: #ffffff;
--primary-text-color: #000000;
--nav-bg-color: #f8f8f8;
--nav-border-color: #cccccc;
--nav-link-color: #000000;
--nav-link-hover-color: #38a63d;
--warning-color: #FF4500;
--border-color: #222;
}
*:not(td, tr, td, .gmain) {
border-radius: var(--border-radius) !important;
}
html {
font-size: var(--base-font-size);
}
body {
background-color: var(--blender-window-background, var(--bg-color));
color: var(--blender-text, var(--primary-text-color));
margin: 0;
font-family: var(--font-family);
display: flex;
flex-direction: column;
min-height: 100vh;
}
#container {
flex: 1;
padding: var(--margin-small);
}
h3 {
margin-top: 0;
}
nav {
background-color: var(--blender-top-bar-header, var(--nav-bg-color));
height: var(--nav-height);
padding: var(--padding-medium) 0;
display: flex;
align-items: center;
position: relative;
border-bottom: 2px solid var(--blender-tab-outline, var(--nav-border-color));
}
nav .logo {
margin-left: var(--margin-large);
height: var(--logo-height);
}
nav ul {
list-style-type: none;
margin: 0;
display: flex;
flex: 1;
justify-content: center;
}
nav ul li {
margin-right: var(--margin-large);
}
nav ul li a {
text-decoration: none;
color: var(--blender-text, var(--nav-link-color));
}
nav ul li a:hover,
nav ul li a.active {
color: var(--blender-selected-object, var(--nav-link-hover-color));
}
.warning,
.warning-icon {
color: var(--blender-info-warning, var(--warning-color));
}
.table-description { .table-description {
margin-bottom: var(--margin-medium); margin-bottom: var(--margin-medium);
width: 50%; width: 50%;
background-color: transparent; background-color: transparent;
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
border-color: var(--blender-tab-outline, var(--border-color)); border-color: var(--blender-tab-outline, var(--border-color));
border: 1px solid var(--blender-tab-outline, var(--border-color)); border: 1px solid var(--blender-tab-outline, var(--border-color));
border-radius: 0.25rem; border-radius: 0.25rem;
box-shadow: var(--box-shadow); box-shadow: var(--box-shadow);
text-align: center; text-align: center;
} }
.table-description tr { .table-description tr {
display: table-row; display: table-row;
border-bottom: 1px solid var(--blender-tab-outline, var(--border-color)); border-bottom: 1px solid var(--blender-tab-outline, var(--border-color));
} }
.table-description tr:nth-child(even) { .table-description tr:nth-child(even) {
background-color: var(--blender-even-row); background-color: var(--blender-even-row);
} }
.table-description tr:nth-child(odd) { .table-description tr:nth-child(odd) {
background-color: var(--blender-odd-row); background-color: var(--blender-odd-row);
} }
#toggle-theme { #toggle-theme {
border: none; border: none;
background: none; background: none;
cursor: pointer; cursor: pointer;
font-size: var(--font-size-large); font-size: var(--font-size-large);
margin-right: var(--margin-medium); margin-right: var(--margin-medium);
} }
#toggle-theme:focus { #toggle-theme:focus {
outline: none; outline: none;
} }
#client-list { #client-list {
position: absolute; position: absolute;
top: calc(0 + var(--nav-height)); top: calc(0 + var(--nav-height));
overflow-y: auto; overflow-y: auto;
overflow: hidden; overflow: hidden;
transition: opacity 0.3s ease-out, visibility 0.3s ease-out; transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
border: 1px solid var(--blender-tab-outline, var(--border-color)); border: 1px solid var(--blender-tab-outline, var(--border-color));
background-color: var(--blender-panel-background, var(--nav-bg-color)); background-color: var(--blender-panel-background, var(--nav-bg-color));
z-index: 1; z-index: 1;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
width: auto; width: auto;
} }
#client-list.show { #client-list.show {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
#connected-list-div { #connected-list-div {
display: inline-block; display: inline-block;
} }
.client { .client {
padding: var(--margin-small); padding: var(--margin-small);
border-bottom: 1px solid var(--blender-tab-outline, var(--border-color)); border-bottom: 1px solid var(--blender-tab-outline, var(--border-color));
cursor: pointer; cursor: pointer;
} }
.client-details { .client-details {
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
padding-left: var(--padding-small); padding-left: var(--padding-small);
transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out; transition: max-height 0.2s ease-out, padding 0.2s ease-out,
background-color: var(--blender-panel-background, var(--nav-bg-color)); opacity 0.1s ease-out;
margin-top: var(--margin-tiny); background-color: var(--blender-panel-background, var(--nav-bg-color));
opacity: 0; margin-top: var(--margin-tiny);
opacity: 0;
} }
.client-details.show { .client-details.show {
max-height: none; max-height: none;
opacity: 1; opacity: 1;
} }
.client-detail { .client-detail {
border-bottom: 1px solid var(--blender-tab-outline, var(--border-color)); border-bottom: 1px solid var(--blender-tab-outline, var(--border-color));
padding: var(--padding-small); padding: var(--padding-small);
} }
#show-connected-button { #show-connected-button {
width: auto; width: auto;
background-color: var(--blender-panel-header, var(--bg-color)); background-color: var(--blender-panel-header, var(--bg-color));
font-size: var(--base-font-size); font-size: var(--base-font-size);
} }
#show-connected-button:hover, #show-connected-button:hover,
.scroll-button:hover { .scroll-button:hover {
cursor: pointer; cursor: pointer;
} }
.scroll-button { .scroll-button {
font-size: var(--base-font-size); font-size: var(--base-font-size);
margin-left: var(--margin-tiny); margin-left: var(--margin-tiny);
margin-top: var(--margin-small); margin-top: var(--margin-small);
} }
footer { footer {
background-color: var(--blender-top-bar-header, var(--nav-bg-color)); background-color: var(--blender-top-bar-header, var(--nav-bg-color));
text-align: right; text-align: right;
padding: var(--padding-tiny); padding: var(--padding-tiny);
border-top: 1px solid var(--blender-tab-outline, var(--nav-border-color)); border-top: 1px solid var(--blender-tab-outline, var(--nav-border-color));
} }
footer p { footer p {
margin: 0; margin: 0;
color: var(--blender-text, var(--nav-link-color)); color: var(--blender-text, var(--nav-link-color));
margin-right: var(--margin-small); margin-right: var(--margin-small);
font-size: 0.8rem; font-size: 0.8rem;
} }
.gantt-info { .gantt-info {
margin: 0.5rem; margin: 0.5rem;
font-size: var(--font-size-small); font-size: var(--font-size-small);
font-weight: bold; font-weight: bold;
} }
.btn { .btn {
margin: 0.5rem; margin: 0.5rem;
font-size: var(--font-size-small); font-size: var(--font-size-small);
cursor: pointer; cursor: pointer;
} }
@media print { @media print {
.no-print { .no-print {
display: none; display: none;
} }
} }
button, button,
select { select {
background-color: var(--blender-button-background, var(--bg-color)); background-color: var(--blender-button-background, var(--bg-color));
color: var(--blender-button-text, var(--text-color)); color: var(--blender-button-text, var(--text-color));
border-color: var(--blender-button-border, var(--border-color)); border-color: var(--blender-button-border, var(--border-color));
transition: filter 0.2s ease; transition: filter 0.2s ease;
} }
button:hover { button:hover {
filter: brightness(1.2); filter: brightness(1.2);
} }
/* ------------ Overwriting JSGantt CSS rules ------------ */ /* ------------ Overwriting JSGantt CSS rules ------------ */
/* ------------------- for dark theme ------------------- */ /* ------------------- for dark theme ------------------- */
:root.dark div.gantt { :root.dark div.gantt {
background-color: var(--bg-color); background-color: var(--bg-color);
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
:root.dark .gantt table, :root.dark .gantt table,
:root.dark .gantt td { :root.dark .gantt td {
border-color: var(--border-color); border-color: var(--border-color);
} }
/* Headings and cell defaults */ /* Headings and cell defaults */
@@ -295,8 +173,8 @@ button:hover {
:root.dark .gname, :root.dark .gname,
:root.dark .ggroupitem, :root.dark .ggroupitem,
:root.dark .gtaskheading { :root.dark .gtaskheading {
background-color: var(--bg-color); background-color: var(--bg-color);
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.dark .gtaskheading, :root.dark .gtaskheading,
@@ -312,129 +190,128 @@ button:hover {
:root.dark .gchartlbl, :root.dark .gchartlbl,
:root.dark .gcontainercol, :root.dark .gcontainercol,
:root.dark .genddate { :root.dark .genddate {
color: var(--secondary-text-color); color: var(--secondary-text-color);
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.dark .gtaskname>div { :root.dark .gtaskname > div {
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
:root.dark .gtaskbarcontainer.gplan, :root.dark .gtaskbarcontainer.gplan,
:root.dark .gchartlbl.gcontainercol { :root.dark .gchartlbl.gcontainercol {
background: var(--bg-color); background: var(--bg-color);
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.dark .gtaskname div, :root.dark .gtaskname div,
:root.dark .gtaskheading div, :root.dark .gtaskheading div,
:root.dark .gtaskname span { :root.dark .gtaskname span {
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
:root.dark .gtasklist, :root.dark .gtasklist,
:root.dark .gadditional { :root.dark .gadditional {
border: var(--border-color) 1px solid; border: var(--border-color) 1px solid;
} }
:root.dark .gchartgrid { :root.dark .gchartgrid {
background-color: var(--bg-color); background-color: var(--bg-color);
} }
:root.dark .glistgrid, :root.dark .glistgrid,
:root.dark .glistlbl { :root.dark .glistlbl {
background-color: var(--bg-color); background-color: var(--bg-color);
border-color: var(--border-color); border-color: var(--border-color);
} }
/* Dark mode scrollbar */ /* Dark mode scrollbar */
:root.dark .frame::-webkit-scrollbar-thumb, :root.dark .frame::-webkit-scrollbar-thumb,
:root.dark .frame::-webkit-scrollbar-track { :root.dark .frame::-webkit-scrollbar-track {
background-color: var(--bg-color); background-color: var(--bg-color);
} }
/* Highlight row */ /* Highlight row */
:root.dark .gitemhighlight td { :root.dark .gitemhighlight td {
background-color: var(--highlight-color); background-color: var(--highlight-color);
color: var(--nav-link-color); color: var(--nav-link-color);
} }
/* Differentiate Group, Milestone and Ordinary task items (applied to row) */ /* Differentiate Group, Milestone and Ordinary task items (applied to row) */
:root.dark .ggroupitem { :root.dark .ggroupitem {
background-color: var(--bg-color); background-color: var(--bg-color);
font-weight: bold; font-weight: bold;
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.dark .gmileitem, :root.dark .gmileitem,
:root.dark .glineitem { :root.dark .glineitem {
background-color: var(--bg-color); background-color: var(--bg-color);
} }
/* Task bar caption text styles */ /* Task bar caption text styles */
:root.dark .gmilecaption, :root.dark .gmilecaption,
:root.dark .ggroupcaption, :root.dark .ggroupcaption,
:root.dark .gcaption { :root.dark .gcaption {
color: var(--nav-link-color); color: var(--nav-link-color);
} }
/* Task complete %age bar */ /* Task complete %age bar */
:root.dark .gtaskcomplete { :root.dark .gtaskcomplete {
background-color: var(--task-complete-bg-color); background-color: var(--task-complete-bg-color);
} }
/* Milestones */ /* Milestones */
:root.dark .gmdtop, :root.dark .gmdtop,
:root.dark .gmdbottom { :root.dark .gmdbottom {
border-bottom: 5px solid var(--milestone-border-color); border-bottom: 5px solid var(--milestone-border-color);
} }
:root.dark .gfoldercollapse { :root.dark .gfoldercollapse {
color: var(--secondary-text-color); color: var(--secondary-text-color);
cursor: pointer; cursor: pointer;
font-weight: bold; font-weight: bold;
font-size: var(--folder-collapse-font-size); font-size: var(--folder-collapse-font-size);
font-family: var(--folder-collapse-font-family); font-family: var(--folder-collapse-font-family);
} }
/* Highlight for collapsible row */ /* Highlight for collapsible row */
:root.dark .gname.ggroupitem { :root.dark .gname.ggroupitem {
background-color: var(--group-item-bg-color); background-color: var(--group-item-bg-color);
} }
/* Form label and selected highlighting */ /* Form label and selected highlighting */
:root.dark .gformlabel { :root.dark .gformlabel {
background-color: var(--formlabel-bg-color); background-color: var(--formlabel-bg-color);
color: var(--secondary-text-color); color: var(--secondary-text-color);
border: var(--formlabel-border-color) 1px solid; border: var(--formlabel-border-color) 1px solid;
} }
:root.dark span.gformlabel:hover { :root.dark span.gformlabel:hover {
background-color: var(--hover-bg-color); background-color: var(--hover-bg-color);
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.dark span.gselected { :root.dark span.gselected {
background-color: var(--formlabel-selected-bg-color); background-color: var(--formlabel-selected-bg-color);
border-color: var(--task-complete-bg-color); border-color: var(--task-complete-bg-color);
color: var(--nav-link-color); color: var(--nav-link-color);
} }
:root.dark .gantt-inputtable { :root.dark .gantt-inputtable {
background-color: var(--input-bg-color); background-color: var(--input-bg-color);
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--input-border-color); border: 1px solid var(--input-border-color);
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
/* ------------------- for blender generated theme ------------------- */ /* ------------------- for blender generated theme ------------------- */
:root.blender div.gantt, :root.blender div.gantt,
:root.blender .gantt table, :root.blender .gantt table,
:root.blender .gantt td { :root.blender .gantt td {
color: var(--blender-text); color: var(--blender-text);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
:root.blender .gchartgrid, :root.blender .gchartgrid,
@@ -443,11 +320,10 @@ button:hover {
:root.blender .gchartlbl.gcontainercol, :root.blender .gchartlbl.gcontainercol,
:root.blender .gminorheading, :root.blender .gminorheading,
:root.blender .gtaskcell { :root.blender .gtaskcell {
background-color: var(--blender-odd-row); background-color: var(--blender-odd-row);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
/* Headings and cell defaults */ /* Headings and cell defaults */
:root.blender .gtaskheading, :root.blender .gtaskheading,
:root.blender .gchartlbl.gcontainercol .gmajorheading, :root.blender .gchartlbl.gcontainercol .gmajorheading,
@@ -460,13 +336,13 @@ button:hover {
:root.blender .gchartlbl.gcontainercol .ggroupitem, :root.blender .gchartlbl.gcontainercol .ggroupitem,
:root.blender .glistlbl.gcontainercol .gtaskname, :root.blender .glistlbl.gcontainercol .gtaskname,
:root.blender .glistlbl.gcontainercol .gtasklist { :root.blender .glistlbl.gcontainercol .gtasklist {
background-color: var(--blender-panel-header); background-color: var(--blender-panel-header);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
:root.blender .gtaskcellcurrent { :root.blender .gtaskcellcurrent {
background-color: var(--blender-odd-row); background-color: var(--blender-odd-row);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
:root.blender .gtaskheading, :root.blender .gtaskheading,
@@ -482,103 +358,102 @@ button:hover {
:root.blender .gchartlbl, :root.blender .gchartlbl,
:root.blender .gcontainercol, :root.blender .gcontainercol,
:root.blender .genddate { :root.blender .genddate {
color: var(--blender-text); color: var(--blender-text);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
:root.blender .gtaskname>div, :root.blender .gtaskname > div,
:root.blender .gtaskname div, :root.blender .gtaskname div,
:root.blender .gtaskheading div, :root.blender .gtaskheading div,
:root.blender .gtaskname span { :root.blender .gtaskname span {
color: var(--blender-text); color: var(--blender-text);
} }
:root.blender .gantt-chart tr:not(.gname.glineitem):not(.gname.ggroupitem) { :root.blender .gantt-chart tr:not(.gname.glineitem):not(.gname.ggroupitem) {
background-color: var(--blender-odd-row); background-color: var(--blender-odd-row);
} }
:root.blender .gtasklist, :root.blender .gtasklist,
:root.blender .gadditional { :root.blender .gadditional {
border: var(--blender-tab-outline) 1px solid; border: var(--blender-tab-outline) 1px solid;
} }
:root.blender .glistgrid, :root.blender .glistgrid,
:root.blender .glistlbl { :root.blender .glistlbl {
/* This is a border that needs background color, somehow. */ /* This is a border that needs background color, somehow. */
background-color: var(--blender-tab-outline); background-color: var(--blender-tab-outline);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
/* Highlight row */ /* Highlight row */
:root.blender .gitemhighlight td, :root.blender .gitemhighlight td,
:root.blender .gitemhighlight .gantt-inputtable, :root.blender .gitemhighlight .gantt-inputtable,
:root.blender .gitemhighlight .gcaption, :root.blender .gitemhighlight .gcaption,
:root.blender .gitemhighlight .ggroupcaption { :root.blender .gitemhighlight .ggroupcaption {
background-color: var(--blender-active-highlight) !important; background-color: var(--blender-active-highlight) !important;
color: var(--blender-active-text-highlight) !important; color: var(--blender-active-text-highlight) !important;
} }
/* Differentiate Group, Milestone and Ordinary task items (applied to row) */ /* Differentiate Group, Milestone and Ordinary task items (applied to row) */
:root.blender .ggroupitem { :root.blender .ggroupitem {
font-weight: bold; font-weight: bold;
border-color: var(--border-color); border-color: var(--border-color);
} }
:root.blender .gmileitem, :root.blender .gmileitem,
:root.blender .glineitem { :root.blender .glineitem {
background-color: var(--blender-odd-row); background-color: var(--blender-odd-row);
} }
/* Task bar caption text styles */ /* Task bar caption text styles */
:root.blender .gmilecaption, :root.blender .gmilecaption,
:root.blender .ggroupcaption, :root.blender .ggroupcaption,
:root.blender .gcaption { :root.blender .gcaption {
color: var(--blender-text); color: var(--blender-text);
} }
/* Milestones */ /* Milestones */
:root.blender .gmdtop, :root.blender .gmdtop,
:root.blender .gmdbottom { :root.blender .gmdbottom {
border-bottom: 5px solid var(--blender-tab-outline); border-bottom: 5px solid var(--blender-tab-outline);
} }
:root.blender .gfoldercollapse { :root.blender .gfoldercollapse {
color: var(--blender-text); color: var(--blender-text);
cursor: pointer; cursor: pointer;
font-weight: bold; font-weight: bold;
font-size: var(--folder-collapse-font-size); font-size: var(--folder-collapse-font-size);
font-family: var(--folder-collapse-font-family); font-family: var(--folder-collapse-font-family);
} }
/* Highlight for collapsible row */ /* Highlight for collapsible row */
:root.blender .gname.ggroupitem { :root.blender .gname.ggroupitem {
background-color: var(--blender-panel-background); background-color: var(--blender-panel-background);
} }
/* Form label and selected highlighting */ /* Form label and selected highlighting */
:root.blender .gformlabel { :root.blender .gformlabel {
background-color: var(--blender-panel-header); background-color: var(--blender-panel-header);
color: var(--blender-text); color: var(--blender-text);
border: var(--blender-tab-outline) 1px solid; border: var(--blender-tab-outline) 1px solid;
} }
:root.blender span.gformlabel:hover, :root.blender span.gformlabel:hover,
:root.blender span.gselected { :root.blender span.gselected {
background-color: var(--blender-active-highlight); background-color: var(--blender-active-highlight);
color: var(--blender-active-text-highlight); color: var(--blender-active-text-highlight);
border-color: var(--blender-tab-outline); border-color: var(--blender-tab-outline);
} }
:root.blender .gantt-inputtable { :root.blender .gantt-inputtable {
background-color: var(--blender-panel-header); background-color: var(--blender-panel-header);
box-sizing: border-box; box-sizing: border-box;
border: 2px solid var(--blender-button-border); border: 2px solid var(--blender-button-border);
color: var(--blender-text); color: var(--blender-text);
} }
/* Dark mode scrollbar */ /* Dark mode scrollbar */
:root.blender .frame::-webkit-scrollbar-thumb, :root.blender .frame::-webkit-scrollbar-thumb,
:root.blender .frame::-webkit-scrollbar-track { :root.blender .frame::-webkit-scrollbar-track {
background-color: var(--blender-window-background); background-color: var(--blender-window-background);
} }
@@ -1,214 +1,239 @@
:root { :root {
--font-family: Arial, sans-serif; --font-family: Arial, sans-serif;
--base-font-size: 16px; --base-font-size: 16px;
--margin-tiny: 0.125rem; --margin-tiny: 0.125rem;
--margin-small: 0.625rem; --margin-small: 0.625rem;
--margin-medium: 1.25rem; --margin-medium: 1.25rem;
--margin-large: 2.5rem; --margin-large: 2.5rem;
--padding-tiny: 0.125rem; --padding-tiny: 0.125rem;
--padding-small: 0.625rem; --padding-small: 0.625rem;
--padding-medium: 1rem; --padding-medium: 1rem;
--font-size-large: 1.2rem; --font-size-small: 1rem;
--logo-height: 1.5rem; --font-size-large: 1.2rem;
--nav-height: 0.625rem; --logo-height: 1.5rem;
--border-radius: 0.3rem; --nav-height: 0.625rem;
--border-radius: 0.3rem;
--folder-collapse-font-size: 0.75rem;
--folder-collapse-font-family: Courier, "Courier New", monospace;
--box-shadow: 0 0 0.7rem #5f5f5f66;
} }
:root.dark { :root.dark {
color-scheme: dark; color-scheme: dark;
--bg-color: #252525; --bg-color: #252525;
--text-color: #e0e0e0; --primary-text-color: #e0e0e0;
--nav-bg-color: #121212; --secondary-text-color: #c7c7c7;
--nav-border-color: #25682a; --nav-bg-color: #121212;
--nav-link-color: #fff; --nav-border-color: #25682a;
--nav-link-hover-color: #3fb449; --nav-link-color: #fff;
--warning-color: #FFDB8F; --nav-link-hover-color: #3fb449;
--border-color: #464444; --warning-color: #ffdb8f;
--border-color: #464444;
--hover-bg-color: #3a3a3a;
--highlight-color: #009136;
--task-complete-bg-color: #777777;
--milestone-border-color: #ffffff;
--group-item-bg-color: #4b4b4b;
--input-bg-color: #3b3b3b;
--input-border-color: #000;
--border-color: #464444;
} }
:root.light { :root.light {
color-scheme: light; color-scheme: light;
--bg-color: #ffffff; --bg-color: #ffffff;
--text-color: #000000; --primary-text-color: #000000;
--nav-bg-color: #f8f8f8; --nav-bg-color: #f8f8f8;
--nav-border-color: #cccccc; --nav-border-color: #cccccc;
--nav-link-color: #000000; --nav-link-color: #000000;
--nav-link-hover-color: #38a63d; --nav-link-hover-color: #38a63d;
--warning-color: #FF4500; --warning-color: #ff4500;
--border-color: #222; --border-color: #222;
} }
*:not(.tabulator-cell) { *:not(td, tr, td, .gmain) {
border-radius: var(--border-radius) !important; border-radius: var(--border-radius) !important;
} }
html { html {
font-size: var(--base-font-size); font-size: var(--base-font-size);
} }
body { body {
background-color: var(--blender-window-background, var(--bg-color)); background-color: var(--blender-window-background, var(--bg-color));
color: var(--blender-text, var(--text-color)); color: var(--blender-text, var(--primary-text-color));
margin: 0; margin: 0;
font-family: var(--font-family); font-family: var(--font-family);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
} }
#container { #container {
position: relative; flex: 1;
padding: var(--margin-small); padding: var(--margin-small);
flex: 1;
} }
h3 { h3 {
margin-top: 0; margin-top: 0;
} }
nav { nav {
background-color: var(--blender-top-bar-header, var(--nav-bg-color)); background-color: var(--blender-top-bar-header, var(--nav-bg-color));
height: var(--nav-height); height: var(--nav-height);
padding: var(--padding-medium) 0; padding: var(--padding-medium) 0;
display: flex; display: flex;
align-items: center; align-items: center;
position: relative; position: relative;
border-bottom: 2px solid var(--blender-tab-outline, var(--nav-border-color)); border-bottom: 2px solid var(--blender-tab-outline, var(--nav-border-color));
} }
nav .logo { nav .logo {
margin-left: var(--margin-large); margin-left: var(--margin-large);
height: var(--logo-height); height: var(--logo-height);
} }
nav ul { nav ul {
list-style-type: none; list-style-type: none;
margin: 0; margin: 0;
display: flex; display: flex;
flex: 1; flex: 1;
justify-content: center; justify-content: center;
} }
nav ul li { nav ul li {
margin-right: var(--margin-large); margin-right: var(--margin-large);
} }
nav ul li a { nav ul li a {
text-decoration: none; text-decoration: none;
color: var(--blender-text, var(--nav-link-color)); color: var(--blender-text, var(--nav-link-color));
} }
nav ul li a:hover, nav ul li a:hover,
nav ul li a.active { nav ul li a.active {
color: var(--blender-selected-object, var(--nav-link-hover-color)); color: var(--blender-selected-object, var(--nav-link-hover-color));
} }
.warning, .warning,
.warning-icon { .warning-icon {
color: var(--blender-info-warning, var(--warning-color)); color: var(--blender-info-warning, var(--warning-color));
}
#toggle-theme {
border: none;
background: none;
cursor: pointer;
font-size: var(--font-size-large);
margin-right: var(--margin-medium);
} }
#toggle-theme:focus { #toggle-theme:focus {
outline: none; outline: none;
} }
#client-list { #client-list {
position: absolute; position: absolute;
top: calc(0 + var(--nav-height)); top: calc(0 + var(--nav-height));
overflow-y: auto; overflow-y: auto;
overflow: hidden; overflow: hidden;
transition: opacity 0.3s ease-out, visibility 0.3s ease-out; transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
border: 1px solid var(--blender-tab-outline, var(--border-color)); border: 1px solid var(--blender-tab-outline, var(--border-color));
background-color: var(--blender-panel-background, var(--nav-bg-color)); background-color: var(--blender-panel-background, var(--nav-bg-color));
z-index: 1; z-index: 1;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
width: auto; width: auto;
} }
#client-list.show { #client-list.show {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
#connected-list-div { #connected-list-div {
display: inline-block; display: inline-block;
} }
.client { .client {
padding: var(--margin-small); padding: var(--margin-small);
border-bottom: 1px solid var(--blender-tab-outline, var(--border-color)); border-bottom: 1px solid var(--blender-tab-outline, var(--border-color));
cursor: pointer; cursor: pointer;
} }
.client-details { .client-details {
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
padding-left: var(--padding-small); padding-left: var(--padding-small);
transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out; transition: max-height 0.2s ease-out, padding 0.2s ease-out,
background-color: var(--blender-panel-background, var(--nav-bg-color)); opacity 0.1s ease-out;
margin-top: var(--margin-tiny); background-color: var(--blender-panel-background, var(--nav-bg-color));
opacity: 0; margin-top: var(--margin-tiny);
opacity: 0;
} }
.client-details.show { .client-details.show {
max-height: none; max-height: none;
opacity: 1; opacity: 1;
} }
.client-detail { .client-detail {
border-bottom: 1px solid var(--blender-tab-outline, var(--border-color)); border-bottom: 1px solid var(--blender-tab-outline, var(--border-color));
padding: var(--padding-small); padding: var(--padding-small);
} }
#show-connected-button { #show-connected-button {
width: auto; width: auto;
background-color: var(--blender-panel-header, var(--bg-color)); background-color: var(--blender-panel-header, var(--bg-color));
font-size: var(--base-font-size); font-size: var(--base-font-size);
color: var(--blender-text, var(--text-color)) color: var(--blender-text, var(--text-color));
} }
#show-connected-button:hover, #show-connected-button:hover,
.scroll-button:hover { .scroll-button:hover {
cursor: pointer; cursor: pointer;
} }
.scroll-button { .scroll-button {
font-size: var(--base-font-size); font-size: var(--base-font-size);
margin-left: var(--margin-tiny); margin-left: var(--margin-tiny);
margin-top: var(--margin-small); margin-top: var(--margin-small);
} }
footer { footer {
background-color: var(--blender-top-bar-header, var(--nav-bg-color)); background-color: var(--blender-top-bar-header, var(--nav-bg-color));
text-align: right; text-align: right;
padding: var(--padding-tiny); padding: var(--padding-tiny);
border-top: 1px solid var(--blender-tab-outline, var(--nav-border-color)); border-top: 1px solid var(--blender-tab-outline, var(--nav-border-color));
} }
footer p { footer p {
margin: 0; margin: 0;
color: var(--blender-text, var(--nav-link-color)); color: var(--blender-text, var(--nav-link-color));
margin-right: var(--margin-small); margin-right: var(--margin-small);
font-size: 0.8rem; font-size: 0.8rem;
} }
button, button,
select { select {
background-color: var(--blender-button-background, var(--bg-color)); background-color: var(--blender-button-background, var(--bg-color));
color: var(--blender-button-text, var(--text-color)); color: var(--blender-button-text, var(--text-color));
border-color: var(--blender-button-border, var(--border-color)); border-color: var(--blender-button-border, var(--border-color));
transition: filter 0.2s ease; transition: filter 0.2s ease;
} }
button:hover { button:hover {
filter: brightness(1.2); filter: brightness(1.2);
} }
.row-container {
width: 100%;
border-collapse: collapse;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.column-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
flex-wrap: wrap;
}
label {
margin-right: var(--margin-small);
margin-bottom: var(--margin-small);
}
@@ -1,8 +1,10 @@
import { CostUI } from './utilities/costui.js'; import { CostUI } from "./utilities/costui.js";
const connectedClients = {}; const connectedClients = {};
let socket; let socket;
let isScheduleLoad = {};
$(document).ready(function () { $(document).ready(function () {
var defaultTheme = "blender"; var defaultTheme = "blender";
var theme = localStorage.getItem("theme") || defaultTheme; var theme = localStorage.getItem("theme") || defaultTheme;
@@ -21,12 +23,28 @@ function connectSocket() {
socket.on("connected_clients", handleConnectedClients); socket.on("connected_clients", handleConnectedClients);
socket.on("theme_data", handleThemeData); socket.on("theme_data", handleThemeData);
socket.on("connect", handleWebConnect); socket.on("connect", handleWebConnect);
socket.on("predefined_types", handlePredefinedTypes);
socket.on("cost_schedules", handleCostSchedulesData); socket.on("cost_schedules", handleCostSchedulesData);
socket.on("cost_items", handleCostItemsData); socket.on("cost_items", handleCostItemsData);
socket.on("cost_values", handleCostValuesData); socket.on("cost_values", handleCostValuesData);
socket.on("cost_value", handleCostValueData); socket.on("cost_value", handleCostValueData);
} }
function handlePredefinedTypes(data) {
CostUI.enableAddingCostSchedule(
data.data["predefined_types"],
addCostSchedule
);
}
function addCostSchedule(name, predefinedType) {
executeOperator({
type: "addCostSchedule",
name: name,
predefinedType: predefinedType,
});
}
function handleBlenderConnect(blenderId) { function handleBlenderConnect(blenderId) {
if (!connectedClients.hasOwnProperty(blenderId)) { if (!connectedClients.hasOwnProperty(blenderId)) {
connectedClients[blenderId] = { shown: false, ifc_file: "" }; connectedClients[blenderId] = { shown: false, ifc_file: "" };
@@ -35,7 +53,6 @@ function handleBlenderConnect(blenderId) {
$("#blender-count").text(function (i, text) { $("#blender-count").text(function (i, text) {
return parseInt(text, 10) + 1; return parseInt(text, 10) + 1;
}); });
console.log("Blender connected", blenderId);
} }
function handleBlenderDisconnect(blenderId) { function handleBlenderDisconnect(blenderId) {
@@ -53,24 +70,24 @@ function removeTableElement(blenderId) {
$("#cost-items-" + blenderId).remove(); $("#cost-items-" + blenderId).remove();
} }
const costValueCallbacks = { const costValueCallbacks = {
'editCostValues': editCostValues, editCostValues: editCostValues,
'addCostValue': addCostValue, addCostValue: addCostValue,
'deleteCostValue': deleteCostValue, deleteCostValue: deleteCostValue,
}; };
function handleCostValueData(data) { function handleCostValueData(data) {
const costItemId = data.data["cost_value"]["cost_item_id"]; const costItemId = data.data["cost_value"]["cost_item_id"];
const costValueId = data.data["cost_value"]["cost_value_id"]; const costValueId = data.data["cost_value"]["cost_value_id"];
console.log("Handling cost value data", costItemId, costValueId);
CostUI.addNewCostValueRow(costItemId, costValueId, costValueCallbacks); CostUI.addNewCostValueRow(costItemId, costValueId, costValueCallbacks);
} }
function deleteCostValue(costItemId, costValueId) { function deleteCostValue(costItemId, costValueId) {
executeOperator({ type: "deleteCostValue", costItemId: costItemId, costValueId: costValueId }); executeOperator({
type: "deleteCostValue",
costItemId: costItemId,
costValueId: costValueId,
});
} }
function handleConnectedClients(data) { function handleConnectedClients(data) {
@@ -86,14 +103,13 @@ function handleCostValuesData(data) {
costValues: data.data["cost_values"]["cost_values"], costValues: data.data["cost_values"]["cost_values"],
costItemId: data.data["cost_values"]["cost_item_id"], costItemId: data.data["cost_values"]["cost_item_id"],
callbacks: { callbacks: {
'editCostValues': editCostValues, editCostValues: editCostValues,
'addCostValue': addCostValue, addCostValue: addCostValue,
'deleteCostValue': deleteCostValue, deleteCostValue: deleteCostValue,
}, },
}); });
CostUI.highlightCostItem(data.data["cost_values"]["cost_item_id"]); CostUI.highlightCostItem(data.data["cost_values"]["cost_item_id"]);
} }
function addCostValue(costItemId) { function addCostValue(costItemId) {
@@ -101,10 +117,10 @@ function addCostValue(costItemId) {
} }
function editCostValues(costItemId, costValues) { function editCostValues(costItemId, costValues) {
executeOperator({ executeOperator({
type: "editCostValues", type: "editCostValues",
costItemId: costItemId, costItemId: costItemId,
costValues: costValues costValues: costValues,
}); });
} }
@@ -159,7 +175,11 @@ function addCostItem(costItemId) {
} }
function editCostItemName(costItemId, name) { function editCostItemName(costItemId, name) {
executeOperator({ type: "editCostItemName", costItemId: costItemId, name: name }); executeOperator({
type: "editCostItemName",
costItemId: costItemId,
name: name,
});
} }
function selectAssignedElements(costItemId) { function selectAssignedElements(costItemId) {
@@ -167,44 +187,52 @@ function selectAssignedElements(costItemId) {
} }
function handleWebConnect() { function handleWebConnect() {
executeOperator({ type: "getPredefinedTypes" });
getCostSchedules(); getCostSchedules();
} }
function addSummaryCostItem(costScheduleId) {
executeOperator({
type: "addSummaryCostItem",
costScheduleId: costScheduleId,
});
}
function handleCostSchedulesData(data) { function handleCostSchedulesData(data) {
const blenderId = data.blenderId; const blenderId = data.blenderId;
const costSchedules = data.data["cost_schedules"]["cost_schedules"]; const costSchedules = data.data["cost_schedules"]["cost_schedules"];
const currency = data.data["cost_schedules"]["currency"]["name"]; if (costSchedules.length === 0) {
const costScheduleDiv = $("#cost-schedules"); return;
}
const currency = data.data["cost_schedules"]["currency"]
? data.data["cost_schedules"]["currency"]["name"]
: "Undefined";
const costScheduleDiv = document.getElementById("cost-schedules");
costScheduleDiv.innerHTML = "";
costSchedules.forEach((costSchedule) => { costSchedules.forEach((costSchedule) => {
costSchedule.UpdateDate = new Date(costSchedule.UpdateDate); costSchedule.UpdateDate = new Date(costSchedule.UpdateDate);
const mainContainer = CostUI.text("Updated On: " + costSchedule.UpdateDate); const mainContainer = CostUI.text("Updated On: " + costSchedule.UpdateDate);
const callback = () => loadCostSchedule(costSchedule.id, blenderId); const callback = () => loadCostSchedule(costSchedule.id, blenderId);
const card = CostUI.createCard(costSchedule.Name, mainContainer, callback); const card = CostUI.createCard(costSchedule.Name, mainContainer, callback);
costScheduleDiv.append(card); costScheduleDiv.append(card);
}); });
const firstCostSchedule = costSchedules[0];
if (firstCostSchedule) {
loadCostSchedule(firstCostSchedule.id, blenderId);
}
} }
function handleCostItemsData(data) { function handleCostItemsData(data) {
console.log("Handling cost items data", data);
CostUI.createCostSchedule({ CostUI.createCostSchedule({
data: data.data["cost_items"], data: data.data["cost_items"]["cost_items"],
costScheduleId: data.data["cost_items"]["cost_schedule_id"],
blenderID: data.blenderId, blenderID: data.blenderId,
callbacks: { callbacks: {
"addCostItem": addCostItem, addCostItem: addCostItem,
"deleteCostItem": deleteCostItem, deleteCostItem: deleteCostItem,
"duplicateCostItem": duplicateCostItem, duplicateCostItem: duplicateCostItem,
"selectAssignedElements": selectAssignedElements, selectAssignedElements: selectAssignedElements,
'editCostItemName': editCostItemName, editCostItemName: editCostItemName,
'enableEditingCostValues': enableEditingCostValues, enableEditingCostValues: enableEditingCostValues,
} addSummaryCostItem: addSummaryCostItem,
},
}); });
} }
@@ -224,7 +252,10 @@ function executeOperator(operator, blenderId) {
} }
function loadCostSchedule(costScheduleId, blenderId) { function loadCostSchedule(costScheduleId, blenderId) {
executeOperator({ type: "loadCostSchedule", costScheduleId: costScheduleId }, blenderId); executeOperator(
{ type: "loadCostSchedule", costScheduleId: costScheduleId },
blenderId
);
} }
function getCostSchedules(blenderId) { function getCostSchedules(blenderId) {
@@ -232,5 +263,5 @@ function getCostSchedules(blenderId) {
} }
function enableEditingCostValues(costItemId) { function enableEditingCostValues(costItemId) {
executeOperator({ type: "enableEditingCostValues", costItemId: costItemId}); executeOperator({ type: "enableEditingCostValues", costItemId: costItemId });
} }
File diff suppressed because it is too large Load Diff
@@ -84,8 +84,14 @@
</button> </button>
<div id="client-list"></div> <div id="client-list"></div>
</div> </div>
<div id="cost-schedules"></div> <h1>Costing</h1>
<div id="UI"></div> <div id="" >
<li id="add-cost-schedule" class="action-button fas fa-plus"> </li>
Add New Schedule
</div>
<div id="cost-schedules" class="row-container"></div>
<div id="UI" class="row-container"></div>
<div id="cost-items"></div> <div id="cost-items"></div>
<footer> <footer>
@@ -81,8 +81,8 @@
</button> </button>
<div id="client-list" class="no-print"></div> <div id="client-list" class="no-print"></div>
</div> </div>
<div id="work_schedules"></div> <div id="work_schedules" class="row-container"></div>
<div id="container"></div> <div id="container" ></div>
<footer> <footer>
<p>Bonsai Version: {{version}}</p> <p>Bonsai Version: {{version}}</p>
</footer> </footer>
+3 -13
View File
@@ -279,19 +279,9 @@ class CostSchedulesData:
@classmethod @classmethod
def get_cost_schedule_types(cls): def get_cost_schedule_types(cls):
results = [] types = ifcopenshell.util.cost.get_cost_schedule_types(tool.Ifc.get())
declaration = tool.Ifc().schema().declaration_by_name("IfcCostSchedule") return [(t['name'], t['name'], t['description']) for t in types]
version = tool.Ifc.get_schema()
for attribute in declaration.attributes():
if attribute.name() == "PredefinedType":
results.extend(
[
(e, e, get_predefined_type_doc(version, "IfcCostSchedule", e))
for e in attribute.type_of_attribute().declared_type().enumeration_items()
]
)
break
return results
class CostItemRatesData: class CostItemRatesData:
+33 -2
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell.util.cost
import bpy import bpy
from bonsai.bim.module.web.data import WebData from bonsai.bim.module.web.data import WebData
import bonsai.core.tool import bonsai.core.tool
@@ -341,9 +342,26 @@ class Web(bonsai.core.tool.Web):
Args: Args:
operator_data (dict): A dictionary containing the operator data. operator_data (dict): A dictionary containing the operator data.
""" """
print("Handling cost operator")
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
if operator_data["type"] == "getPredefinedTypes":
print('getting predefined types')
predefined_types = ifcopenshell.util.cost.get_cost_schedule_types(ifc_file)
cls.send_webui_data(data=predefined_types, data_key="predefined_types", event="predefined_types")
if operator_data["type"] == "addCostSchedule":
bonsai.core.cost.add_cost_schedule(
tool.Ifc,
name=operator_data["name"],
predefined_type=operator_data["type"]
)
cost_schedules = ifc_file.by_type("IfcCostSchedule")
cost_schedules_json = [cs.get_info(recursive=True) for cs in cost_schedules]
currency = tool.Cost.currency()
cls.send_webui_data(data={
"cost_schedules": cost_schedules_json,
"currency": currency
}, data_key="cost_schedules", event="cost_schedules")
if operator_data["type"] == "getCostSchedules": if operator_data["type"] == "getCostSchedules":
print('getting cost schedules')
cost_schedules = ifc_file.by_type("IfcCostSchedule") cost_schedules = ifc_file.by_type("IfcCostSchedule")
cost_schedules_json = [cs.get_info(recursive=True) for cs in cost_schedules] cost_schedules_json = [cs.get_info(recursive=True) for cs in cost_schedules]
currency = tool.Cost.currency() currency = tool.Cost.currency()
@@ -353,13 +371,23 @@ class Web(bonsai.core.tool.Web):
event="cost_schedules", event="cost_schedules",
) )
if operator_data["type"] == "loadCostSchedule": if operator_data["type"] == "loadCostSchedule":
print('loading cost schedule')
cost_schedule = ifc_file.by_id(operator_data["costScheduleId"]) cost_schedule = ifc_file.by_id(operator_data["costScheduleId"])
bonsai.core.cost.enable_editing_cost_items(tool.Cost, cost_schedule=cost_schedule) bonsai.core.cost.enable_editing_cost_items(tool.Cost, cost_schedule=cost_schedule)
cls.load_cost_schedule_web_ui(cost_schedule) cls.load_cost_schedule_web_ui(cost_schedule)
if operator_data["type"] == "selectAssignedElements": if operator_data["type"] == "selectAssignedElements":
print('selecting assigned elements')
cost_item = tool.Ifc.get().by_id(operator_data["costItemId"]) cost_item = tool.Ifc.get().by_id(operator_data["costItemId"])
products = tool.Cost.get_cost_item_products(cost_item, is_deep=True) products = tool.Cost.get_cost_item_products(cost_item, is_deep=True)
tool.Spatial.select_products(products, unhide=True) tool.Spatial.select_products(products, unhide=True)
if operator_data["type"] == "addSummaryCostItem":
cost_schedule=ifc_file.by_id(operator_data["costScheduleId"])
bonsai.core.cost.add_summary_cost_item(
tool.Ifc,
tool.Cost,
cost_schedule=cost_schedule
)
cls.load_cost_schedule_web_ui(cost_schedule)
if operator_data["type"] == "addCostItem": if operator_data["type"] == "addCostItem":
bpy.ops.bim.add_cost_item(cost_item=operator_data["costItemId"]) bpy.ops.bim.add_cost_item(cost_item=operator_data["costItemId"])
cost_schedule = tool.Cost.get_cost_schedule(cost_item=tool.Ifc.get().by_id(operator_data["costItemId"])) cost_schedule = tool.Cost.get_cost_schedule(cost_item=tool.Ifc.get().by_id(operator_data["costItemId"]))
@@ -424,7 +452,10 @@ class Web(bonsai.core.tool.Web):
@classmethod @classmethod
def load_cost_schedule_web_ui(cls, cost_schedule): def load_cost_schedule_web_ui(cls, cost_schedule):
json_data = tool.Cost.create_cost_schedule_json(cost_schedule) json_data = tool.Cost.create_cost_schedule_json(cost_schedule)
cls.send_webui_data(data=json_data, data_key="cost_items", event="cost_items") cls.send_webui_data(data={
"cost_items": json_data,
"cost_schedule_id": cost_schedule.id()
}, data_key="cost_items", event="cost_items")
@classmethod @classmethod
def handle_gantt_operator(cls, operator_data: dict) -> None: def handle_gantt_operator(cls, operator_data: dict) -> None:
@@ -19,7 +19,8 @@
import lark import lark
import ifcopenshell import ifcopenshell
from typing import Optional, Union, Literal, Generator, Any from typing import Optional, Union, Literal, Generator, Any
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
from ifcopenshell.util.doc import get_predefined_type_doc
arithmetic_operator_symbols = {"ADD": "+", "DIVIDE": "/", "MULTIPLY": "*", "SUBTRACT": "-"} arithmetic_operator_symbols = {"ADD": "+", "DIVIDE": "/", "MULTIPLY": "*", "SUBTRACT": "-"}
symbol_arithmetic_operators = {"+": "ADD", "/": "DIVIDE", "*": "MULTIPLY", "-": "SUBTRACT"} symbol_arithmetic_operators = {"+": "ADD", "/": "DIVIDE", "*": "MULTIPLY", "-": "SUBTRACT"}
@@ -265,6 +266,20 @@ def get_cost_values(cost_item: ifcopenshell.entity_instance) -> list[dict[str, s
print(results) print(results)
return results return results
def get_cost_schedule_types(file):
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(file.schema)
results = []
declaration = schema.declaration_by_name("IfcCostSchedule")
version = file.schema_identifier
for attribute in declaration.attributes():
if attribute.name() == "PredefinedType":
for enumeration in attribute.type_of_attribute().declared_type().enumeration_items():
results.append({
"name": enumeration,
'description': get_predefined_type_doc(version, "IfcCostSchedule",enumeration),
})
break
return results
class CostValueUnserialiser: class CostValueUnserialiser:
def parse(self, formula: str): def parse(self, formula: str):