mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
- 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:
@@ -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,127 +1,5 @@
|
|||||||
@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);
|
||||||
@@ -194,7 +72,8 @@ nav ul li a.active {
|
|||||||
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,
|
||||||
|
opacity 0.1s ease-out;
|
||||||
background-color: var(--blender-panel-background, var(--nav-bg-color));
|
background-color: var(--blender-panel-background, var(--nav-bg-color));
|
||||||
margin-top: var(--margin-tiny);
|
margin-top: var(--margin-tiny);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -259,7 +138,6 @@ footer p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
button,
|
button,
|
||||||
select {
|
select {
|
||||||
background-color: var(--blender-button-background, var(--bg-color));
|
background-color: var(--blender-button-background, var(--bg-color));
|
||||||
@@ -316,7 +194,7 @@ button:hover {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +307,6 @@ button:hover {
|
|||||||
|
|
||||||
/* ------------------- 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 {
|
||||||
@@ -447,7 +324,6 @@ button:hover {
|
|||||||
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,
|
||||||
@@ -486,7 +362,7 @@ button:hover {
|
|||||||
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 {
|
||||||
@@ -509,7 +385,6 @@ button:hover {
|
|||||||
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,
|
||||||
|
|||||||
@@ -8,37 +8,50 @@
|
|||||||
--padding-tiny: 0.125rem;
|
--padding-tiny: 0.125rem;
|
||||||
--padding-small: 0.625rem;
|
--padding-small: 0.625rem;
|
||||||
--padding-medium: 1rem;
|
--padding-medium: 1rem;
|
||||||
|
--font-size-small: 1rem;
|
||||||
--font-size-large: 1.2rem;
|
--font-size-large: 1.2rem;
|
||||||
--logo-height: 1.5rem;
|
--logo-height: 1.5rem;
|
||||||
--nav-height: 0.625rem;
|
--nav-height: 0.625rem;
|
||||||
--border-radius: 0.3rem;
|
--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;
|
||||||
|
--secondary-text-color: #c7c7c7;
|
||||||
--nav-bg-color: #121212;
|
--nav-bg-color: #121212;
|
||||||
--nav-border-color: #25682a;
|
--nav-border-color: #25682a;
|
||||||
--nav-link-color: #fff;
|
--nav-link-color: #fff;
|
||||||
--nav-link-hover-color: #3fb449;
|
--nav-link-hover-color: #3fb449;
|
||||||
--warning-color: #FFDB8F;
|
--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;
|
--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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +61,7 @@ html {
|
|||||||
|
|
||||||
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;
|
||||||
@@ -57,9 +70,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
position: relative;
|
|
||||||
padding: var(--margin-small);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
padding: var(--margin-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
@@ -108,14 +120,6 @@ nav ul li a.active {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -153,7 +157,8 @@ nav ul li a.active {
|
|||||||
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,
|
||||||
|
opacity 0.1s ease-out;
|
||||||
background-color: var(--blender-panel-background, var(--nav-bg-color));
|
background-color: var(--blender-panel-background, var(--nav-bg-color));
|
||||||
margin-top: var(--margin-tiny);
|
margin-top: var(--margin-tiny);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -173,7 +178,7 @@ nav ul li a.active {
|
|||||||
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,
|
||||||
@@ -212,3 +217,23 @@ select {
|
|||||||
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) {
|
||||||
@@ -104,7 +120,7 @@ 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 });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export class CostUI {
|
|||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
static isCostScheduleLoaded(id) {
|
static isCostScheduleLoaded(id) {
|
||||||
const existingTable = document.getElementById('cost-items-' + id);
|
const existingTable = document.getElementById("cost-items-" + id);
|
||||||
return existingTable !== null;
|
return existingTable !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,11 +13,18 @@ export class CostUI {
|
|||||||
CostUI.isCostScheduleLoaded(id) ? CostUI.removeCostSchedule(id) : null;
|
CostUI.isCostScheduleLoaded(id) ? CostUI.removeCostSchedule(id) : null;
|
||||||
|
|
||||||
const table = document.createElement("table");
|
const table = document.createElement("table");
|
||||||
table.id = 'cost-items-' + id;
|
table.id = "cost-items-" + id;
|
||||||
const tbody = document.createElement("tbody");
|
const tbody = document.createElement("tbody");
|
||||||
tbody.setAttribute("id", "cost-items");
|
tbody.setAttribute("id", "cost-items");
|
||||||
|
|
||||||
const columnHeaders = ["Name", "Quantity", "Unit", "Cost", "Total Cost", "Action"];
|
const columnHeaders = [
|
||||||
|
"Name",
|
||||||
|
"Quantity",
|
||||||
|
"Unit",
|
||||||
|
"Cost",
|
||||||
|
"Total Cost",
|
||||||
|
"Action",
|
||||||
|
];
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
|
|
||||||
for (let i = 0; i < columnHeaders.length; i++) {
|
for (let i = 0; i < columnHeaders.length; i++) {
|
||||||
@@ -40,7 +47,7 @@ export class CostUI {
|
|||||||
|
|
||||||
CostUI.addTableStyles(id);
|
CostUI.addTableStyles(id);
|
||||||
CostUI.createContextMenu(callbacks);
|
CostUI.createContextMenu(callbacks);
|
||||||
table.get_blender_id = function() {
|
table.get_blender_id = function () {
|
||||||
return this.getAttribute("id").split("-")[2];
|
return this.getAttribute("id").split("-")[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,8 +69,7 @@ export class CostUI {
|
|||||||
`;
|
`;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
}
|
}
|
||||||
|
static createContextMenu(callbacks) {
|
||||||
static createContextMenu(callbacks) {
|
|
||||||
const contextMenu = document.createElement("div");
|
const contextMenu = document.createElement("div");
|
||||||
contextMenu.id = "context-menu";
|
contextMenu.id = "context-menu";
|
||||||
contextMenu.classList.add("context-menu");
|
contextMenu.classList.add("context-menu");
|
||||||
@@ -71,11 +77,11 @@ export class CostUI {
|
|||||||
<button id="edit-cost-values-button">Edit Cost Values</button>
|
<button id="edit-cost-values-button">Edit Cost Values</button>
|
||||||
<button id="add-cost-item-button">Add sub-cost</button>
|
<button id="add-cost-item-button">Add sub-cost</button>
|
||||||
<button id="duplicate-button">Duplicate</button>
|
<button id="duplicate-button">Duplicate</button>
|
||||||
<button id="delete-button">Delete</button>
|
<button id="delete-cost-item">Delete</button>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(contextMenu);
|
document.body.appendChild(contextMenu);
|
||||||
|
|
||||||
document.addEventListener("contextmenu", function(event) {
|
document.addEventListener("contextmenu", function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const targetRow = event.target.closest("tr");
|
const targetRow = event.target.closest("tr");
|
||||||
const targetCell = event.target.closest("td");
|
const targetCell = event.target.closest("td");
|
||||||
@@ -92,21 +98,26 @@ export class CostUI {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("click", function(event) {
|
document.addEventListener("click", function (event) {
|
||||||
const contextMenu = document.getElementById("context-menu");
|
const contextMenu = document.getElementById("context-menu");
|
||||||
if (!contextMenu.contains(event.target)) {
|
if (!contextMenu.contains(event.target)) {
|
||||||
contextMenu.style.display = "none";
|
contextMenu.style.display = "none";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const editCostValuesButton = document.getElementById("edit-cost-values-button");
|
const editCostValuesButton = document.getElementById(
|
||||||
editCostValuesButton.addEventListener("click", function() {
|
"edit-cost-values-button"
|
||||||
|
);
|
||||||
|
editCostValuesButton.addEventListener("click", function () {
|
||||||
const targetRow = document.getElementById("context-menu").targetRow;
|
const targetRow = document.getElementById("context-menu").targetRow;
|
||||||
const targetCell = document.getElementById("context-menu").targetCell;
|
const targetCell = document.getElementById("context-menu").targetCell;
|
||||||
if (targetRow) {
|
if (targetRow) {
|
||||||
const costItemId = parseInt(targetRow.getAttribute("id"));
|
const costItemId = parseInt(targetRow.getAttribute("id"));
|
||||||
callbacks.enableEditingCostValues ? callbacks.enableEditingCostValues(costItemId) : null;
|
callbacks.enableEditingCostValues
|
||||||
|
? callbacks.enableEditingCostValues(costItemId)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
document.getElementById("context-menu").style.display = "none";
|
||||||
});
|
});
|
||||||
|
|
||||||
const addButton = document.getElementById("add-cost-item-button");
|
const addButton = document.getElementById("add-cost-item-button");
|
||||||
@@ -124,51 +135,54 @@ export class CostUI {
|
|||||||
addButton.dataset.listenerAdded = "true";
|
addButton.dataset.listenerAdded = "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteButton = document.getElementById("delete-button");
|
const deleteCostItem = document.getElementById("delete-cost-item");
|
||||||
if (deleteButton && !deleteButton.hasListener) {
|
if (deleteCostItem && !deleteCostItem.hasListener) {
|
||||||
deleteButton.addEventListener("click", function() {
|
deleteCostItem.addEventListener("click", function () {
|
||||||
const targetRow = document.getElementById("context-menu").targetRow;
|
const targetRow = document.getElementById("context-menu").targetRow;
|
||||||
if (targetRow) {
|
if (targetRow) {
|
||||||
const costItemId = parseInt(targetRow.getAttribute("id"));
|
const costItemId = parseInt(targetRow.getAttribute("id"));
|
||||||
let expandedState = JSON.parse(localStorage.getItem('expandedState')) || {};
|
let expandedState =
|
||||||
expandedState = CostUI.deleteRow(targetRow, expandedState)
|
JSON.parse(localStorage.getItem("expandedState")) || {};
|
||||||
localStorage.setItem('expandedState', JSON.stringify(expandedState));
|
expandedState = CostUI.deleteRow(targetRow, expandedState);
|
||||||
|
localStorage.setItem("expandedState", JSON.stringify(expandedState));
|
||||||
callbacks.deleteCostItem(costItemId);
|
callbacks.deleteCostItem(costItemId);
|
||||||
}
|
}
|
||||||
|
document.getElementById("context-menu").style.display = "none";
|
||||||
});
|
});
|
||||||
deleteButton.hasListener = true;
|
deleteCostItem.hasListener = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const duplicateButton = document.getElementById("duplicate-button");
|
const duplicateButton = document.getElementById("duplicate-button");
|
||||||
if (duplicateButton && !duplicateButton.hasListener) {
|
if (duplicateButton && !duplicateButton.hasListener) {
|
||||||
duplicateButton.addEventListener("click", function() {
|
duplicateButton.addEventListener("click", function () {
|
||||||
const targetRow = document.getElementById("context-menu").targetRow;
|
const targetRow = document.getElementById("context-menu").targetRow;
|
||||||
if (targetRow) {
|
if (targetRow) {
|
||||||
const costItemId = parseInt(targetRow.getAttribute("id"));
|
const costItemId = parseInt(targetRow.getAttribute("id"));
|
||||||
callbacks.duplicateCostItem(costItemId);
|
callbacks.duplicateCostItem(costItemId);
|
||||||
}
|
}
|
||||||
|
document.getElementById("context-menu").style.display = "none";
|
||||||
});
|
});
|
||||||
duplicateButton.hasListener = true;
|
duplicateButton.hasListener = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static deleteRow(targetRow, expandedState) {
|
static deleteRow(targetRow, expandedState) {
|
||||||
if (!targetRow) {
|
if (!targetRow) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
delete expandedState[targetRow.id]
|
delete expandedState[targetRow.id];
|
||||||
targetRow.remove()
|
targetRow.remove();
|
||||||
const subRows = document.querySelectorAll(`[parent-id='${targetRow.id}']`);
|
const subRows = document.querySelectorAll(`[parent-id='${targetRow.id}']`);
|
||||||
subRows.forEach(subRow => {
|
subRows.forEach((subRow) => {
|
||||||
CostUI.deleteRow(subRow, expandedState)
|
CostUI.deleteRow(subRow, expandedState);
|
||||||
});
|
});
|
||||||
return expandedState
|
return expandedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
static addResizer(resizer) {
|
static addResizer(resizer) {
|
||||||
let startX, startWidth, th;
|
let startX, startWidth, th;
|
||||||
|
|
||||||
resizer.addEventListener("mousedown", function(e) {
|
resizer.addEventListener("mousedown", function (e) {
|
||||||
th = e.target.parentElement;
|
th = e.target.parentElement;
|
||||||
startX = e.pageX;
|
startX = e.pageX;
|
||||||
startWidth = th.offsetWidth;
|
startWidth = th.offsetWidth;
|
||||||
@@ -200,9 +214,17 @@ export class CostUI {
|
|||||||
const num = parseInt(color.slice(1), 16),
|
const num = parseInt(color.slice(1), 16),
|
||||||
amt = Math.round(2.55 * percent),
|
amt = Math.round(2.55 * percent),
|
||||||
R = (num >> 16) + amt,
|
R = (num >> 16) + amt,
|
||||||
G = (num >> 8 & 0x00FF) + amt,
|
G = ((num >> 8) & 0x00ff) + amt,
|
||||||
B = (num & 0x0000FF) + amt;
|
B = (num & 0x0000ff) + amt;
|
||||||
return `#${(0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1).toUpperCase()}`;
|
return `#${(
|
||||||
|
0x1000000 +
|
||||||
|
(R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
|
||||||
|
(G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
|
||||||
|
(B < 255 ? (B < 1 ? 0 : B) : 255)
|
||||||
|
)
|
||||||
|
.toString(16)
|
||||||
|
.slice(1)
|
||||||
|
.toUpperCase()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static applyColorScheme(tableId, colorScheme) {
|
static applyColorScheme(tableId, colorScheme) {
|
||||||
@@ -213,18 +235,81 @@ export class CostUI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enableAddingCostSchedule(types, addCostSchedule) {
|
||||||
|
const addNewSchedule = document.getElementById("add-cost-schedule");
|
||||||
|
|
||||||
|
addNewSchedule.addEventListener("click", function () {
|
||||||
|
const name = "Add New Cost Schedule";
|
||||||
|
|
||||||
|
const form = CostUI.Form({
|
||||||
|
id: "add-cost-schedule-form",
|
||||||
|
name: name,
|
||||||
|
className: "floating-form",
|
||||||
|
});
|
||||||
|
|
||||||
|
const nameLabel = document.createElement("label");
|
||||||
|
nameLabel.textContent = "Name:";
|
||||||
|
form.appendChild(nameLabel);
|
||||||
|
form.classList.add("column-container");
|
||||||
|
|
||||||
|
const nameInput = document.createElement("input");
|
||||||
|
nameInput.type = "text";
|
||||||
|
nameInput.name = "name";
|
||||||
|
form.appendChild(nameInput);
|
||||||
|
|
||||||
|
const typeLabel = document.createElement("label");
|
||||||
|
typeLabel.textContent = "Type:";
|
||||||
|
form.appendChild(typeLabel);
|
||||||
|
|
||||||
|
const typeSelect = document.createElement("select");
|
||||||
|
typeSelect.name = "Predefined Type";
|
||||||
|
|
||||||
|
console.log(types);
|
||||||
|
types.forEach((type) => {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = type.name;
|
||||||
|
option.textContent = type.name;
|
||||||
|
option.title = type.description;
|
||||||
|
typeSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
form.appendChild(typeSelect);
|
||||||
|
|
||||||
|
const submitButton = document.createElement("button");
|
||||||
|
submitButton.type = "submit";
|
||||||
|
submitButton.textContent = "Add";
|
||||||
|
submitButton.classList.add("action-button");
|
||||||
|
form.appendChild(submitButton);
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
|
||||||
|
form.addEventListener("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const data = {};
|
||||||
|
formData.forEach((value, key) => {
|
||||||
|
data[key] = value;
|
||||||
|
});
|
||||||
|
console.log("Data:", data);
|
||||||
|
addCostSchedule(data.name, data["Predefined Type"]);
|
||||||
|
form.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static createColorPicker() {
|
static createColorPicker() {
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.classList.add("card");
|
||||||
const colorPicker = document.createElement("input");
|
const colorPicker = document.createElement("input");
|
||||||
colorPicker.type = "color";
|
colorPicker.type = "color";
|
||||||
colorPicker.id = "color-picker";
|
colorPicker.id = "color-picker";
|
||||||
colorPicker.value = "#ff0000";
|
colorPicker.value = "#ff0000";
|
||||||
const colorText = document.createElement("p");
|
const colorText = document.createElement("p");
|
||||||
colorText.textContent = "Select a color to change row color:";
|
colorText.textContent = "Select a color to change row color:";
|
||||||
document.getElementById("UI").appendChild(colorText);
|
div.appendChild(colorText);
|
||||||
document.getElementById("UI").appendChild(colorPicker);
|
div.appendChild(colorPicker);
|
||||||
|
document.getElementById("UI").appendChild(div);
|
||||||
|
|
||||||
colorPicker.addEventListener("input", function() {
|
colorPicker.addEventListener("input", function () {
|
||||||
const baseColor = colorPicker.value;
|
const baseColor = colorPicker.value;
|
||||||
const colorScheme = CostUI.generateColorScheme(baseColor);
|
const colorScheme = CostUI.generateColorScheme(baseColor);
|
||||||
CostUI.applyColorScheme("cost-items", colorScheme);
|
CostUI.applyColorScheme("cost-items", colorScheme);
|
||||||
@@ -233,33 +318,81 @@ export class CostUI {
|
|||||||
CostUI.applyColorScheme("cost-items", colorScheme);
|
CostUI.applyColorScheme("cost-items", colorScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createCostSchedule({ data, blenderID, title, callbacks = {} }) {
|
static createCostSchedule({
|
||||||
|
data,
|
||||||
|
costScheduleId,
|
||||||
|
blenderID,
|
||||||
|
callbacks = {},
|
||||||
|
}) {
|
||||||
const [table, tbody] = CostUI.createTable(blenderID, callbacks);
|
const [table, tbody] = CostUI.createTable(blenderID, callbacks);
|
||||||
|
if (data.length === 0) {
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
const td = document.createElement("td");
|
||||||
|
td.colSpan = 6;
|
||||||
|
td.textContent = "No cost items found";
|
||||||
|
tr.appendChild(td);
|
||||||
|
tbody.appendChild(tr);
|
||||||
|
|
||||||
|
const addSummaryCostItemButton = document.createElement("button");
|
||||||
|
addSummaryCostItemButton.textContent = "Add Summary Cost Item";
|
||||||
|
addSummaryCostItemButton.addEventListener("click", function () {
|
||||||
|
callbacks.addSummaryCostItem
|
||||||
|
? callbacks.addSummaryCostItem(costScheduleId)
|
||||||
|
: null;
|
||||||
|
});
|
||||||
|
td.appendChild(addSummaryCostItemButton);
|
||||||
|
addSummaryCostItemButton.classList.add("action-button");
|
||||||
|
} else {
|
||||||
CostUI.createCostItem(data, tbody, 0, null, callbacks);
|
CostUI.createCostItem(data, tbody, 0, null, callbacks);
|
||||||
CostUI.applyExpandedState();
|
CostUI.applyExpandedState();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static createCostItem(data, container, nestingLevel = 0, parentID = null, callbacks = {}) {
|
static createCostItem(
|
||||||
data.forEach(costItem => {
|
data,
|
||||||
|
container,
|
||||||
|
nestingLevel = 0,
|
||||||
|
parentID = null,
|
||||||
|
callbacks = {}
|
||||||
|
) {
|
||||||
|
data.forEach((costItem) => {
|
||||||
const row = CostUI.createRow(costItem, nestingLevel, parentID, callbacks);
|
const row = CostUI.createRow(costItem, nestingLevel, parentID, callbacks);
|
||||||
container.appendChild(row);
|
container.appendChild(row);
|
||||||
|
|
||||||
if (costItem.is_nested_by && costItem.is_nested_by.length > 0) {
|
if (costItem.is_nested_by && costItem.is_nested_by.length > 0) {
|
||||||
CostUI.createCostItem(costItem.is_nested_by, container, nestingLevel + 1, costItem.id, callbacks);
|
CostUI.createCostItem(
|
||||||
|
costItem.is_nested_by,
|
||||||
|
container,
|
||||||
|
nestingLevel + 1,
|
||||||
|
costItem.id,
|
||||||
|
callbacks
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static createRow(costItem, nestingLevel, parentID, callbacks = {}) {
|
static createRow(costItem, nestingLevel, parentID, callbacks = {}) {
|
||||||
const totalQuantity = costItem.TotalCostQuantity ? parseFloat(costItem.TotalCostQuantity).toFixed(2) : '-';
|
const totalQuantity = costItem.TotalCostQuantity
|
||||||
|
? parseFloat(costItem.TotalCostQuantity).toFixed(2)
|
||||||
|
: "-";
|
||||||
const row = CostUI.createTableRow(costItem, nestingLevel, parentID);
|
const row = CostUI.createTableRow(costItem, nestingLevel, parentID);
|
||||||
const expandButton = CostUI.createExpandButton(costItem);
|
const expandButton = CostUI.createExpandButton(costItem);
|
||||||
const nameCell = CostUI.createNameCell(costItem, nestingLevel, expandButton, callbacks);
|
const nameCell = CostUI.createNameCell(
|
||||||
|
costItem,
|
||||||
|
nestingLevel,
|
||||||
|
expandButton,
|
||||||
|
callbacks
|
||||||
|
);
|
||||||
const totalCostQuantityCell = CostUI.createTableCell(totalQuantity);
|
const totalCostQuantityCell = CostUI.createTableCell(totalQuantity);
|
||||||
const unitSymbolCell = CostUI.createTableCell(costItem.UnitSymbol);
|
const unitSymbolCell = CostUI.createTableCell(costItem.UnitSymbol);
|
||||||
const totalAppliedValueCell = CostUI.createTableCell(costItem.TotalAppliedValue);
|
const totalAppliedValueCell = CostUI.createTableCell(
|
||||||
|
costItem.TotalAppliedValue
|
||||||
|
);
|
||||||
const totalCostCell = CostUI.createTotalCostCell(costItem);
|
const totalCostCell = CostUI.createTotalCostCell(costItem);
|
||||||
const flexContainerCell = CostUI.createFlexContainerCell(costItem, callbacks);
|
const flexContainerCell = CostUI.createFlexContainerCell(
|
||||||
|
costItem,
|
||||||
|
callbacks
|
||||||
|
);
|
||||||
|
|
||||||
row.appendChild(nameCell);
|
row.appendChild(nameCell);
|
||||||
row.appendChild(totalCostQuantityCell);
|
row.appendChild(totalCostQuantityCell);
|
||||||
@@ -268,11 +401,11 @@ export class CostUI {
|
|||||||
row.appendChild(totalCostCell);
|
row.appendChild(totalCostCell);
|
||||||
row.appendChild(flexContainerCell);
|
row.appendChild(flexContainerCell);
|
||||||
|
|
||||||
row.get_id = function() {
|
row.get_id = function () {
|
||||||
return this.getAttribute("id");
|
return this.getAttribute("id");
|
||||||
};
|
};
|
||||||
|
|
||||||
row.get_parent = function() {
|
row.get_parent = function () {
|
||||||
const parentId = this.getAttribute("parent-id");
|
const parentId = this.getAttribute("parent-id");
|
||||||
return parentId ? document.getElementById(parentId) : null;
|
return parentId ? document.getElementById(parentId) : null;
|
||||||
};
|
};
|
||||||
@@ -297,58 +430,53 @@ export class CostUI {
|
|||||||
expandButton.classList.add("fa-angle-right");
|
expandButton.classList.add("fa-angle-right");
|
||||||
|
|
||||||
if (row.is_nested_by && row.is_nested_by.length > 0) {
|
if (row.is_nested_by && row.is_nested_by.length > 0) {
|
||||||
expandButton.classList.add('fa-angle-right');
|
expandButton.classList.add("fa-angle-right");
|
||||||
} else {
|
} else {
|
||||||
expandButton.style.visibility = "hidden";
|
expandButton.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
expandButton.addEventListener("click", function(event) {
|
expandButton.addEventListener("click", function (event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
let isExpanded = CostUI.isRowExpanded(row.id);
|
let isExpanded = CostUI.isRowExpanded(row.id);
|
||||||
console.log("Row is expanded", isExpanded);
|
console.log("Row is expanded", isExpanded);
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
CostUI.contractRow(row.id);
|
CostUI.contractRow(row.id, true);
|
||||||
CostUI.updateExpandedState(row.id, false, true);
|
CostUI.updateExpandedState(row.id, false, true);
|
||||||
} else {
|
} else {
|
||||||
CostUI.expandRow(row.id);
|
CostUI.expandRow(row.id, true);
|
||||||
CostUI.updateExpandedState(row.id, true, true);
|
CostUI.updateExpandedState(row.id, true, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
CostUI.contractRow(row.id);
|
CostUI.contractRow(row.id, true);
|
||||||
CostUI.updateExpandedState(row.id, false);
|
CostUI.updateExpandedState(row.id, false);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
CostUI.expandRow(row.id);
|
CostUI.expandRow(row.id);
|
||||||
CostUI.updateExpandedState(row.id, true);
|
CostUI.updateExpandedState(row.id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CostUI.applyExpandedState();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return expandButton;
|
return expandButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static hideRow(id) {
|
static hideRow(id) {
|
||||||
const row = document.getElementById(id);
|
const row = document.getElementById(id);
|
||||||
if (row) {
|
if (row) {
|
||||||
row.classList.add("nested");
|
row.classList.add("nested");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static contractRow(parentId, recursive=false) {
|
static contractRow(parentId, recursive = false) {
|
||||||
CostUI.updateToggleButton(parentId, 'contract');
|
CostUI.updateToggleButton(parentId, "contract");
|
||||||
const rows = document.querySelectorAll(`[parent-id='${parentId}']`);
|
const rows = document.querySelectorAll(`[parent-id='${parentId}']`);
|
||||||
rows.forEach(row => {
|
rows.forEach((row) => {
|
||||||
const childId = row.getAttribute('id');
|
const childId = row.getAttribute("id");
|
||||||
CostUI.hideRow(childId);
|
CostUI.hideRow(childId);
|
||||||
if (recursive || (childId && CostUI.isRowExpanded(childId))) {
|
if (recursive || (childId && CostUI.isRowExpanded(childId))) {
|
||||||
CostUI.contractRow(childId, recursive)
|
CostUI.contractRow(childId, recursive);
|
||||||
}
|
}
|
||||||
// CostUI.contractRow(childId);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,27 +487,26 @@ export class CostUI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static updateToggleButton(id, type='contract') {
|
static updateToggleButton(id, type = "contract") {
|
||||||
const toggleButton = document.querySelector(`[id='${id}'] .action-button`);
|
const toggleButton = document.querySelector(`[id='${id}'] .action-button`);
|
||||||
if (!toggleButton) {
|
if (!toggleButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type === 'expand') {
|
if (type === "expand") {
|
||||||
toggleButton.classList.remove("fa-angle-right");
|
toggleButton.classList.remove("fa-angle-right");
|
||||||
toggleButton.classList.add("fa-angle-up");
|
toggleButton.classList.add("fa-angle-up");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
toggleButton.classList.remove("fa-angle-up");
|
toggleButton.classList.remove("fa-angle-up");
|
||||||
toggleButton.classList.add("fa-angle-right");
|
toggleButton.classList.add("fa-angle-right");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static expandRow(parentId, recursive=false) {
|
static expandRow(parentId, recursive = false) {
|
||||||
CostUI.updateExpandedState(parentId, true);
|
CostUI.updateExpandedState(parentId, true);
|
||||||
CostUI.updateToggleButton(parentId, 'expand');
|
CostUI.updateToggleButton(parentId, "expand");
|
||||||
const rows = document.querySelectorAll(`[parent-id='${parentId}']`);
|
const rows = document.querySelectorAll(`[parent-id='${parentId}']`);
|
||||||
rows.forEach(row => {
|
rows.forEach((row) => {
|
||||||
const childId = row.getAttribute('id');
|
const childId = row.getAttribute("id");
|
||||||
CostUI.showRow(childId);
|
CostUI.showRow(childId);
|
||||||
if (recursive || (childId && CostUI.isRowExpanded(childId))) {
|
if (recursive || (childId && CostUI.isRowExpanded(childId))) {
|
||||||
CostUI.expandRow(childId, recursive);
|
CostUI.expandRow(childId, recursive);
|
||||||
@@ -387,27 +514,28 @@ export class CostUI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static updateExpandedState(id, isExpanded, recursive=false) {
|
static updateExpandedState(id, isExpanded, recursive = false) {
|
||||||
const expandedState = JSON.parse(localStorage.getItem('expandedState')) || {};
|
const expandedState =
|
||||||
|
JSON.parse(localStorage.getItem("expandedState")) || {};
|
||||||
expandedState[id] = isExpanded;
|
expandedState[id] = isExpanded;
|
||||||
localStorage.setItem('expandedState', JSON.stringify(expandedState));
|
localStorage.setItem("expandedState", JSON.stringify(expandedState));
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
const rows = document.querySelectorAll(`[parent-id='${id}']`);
|
const rows = document.querySelectorAll(`[parent-id='${id}']`);
|
||||||
rows.forEach(row => {
|
rows.forEach((row) => {
|
||||||
CostUI.updateExpandedState(row.id, isExpanded, recursive);
|
CostUI.updateExpandedState(row.id, isExpanded, recursive);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static applyExpandedState() {
|
static applyExpandedState() {
|
||||||
const expandedState = JSON.parse(localStorage.getItem('expandedState')) || CostUI.getAllCostItemsIds().reduce((acc, id) => {
|
const expandedState =
|
||||||
|
JSON.parse(localStorage.getItem("expandedState")) ||
|
||||||
|
CostUI.getAllCostItemsIds().reduce((acc, id) => {
|
||||||
acc[id] = true;
|
acc[id] = true;
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
console.log("Expanded state", expandedState);
|
Object.keys(expandedState).forEach((id) => {
|
||||||
|
|
||||||
Object.keys(expandedState).forEach(id => {
|
|
||||||
if (expandedState[id]) {
|
if (expandedState[id]) {
|
||||||
CostUI.expandRow(id);
|
CostUI.expandRow(id);
|
||||||
} else {
|
} else {
|
||||||
@@ -417,7 +545,8 @@ export class CostUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static isRowExpanded(id) {
|
static isRowExpanded(id) {
|
||||||
const expandedState = JSON.parse(localStorage.getItem('expandedState')) || {};
|
const expandedState =
|
||||||
|
JSON.parse(localStorage.getItem("expandedState")) || {};
|
||||||
return expandedState[id] || false;
|
return expandedState[id] || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,13 +555,17 @@ export class CostUI {
|
|||||||
const nameInput = document.createElement("input");
|
const nameInput = document.createElement("input");
|
||||||
nameInput.value = costItem.name ? costItem.name : "Unnamed";
|
nameInput.value = costItem.name ? costItem.name : "Unnamed";
|
||||||
|
|
||||||
nameInput.addEventListener("change", function() {
|
nameInput.addEventListener("change", function () {
|
||||||
callbacks.editCostItemName ? callbacks.editCostItemName(costItem.id, this.value) : null;
|
callbacks.editCostItemName
|
||||||
|
? callbacks.editCostItemName(costItem.id, this.value)
|
||||||
|
: null;
|
||||||
});
|
});
|
||||||
|
|
||||||
nameInput.addEventListener("keydown", function(event) {
|
nameInput.addEventListener("keydown", function (event) {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
callbacks.editCostItemName ? callbacks.editCostItemName(costItem.id, this.value) : null;
|
callbacks.editCostItemName
|
||||||
|
? callbacks.editCostItemName(costItem.id, this.value)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -453,18 +586,16 @@ export class CostUI {
|
|||||||
static createTotalCostCell(costItem) {
|
static createTotalCostCell(costItem) {
|
||||||
const totalCostCell = document.createElement("td");
|
const totalCostCell = document.createElement("td");
|
||||||
const totalCost = parseFloat(costItem.TotalCost).toFixed(2);
|
const totalCost = parseFloat(costItem.TotalCost).toFixed(2);
|
||||||
totalCostCell.textContent = costItem.is_sum ? totalCost + " (Σ)" : totalCost;
|
totalCostCell.textContent = costItem.is_sum
|
||||||
|
? totalCost + " (Σ)"
|
||||||
|
: totalCost;
|
||||||
return totalCostCell;
|
return totalCostCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createFlexContainerCell(costItem, callbacks) {
|
static createFlexContainerCell(costItem, callbacks) {
|
||||||
const divFlex = document.createElement("div");
|
const divFlex = document.createElement("div");
|
||||||
divFlex.classList.add("flex-container");
|
divFlex.classList.add("row-container");
|
||||||
|
|
||||||
const addButton = CostUI.createAddButton(costItem, callbacks);
|
|
||||||
const selectButton = CostUI.createSelectButton(costItem, callbacks);
|
const selectButton = CostUI.createSelectButton(costItem, callbacks);
|
||||||
|
|
||||||
divFlex.appendChild(addButton);
|
|
||||||
divFlex.appendChild(selectButton);
|
divFlex.appendChild(selectButton);
|
||||||
|
|
||||||
const flexContainerCell = document.createElement("td");
|
const flexContainerCell = document.createElement("td");
|
||||||
@@ -472,24 +603,15 @@ export class CostUI {
|
|||||||
return flexContainerCell;
|
return flexContainerCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createAddButton(costItem, callbacks) {
|
|
||||||
const addButton = document.createElement("button");
|
|
||||||
addButton.textContent = "+";
|
|
||||||
addButton.classList.add("add-button");
|
|
||||||
addButton.addEventListener("click", function(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
callbacks.addCostItem ? callbacks.addCostItem(costItem.id) : null;
|
|
||||||
});
|
|
||||||
return addButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
static createSelectButton(costItem, callbacks) {
|
static createSelectButton(costItem, callbacks) {
|
||||||
const selectButton = document.createElement("button");
|
const selectButton = document.createElement("button");
|
||||||
selectButton.classList.add("action-button");
|
selectButton.classList.add("action-button");
|
||||||
selectButton.textContent = "Select";
|
selectButton.textContent = "Select";
|
||||||
selectButton.addEventListener("click", function(e) {
|
selectButton.addEventListener("click", function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
callbacks.selectAssignedElements ? callbacks.selectAssignedElements(costItem.id) : null;
|
callbacks.selectAssignedElements
|
||||||
|
? callbacks.selectAssignedElements(costItem.id)
|
||||||
|
: null;
|
||||||
});
|
});
|
||||||
return selectButton;
|
return selectButton;
|
||||||
}
|
}
|
||||||
@@ -511,14 +633,12 @@ export class CostUI {
|
|||||||
static getAllCostItemsIds() {
|
static getAllCostItemsIds() {
|
||||||
const rows = document.querySelectorAll("#cost-items tr");
|
const rows = document.querySelectorAll("#cost-items tr");
|
||||||
const ids = [];
|
const ids = [];
|
||||||
rows.forEach(row => {
|
rows.forEach((row) => {
|
||||||
ids.push(row.id);
|
ids.push(row.id);
|
||||||
});
|
});
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static text(label) {
|
static text(label) {
|
||||||
const text = document.createElement("p");
|
const text = document.createElement("p");
|
||||||
text.textContent = label;
|
text.textContent = label;
|
||||||
@@ -563,15 +683,23 @@ export class CostUI {
|
|||||||
if (existingForm) {
|
if (existingForm) {
|
||||||
existingForm.remove();
|
existingForm.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
const form = CostUI.createFormElement(formId, "cost-values-form");
|
|
||||||
const costItemName = CostUI.getCostItemName(costItemId);
|
const costItemName = CostUI.getCostItemName(costItemId);
|
||||||
const header = CostUI.createHeader("Cost Values Form for " + costItemName);
|
|
||||||
form.appendChild(header);
|
|
||||||
|
|
||||||
const table = CostUI.createCostValuesTable(costItemId, ["Type", "Category", "Value", ""]);
|
let formName = "Cost Values: " + costItemName;
|
||||||
|
const form = CostUI.Form({
|
||||||
|
id: formId,
|
||||||
|
name: formName,
|
||||||
|
className: "floating-form",
|
||||||
|
});
|
||||||
|
|
||||||
costValues.forEach(costValue => {
|
const table = CostUI.createCostValuesTable(costItemId, [
|
||||||
|
"Type",
|
||||||
|
"Category",
|
||||||
|
"Value",
|
||||||
|
"",
|
||||||
|
]);
|
||||||
|
|
||||||
|
costValues.forEach((costValue) => {
|
||||||
const tr = CostUI.createCostvaluesRow(costItemId, costValue, callbacks);
|
const tr = CostUI.createCostvaluesRow(costItemId, costValue, callbacks);
|
||||||
table.appendChild(tr);
|
table.appendChild(tr);
|
||||||
});
|
});
|
||||||
@@ -581,17 +709,11 @@ export class CostUI {
|
|||||||
const addButton = CostUI.createAddCostValueButton(costItemId, callbacks);
|
const addButton = CostUI.createAddCostValueButton(costItemId, callbacks);
|
||||||
form.appendChild(addButton);
|
form.appendChild(addButton);
|
||||||
|
|
||||||
const closeButton = CostUI.createCloseButton(form);
|
|
||||||
form.appendChild(closeButton);
|
|
||||||
|
|
||||||
CostUI.makeHeaderDraggable(header, form);
|
|
||||||
|
|
||||||
document.body.appendChild(form);
|
document.body.appendChild(form);
|
||||||
|
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static getCostValuesTable(costItemId) {
|
static getCostValuesTable(costItemId) {
|
||||||
return document.getElementById("cost-values-table-" + costItemId);
|
return document.getElementById("cost-values-table-" + costItemId);
|
||||||
}
|
}
|
||||||
@@ -602,9 +724,17 @@ export class CostUI {
|
|||||||
console.log("Cost values table not found for cost item ID:", costItemId);
|
console.log("Cost values table not found for cost item ID:", costItemId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Adding new cost value row", costValueId);
|
const tr = CostUI.createCostvaluesRow(
|
||||||
console.log(table)
|
costItemId,
|
||||||
const tr = CostUI.createCostvaluesRow(costItemId, {"category": "", "name": "", "applied_value": 0, "id": costValueId, "parent": costItemId}, costValueCallbacks);
|
{
|
||||||
|
category: "",
|
||||||
|
name: "",
|
||||||
|
applied_value: 0,
|
||||||
|
id: costValueId,
|
||||||
|
parent: costItemId,
|
||||||
|
},
|
||||||
|
costValueCallbacks
|
||||||
|
);
|
||||||
table.appendChild(tr);
|
table.appendChild(tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +744,7 @@ export class CostUI {
|
|||||||
table.id = "cost-values-table-" + costItemId;
|
table.id = "cost-values-table-" + costItemId;
|
||||||
|
|
||||||
const headerRow = document.createElement("tr");
|
const headerRow = document.createElement("tr");
|
||||||
headers.forEach(headerText => {
|
headers.forEach((headerText) => {
|
||||||
const th = document.createElement("th");
|
const th = document.createElement("th");
|
||||||
th.textContent = headerText;
|
th.textContent = headerText;
|
||||||
headerRow.appendChild(th);
|
headerRow.appendChild(th);
|
||||||
@@ -624,9 +754,9 @@ export class CostUI {
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createCostvaluesRow(costItemId,costValue, costValueCallbacks) {
|
static createCostvaluesRow(costItemId, costValue, costValueCallbacks) {
|
||||||
function cleanLabel(value) {
|
function cleanLabel(value) {
|
||||||
return value.replace(/[^0-9.]/g, '');
|
return value.replace(/[^0-9.]/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.getElementById(costValue.id)) {
|
if (document.getElementById(costValue.id)) {
|
||||||
@@ -640,23 +770,23 @@ export class CostUI {
|
|||||||
let costType = "FIXED";
|
let costType = "FIXED";
|
||||||
if (costValue.category === "*") {
|
if (costValue.category === "*") {
|
||||||
costType = "SUM";
|
costType = "SUM";
|
||||||
}
|
} else if (costValue.category && costValue.category !== "*") {
|
||||||
else if (costValue.category && costValue.category !== "*") {
|
|
||||||
costType = "CATEGORY";
|
costType = "CATEGORY";
|
||||||
}
|
} else if (costValue.applied_value) {
|
||||||
else if (costValue.applied_value) {
|
|
||||||
costType = "FIXED";
|
costType = "FIXED";
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeCell = CostUI.createTableDropdown("type", costType);
|
const typeCell = CostUI.createTableDropdown("type", costType);
|
||||||
const dropdown = typeCell.querySelector("select");
|
const dropdown = typeCell.querySelector("select");
|
||||||
dropdown.addEventListener("change", function() {
|
dropdown.addEventListener("change", function () {
|
||||||
const selectedType = this.value;
|
const selectedType = this.value;
|
||||||
CostUI.updateRowBasedOnType(selectedType, categoryCell, valueCell1);
|
CostUI.updateRowBasedOnType(selectedType, categoryCell, valueCell1);
|
||||||
|
|
||||||
if (selectedType === "SUM") {
|
if (selectedType === "SUM") {
|
||||||
const costValueId = parseInt(this.closest("tr").getAttribute("id"));
|
const costValueId = parseInt(this.closest("tr").getAttribute("id"));
|
||||||
const appliedValue = parseFloat(valueCell1.querySelector("input").value);
|
const appliedValue = parseFloat(
|
||||||
|
valueCell1.querySelector("input").value
|
||||||
|
);
|
||||||
const costCategory = categoryCell.querySelector("input").value;
|
const costCategory = categoryCell.querySelector("input").value;
|
||||||
|
|
||||||
if (costValueCallbacks.editCostValues) {
|
if (costValueCallbacks.editCostValues) {
|
||||||
@@ -666,24 +796,27 @@ export class CostUI {
|
|||||||
costCategory: costCategory,
|
costCategory: costCategory,
|
||||||
appliedValue: appliedValue,
|
appliedValue: appliedValue,
|
||||||
id: costValueId,
|
id: costValueId,
|
||||||
costItemId: costItemId
|
costItemId: costItemId,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tr.appendChild(typeCell);
|
tr.appendChild(typeCell);
|
||||||
|
|
||||||
const categoryCell = CostUI.createTableInput("text", "category", costValue.category);
|
const categoryCell = CostUI.createTableInput(
|
||||||
|
"text",
|
||||||
|
"category",
|
||||||
|
costValue.category
|
||||||
|
);
|
||||||
tr.appendChild(categoryCell);
|
tr.appendChild(categoryCell);
|
||||||
|
|
||||||
let value
|
let value;
|
||||||
|
|
||||||
if (costValue.category === "*"){
|
if (costValue.category === "*") {
|
||||||
value = cleanLabel(costValue.label)
|
value = cleanLabel(costValue.label);
|
||||||
}
|
} else {
|
||||||
else {
|
value = costValue.applied_value;
|
||||||
value = costValue.applied_value
|
|
||||||
}
|
}
|
||||||
const valueCell1 = CostUI.createTableInput("number", "value", value);
|
const valueCell1 = CostUI.createTableInput("number", "value", value);
|
||||||
tr.appendChild(valueCell1);
|
tr.appendChild(valueCell1);
|
||||||
@@ -695,16 +828,19 @@ export class CostUI {
|
|||||||
costCategory: categoryCell.querySelector("input").value,
|
costCategory: categoryCell.querySelector("input").value,
|
||||||
appliedValue: parseFloat(this.value),
|
appliedValue: parseFloat(this.value),
|
||||||
id: costValue.id,
|
id: costValue.id,
|
||||||
costItemId: costItemId
|
costItemId: costItemId,
|
||||||
}
|
};
|
||||||
if (costValueCallbacks.editCostValues) {
|
if (costValueCallbacks.editCostValues) {
|
||||||
costValueCallbacks.editCostValues(costItemId, [costValueData]);
|
costValueCallbacks.editCostValues(costItemId, [costValueData]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputValue.addEventListener("change", handleCostValueChange.bind(inputValue, costItemId));
|
inputValue.addEventListener(
|
||||||
|
"change",
|
||||||
|
handleCostValueChange.bind(inputValue, costItemId)
|
||||||
|
);
|
||||||
|
|
||||||
inputValue.addEventListener("keydown", function(event) {
|
inputValue.addEventListener("keydown", function (event) {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleCostValueChange.call(this, costItemId);
|
handleCostValueChange.call(this, costItemId);
|
||||||
@@ -712,14 +848,14 @@ export class CostUI {
|
|||||||
});
|
});
|
||||||
const deleteCell = document.createElement("td");
|
const deleteCell = document.createElement("td");
|
||||||
tr.appendChild(deleteCell);
|
tr.appendChild(deleteCell);
|
||||||
const deleteButton = document.createElement("button");
|
const deleteCostValue = document.createElement("button");
|
||||||
deleteButton.classList.add("action-button");
|
deleteCostValue.classList.add("action-button");
|
||||||
deleteButton.textContent = "Delete";
|
deleteCostValue.textContent = "Delete";
|
||||||
deleteButton.addEventListener("click", function() {
|
deleteCostValue.addEventListener("click", function () {
|
||||||
costValueCallbacks.deleteCostValue(costItemId, costValue.id);
|
costValueCallbacks.deleteCostValue(costItemId, costValue.id);
|
||||||
tr.remove();
|
tr.remove();
|
||||||
});
|
});
|
||||||
deleteCell.appendChild(deleteButton);
|
deleteCell.appendChild(deleteCostValue);
|
||||||
CostUI.updateRowBasedOnType(costType, categoryCell, valueCell1);
|
CostUI.updateRowBasedOnType(costType, categoryCell, valueCell1);
|
||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
@@ -743,13 +879,13 @@ export class CostUI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static createTableDropdown(name, value="FIXED") {
|
static createTableDropdown(name, value = "FIXED") {
|
||||||
const cell = document.createElement("td");
|
const cell = document.createElement("td");
|
||||||
const dropdown = document.createElement("select");
|
const dropdown = document.createElement("select");
|
||||||
dropdown.name = name;
|
dropdown.name = name;
|
||||||
|
|
||||||
const options = ["FIXED", "CATEGORY", "SUM"];
|
const options = ["FIXED", "CATEGORY", "SUM"];
|
||||||
options.forEach(optionValue => {
|
options.forEach((optionValue) => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.value = optionValue;
|
option.value = optionValue;
|
||||||
option.textContent = optionValue;
|
option.textContent = optionValue;
|
||||||
@@ -777,14 +913,14 @@ export class CostUI {
|
|||||||
const addButton = document.createElement("button");
|
const addButton = document.createElement("button");
|
||||||
addButton.classList.add("action-button");
|
addButton.classList.add("action-button");
|
||||||
addButton.textContent = " + Add Cost Value";
|
addButton.textContent = " + Add Cost Value";
|
||||||
addButton.addEventListener("click", function(e) {
|
addButton.addEventListener("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
callbacks.addCostValue ? callbacks.addCostValue(costItemId) : null;
|
callbacks.addCostValue ? callbacks.addCostValue(costItemId) : null;
|
||||||
});
|
});
|
||||||
return addButton;
|
return addButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createFormElement(id, className) {
|
static Form({ id, name, className }) {
|
||||||
const form = document.createElement("form");
|
const form = document.createElement("form");
|
||||||
form.id = id;
|
form.id = id;
|
||||||
form.classList.add(className);
|
form.classList.add(className);
|
||||||
@@ -792,8 +928,70 @@ export class CostUI {
|
|||||||
form.style.top = "50%";
|
form.style.top = "50%";
|
||||||
form.style.left = "50%";
|
form.style.left = "50%";
|
||||||
form.style.transform = "translate(-50%, -50%)";
|
form.style.transform = "translate(-50%, -50%)";
|
||||||
|
const header = CostUI.createHeader(name);
|
||||||
|
const closeButton = CostUI.createCloseButton(form);
|
||||||
|
form.appendChild(header);
|
||||||
|
form.appendChild(closeButton);
|
||||||
|
CostUI.makeFormDraggable(form);
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
static makeFormDraggable(form) {
|
||||||
|
let pos1 = 0,
|
||||||
|
pos2 = 0,
|
||||||
|
pos3 = 0,
|
||||||
|
pos4 = 0;
|
||||||
|
form.onmousedown = function (e) {
|
||||||
|
if (!e.target.closest("input, select, button")) {
|
||||||
|
dragMouseDown(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formElements = form.querySelectorAll("input, select, button");
|
||||||
|
formElements.forEach((element) => {
|
||||||
|
element.onmousedown = function (e) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function dragMouseDown(e) {
|
||||||
|
e = e || window.event;
|
||||||
|
e.preventDefault();
|
||||||
|
pos3 = e.clientX;
|
||||||
|
pos4 = e.clientY;
|
||||||
|
document.onmouseup = closeDragElement;
|
||||||
|
document.onmousemove = elementDrag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function elementDrag(e) {
|
||||||
|
e = e || window.event;
|
||||||
|
e.preventDefault();
|
||||||
|
pos1 = pos3 - e.clientX;
|
||||||
|
pos2 = pos4 - e.clientY;
|
||||||
|
pos3 = e.clientX;
|
||||||
|
pos4 = e.clientY;
|
||||||
|
|
||||||
|
let newTop = form.offsetTop - pos2;
|
||||||
|
let newLeft = form.offsetLeft - pos1;
|
||||||
|
|
||||||
|
const minTop = form.offsetHeight / 2;
|
||||||
|
const minLeft = form.offsetWidth / 2;
|
||||||
|
const maxTop = window.innerHeight - form.offsetHeight / 2;
|
||||||
|
const maxLeft = window.innerWidth - form.offsetWidth / 2;
|
||||||
|
|
||||||
|
if (newTop < minTop) newTop = minTop;
|
||||||
|
if (newTop > maxTop) newTop = maxTop;
|
||||||
|
if (newLeft < minLeft) newLeft = minLeft;
|
||||||
|
if (newLeft > maxLeft) newLeft = maxLeft;
|
||||||
|
|
||||||
|
form.style.top = newTop + "px";
|
||||||
|
form.style.left = newLeft + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDragElement() {
|
||||||
|
document.onmouseup = null;
|
||||||
|
document.onmousemove = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static createHeader(text) {
|
static createHeader(text) {
|
||||||
const header = document.createElement("div");
|
const header = document.createElement("div");
|
||||||
@@ -806,7 +1004,7 @@ export class CostUI {
|
|||||||
const closeButton = document.createElement("span");
|
const closeButton = document.createElement("span");
|
||||||
closeButton.classList.add("close-button");
|
closeButton.classList.add("close-button");
|
||||||
closeButton.innerHTML = "×";
|
closeButton.innerHTML = "×";
|
||||||
closeButton.addEventListener("click", function() {
|
closeButton.addEventListener("click", function () {
|
||||||
form.remove();
|
form.remove();
|
||||||
const costItemId = form.id.split("-")[3];
|
const costItemId = form.id.split("-")[3];
|
||||||
CostUI.unhighlightCostItem(costItemId);
|
CostUI.unhighlightCostItem(costItemId);
|
||||||
@@ -814,24 +1012,4 @@ export class CostUI {
|
|||||||
|
|
||||||
return closeButton;
|
return closeButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
static makeHeaderDraggable(header, form) {
|
|
||||||
header.addEventListener("mousedown", function(e) {
|
|
||||||
let offsetX = e.clientX - form.getBoundingClientRect().left;
|
|
||||||
let offsetY = e.clientY - form.getBoundingClientRect().top;
|
|
||||||
|
|
||||||
function mouseMoveHandler(e) {
|
|
||||||
form.style.left = `${e.clientX - offsetX}px`;
|
|
||||||
form.style.top = `${e.clientY - offsetY}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseUpHandler() {
|
|
||||||
document.removeEventListener("mousemove", mouseMoveHandler);
|
|
||||||
document.removeEventListener("mouseup", mouseUpHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("mousemove", mouseMoveHandler);
|
|
||||||
document.addEventListener("mouseup", mouseUpHandler);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user