${panelObj.displayData(
+ `
${panelObj.displayData(
data
)}
`,
- css: { overflow: "auto", "max-height": "85%" },
+ borderless: true,
+ css: "data-panel-employee-list",
data: [],
on: {
onViewShow() {
@@ -1405,16 +1418,40 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
}
return {
- id: this.ids.dataPanel,
- hidden: true,
- view: "tabview",
- width: 450,
- tabbar: {
- height: 60,
- type: "bottom",
- css: "webix_dark",
- },
- cells,
+ height: 600,
+ type: "clean",
+ rows: [
+ {
+ view: "template",
+ borderless: true,
+ template: `
+ ${this.label("Staff Assignment")}
+
+
`,
+ height: 35,
+ onClick: {
+ "data-panel-close": () => {
+ $$(this.ids.dataPanelPopup).hide();
+ return false;
+ },
+ },
+ },
+ {
+ id: this.ids.dataPanel,
+ view: "tabview",
+ css: "data-panel-tabview",
+ width: 250,
+ borderless: true,
+ tabbar: {
+ height: 25,
+ // width: 300,
+ align: "left",
+ // type: "bottom",
+ css: "data-panel-tabbar",
+ },
+ cells,
+ },
+ ],
};
}
@@ -1460,7 +1497,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
],
},
- self._uiDataPanel(),
],
}).$view;
chartDom.appendChild($chartDomComponents);
@@ -1470,10 +1506,25 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$filterButton.innerHTML = `
Filter`;
$filterButton.classList.add("filter-button");
$filterButton.onclick = self._fnShowFilterPopup;
+ const $dataPanelButton = document.createElement("div");
+ $dataPanelButton.innerHTML = `
+
+
+ ${self.label("Staff Assignment")}
+
+
`;
+ $dataPanelButton.classList.add("data-panel-button");
+ $dataPanelButton.querySelector(".data-panel-open").onclick = (
+ ev
+ ) => self._showDataPanel(ev);
$chartDomComponents.children[0].children[0].children[0].append(
- $filterButton
+ $filterButton,
+ $dataPanelButton
);
- $$(ids.dataPanel).show();
},
},
},
@@ -1799,7 +1850,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$$(ids.teamFormPopup)?.destructor();
$$(ids.contentForm)?.destructor();
await this.pullData();
- this._showDataPanel();
+ // this._showDataPanel();
this._showOrgChart();
this._pageData();
this.ready();
diff --git a/styles/team-widget.css b/styles/team-widget.css
index 29bc44f0..41396e81 100644
--- a/styles/team-widget.css
+++ b/styles/team-widget.css
@@ -262,3 +262,128 @@ org-chart tr.lines .downLine {
50% { background-color: #eee; }
100% { background-color: #ddd}
}
+
+/* -- DATA PANEL -- */
+.data-panel-button {
+ display: flex;
+ border-radius: 10px;
+ background: #fff;
+ box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+ float: right;
+ padding: 5px;
+ width: 230px;
+ margin-right: 25px;
+}
+
+.data-panel-close {
+ background: #2F27CE;
+ color: #FFF;
+ border-radius: 5px;
+ padding: 4px 5px;
+ float: right;
+}
+
+.data-panel-close:hover {
+ background: #FFF;
+ color: #2F27CE;
+ border: 1px solid #2F27CE;
+}
+
+.data-panel-employee {
+ margin-top: 3px;
+ text-align: center;
+ border-radius: 8px;
+ border: 2px solid #868686;
+ height: 22px;
+ font-family: Jomhuria;
+ font-size: 18px;
+ line-height: 25px;
+}
+
+.data-panel-employee-list .webix_list_item {
+ border-bottom: unset;
+ background: transparent;
+ overflow: auto;
+ max-height: 95%;
+}
+
+.data-panel-open {
+ background: #FFF;
+ color: #2F27CE;
+ border-radius: 5px;
+ padding: 4px;
+ float: right;
+}
+
+.data-panel-open:hover {
+ background: #2F27CE;
+ color: #FFF !important;
+}
+
+.data-panel-popup {
+ border-radius: 10px;
+ background: #fff;
+ box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+ padding: 10px;
+}
+
+.data-panel-tabbar {
+ border: solid black;
+ border-width: 1px 0px 1px 0px !important;
+ padding: 5px;
+}
+
+.data-panel-tabbar .webix_all_tabs {
+ float: left;
+ display: flex;
+ gap: 10px;
+ height: 25px;
+}
+
+.data-panel-tabbar .webix_all_tabs .webix_item_tab {
+ color: #000;
+ border-radius: 7px;
+ background: #FFF;
+ font-family: "Jomhuria", sans-serif;
+ font-size:20px;
+ line-height: normal;
+ box-shadow: none;
+ border: none;
+ display: flex;
+ width: 54px !important;
+ height: 24px;
+ justify-content: center;
+ align-items: center;
+}
+
+.data-panel-tabbar .webix_all_tabs .webix_selected {
+ color: #FFF;
+ background: #000 !important;
+}
+
+.data-panel-tabbar .webix_all_tabs .webix_item_tab:hover {
+ color: #000;
+ background: rgba(0, 0, 0, 0.20) !important;
+ box-shadow: none;
+}
+
+.data-panel-tabbar .webix_all_tabs .webix_item_tab:focus {
+ color: #FFF;
+ background: #222 !important;
+ box-shadow: none;
+}
+
+.data-panel-tabview .webix_multiview {
+ margin-top: 0px !important;
+}
+
+.data-panel-tabview .webix_multiview .webix_list {
+ height: 530px !important;
+}
+
+/* following a comment here: https://docs.webix.com/api__refs__ui.popup.html
+ * so that the popup doesn't close. Not sure if we want to do it this way */
+.webix_modal {
+ width: 0;
+ height: 0;
+}
From 6767c64eb06c8d6f89e7dac10c74ac2e8e947d33 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Wed, 8 Jan 2025 14:42:23 +0700
Subject: [PATCH 089/129] resize widget when screen changes
---
.../platform/views/viewComponent/ABViewOrgChartTeamsComponent.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 7462c097..fdeae461 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1472,6 +1472,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
{
id: ids.chartView,
view: "template",
+ responsive: true,
template: `
`,
css: {
position: "relative",
From b8abc55572b6ea205b87cb411ec34f4ccfe0fb75 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Wed, 8 Jan 2025 14:59:00 +0700
Subject: [PATCH 090/129] fix populating filter complex ui with in query
filters
---
AppBuilder/platform/FilterComplex.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/AppBuilder/platform/FilterComplex.js b/AppBuilder/platform/FilterComplex.js
index 977e81a9..a34f7b4e 100644
--- a/AppBuilder/platform/FilterComplex.js
+++ b/AppBuilder/platform/FilterComplex.js
@@ -40,6 +40,13 @@ function _toInternal(cond, fields = []) {
};
if (Array.isArray(cond.value)) cond.includes = cond.value;
+ if (
+ cond.rule === "in_query_field" ||
+ cond.rule === "not_in_query_field"
+ ) {
+ cond.includes = cond.value.split(":");
+ }
+
// else cond.includes = cond.value?.split?.(/,|:/) ?? [];
// if (field?.key == "date" || field?.key == "datetime") {
From f14fbe30ecd6071bd5ebcdb2dc6af0e06f65379a Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Wed, 8 Jan 2025 14:59:00 +0700
Subject: [PATCH 091/129] fix populating filter complex ui with in query
filters
---
AppBuilder/platform/FilterComplex.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/AppBuilder/platform/FilterComplex.js b/AppBuilder/platform/FilterComplex.js
index 977e81a9..a34f7b4e 100644
--- a/AppBuilder/platform/FilterComplex.js
+++ b/AppBuilder/platform/FilterComplex.js
@@ -40,6 +40,13 @@ function _toInternal(cond, fields = []) {
};
if (Array.isArray(cond.value)) cond.includes = cond.value;
+ if (
+ cond.rule === "in_query_field" ||
+ cond.rule === "not_in_query_field"
+ ) {
+ cond.includes = cond.value.split(":");
+ }
+
// else cond.includes = cond.value?.split?.(/,|:/) ?? [];
// if (field?.key == "date" || field?.key == "datetime") {
From 45fb6084ee2e5eb20cf6405b72fd6380a53a58d9 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 8 Jan 2025 20:04:09 +0700
Subject: [PATCH 092/129] Fix the typo bug, End Date validation, form type
convertion and warning popup
---
.../ABViewOrgChartTeamsComponent.js | 333 +++++++++++++-----
styles/orgchart-webcomponents.css | 8 +
2 files changed, 247 insertions(+), 94 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 5857ffba..44d36f14 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -536,7 +536,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const fieldName = field.columnName;
// TODO (Guy): Add validators.
- rules[fieldName] = () => true;
+ let invalidMessage = "";
+ switch (fieldName) {
+ case contentDateEndFieldColumnName:
+ invalidMessage = `The ${field.label} must be today or earlier.`;
+ rules[fieldName] = (value) => value <= new Date();
+ break;
+ default:
+ rules[fieldName] = () => true;
+ break;
+ }
const fieldLabel = field.label;
const settings = field.settings;
switch (fieldKey) {
@@ -546,6 +555,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
name: fieldName,
label: fieldLabel,
labelWidth,
+ invalidMessage,
};
case "number":
return {
@@ -554,6 +564,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
label: fieldLabel,
labelWidth,
type: "number",
+ invalidMessage,
};
case "list":
return {
@@ -567,6 +578,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
id: option.id,
value: option.text,
})),
+ invalidMessage,
};
case "user":
case "connectObject":
@@ -580,6 +592,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
label: "Name",
disabled: true,
labelWidth,
+ invalidMessage,
on: {
async onViewShow() {
abWebix.extend(this, abWebix.ProgressBar);
@@ -642,6 +655,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
label: fieldLabel,
disabled: true,
labelWidth,
+ invalidMessage,
options: [],
on: {
onViewShow,
@@ -654,6 +668,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
labelWidth,
stringResult: false,
labelAlign: "left",
+ invalidMessage,
options: [],
on: {
onViewShow,
@@ -666,6 +681,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
name: fieldName,
label: fieldLabel,
labelWidth,
+ invalidMessage,
timepicker: fieldKey === "datetime",
};
case "file":
@@ -676,6 +692,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
name: fieldName,
label: fieldLabel,
labelWidth,
+ invalidMessage,
};
// case "json":
// case "LongText":
@@ -687,10 +704,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
name: fieldName,
label: fieldLabel,
labelWidth,
+ invalidMessage,
};
}
}
);
+ const Webix = AB.Webix;
contentFormElements.push({
view: "button",
value: this.label("Save"),
@@ -716,78 +735,95 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$contentForm.$view.remove();
$contentForm.destructor();
if (!isDataChanged) return;
- webix
- .confirm({
- title: "Warning",
- ok: "Yes",
- cancel: "No",
- text: "You are about to confirm. Are you sure?",
- })
- .then(async () => {
- this.busy();
- const teamDC = this.datacollection;
- const contentDC = this._contentDC;
- const dataID = newFormData.id;
- const $contentNode = document.getElementById(
- this.contentNodeID(dataID)
- );
- delete newFormData["created_at"];
- delete newFormData["updated_at"];
- delete newFormData["properties"];
- for (const editContentFieldToCreateNew of editContentFieldsToCreateNew) {
- const editContentFieldToCreateNewColumnName =
- contentObj.fieldByID(
- editContentFieldToCreateNew
- )?.columnName;
- if (
- JSON.stringify(
- newFormData[
- editContentFieldToCreateNewColumnName
- ] ?? ""
- ) !==
- JSON.stringify(
- contentDataRecord[
- editContentFieldToCreateNewColumnName
- ] ?? ""
- )
- ) {
- const pendingPromises = [];
- const oldData = {};
-
- oldData[contentDateEndFieldColumnName] = new Date();
- pendingPromises.push(
- contentModel.update(dataID, oldData)
- );
- newFormData[contentDateStartFieldColumnName] =
- oldData[contentDateEndFieldColumnName];
- delete newFormData["id"];
- delete newFormData["uuid"];
- delete newFormData[contentDateEndFieldColumnName];
- pendingPromises.push(
- contentModel.create(newFormData)
- );
- try {
- await Promise.all(pendingPromises);
- } catch (err) {
- // TODO (Guy): The update data error.
- console.error(err);
- }
- try {
- await Promise.all([
- this._reloadDCData(teamDC),
- this._reloadDCData(contentDC),
- ]);
- // await this._reloadAllDC();
- } catch (err) {
- // TODO (Guy): The reload DCs error.
- console.error(err);
- }
- await this.refresh();
- $contentNode.remove();
- this.ready();
- return;
+ const teamDC = this.datacollection;
+ const contentDC = this._contentDC;
+ const dataID = newFormData.id;
+ const $contentNode = document.getElementById(
+ this.contentNodeID(dataID)
+ );
+ delete newFormData["created_at"];
+ delete newFormData["updated_at"];
+ delete newFormData["properties"];
+ for (const editContentFieldToCreateNew of editContentFieldsToCreateNew) {
+ const editContentFieldToCreateNewColumnName =
+ contentObj.fieldByID(
+ editContentFieldToCreateNew
+ )?.columnName;
+ if (
+ JSON.stringify(
+ newFormData[editContentFieldToCreateNewColumnName] ?? ""
+ ) !==
+ JSON.stringify(
+ contentDataRecord[
+ editContentFieldToCreateNewColumnName
+ ] ?? ""
+ )
+ ) {
+ Webix.confirm({
+ title: this.label("Caution: Creating New Assignment"),
+ ok: this.label("Continue with new assignment"),
+ cancel: this.label("Cancel"),
+ text: this.label(
+ "When you change the Role type or Job title, then the current assignment is closed with the current date and a new assignment is created for this team."
+ ),
+ css: "orgchart-teams-edit-content-confirm-popup",
+ }).then(async () => {
+ this.busy();
+ const pendingPromises = [];
+ const oldData = {};
+
+ oldData[contentDateEndFieldColumnName] = new Date();
+ pendingPromises.push(
+ contentModel.update(dataID, oldData)
+ );
+ newFormData[contentDateStartFieldColumnName] =
+ oldData[contentDateEndFieldColumnName];
+ delete newFormData["id"];
+ delete newFormData["uuid"];
+ delete newFormData[contentDateEndFieldColumnName];
+ pendingPromises.push(contentModel.create(newFormData));
+ try {
+ await Promise.all(pendingPromises);
+ } catch (err) {
+ // TODO (Guy): The update data error.
+ console.error(err);
}
- }
+ try {
+ await Promise.all([
+ this._reloadDCData(teamDC),
+ this._reloadDCData(contentDC),
+ ]);
+ // await this._reloadAllDC();
+ } catch (err) {
+ // TODO (Guy): The reload DCs error.
+ console.error(err);
+ }
+ await this.refresh();
+ $contentNode.remove();
+ this.ready();
+ });
+ return;
+ }
+ }
+ if (
+ new Date(newFormData[contentDateEndFieldColumnName]) <=
+ new Date()
+ ) {
+ Webix.confirm({
+ title: this.label("Caution: Ending Current Assignment"),
+ ok: this.label("Continue with ending this assignment"),
+ cancel: this.label("Cancel"),
+ text: [
+ this.label(
+ "When you provide an End Date, the current assignment is ended when the date = the current date and the assignment will no longer show on this team."
+ ),
+ this.label(
+ "This will put the team member back into the unassigned list box if they have no other active assignments."
+ ),
+ ].join("\n"),
+ css: "orgchart-teams-edit-content-confirm-popup",
+ }).then(async () => {
+ this.busy();
try {
await contentModel.update(dataID, newFormData);
} catch (err) {
@@ -808,9 +844,31 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$contentNode.remove();
this.ready();
});
+ return;
+ }
+ this.busy();
+ try {
+ await contentModel.update(dataID, newFormData);
+ } catch (err) {
+ // TODO (Guy): The update data error.
+ console.error(err);
+ }
+ try {
+ await Promise.all([
+ this._reloadDCData(teamDC),
+ this._reloadDCData(contentDC),
+ ]);
+ // await this._reloadAllDC();
+ } catch (err) {
+ // TODO (Guy): The reload DCs error.
+ console.error(err);
+ }
+ await this.refresh();
+ $contentNode.remove();
+ this.ready();
},
});
- AB.Webix.ui({
+ Webix.ui({
view: "popup",
id: ids.contentForm,
close: true,
@@ -860,7 +918,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
}).show();
const $contentFormData = $$(ids.contentFormData);
- $contentFormData.setValues(contentDataRecord);
+ $contentFormData.setValues(
+ this._convertToFormValueByType(structuredClone(contentDataRecord))
+ );
$contentFormData.show();
};
this._fnShowFilterPopup = async (event) => {
@@ -995,6 +1055,33 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
})();
}
+ _convertToFormValueByType(contentRecord) {
+ const contentAllFields = this._contentDC.datasource.fields();
+ for (const field of contentAllFields) {
+ const columnName = field.columnName;
+ const value = contentRecord[columnName];
+ switch (field.key) {
+ case "boolean":
+ if (value === true) contentRecord[columnName] = 1;
+ else if (value === false) contentRecord[columnName] = 0;
+ else {
+ const parsedValue = parseInt(value);
+ contentRecord[columnName] = isNaN(parsedValue)
+ ? 0
+ : parsedValue;
+ }
+ break;
+ case "date":
+ case "datetime":
+ contentRecord[columnName] = new Date(value);
+ break;
+ default:
+ break;
+ }
+ }
+ return contentRecord;
+ }
+
async _createUIContentRecord(data, color) {
const $ui = element("div", "team-group-record");
$ui.setAttribute("id", this.contentNodeID(data.id));
@@ -1322,22 +1409,80 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
_parseFormValueByType(oldFormData, newFormData) {
- for (const key in newFormData) {
- const oldValue = oldFormData[key];
- const newValue = newFormData[key];
- switch (typeof oldValue) {
- case "boolean":
- if (newValue == 0) newFormData[key] = false;
- else newFormData[key] = true;
- break;
- case "number":
- newFormData[key] = parseInt(newValue);
+ const contentAllFields = this._contentDC.datasource.fields();
+ for (const field of contentAllFields) {
+ const fieldKey = field.key;
+ const columnName = field.columnName;
+ const oldValue = oldFormData[columnName];
+ const newValue = newFormData[columnName];
+ switch (fieldKey) {
+ case "date":
+ case "datetime":
+ if (oldValue === undefined && newValue == null)
+ delete newFormData[columnName];
+ try {
+ newValue instanceof Date &&
+ (newFormData[columnName] = newValue.toISOString());
+ } catch {
+ delete newFormData[columnName];
+ }
break;
- case "string":
- newFormData[key] = newValue?.toString();
+ case "connectObject":
+ switch (typeof oldValue) {
+ case "number":
+ newFormData[columnName] = parseInt(newValue) || null;
+ break;
+ default:
+ newFormData[columnName] = newValue?.toString() || null;
+ break;
+ }
break;
default:
- newFormData[key] = newValue;
+ if (newValue == null || newValue === "")
+ if (oldValue === undefined) {
+ delete newFormData[columnName];
+ break;
+ } else if (oldValue === "") {
+ newFormData[columnName] = "";
+ break;
+ }
+ switch (fieldKey) {
+ case "boolean":
+ switch (typeof oldValue) {
+ case "number":
+ newFormData[columnName] = newValue;
+ break;
+ case "string":
+ newFormData[columnName] = newValue === 1 ? "1" : "0";
+ break;
+ default:
+ newFormData[columnName] = newValue == 1;
+ break;
+ }
+ break;
+ case "number":
+ const paredNewValue = parseInt(newValue);
+ if (isNaN(parseInt(newValue))) {
+ if (oldValue === undefined)
+ delete newFormData[columnName];
+ else newFormData[columnName] = oldValue;
+ break;
+ }
+ switch (typeof oldValue) {
+ case "string":
+ newFormData[columnName] = paredNewValue.toString();
+ break;
+ default:
+ newFormData[columnName] = paredNewValue;
+ break;
+ }
+ break;
+ case "string":
+ newFormData[columnName] = newValue?.toString() || "";
+ break;
+ default:
+ break;
+ }
break;
}
}
@@ -2071,12 +2216,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
.getData(
(contentDisplayRecord) =>
contentDisplayRecord[currentContentDisplayFieldColumnName]
- .toString()
+ ?.toString()
.toLowerCase()
.indexOf(currentContentDisplayFilterValue) > -1
)
.map((contentDisplayRecord) =>
- contentDisplayRecord[currentContentDisplayObjPK].toString()
+ contentDisplayRecord[currentContentDisplayObjPK]?.toString()
);
} else if (currentContentDisplayRecords.length > 0) {
currentContentDisplayFieldColumnName = AB.definitionByID(
@@ -2100,7 +2245,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
) > -1
) > -1
: currentContentDisplayRecords.indexOf(
- contentDisplayRecordData.toString()
+ contentDisplayRecordData?.toString()
) > -1;
})
.map((contentDisplayRecord) =>
@@ -2140,13 +2285,15 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
async teamAddChild(values, isServerSideUpdate = true) {
const entityDC = this._entityDC;
+ const teamDC = this.datacollection;
+ const teamObjID = teamDC.datasource.id;
// Add the entity value
if (entityDC) {
const connection =
isServerSideUpdate &&
entityDC.datasource.connectFields(
- (f) => f.settings.linkObject === datacollection.datasource.id
+ (f) => f.settings.linkObject === teamObjID
)[0];
if (connection) {
const entity = entityDC.getCursor();
@@ -2157,9 +2304,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
}
const _rawData =
- (isServerSideUpdate &&
- (await this.datacollection.model.create(values))) ||
- values;
+ (isServerSideUpdate && (await teamDC.model.create(values))) || values;
const id = _rawData.id;
const linkField = this.AB.definitionByID(
this.getSettingField("teamLink").settings.linkColumn
diff --git a/styles/orgchart-webcomponents.css b/styles/orgchart-webcomponents.css
index e1c4ab88..d8cd1b19 100644
--- a/styles/orgchart-webcomponents.css
+++ b/styles/orgchart-webcomponents.css
@@ -515,3 +515,11 @@ org-chart .slide-left {
org-chart.l2r .node.slide-left, org-chart.r2l .node.slide-left {
left: -40px;
}
+
+.orgchart-teams-edit-content-confirm-popup {
+ min-width: 450px;
+}
+
+.orgchart-teams-edit-content-confirm-popup .webix_popup_button {
+ padding: 0px 10px;
+}
From df70f4959d350e4d971bef45596858fb374becc8 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 9 Jan 2025 10:38:49 +0700
Subject: [PATCH 093/129] Fix the new data panel list render bugs
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 7ae5365b..3434c6d2 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -364,7 +364,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// TODO (Guy): Hardcode data panel DCs for Employee.
$$(this.ids.dataPanel)
- .getChildViews()[1]
+ ?.getChildViews()[1]
.getChildViews()
.forEach(($childView) => $childView.callEvent("onViewShow"));
if (isContentDone) resolve();
@@ -1535,6 +1535,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
});
}
$panel.show(ev.currentTarget, { x: -30, y: -35 });
+ $$(this.ids.dataPanel)
+ .getChildViews()[1]
+ .getChildViews()
+ .forEach(($childView) => $childView.callEvent("onViewShow"));
}
_showOrgChart() {
From efea240c36fa3d463b1c88e56629400376664eee Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 9 Jan 2025 11:03:47 +0700
Subject: [PATCH 094/129] Hide inactive data
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 3434c6d2..dced675c 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1631,10 +1631,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this.clearAll();
this.define(
"data",
- // _dataPanelDC.getData()
// TODO (Guy): Hardcode Employee DC.
_dataPanelDC
.getData((panelRecord) =>
+ panelRecord.isinactive !== "T" &&
header === "Unassigned"
? contentDC.getData(
(contentRecord) =>
From 9062cbd08670f269494c9ab52f52da9c486cead4 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 9 Jan 2025 12:57:35 +0700
Subject: [PATCH 095/129] Fix empty chartData error, Change data panel filter
by tab label -> tab index
---
.../ABViewOrgChartTeamsComponent.js | 27 ++++++++++++++-----
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index dced675c..c2b53f65 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -498,7 +498,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this._waitDCPending(contentDisplayDC)
),
]);
- this.__orgchart.remove();
+ this.__orgchart?.remove();
this.__orgchart = null;
await this.refresh();
this.ready();
@@ -1546,8 +1546,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const AB = this.AB;
const draggable = settings.draggable === 1;
const ids = this.ids;
+ const chartData = this._chartData;
+ if (chartData == null) {
+ this.__orgchart = null;
+ return;
+ }
const orgchart = new this._OrgChart({
- data: AB.cloneDeep(this._chartData),
+ data: AB.cloneDeep(chartData),
direction: settings.direction,
// depth: settings.depth,
chartContainer: `#${ids.chartDom}`,
@@ -1583,7 +1588,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const contentObjID = this._contentDC?.datasource?.id;
const cells = [];
for (const key in dataPanelDCs) {
- const dataPanelDCID = key.split(".")[1];
+ const [tabIndex, dataPanelDCID] = key.split(".");
// TODO (Guy): Hardcode data panel DCs for Employee.
// const _dataPanelDC = _dataPanelDCs.find(
@@ -1635,19 +1640,26 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
_dataPanelDC
.getData((panelRecord) =>
panelRecord.isinactive !== "T" &&
- header === "Unassigned"
+ tabIndex === "0"
? contentDC.getData(
(contentRecord) =>
contentRecord[
contentLinkedFieldColumnName
] == panelRecord.id
)[0] == null
- : contentDC.getData(
+ : tabIndex === "1"
+ ? contentDC.getData(
(contentRecord) =>
contentRecord[
contentLinkedFieldColumnName
] == panelRecord.id
)[0] != null
+ : _dataPanelDCs
+ .find(
+ (dataPanelDC) =>
+ dataPanelDC.id === dataPanelDCID
+ )
+ .getData()
)
.sort((a, b) => {
if (a.firstName < b.firstName) {
@@ -1843,7 +1855,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const _oldOnDragStart = OrgChart.prototype._onDragStart;
OrgChart.prototype._onDragStart = (event) => {
event.dataTransfer.setData("isnode", 1);
- _oldOnDragStart.call(this.__orgchart, event);
+ this.__orgchart != null &&
+ _oldOnDragStart.call(this.__orgchart, event);
};
return OrgChart;
})());
@@ -2085,7 +2098,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const topFromField = dc.getData((e) => e[topNodeColumn] == 1)[0];
topNode = topFromField ? topFromField : topNode;
}
- if (!topNode) return null;
+ if (!topNode) return;
/**
* Recursive function to prepare child node data
From a200f5b7521225676a9c3e9933b4a620a25125bc Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 9 Jan 2025 15:33:56 +0700
Subject: [PATCH 096/129] Hot fix for lost data DC
---
.../ABViewOrgChartTeamsComponent.js | 75 +++++++++++--------
1 file changed, 42 insertions(+), 33 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index c2b53f65..7659a3f6 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -217,6 +217,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
console.log(err);
}
try {
+ // TODO (Guy): Logic to not reload dcs.
await Promise.all([
this._reloadDCData(this.datacollection),
this._reloadDCData(this._contentDC),
@@ -333,6 +334,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
console.error(err);
}
try {
+ // TODO (Guy): Logic to not reload dcs.
await Promise.all([
this._reloadDCData(dc),
this._reloadDCData(this._contentDC),
@@ -416,6 +418,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
await this._waitDCReady(dc);
let records = dc.getData();
try {
+ // TODO (Guy): Figure out later why the employee dc which is not reloaded lost the data.
+ if (records.length < DC_OFFSET) await dc.loadData();
+ records = dc.getData();
if (
records.length < DC_OFFSET ||
(records.length - DC_OFFSET) % RECORD_LIMIT > 0
@@ -790,6 +795,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
console.error(err);
}
try {
+ // TODO (Guy): Logic to not reload dcs.
await Promise.all([
this._reloadDCData(teamDC),
this._reloadDCData(contentDC),
@@ -832,6 +838,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
console.error(err);
}
try {
+ // TODO (Guy): Logic to not reload dcs.
await Promise.all([
this._reloadDCData(teamDC),
this._reloadDCData(contentDC),
@@ -855,6 +862,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
console.error(err);
}
try {
+ // TODO (Guy): Logic to not reload dcs.
await Promise.all([
this._reloadDCData(teamDC),
this._reloadDCData(contentDC),
@@ -1634,42 +1642,43 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const contentLinkedFieldColumnName =
contentLinkedField.columnName;
this.clearAll();
+ debugger;
this.define(
"data",
// TODO (Guy): Hardcode Employee DC.
- _dataPanelDC
- .getData((panelRecord) =>
- panelRecord.isinactive !== "T" &&
- tabIndex === "0"
- ? contentDC.getData(
- (contentRecord) =>
- contentRecord[
- contentLinkedFieldColumnName
- ] == panelRecord.id
- )[0] == null
- : tabIndex === "1"
- ? contentDC.getData(
- (contentRecord) =>
- contentRecord[
- contentLinkedFieldColumnName
- ] == panelRecord.id
- )[0] != null
- : _dataPanelDCs
- .find(
- (dataPanelDC) =>
- dataPanelDC.id === dataPanelDCID
- )
- .getData()
- )
- .sort((a, b) => {
- if (a.firstName < b.firstName) {
- return -1;
- }
- if (a.firstName > b.firstName) {
- return 1;
- }
- return 0;
- })
+ (parseInt(tabIndex) < 2
+ ? _dataPanelDC.getData(
+ (panelRecord) =>
+ panelRecord.isinactive !== "T" &&
+ (tabIndex === "0"
+ ? contentDC.getData(
+ (contentRecord) =>
+ contentRecord[
+ contentLinkedFieldColumnName
+ ] == panelRecord.id
+ )[0] == null
+ : contentDC.getData(
+ (contentRecord) =>
+ contentRecord[
+ contentLinkedFieldColumnName
+ ] == panelRecord.id
+ )[0] != null)
+ )
+ : _dataPanelDCs
+ .find(
+ (dataPanelDC) =>
+ dataPanelDC.id === dataPanelDCID
+ )
+ .getData()
+ ).sort((a, b) => {
+ if (a.firstName < b.firstName) {
+ return -1;
+ }
+ if (a.firstName > b.firstName) {
+ return 1;
+ }
+ return 0;
+ })
);
await self._callAfterRender(() => {
const $itemElements =
From 2c979aa7290862617123d9591e665418f07b9f25 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 9 Jan 2025 15:39:58 +0700
Subject: [PATCH 097/129] sort drop down by label and allow type to filter
---
.../views/viewComponent/ABViewDataSelectComponent.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewDataSelectComponent.js b/AppBuilder/platform/views/viewComponent/ABViewDataSelectComponent.js
index 57660190..a68dbaa0 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewDataSelectComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewDataSelectComponent.js
@@ -16,7 +16,7 @@ export default class ABViewDataSelectComponent extends ABViewComponent {
ui() {
const _ui = super.ui([
{
- view: "richselect",
+ view: "combo",
id: this.ids.select,
on: {
onChange: (n, o) => {
@@ -41,7 +41,8 @@ export default class ABViewDataSelectComponent extends ABViewComponent {
)?.columnName;
const options = dc
.getData()
- .map((o) => ({ id: o.id, value: o[labelField] }));
+ .map((o) => ({ id: o.id, value: o[labelField] }))
+ .sort((a, b) => (a.value > b.value ? 1 : -1));
const $select = $$(this.ids.select);
$select.define("options", options);
$select.refresh();
From d4d77fd554c79caf2cacda98019e06c53c03a5b2 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 10 Jan 2025 11:34:57 +0700
Subject: [PATCH 098/129] Fix the chart exist after switch to empty chart
entity and the team inactive bugs
---
.../ABViewOrgChartTeamsComponent.js | 47 ++++++++++++-------
1 file changed, 31 insertions(+), 16 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 7659a3f6..ee49fabd 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -304,7 +304,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$deleteButton.onclick = () => this.teamDelete(values);
$buttons.append($deleteButton);
}
- if (this.__filters.inactive === 1) {
+ if (this.__filters.inactive == 1) {
const isInactive = data.isInactive;
const activeClass = isInactive ? "is-inactive" : "is-active";
const $active = element("div", `team-button ${activeClass}`);
@@ -1642,7 +1642,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const contentLinkedFieldColumnName =
contentLinkedField.columnName;
this.clearAll();
- debugger;
this.define(
"data",
// TODO (Guy): Hardcode Employee DC.
@@ -2097,6 +2096,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
* load the data and format it for display
*/
async pullData() {
+ this._chartData = null;
const dc = this.datacollection;
if (dc == null) return;
const settings = this.settings;
@@ -2123,7 +2123,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// Don't show inactive teams
if (
!childData ||
- (this.__filters?.inactive !== 1 &&
+ (this.__filters?.inactive == 0 &&
childData[this.getSettingField("teamInactive").columnName])
)
return;
@@ -2381,8 +2381,21 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
values[cName] = entity;
}
}
- const _rawData =
- (isServerSideUpdate && (await teamDC.model.create(values))) || values;
+ let _rawData;
+ try {
+ _rawData =
+ (isServerSideUpdate && (await teamDC.model.create(values))) ||
+ values;
+ } catch (err) {
+ // TODO (Guy): The update error.
+ console.error(err);
+ }
+ if (
+ this.__filters?.inactive == 0 &&
+ (_rawData == null ||
+ _rawData[this.getSettingField("teamInactive").columnName])
+ )
+ return;
const id = _rawData.id;
const linkField = this.AB.definitionByID(
this.getSettingField("teamLink").settings.linkColumn
@@ -2445,7 +2458,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return true;
}
- teamDelete(values) {
+ teamDelete(values, isServerSideUpdate = true) {
if (!this.teamCanDelete(values)) {
this.AB.Webix.message({
text: "This team cannot be deleted",
@@ -2457,7 +2470,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return this.AB.Webix.confirm({
text: "This can't be undone, are you sure?",
}).then(() => {
- this.datacollection.model.delete(values.id);
+ isServerSideUpdate && this.datacollection.model.delete(values.id);
const nodeID = this.teamNodeID(values.id);
this.__orgchart.removeNodes(document.querySelector(`#${nodeID}`));
});
@@ -2471,12 +2484,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// TODO (Guy): Fix the values later.
// delete values[`${strategyLink}__relation`];
- isServerSideUpdate &&
- (await this.datacollection.model
- .update(values.id, values)
- .catch((err) => {
- //TODO
- }));
+ try {
+ isServerSideUpdate &&
+ (await this.datacollection.model.update(values.id, values));
+ } catch (err) {
+ // TODO (Guy): the update error
+ console.error(err);
+ }
const nodeID = this.teamNodeID(values.id);
const node = document.querySelector(`#${nodeID}`);
const currentStrategy = node.classList?.value?.match(/strategy-\S+/)[0];
@@ -2487,12 +2501,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
node.classList?.add(newStrategy);
}
- const inactive = this.getSettingField("teamInactive").columnName;
// Remove inactive node from display, unless the filter setting to show
// inctive nodes is on.
- if (this.__filters?.inactive !== 1 && values[inactive] === 1) {
+ if (
+ this.__filters?.inactive == 0 &&
+ values[this.getSettingField("teamInactive").columnName]
+ )
this.__orgchart.removeNodes(node);
- }
const nameCol = this.getSettingField("teamName").columnName;
node.querySelector(".title").innerHTML = values[nameCol];
}
From 4df1b63fc8a20074c8f0e52125ea274bf1a0598b Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Mon, 13 Jan 2025 16:24:15 +0700
Subject: [PATCH 099/129] fix respond to window resize
---
.../ABViewOrgChartTeamsComponent.js | 141 ++++++++++--------
styles/team-widget.css | 16 +-
2 files changed, 88 insertions(+), 69 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index ee49fabd..ce4754c5 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -10,10 +10,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
Object.assign(
{
chartView: "",
- chartDom: "",
+ // chartDom: "",
chartContent: "",
+ chartHeader: "",
dataPanel: "",
+ dataPanelButton: "",
dataPanelPopup: "",
+ filterButton: "",
filterPopup: "",
filterForm: "",
contentForm: "",
@@ -1010,7 +1013,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
});
}
- $popup.show(event.currentTarget);
+ $popup.show($$(this.ids.filterButton).$view);
};
// Generate strategy css
@@ -1530,7 +1533,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
await this._waitDCReady(dc);
}
- _showDataPanel(ev) {
+ _showDataPanel() {
let $panel = $$(this.ids.dataPanelPopup);
if (!$panel) {
$panel = this.AB.Webix.ui({
@@ -1542,7 +1545,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
modal: true,
});
}
- $panel.show(ev.currentTarget, { x: -30, y: -35 });
+ const $dpButtonWebix = $$(this.ids.dataPanelButton).$view;
+ const $dpButtonElem = $dpButtonWebix.querySelector(".data-panel-button");
+ // Ensure the popup will stay to the right when resizing
+ if (!this._resizeObserver) {
+ this._resizeObserver = new ResizeObserver(() => {
+ $panel.show($dpButtonElem, { x: -30, y: -35 });
+ });
+ }
+ this._resizeObserver.observe($dpButtonWebix);
+ $panel.show($dpButtonElem, { x: -30, y: -35 });
$$(this.ids.dataPanel)
.getChildViews()[1]
.getChildViews()
@@ -1563,7 +1575,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
data: AB.cloneDeep(chartData),
direction: settings.direction,
// depth: settings.depth,
- chartContainer: `#${ids.chartDom}`,
+ // chartContainer: `#${ids.chartDom}`,
pan: true, // settings.pan == 1,
zoom: false, // settings.zoom == 1,
draggable,
@@ -1584,9 +1596,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
orgchart.setAttribute("style", oldOrgchart.getAttribute("style"));
oldOrgchart.remove();
}
- $$(ids.chartContent).$view.children[0].appendChild(
- (this.__orgchart = orgchart)
- );
+ $$(ids.chartContent).$view.appendChild((this.__orgchart = orgchart));
}
_uiDataPanel() {
@@ -1731,6 +1741,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
onClick: {
"data-panel-close": () => {
$$(this.ids.dataPanelPopup).hide();
+ this._resizeObserver?.unobserve(
+ $$(this.ids.dataPanelButton).$view
+ );
return false;
},
},
@@ -1790,63 +1803,59 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const _ui = super.ui([
{
id: ids.chartView,
- view: "template",
+ // view: "template",
responsive: true,
- template: ``,
- css: {
- position: "relative",
- },
- on: {
- onAfterRender() {
- Webix.extend(this, Webix.ProgressBar);
- const chartDom = document.querySelector(`#${ids.chartDom}`);
- chartDom.textContent = "";
- chartDom.innerHTML = "";
- const $chartDomComponents = AB.Webix.ui({
- cols: [
- {
- rows: [
- {
- view: "template",
- height: 50,
- },
- {
- id: ids.chartContent,
- view: "template",
- scroll: "auto",
- },
- ],
+ type: "clean",
+ rows: [
+ {
+ responsive: true,
+ id: ids.chartHeader,
+ view: "toolbar",
+ height: 50,
+ type: "clean",
+ cols: [
+ {
+ view: "template",
+ id: this.ids.filterButton,
+ template: ``,
+ align: "left",
+ onClick: {
+ "filter-button": (ev) => self._fnShowFilterPopup(ev),
},
- ],
- }).$view;
- chartDom.appendChild($chartDomComponents);
-
- // Add the filter button to the UI
- const $filterButton = document.createElement("button");
- $filterButton.innerHTML = ` Filter`;
- $filterButton.classList.add("filter-button");
- $filterButton.onclick = self._fnShowFilterPopup;
- const $dataPanelButton = document.createElement("div");
- $dataPanelButton.innerHTML = `
-
-
- ${self.label("Staff Assignment")}
-
-
`;
- $dataPanelButton.classList.add("data-panel-button");
- $dataPanelButton.querySelector(".data-panel-open").onclick = (
- ev
- ) => self._showDataPanel(ev);
- $chartDomComponents.children[0].children[0].children[0].append(
- $filterButton,
- $dataPanelButton
- );
+ },
+ {
+ view: "template",
+ id: this.ids.dataPanelButton,
+ template: ``,
+ align: "right",
+ onClick: {
+ "data-panel-open": (ev) => self._showDataPanel(ev),
+ },
+ },
+ ],
},
- },
+ {
+ responsive: true,
+ id: ids.chartContent,
+ view: "template",
+ scroll: "auto",
+
+ on: {
+ onAfterRender() {
+ Webix.extend(this, Webix.ProgressBar);
+ },
+ },
+ },
+ ],
},
]);
delete _ui.type;
@@ -2698,27 +2707,27 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
closest(el, fn) {
return (
el &&
- (fn(el) && el !== document.querySelector(`#${this.ids.chartDom}`)
+ (fn(el) && el !== document.querySelector(`#${this.ids.chartContent}`)
? el
: this.closest(el.parentNode, fn))
);
}
busy() {
- const $chartView = $$(this.ids.chartView);
+ const $chartView = $$(this.ids.chartContent);
$chartView.disable();
$chartView.showProgress({ type: "icon" });
}
ready() {
- const $chartView = $$(this.ids.chartView);
+ const $chartView = $$(this.ids.chartContent);
$chartView.enable();
$chartView.hideProgress();
}
};
/**
- * Creates a new HTML element with the given type and classes.
+ * Creates a new HTML element with the given type and classes
* @param {string} type - The type of the HTML element to create.
* @param {string} classes - A space-separated list of classes to add to the element.
* @returns {Element} The newly created HTML element.
diff --git a/styles/team-widget.css b/styles/team-widget.css
index 41396e81..efa6b740 100644
--- a/styles/team-widget.css
+++ b/styles/team-widget.css
@@ -275,6 +275,11 @@ org-chart tr.lines .downLine {
margin-right: 25px;
}
+.data-panel-button .fa-users {
+ display: block;
+ color: #2F27CE;
+}
+
.data-panel-close {
background: #2F27CE;
color: #FFF;
@@ -310,9 +315,14 @@ org-chart tr.lines .downLine {
.data-panel-open {
background: #FFF;
color: #2F27CE;
- border-radius: 5px;
- padding: 4px;
- float: right;
+ font-family: "Roboto";
+ font-size: 17px;
+ font-weight: 900;
+ border-radius: 10px;
+ float: right !important;
+ width: 90%;
+ padding: 5px;
+ margin-left: 10px;
}
.data-panel-open:hover {
From f66f778311d510a9f772150365fca8b9f003334c Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Tue, 14 Jan 2025 14:50:15 +0700
Subject: [PATCH 100/129] fix: hide popup when swicthing to another page
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index ce4754c5..3968d181 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1549,7 +1549,11 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const $dpButtonElem = $dpButtonWebix.querySelector(".data-panel-button");
// Ensure the popup will stay to the right when resizing
if (!this._resizeObserver) {
- this._resizeObserver = new ResizeObserver(() => {
+ this._resizeObserver = new ResizeObserver(([e]) => {
+ // Hide the panel when the widget is hidden (ex. switched to another App)
+ if (e.contentRect.width == 0 && e.contentRect.height == 0) {
+ return $panel.hide();
+ }
$panel.show($dpButtonElem, { x: -30, y: -35 });
});
}
From 6e43546cc5ad6a2fb68cf444af3a578440fd3a7e Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 16 Jan 2025 13:45:34 +0700
Subject: [PATCH 101/129] UI fixes, optimize things and fix bugs
---
.../ABViewOrgChartTeamsComponent.js | 493 ++++++++++++------
styles/team-widget.css | 16 +-
2 files changed, 353 insertions(+), 156 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 3968d181..6109680e 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -263,7 +263,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const $group = element("div", "team-group-section");
$content.appendChild($group);
const groupStyle = $group.style;
- groupStyle["minHeight"] = `${225 / contentGroupOptionsLength}px`;
+ groupStyle["minHeight"] = `${325 / contentGroupOptionsLength}px`;
// TODO: should this be a config option
const groupColor = group.name === "Leader" ? "#003366" : "#DDDDDD";
@@ -301,6 +301,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this.teamForm("Add", { __parentID: dataID });
};
$editButton.onclick = () => this.teamForm("Edit", values);
+ $node.querySelector(".title").ondblclick = () =>
+ this.teamForm("Edit", values);
if (this.teamCanDelete(values)) {
const $deleteButton = element("div", "team-button");
$deleteButton.append(element("i", "fa fa-trash"));
@@ -380,7 +382,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
resolve
);
};
- (this._fnPageContentGroupCallback = async (
+ this._fnPageContentGroupCallback = async (
contentGroupRecords,
isContentGroupDone,
contentGroupDC,
@@ -395,28 +397,28 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this._fnPageContentGroupCallback,
resolve
);
- }),
- (this._fnPageContentDisplayCallback = (
- contentDisplayRecords,
- isContentDisplayDone,
- contentDisplayDC,
- resolve
- ) => {
- const contentDC = this._contentDC;
- this._fnPageContentCallback(
- contentDC.getData(),
- true,
- contentDC,
- () => {}
+ };
+ this._fnPageContentDisplayCallback = (
+ contentDisplayRecords,
+ isContentDisplayDone,
+ contentDisplayDC,
+ resolve
+ ) => {
+ const contentDC = this._contentDC;
+ this._fnPageContentCallback(
+ contentDC.getData(),
+ true,
+ contentDC,
+ () => {}
+ );
+ if (isContentDisplayDone) resolve();
+ else
+ this._callPagingEvent(
+ contentDisplayDC,
+ this._fnPageContentDisplayCallback,
+ resolve
);
- if (isContentDisplayDone) resolve();
- else
- this._callPagingEvent(
- contentDisplayDC,
- this._fnPageContentDisplayCallback,
- resolve
- );
- });
+ };
this._fnPageData = async (dc, callback, resolve) => {
await this._waitDCReady(dc);
let records = dc.getData();
@@ -460,7 +462,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
await this.teamAddChild(teamRecord, false);
$teamNode = document.getElementById(teamNodeID);
if ($teamNode == null) continue;
- } else await this.teamEdit(teamRecord, null, false);
+ } else await this.teamEdit(teamRecord, false);
const contentRecords = contentDC.getData(
(contentRecord) =>
teamRecord[contentFieldColumnName].indexOf(
@@ -525,7 +527,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
"contentFieldDateEnd"
)?.columnName;
const contentDataRecord = JSON.parse(
- event.currentTarget.dataset.source
+ event.currentTarget.dataset.source ||
+ event.currentTarget.parentElement.dataset.source
);
const rules = {};
const labelWidth = 200;
@@ -640,7 +643,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
abWebix.extend(this, abWebix.ProgressBar);
this.showProgress({ type: "icon" });
try {
- // TODO (Guy): Add spinner.
this.define(
"options",
(await fieldLinkObj.model().findAll()).data.map(
@@ -726,24 +728,17 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
click: async () => {
const $contentFormData = $$(ids.contentFormData);
if (!$contentFormData.validate()) return;
- let isDataChanged = false;
const newFormData = this._parseFormValueByType(
+ contentObj,
contentDataRecord,
$contentFormData.getValues()
);
- for (const key in newFormData)
- if (
- JSON.stringify(newFormData[key]) !==
- JSON.stringify(contentDataRecord[key])
- ) {
- isDataChanged = true;
- break;
- }
const $contentForm = $$(ids.contentForm);
$contentForm.blockEvent();
$contentForm.$view.remove();
$contentForm.destructor();
- if (!isDataChanged) return;
+ if (!this._checkDataIsChanged(contentDataRecord, newFormData))
+ return;
const teamDC = this.datacollection;
const contentDC = this._contentDC;
const dataID = newFormData.id;
@@ -1099,7 +1094,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$ui.setAttribute("id", this.contentNodeID(data.id));
$ui.setAttribute("data-source", JSON.stringify(data));
$ui.style.borderColor = color;
- $ui.addEventListener("click", this._fnShowContentForm);
+ $ui.addEventListener("dblclick", this._fnShowContentForm);
if (this.settings.draggable === 1) {
$ui.setAttribute("draggable", "true");
$ui.addEventListener("dragstart", this._fnContentDragStart);
@@ -1322,6 +1317,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
!isShown && (hardcodedDisplayStyle.display = "none");
}
+ const $editIcon = element("div", "team-group-record-edit-icon");
+ $editIcon.appendChild(element("i", "fa fa-pencil"));
+ $editIcon.addEventListener("click", this._fnShowContentForm);
+ $ui.appendChild($editIcon);
return $ui;
}
@@ -1344,6 +1343,14 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this.emit("pageData", dc, callback, resolve);
}
+ _checkDataIsChanged(olaValues, newValues) {
+ // TODO (Guy): Check array in the future.
+ for (const key in newValues)
+ if (JSON.stringify(newValues[key]) !== JSON.stringify(olaValues[key]))
+ return true;
+ return false;
+ }
+
_initDC(dc) {
dc.init();
if (dc.dataStatus === dc.dataStatusFlag.notInitial) dc.loadData();
@@ -1420,12 +1427,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
);
}
- _parseFormValueByType(oldFormData, newFormData) {
- const contentAllFields = this._contentDC.datasource.fields();
- for (const field of contentAllFields) {
+ _parseFormValueByType(obj, oldFormData, newFormData) {
+ const allFields = obj.fields();
+ for (const field of allFields) {
const fieldKey = field.key;
const columnName = field.columnName;
- const oldValue = oldFormData[columnName];
+ const oldValue = oldFormData?.[columnName];
const newValue = newFormData[columnName];
switch (fieldKey) {
case "date":
@@ -1440,14 +1447,23 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
break;
case "connectObject":
- switch (typeof oldValue) {
- case "number":
- newFormData[columnName] = parseInt(newValue) || null;
- break;
- default:
- newFormData[columnName] = newValue?.toString() || null;
- break;
- }
+ delete newFormData[`${columnName}__relation`];
+ if (field.linkType() === "one")
+ switch (typeof oldValue) {
+ case "number":
+ newFormData[columnName] = parseInt(newValue) || null;
+ break;
+ default:
+ newFormData[columnName] = newValue?.toString() || null;
+ if (
+ oldValue === undefined &&
+ newFormData[columnName] == null
+ )
+ delete newFormData[columnName];
+ break;
+ }
+ // TODO (Guy): Many logic in the future. Now we don't have an array data changed.
+ else delete newFormData[columnName];
break;
default:
if (newValue == null || newValue === "")
@@ -2093,6 +2109,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this._resolveInit();
}
+ getChartData(id, chartData = this._chartData) {
+ if (this.teamNodeID(id) === chartData.id) return chartData;
+ if (chartData.children?.length > 0) {
+ for (let child of chartData.children) {
+ child = this.getChartData(id, child);
+ if (child != null) return child;
+ }
+ }
+ }
+
async onShow() {
this.busy();
this.AB.performance.mark("TeamChart.onShow");
@@ -2374,9 +2400,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return this.AB.definitionByID(this.settings[setting]);
}
- async teamAddChild(values, isServerSideUpdate = true) {
+ async teamAddChild(values, isServerSideUpdate = true, children = []) {
const entityDC = this._entityDC;
const teamDC = this.datacollection;
+ const teamObj = teamDC.datasource;
const teamObjID = teamDC.datasource.id;
// Add the entity value
@@ -2394,14 +2421,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
values[cName] = entity;
}
}
- let _rawData;
- try {
- _rawData =
- (isServerSideUpdate && (await teamDC.model.create(values))) ||
- values;
- } catch (err) {
- // TODO (Guy): The update error.
- console.error(err);
+ let _rawData = values;
+ if (isServerSideUpdate) {
+ this.busy();
+ try {
+ _rawData = await teamDC.model.create(values);
+ } catch (err) {
+ // TODO (Guy): The update error.
+ console.error(err);
+ }
+ this.ready();
}
if (
this.__filters?.inactive == 0 &&
@@ -2409,37 +2438,62 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
_rawData[this.getSettingField("teamInactive").columnName])
)
return;
- const id = _rawData.id;
- const linkField = this.AB.definitionByID(
- this.getSettingField("teamLink").settings.linkColumn
- ).columnName;
- const nameField = this.getSettingField("teamName").columnName;
const parent = document.querySelector(
- `#${this.teamNodeID(values[linkField])}`
+ `#${this.teamNodeID(
+ _rawData[
+ this.AB.definitionByID(
+ this.getSettingField("teamLink").settings.linkColumn
+ ).columnName
+ ]
+ )}`
);
if (parent == null) return;
- const strategyLink = this.getSettingField("teamStrategy").columnName;
- const strategyField = this.getSettingField("strategyCode").columnName;
- const strategyCode =
- _rawData[`${strategyLink}__relation`]?.[strategyField];
const hasChild = parent.parentNode.colSpan > 1;
+ const teamID = _rawData.id;
const newChild = {
- name: values[nameField],
- id: this.teamNodeID(id),
+ name: _rawData[this.getSettingField("teamName").columnName],
+ filteredOut: false,
+ isInactive: _rawData[this.getSettingField("teamInactive").columnName],
+ id: this.teamNodeID(teamID),
relationship: hasChild ? "110" : "100",
- className: `strategy-${strategyCode}`,
+ className: `strategy-${
+ _rawData[
+ `${this.getSettingField("teamStrategy").columnName}__relation`
+ ]?.[this.getSettingField("strategyCode").columnName]
+ }`,
_rawData,
};
+ newChild.filteredOut = this.filterTeam(newChild);
// Need to add differently if the node already has child nodes
- if (hasChild) {
- const sibling = this.closest(parent, (el) => el.nodeName === "TABLE")
- .querySelector(".nodes")
- .querySelector(".node");
- this.__orgchart.addSiblings(sibling, { siblings: [newChild] });
- } else {
- this.__orgchart.addChildren(parent, { children: [newChild] });
- }
+ if (hasChild)
+ this.__orgchart.addSiblings(
+ // Sibling
+ this.closest(parent, (el) => el.nodeName === "TABLE")
+ .querySelector(".nodes")
+ .querySelector(".node"),
+ { siblings: [newChild] }
+ );
+ else this.__orgchart.addChildren(parent, { children: [newChild] });
+
+ // TODO(Guy): Render assignment for specific node later.
+ // const contentDC = this._contentDC;
+ // const contentFieldLinkColumnName = teamObj.fieldByID(
+ // this.settings.contentField
+ // ).fieldLink.columnName;
+ // await this._callAfterRender(async () => {
+ // this._fnPageContentCallback(
+ // contentDC.getData((e) => e[contentFieldLinkColumnName] == teamID),
+ // true,
+ // contentDC,
+ // () => {}
+ // );
+ // await Promise.all(
+ // children.map((child) =>
+ // this.teamAddChild(child._rawData, false, child.children)
+ // )
+ // );
+ // });
}
teamCanInactivate(values) {
@@ -2480,95 +2534,137 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
});
return;
}
- return this.AB.Webix.confirm({
- text: "This can't be undone, are you sure?",
- }).then(() => {
- isServerSideUpdate && this.datacollection.model.delete(values.id);
- const nodeID = this.teamNodeID(values.id);
- this.__orgchart.removeNodes(document.querySelector(`#${nodeID}`));
- });
+ const nodeID = this.teamNodeID(values.id);
+ const $teamNode = document.querySelector(`#${nodeID}`);
+ if ($teamNode.querySelectorAll(".team-group-record").length > 0)
+ this.AB.Webix.alert({
+ text: this.label(
+ "Since there are assignments or teams associated with this team, this action cannot be done until all of its assignments are made inactive"
+ ),
+ });
+ else
+ this.AB.Webix.confirm({
+ text: this.label(
+ "This will permanently remove this team. Click OK to continue or Cancel to not remove the team."
+ ),
+ }).then(() => {
+ isServerSideUpdate && this.datacollection.model.delete(values.id);
+ this.__orgchart.removeNodes(document.querySelector(`#${nodeID}`));
+ });
}
- async teamEdit(values, strategy, isServerSideUpdate = true) {
- const strategyLink = this.getSettingField("teamStrategy").columnName;
- const strategyField = this.getSettingField("strategyCode").columnName;
- const strategyCode = strategy?.[strategyField];
- values[strategyLink] = strategy?.id || values[strategyLink];
-
- // TODO (Guy): Fix the values later.
- // delete values[`${strategyLink}__relation`];
- try {
- isServerSideUpdate &&
- (await this.datacollection.model.update(values.id, values));
- } catch (err) {
- // TODO (Guy): the update error
- console.error(err);
- }
- const nodeID = this.teamNodeID(values.id);
- const node = document.querySelector(`#${nodeID}`);
- const currentStrategy = node.classList?.value?.match(/strategy-\S+/)[0];
- const newStrategy =
- (strategyCode && `strategy-${strategyCode}`) || currentStrategy;
- if (currentStrategy !== newStrategy) {
- node.classList?.remove(currentStrategy);
- node.classList?.add(newStrategy);
+ async teamEdit(values, isServerSideUpdate = true) {
+ let _rawData = values;
+ if (isServerSideUpdate) {
+ this.busy();
+ try {
+ _rawData = await this.datacollection.model.update(
+ values.id,
+ values
+ );
+ } catch (err) {
+ // TODO (Guy): the update error
+ console.error(err);
+ }
+ this.ready();
}
+ const $node = document.querySelector(`#${this.teamNodeID(_rawData.id)}`);
// Remove inactive node from display, unless the filter setting to show
// inctive nodes is on.
if (
this.__filters?.inactive == 0 &&
- values[this.getSettingField("teamInactive").columnName]
- )
- this.__orgchart.removeNodes(node);
- const nameCol = this.getSettingField("teamName").columnName;
- node.querySelector(".title").innerHTML = values[nameCol];
+ _rawData[this.getSettingField("teamInactive").columnName]
+ ) {
+ this.__orgchart.removeNodes($node);
+ return;
+ }
+ const oldChartData = JSON.parse($node.dataset.source);
+ const linkFieldColumnName = this.datacollection.datasource.fieldByID(
+ this.getSettingField("teamLink").settings.linkColumn
+ ).columnName;
+ if (
+ oldChartData._rawData[linkFieldColumnName] !=
+ _rawData[linkFieldColumnName]
+ ) {
+ // TODO (Guy): Fix refresh the only updated node and those children and assignments later.
+ await this.refresh();
+ // this.__orgchart.removeNodes($node);
+ // this.teamAddChild(
+ // _rawData,
+ // false,
+ // this.getChartData(_rawData.id)?.children
+ // );
+ return;
+ }
+ const currentStrategy = $node.classList?.value?.match(/strategy-\S+/)[0];
+ const strategyCode =
+ _rawData[
+ `${this.getSettingField("teamStrategy").columnName}__relation`
+ ]?.[this.getSettingField("strategyCode").columnName];
+ const newStrategy =
+ (strategyCode && `strategy-${strategyCode}`) || currentStrategy;
+ if (currentStrategy !== newStrategy) {
+ $node.classList?.remove(currentStrategy);
+ $node.classList?.add(newStrategy);
+ }
+ const teamName = _rawData[this.getSettingField("teamName").columnName];
+ $node.querySelector(".title").innerHTML = teamName;
+ const newChartData = {
+ className: newStrategy,
+ filteredOut: false,
+ id: this.teamNodeID(_rawData.id),
+ isInactive: _rawData[this.getSettingField("teamInactive").columnName],
+ name: teamName,
+ relationship: oldChartData.relationship,
+ _rawData,
+ };
+ newChartData.filteredOut = this.filterTeam(newChartData);
+ $node.dataset.source = JSON.stringify(newChartData);
}
async teamForm(mode, values) {
let $teamFormPopup = $$(this.ids.teamFormPopup);
- const inactive = this.getSettingField("teamInactive").columnName;
- const linkField = this.AB.definitionByID(
- this.getSettingField("teamLink").settings.linkColumn
- ).columnName;
const ids = this.ids;
if (!$teamFormPopup) {
const teamObj = this.datacollection.datasource;
const settings = this.settings;
const nameField = teamObj.fieldByID(settings.teamName);
+ const linkField = teamObj.fieldByID(
+ this.getSettingField("teamLink").settings.linkColumn
+ );
+ const entityDC = this._entityDC;
+ const entityObjID = entityDC.datasource.id;
+ const entityDCCursorID = entityDC.getCursor().id;
const strategyField = teamObj.fieldByID(settings.teamStrategy);
const strategyObj = this.AB.objectByID(
strategyField.settings.linkObject
);
- const entityDC = this._entityDC;
- const entityLink = strategyObj.connectFields(
- (f) => f.settings.linkObject === entityDC.datasource.id
- )[0];
- const cond = {
+ const teamCond = {
glue: "and",
rules: [
{
- key: entityLink.columnName,
- value: entityDC.getCursor().id,
+ key: teamObj.connectFields(
+ (f) => f.settings.linkObject === entityObjID
+ )[0].columnName,
+ value: entityDCCursorID,
rule: "equals",
},
],
};
- const subCol = this.getSettingField("subStrategy").columnName;
- this.entitySrategyOptions = await strategyField.getOptions(
- cond,
- null,
- null,
- null,
- [subCol]
- );
-
- const strategyOptions = this.entitySrategyOptions.map((o) => {
- return {
- id: o.id,
- value: o[`${subCol}__relation`].name,
- };
- });
+ const strategyCond = {
+ glue: "and",
+ rules: [
+ {
+ key: strategyObj.connectFields(
+ (f) => f.settings.linkObject === entityObjID
+ )[0].columnName,
+ value: entityDCCursorID,
+ rule: "equals",
+ },
+ ],
+ };
+ const subStrategyCol = this.getSettingField("subStrategy").columnName;
$teamFormPopup = webix.ui({
view: "popup",
id: ids.teamFormPopup,
@@ -2599,6 +2695,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
{
view: "form",
id: ids.teamForm,
+ hidden: true,
borderless: true,
elements: [
{
@@ -2611,33 +2708,114 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
view: "richselect",
label: strategyField.label,
name: strategyField.columnName,
- options: strategyOptions,
+ options: [],
required: true,
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.disable();
+ this.define(
+ "options",
+ (
+ await strategyField.getOptions(
+ strategyCond,
+ null,
+ null,
+ null,
+ [subStrategyCol]
+ )
+ ).map((e) => ({
+ id: e.id,
+ value: e[
+ `${subStrategyCol}__relation`
+ ].name,
+ // value: strategyObj.displayData(e),
+ }))
+ );
+ this.refresh();
+ this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
+ },
+ },
+ },
+ {
+ view: "combo",
+ label: linkField.label,
+ name: linkField.columnName,
+ options: [],
+ required: true,
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.disable();
+ this.define(
+ "options",
+ (
+ await linkField.getOptions(teamCond)
+ ).map((e) => ({
+ id: e.id,
+ value: teamObj.displayData(e),
+ }))
+ );
+ this.refresh();
+ this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
+ },
+ },
},
{
view: "switch",
id: ids.teamFormInactive,
- name: inactive,
+ name: this.getSettingField("teamInactive")
+ .columnName,
label: "Inactive",
},
{ view: "text", name: "id", hidden: true },
- { view: "text", name: linkField, hidden: true },
{
id: ids.teamFormSubmit,
view: "button",
value: this.label("Save"),
disabled: true,
css: "webix_primary",
- click: () => {
- const values = $$(ids.teamForm).getValues();
- const strategy = strategyOptions.find(
- (f) =>
- f.id === values[strategyField.columnName]
- );
- if (values.id) {
- this.teamEdit(values, strategy);
+ click: async () => {
+ let newValues = $$(ids.teamForm).getValues();
+ if (newValues.id) {
+ const $node = document.getElementById(
+ this.teamNodeID(newValues.id)
+ );
+ const oldValues = JSON.parse(
+ $node.dataset.source
+ )._rawData;
+ newValues = this._parseFormValueByType(
+ teamObj,
+ oldValues,
+ newValues
+ );
+ if (
+ !this._checkDataIsChanged(
+ oldValues,
+ newValues
+ )
+ )
+ return;
+ this.teamEdit(newValues);
} else {
- this.teamAddChild(values, strategy);
+ newValues = this._parseFormValueByType(
+ teamObj,
+ null,
+ newValues
+ );
+ this.teamAddChild(newValues);
}
$teamFormPopup.hide();
},
@@ -2648,7 +2826,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const values = $$(ids.teamForm).getValues();
const valid =
!!values[strategyField.columnName] &&
- !!values[nameField.columnName];
+ !!values[nameField.columnName] &&
+ !!values[linkField.columnName];
const $teamFormSubmit = $$(ids.teamFormSubmit);
if (valid) $teamFormSubmit.enable();
else $teamFormSubmit.disable();
@@ -2657,6 +2836,14 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
],
},
+ on: {
+ onShow() {
+ $$(ids.teamForm).show();
+ },
+ onHide() {
+ $$(ids.teamForm).hide();
+ },
+ },
});
}
if (values.__parentID) {
diff --git a/styles/team-widget.css b/styles/team-widget.css
index efa6b740..4877596d 100644
--- a/styles/team-widget.css
+++ b/styles/team-widget.css
@@ -5,7 +5,7 @@ org-chart .node {
border: 2px dashed transparent;
text-align: center;
justify-content: center;
- width: 325px !important;
+ width: 450px !important;
font-family: "Jomhuria", sans-serif;
font-style: normal;
font-weight: 200;
@@ -38,7 +38,7 @@ org-chart .node .content {
position: relative;
top: -15px;
width: 100%;
- min-height: 225px;
+ min-height: 325px;
border-radius: 0 0 15px 15px;
display: flex;
flex-direction: column;
@@ -98,7 +98,7 @@ org-chart tr.lines .downLine {
flex-direction: row;
align-items: center;
justify-content: center;
- gap: 8%;
+ gap: 5%;
}
.team-group-record:hover {
@@ -397,3 +397,13 @@ org-chart tr.lines .downLine {
width: 0;
height: 0;
}
+
+org-chart .team-group-record > .team-group-record-edit-icon {
+ cursor: pointer;
+ display: none;
+ padding: 4px;
+}
+
+org-chart .team-group-record:hover > .team-group-record-edit-icon {
+ display: block;
+}
From d729452305efeb44f34467a7b2883ec8005a9378 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 09:13:16 +0700
Subject: [PATCH 102/129] Sort the data panel by lastname and convert to
lowercase before sort
---
.../viewComponent/ABViewOrgChartTeamsComponent.js | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 6109680e..72b4963d 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1700,10 +1700,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
)
.getData()
).sort((a, b) => {
- if (a.firstName < b.firstName) {
+ if (
+ a.lastName.toLowerCase() <
+ b.lastName.toLowerCase()
+ ) {
return -1;
}
- if (a.firstName > b.firstName) {
+ if (
+ a.lastName.toLowerCase() >
+ b.lastName.toLowerCase()
+ ) {
return 1;
}
return 0;
@@ -2201,7 +2207,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
} else {
// sort children alphaetically
node.children = node.children.sort((a, b) =>
- a.name > b.name ? 1 : -1
+ a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1
);
}
};
From fa3786975e4465c3b16d9c163000d45d31f86cc1 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 09:26:24 +0700
Subject: [PATCH 103/129] Fix the bug missing the param
---
.../viewComponent/ABViewOrgChartTeamsComponent.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 72b4963d..e7776cd3 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -2630,15 +2630,15 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
async teamForm(mode, values) {
- let $teamFormPopup = $$(this.ids.teamFormPopup);
+ const teamObj = this.datacollection.datasource;
+ const linkField = teamObj.fieldByID(
+ this.getSettingField("teamLink").settings.linkColumn
+ );
const ids = this.ids;
+ let $teamFormPopup = $$(ids.teamFormPopup);
if (!$teamFormPopup) {
- const teamObj = this.datacollection.datasource;
const settings = this.settings;
const nameField = teamObj.fieldByID(settings.teamName);
- const linkField = teamObj.fieldByID(
- this.getSettingField("teamLink").settings.linkColumn
- );
const entityDC = this._entityDC;
const entityObjID = entityDC.datasource.id;
const entityDCCursorID = entityDC.getCursor().id;
From 26d8f36029decb4aceb5a704b754612208491431 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 10:08:35 +0700
Subject: [PATCH 104/129] Hide a trash can when there is at least one
assignment
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index e7776cd3..380aacaa 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1032,6 +1032,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const contentGroupDataPK =
contentRecord[this.getSettingField("contentGroupByField").columnName];
const contentGroupPKField = contentGroupDC.datasource.PK();
+
+ // Hide a trash can when there is at least one assignment.
+ const $trashCan = $teamNode.querySelectorAll(".team-button").item(2);
+ $trashCan && ($trashCan.style.display = "none");
if (
contentGroupDC.getData(
(e) => e[contentGroupPKField] == contentGroupDataPK
From 5ca61489ed362e165d8527fd853f48567932e90b Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 11:07:20 +0700
Subject: [PATCH 105/129] Can not inactive if there is an assignment on the
team
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 380aacaa..30466309 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -2520,8 +2520,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
)
)
return false;
- // @TODO check for active assignment
- // if (hasActiveAssignment) return false;
+ if (
+ document
+ .getElementById(this.teamNodeID(values.id))
+ .querySelectorAll(".team-group-record").length > 0
+ )
+ return false;
return true;
}
From b7a7144a4189aa24e794801e974a4fc8a618c4f8 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 16 Jan 2025 16:48:28 +0700
Subject: [PATCH 106/129] when drag from employee list don't end existing
assignment
---
AppBuilder/core | 2 +-
.../ABViewOrgChartTeamsComponent.js | 26 ++++++++++---------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/AppBuilder/core b/AppBuilder/core
index 621864a4..a45f2151 160000
--- a/AppBuilder/core
+++ b/AppBuilder/core
@@ -1 +1 @@
-Subproject commit 621864a47ee17a6ee68891fda4ee1996502ce57a
+Subproject commit a45f21514a1be50256f217d60491847438f52af6
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 6109680e..50f5d650 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -131,18 +131,20 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentObj.fieldByID(contentLinkedFieldID).columnName;
const pendingPromises = [];
const newDate = new Date();
- const $contentRecords =
- document.getElementsByClassName("team-group-record");
- for (const $contentRecord of $contentRecords) {
- const contentData = JSON.parse($contentRecord.dataset.source);
- if (contentData[contentLinkedFieldColumnName] == dataPK) {
- contentData[contentDateEndFieldColumnName] = newDate;
- pendingPromises.push(
- contentModel.update(contentData.id, contentData)
- );
- draggedNodes.push($contentRecord);
- }
- }
+ // Employee can have multiple assignments, so don't close
+ // existing
+ // const $contentRecords =
+ // document.getElementsByClassName("team-group-record");
+ // for (const $contentRecord of $contentRecords) {
+ // const contentData = JSON.parse($contentRecord.dataset.source);
+ // if (contentData[contentLinkedFieldColumnName] == dataPK) {
+ // contentData[contentDateEndFieldColumnName] = newDate;
+ // pendingPromises.push(
+ // contentModel.update(contentData.id, contentData)
+ // );
+ // draggedNodes.push($contentRecord);
+ // }
+ // }
updatedData = {};
updatedData[contentDateStartFieldColumnName] = newDate;
updatedData[contentLinkedFieldColumnName] =
From dc1591bd9ccc26e83ac9a80c94cd86c09e517230 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 14:37:45 +0700
Subject: [PATCH 107/129] Fix conection field render and hardcode for the Role
Type filter
---
.../ABViewOrgChartTeamsComponent.js | 196 +++++++++++++-----
1 file changed, 141 insertions(+), 55 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 30466309..855d62fe 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -933,7 +933,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this._fnShowFilterPopup = async (event) => {
const contentDisplayedFieldFilters =
this.settings.contentDisplayedFieldFilters;
- let $popup = $$(this.ids.filterPopup);
+ const ids = this.ids;
+ let $popup = $$(ids.filterPopup);
if (!$popup) {
const strategyID =
this.getSettingField("teamStrategy").settings.linkObject;
@@ -942,73 +943,158 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const strategyCodeField = strategyObj.fields(
(f) => f.id === strategyCodeFieldID
)[0];
- const strategyOptions = await strategyCodeField.getOptions();
-
$popup = webix.ui({
view: "popup",
css: "filter-popup",
- id: this.ids.filterPopup,
+ id: ids.filterPopup,
body: {
- view: "form",
- borderless: true,
- id: this.ids.filterForm,
- elements: [
- {
- view: "text",
- label: this.label("Team Name"),
- labelWidth: 90,
- name: "teamName",
- clear: true,
- },
- {
- view: "combo",
- label: this.label("Strategy"),
- labelWidth: 90,
- options: strategyOptions.map(fieldToOption),
- name: "strategy",
- clear: "replace",
- },
+ rows: [
{
- view: "checkbox",
- name: "inactive",
- labelRight: this.label("Show Inactive Teams"),
- labelWidth: 0,
- },
- ...(() => {
- const contentDisplayedFieldFilterViews = [];
- for (const contentDisplayedFieldFilterKey in contentDisplayedFieldFilters) {
- if (
- contentDisplayedFieldFilterKey.split(".")[3] == 1
- ) {
- contentDisplayedFieldFilterViews.push({
- view: "text",
- label: contentDisplayedFieldFilters[
- contentDisplayedFieldFilterKey
- ],
- labelWidth: 90,
- name: contentDisplayedFieldFilterKey,
- clear: true,
- });
- }
- }
- return contentDisplayedFieldFilterViews;
- })(),
- {
- cols: [
- {},
+ view: "form",
+ borderless: true,
+ hidden: true,
+ id: ids.filterForm,
+ elements: [
{
- view: "icon",
- icon: "fa fa-check",
- css: "filter-apply",
- click: () => this.filterApply(),
+ view: "text",
+ label: this.label("Team Name"),
+ labelWidth: 100,
+ name: "teamName",
+ clear: true,
+ },
+ {
+ view: "combo",
+ label: this.label("Strategy"),
+ labelWidth: 100,
+ options: [],
+ name: "strategy",
+ clear: "replace",
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.define(
+ "options",
+ (
+ await strategyCodeField.getOptions()
+ ).map(fieldToOption)
+ );
+ this.refresh();
+ this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
+ },
+ },
+ },
+ {
+ view: "checkbox",
+ name: "inactive",
+ labelRight: this.label("Show Inactive Teams"),
+ labelWidth: 0,
+ },
+ ...(() => {
+ const contentDisplayedFieldFilterViews = [];
+ for (const contentDisplayedFieldFilterKey in contentDisplayedFieldFilters) {
+ const [, objID, fieldID, isActive] =
+ contentDisplayedFieldFilterKey.split(".");
+ if (isActive == 1)
+ switch (fieldID) {
+ // TODO (Guy): Hardcode for the role type filter.
+ case "96dc0d8d-7fb4-4bb1-8b80-a262aae41eed":
+ const obj = this.AB.objectByID(objID);
+ const model = obj.model();
+ const fieldColumnName =
+ obj.fieldByID(fieldID).columnName;
+ contentDisplayedFieldFilterViews.push(
+ {
+ view: "combo",
+ label: contentDisplayedFieldFilters[
+ contentDisplayedFieldFilterKey
+ ],
+ labelWidth: 100,
+ options: [],
+ name: contentDisplayedFieldFilterKey,
+ clear: "replace",
+ on: {
+ async onViewShow() {
+ webix.extend(
+ this,
+ webix.ProgressBar
+ );
+ this.showProgress({
+ type: "icon",
+ });
+ try {
+ this.define(
+ "options",
+ (
+ await model.findAll()
+ ).data.map((e) => ({
+ id: e[
+ fieldColumnName
+ ],
+ value: e[
+ fieldColumnName
+ ],
+ }))
+ );
+ this.refresh();
+ this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
+ },
+ },
+ }
+ );
+ break;
+ default:
+ contentDisplayedFieldFilterViews.push(
+ {
+ view: "text",
+ label: contentDisplayedFieldFilters[
+ contentDisplayedFieldFilterKey
+ ],
+ labelWidth: 100,
+ name: contentDisplayedFieldFilterKey,
+ clear: true,
+ }
+ );
+ break;
+ }
+ }
+ return contentDisplayedFieldFilterViews;
+ })(),
+ {
+ cols: [
+ {},
+ {
+ view: "icon",
+ icon: "fa fa-check",
+ css: "filter-apply",
+ click: () => this.filterApply(),
+ },
+ ],
},
],
},
],
},
+ on: {
+ onShow() {
+ $$(ids.filterForm).show();
+ },
+ onHide() {
+ $$(ids.filterForm).hide();
+ },
+ },
});
}
- $popup.show($$(this.ids.filterButton).$view);
+ $popup.show($$(ids.filterButton).$view);
};
// Generate strategy css
From 95bc31d059cb8cbac410c68cf2f998ec7a55b678 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 16:40:57 +0700
Subject: [PATCH 108/129] Fix the bug that the add/edit team popup is alway the
first time created mode
---
.../ABViewOrgChartTeamsComponent.js | 414 +++++++++---------
1 file changed, 202 insertions(+), 212 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 855d62fe..a21807e8 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -25,7 +25,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
teamFormPopup: "",
teamFormSubmit: "",
teamFormTitle: "",
- teamFormInactive: "",
},
ids
)
@@ -2725,241 +2724,232 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
async teamForm(mode, values) {
const teamObj = this.datacollection.datasource;
+ const ids = this.ids;
+ const settings = this.settings;
+ const nameField = teamObj.fieldByID(settings.teamName);
+ const entityDC = this._entityDC;
+ const entityObjID = entityDC.datasource.id;
+ const entityDCCursorID = entityDC.getCursor().id;
+ const strategyField = teamObj.fieldByID(settings.teamStrategy);
+ const strategyObj = this.AB.objectByID(strategyField.settings.linkObject);
const linkField = teamObj.fieldByID(
this.getSettingField("teamLink").settings.linkColumn
);
- const ids = this.ids;
- let $teamFormPopup = $$(ids.teamFormPopup);
- if (!$teamFormPopup) {
- const settings = this.settings;
- const nameField = teamObj.fieldByID(settings.teamName);
- const entityDC = this._entityDC;
- const entityObjID = entityDC.datasource.id;
- const entityDCCursorID = entityDC.getCursor().id;
- const strategyField = teamObj.fieldByID(settings.teamStrategy);
- const strategyObj = this.AB.objectByID(
- strategyField.settings.linkObject
- );
- const teamCond = {
- glue: "and",
- rules: [
+ const linkFieldColumnName = linkField.columnName;
+ const isEditMode = mode === "Edit";
+ const teamCond = {
+ glue: "and",
+ rules: [
+ {
+ key: teamObj.connectFields(
+ (f) => f.settings.linkObject === entityObjID
+ )[0].columnName,
+ value: entityDCCursorID,
+ rule: "equals",
+ },
+ ],
+ };
+ const strategyCond = {
+ glue: "and",
+ rules: [
+ {
+ key: strategyObj.connectFields(
+ (f) => f.settings.linkObject === entityObjID
+ )[0].columnName,
+ value: entityDCCursorID,
+ rule: "equals",
+ },
+ ],
+ };
+ const subStrategyCol = this.getSettingField("subStrategy").columnName;
+ const $teamFormPopup = webix.ui({
+ view: "popup",
+ id: ids.teamFormPopup,
+ close: true,
+ position: "center",
+ css: { "border-radius": "10px" },
+ body: {
+ rows: [
{
- key: teamObj.connectFields(
- (f) => f.settings.linkObject === entityObjID
- )[0].columnName,
- value: entityDCCursorID,
- rule: "equals",
+ view: "toolbar",
+ css: "webix_dark",
+ cols: [
+ { width: 5 },
+ {
+ view: "label",
+ label: `${this.label(mode)} Team`,
+ align: "left",
+ },
+ {
+ view: "icon",
+ icon: "fa fa-times",
+ align: "right",
+ width: 60,
+ click: () => {
+ $teamFormPopup.blockEvent();
+ $teamFormPopup.$view.remove();
+ $teamFormPopup.destructor();
+ },
+ },
+ ],
},
- ],
- };
- const strategyCond = {
- glue: "and",
- rules: [
{
- key: strategyObj.connectFields(
- (f) => f.settings.linkObject === entityObjID
- )[0].columnName,
- value: entityDCCursorID,
- rule: "equals",
- },
- ],
- };
- const subStrategyCol = this.getSettingField("subStrategy").columnName;
- $teamFormPopup = webix.ui({
- view: "popup",
- id: ids.teamFormPopup,
- close: true,
- position: "center",
- css: { "border-radius": "10px" },
- body: {
- rows: [
- {
- view: "toolbar",
- css: "webix_dark",
- cols: [
- { width: 5 },
- {
- id: ids.teamFormTitle,
- view: "label",
- align: "left",
- },
- {
- view: "icon",
- icon: "fa fa-times",
- align: "right",
- width: 60,
- click: () => $teamFormPopup.hide(),
- },
- ],
- },
- {
- view: "form",
- id: ids.teamForm,
- hidden: true,
- borderless: true,
- elements: [
- {
- view: "text",
- label: nameField.label,
- name: nameField.columnName,
- required: true,
- },
- {
- view: "richselect",
- label: strategyField.label,
- name: strategyField.columnName,
- options: [],
- required: true,
- on: {
- async onViewShow() {
- webix.extend(this, webix.ProgressBar);
- this.showProgress({ type: "icon" });
- try {
- this.disable();
- this.define(
- "options",
- (
- await strategyField.getOptions(
- strategyCond,
- null,
- null,
- null,
- [subStrategyCol]
- )
- ).map((e) => ({
- id: e.id,
- value: e[
- `${subStrategyCol}__relation`
- ].name,
- // value: strategyObj.displayData(e),
- }))
- );
- this.refresh();
- this.enable();
- this.hideProgress();
- } catch {
- // Close popup before response or possily response fail
- }
- },
+ view: "form",
+ id: ids.teamForm,
+ hidden: true,
+ borderless: true,
+ elements: [
+ {
+ view: "text",
+ label: nameField.label,
+ name: nameField.columnName,
+ required: true,
+ },
+ {
+ view: "richselect",
+ label: strategyField.label,
+ name: strategyField.columnName,
+ options: [],
+ required: true,
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.disable();
+ this.define(
+ "options",
+ (
+ await strategyField.getOptions(
+ strategyCond,
+ null,
+ null,
+ null,
+ [subStrategyCol]
+ )
+ ).map((e) => ({
+ id: e.id,
+ value: e[`${subStrategyCol}__relation`]
+ .name,
+ // value: strategyObj.displayData(e),
+ }))
+ );
+ this.refresh();
+ this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
},
},
- {
- view: "combo",
- label: linkField.label,
- name: linkField.columnName,
- options: [],
- required: true,
- on: {
- async onViewShow() {
- webix.extend(this, webix.ProgressBar);
- this.showProgress({ type: "icon" });
- try {
- this.disable();
- this.define(
- "options",
- (
- await linkField.getOptions(teamCond)
- ).map((e) => ({
+ },
+ {
+ view: "combo",
+ label: linkField.label,
+ name: linkFieldColumnName,
+ options: [],
+ required: true,
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.disable();
+ this.define(
+ "options",
+ (await linkField.getOptions(teamCond)).map(
+ (e) => ({
id: e.id,
value: teamObj.displayData(e),
- }))
- );
- this.refresh();
- this.enable();
- this.hideProgress();
- } catch {
- // Close popup before response or possily response fail
- }
- },
- },
- },
- {
- view: "switch",
- id: ids.teamFormInactive,
- name: this.getSettingField("teamInactive")
- .columnName,
- label: "Inactive",
- },
- { view: "text", name: "id", hidden: true },
- {
- id: ids.teamFormSubmit,
- view: "button",
- value: this.label("Save"),
- disabled: true,
- css: "webix_primary",
- click: async () => {
- let newValues = $$(ids.teamForm).getValues();
- if (newValues.id) {
- const $node = document.getElementById(
- this.teamNodeID(newValues.id)
- );
- const oldValues = JSON.parse(
- $node.dataset.source
- )._rawData;
- newValues = this._parseFormValueByType(
- teamObj,
- oldValues,
- newValues
- );
- if (
- !this._checkDataIsChanged(
- oldValues,
- newValues
+ })
)
- )
- return;
- this.teamEdit(newValues);
- } else {
- newValues = this._parseFormValueByType(
- teamObj,
- null,
- newValues
);
- this.teamAddChild(newValues);
+ this.refresh();
+ isEditMode && this.enable();
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
}
- $teamFormPopup.hide();
},
},
- ],
- on: {
- onChange: () => {
- const values = $$(ids.teamForm).getValues();
- const valid =
- !!values[strategyField.columnName] &&
- !!values[nameField.columnName] &&
- !!values[linkField.columnName];
- const $teamFormSubmit = $$(ids.teamFormSubmit);
- if (valid) $teamFormSubmit.enable();
- else $teamFormSubmit.disable();
+ },
+ {
+ view: "switch",
+ disabled: !this.teamCanInactivate(values),
+ name: this.getSettingField("teamInactive").columnName,
+ label: "Inactive",
+ },
+ { view: "text", name: "id", hidden: true },
+ {
+ id: ids.teamFormSubmit,
+ view: "button",
+ value: this.label("Save"),
+ disabled: true,
+ css: "webix_primary",
+ click: async () => {
+ let newValues = $$(ids.teamForm).getValues();
+ if (newValues.id) {
+ const $node = document.getElementById(
+ this.teamNodeID(newValues.id)
+ );
+ const oldValues = JSON.parse(
+ $node.dataset.source
+ )._rawData;
+ newValues = this._parseFormValueByType(
+ teamObj,
+ oldValues,
+ newValues
+ );
+ if (
+ !this._checkDataIsChanged(oldValues, newValues)
+ )
+ return;
+ this.teamEdit(newValues);
+ } else {
+ newValues = this._parseFormValueByType(
+ teamObj,
+ null,
+ newValues
+ );
+ this.teamAddChild(newValues);
+ }
+ $teamFormPopup.blockEvent();
+ $teamFormPopup.$view.remove();
+ $teamFormPopup.destructor();
},
},
+ ],
+ on: {
+ onChange: () => {
+ const values = $$(ids.teamForm).getValues();
+ let valid =
+ !!values[strategyField.columnName] &&
+ !!values[nameField.columnName];
+ if (isEditMode)
+ valid = valid && !!values[linkFieldColumnName];
+ const $teamFormSubmit = $$(ids.teamFormSubmit);
+ if (valid) $teamFormSubmit.enable();
+ else $teamFormSubmit.disable();
+ },
},
- ],
- },
- on: {
- onShow() {
- $$(ids.teamForm).show();
- },
- onHide() {
- $$(ids.teamForm).hide();
},
+ ],
+ },
+ on: {
+ onShow() {
+ $$(ids.teamForm).show();
},
- });
- }
+ onHide() {
+ this.$view.remove();
+ this.destructor();
+ },
+ },
+ });
if (values.__parentID) {
- values[linkField] = values.__parentID;
+ values[linkFieldColumnName] = values.__parentID;
delete values.__parentID;
}
- $$(ids.teamFormTitle).setValue(`${this.label(mode)} Team`);
$$(ids.teamForm).setValues(values);
- $$(ids.teamFormSubmit).disable();
-
- this.teamCanInactivate(values)
- ? $$(ids.teamFormInactive).enable()
- : $$(ids.teamFormInactive).disable();
- if (mode === "Edit") {
- // Check if we can inactivate
- }
$teamFormPopup.show();
}
From 524f64d5f4c60c8d2a1177c1ef496ef3a80e7d3b Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 17 Jan 2025 17:33:52 +0700
Subject: [PATCH 109/129] Validate End Date > Start Date
---
.../ABViewOrgChartTeamsComponent.js | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index a21807e8..975d82bc 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -519,9 +519,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const settings = this.settings;
const editContentFieldsToCreateNew =
settings.editContentFieldsToCreateNew;
- const contentDateStartFieldColumnName = this.getSettingField(
- "contentFieldDateStart"
- )?.columnName;
+ const contentDateStartField = contentObj.fields(
+ (field) => field.id === settings.contentFieldDateStart
+ )[0];
+ const contentDateStartFieldLabel = contentDateStartField?.label;
+ const contentDateStartFieldColumnName =
+ contentDateStartField?.columnName;
const contentDateEndFieldColumnName = this.getSettingField(
"contentFieldDateEnd"
)?.columnName;
@@ -550,8 +553,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
let invalidMessage = "";
switch (fieldName) {
case contentDateEndFieldColumnName:
- invalidMessage = `The ${field.label} must be today or earlier.`;
- rules[fieldName] = (value) => value <= new Date();
+ invalidMessage = `The ${field.label} must be later than the ${contentDateStartFieldLabel}.`;
+ rules[fieldName] = (value) =>
+ value >
+ $$(ids.contentFormData).getValues()[
+ contentDateStartFieldColumnName
+ ];
break;
default:
rules[fieldName] = () => true;
From 0d09a91bd5fdc5cb38406cf29540d370df926b5c Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Mon, 20 Jan 2025 10:43:59 +0700
Subject: [PATCH 110/129] Fix sort
---
.../ABViewOrgChartTeamsComponent.js | 53 ++++++++-----------
1 file changed, 22 insertions(+), 31 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 975d82bc..09286067 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1795,21 +1795,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
dataPanelDC.id === dataPanelDCID
)
.getData()
- ).sort((a, b) => {
- if (
- a.lastName.toLowerCase() <
- b.lastName.toLowerCase()
- ) {
- return -1;
- }
- if (
- a.lastName.toLowerCase() >
- b.lastName.toLowerCase()
- ) {
- return 1;
- }
- return 0;
- })
+ ).sort(sort)
);
await self._callAfterRender(() => {
const $itemElements =
@@ -2302,9 +2288,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete node.children;
} else {
// sort children alphaetically
- node.children = node.children.sort((a, b) =>
- a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1
- );
+ node.children = node.children.sort(sort);
}
};
const chartData = (this._chartData = {
@@ -2323,14 +2307,23 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
pullChildData(chartData);
}
- async refresh() {
+ async refresh(force = true) {
const ids = this.ids;
$$(ids.teamFormPopup)?.destructor();
$$(ids.contentForm)?.destructor();
await this.pullData();
// this._showDataPanel();
this._showOrgChart();
- this._pageData();
+ (force && this._pageData()) ||
+ (await this._callAfterRender(() => {
+ const contentDC = this._contentDC;
+ this._fnPageContentCallback(
+ contentDC.getData(),
+ true,
+ contentDC,
+ () => {}
+ );
+ }));
}
async filterApply() {
@@ -2341,17 +2334,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this.__filters = $$(ids.filterForm).getValues();
this.__orgchart?.remove();
this.__orgchart = null;
- await this.pullData();
- this._showOrgChart();
- await this._callAfterRender(() => {
- const contentDC = this._contentDC;
- this._fnPageContentCallback(
- contentDC.getData(),
- true,
- contentDC,
- () => {}
- );
- });
+ await this.refresh(false);
this.ready();
}
@@ -2577,6 +2560,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
{ siblings: [newChild] }
);
else this.__orgchart.addChildren(parent, { children: [newChild] });
+ await this.refresh(false);
// TODO(Guy): Render assignment for specific node later.
// const contentDC = this._contentDC;
@@ -3032,3 +3016,10 @@ function fieldToOption(f) {
value: f.text,
};
}
+
+function sort(a, b) {
+ return (a.lastName ?? a.name).toLowerCase() >
+ (b.lastName ?? b.name).toLowerCase()
+ ? 1
+ : -1;
+}
From 5b6f17741ad0e20d2a7bf072491101755162101b Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Mon, 20 Jan 2025 11:39:11 +0700
Subject: [PATCH 111/129] Fix the refresh param
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 5cc5d87e..03f75fdd 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -2562,7 +2562,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
{ siblings: [newChild] }
);
else this.__orgchart.addChildren(parent, { children: [newChild] });
- await this.refresh(false);
+ await this.refresh(isServerSideUpdate);
// TODO(Guy): Render assignment for specific node later.
// const contentDC = this._contentDC;
@@ -2680,7 +2680,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
_rawData[linkFieldColumnName]
) {
// TODO (Guy): Fix refresh the only updated node and those children and assignments later.
- await this.refresh();
+ await this.refresh(isServerSideUpdate);
// this.__orgchart.removeNodes($node);
// this.teamAddChild(
// _rawData,
@@ -2713,6 +2713,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
};
newChartData.filteredOut = this.filterTeam(newChartData);
$node.dataset.source = JSON.stringify(newChartData);
+ isServerSideUpdate && await this.refresh(isServerSideUpdate);
}
async teamForm(mode, values) {
From 4edc0a43cdf2591b0c4ba086857b42722eb1749f Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Tue, 21 Jan 2025 12:41:37 +0700
Subject: [PATCH 112/129] Fix the bug the data panal record does not exist
while paging
---
.../viewComponent/ABViewOrgChartTeamsComponent.js | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 03f75fdd..a13d0014 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1811,13 +1811,15 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
"data-content-linked-field-id",
contentFieldID
);
+ const dataPanelRecord = _dataPanelDC.getData(
+ (e) =>
+ e.id ==
+ $itemElement.getAttribute("webix_l_id")
+ )[0];
+ if (dataPanelRecord == null) continue;
$itemElement.setAttribute(
"data-pk",
- _dataPanelDC.getData(
- (e) =>
- e.id ==
- $itemElement.getAttribute("webix_l_id")
- )[0][panelObj.PK()]
+ dataPanelRecord[panelObj.PK()]
);
$itemElement.setAttribute("draggable", "true");
$itemElement.addEventListener(
@@ -2713,7 +2715,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
};
newChartData.filteredOut = this.filterTeam(newChartData);
$node.dataset.source = JSON.stringify(newChartData);
- isServerSideUpdate && await this.refresh(isServerSideUpdate);
+ isServerSideUpdate && (await this.refresh(isServerSideUpdate));
}
async teamForm(mode, values) {
From 0664f710dafa9973e93c5ed9f868a00555f81201 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Tue, 21 Jan 2025 14:49:02 +0700
Subject: [PATCH 113/129] Fix the team delete logic if there are any
assignments ever
---
.../ABViewOrgChartTeamsComponent.js | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index a13d0014..0d2729ae 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1126,10 +1126,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const contentGroupDataPK =
contentRecord[this.getSettingField("contentGroupByField").columnName];
const contentGroupPKField = contentGroupDC.datasource.PK();
-
- // Hide a trash can when there is at least one assignment.
- const $trashCan = $teamNode.querySelectorAll(".team-button").item(2);
- $trashCan && ($trashCan.style.display = "none");
if (
contentGroupDC.getData(
(e) => e[contentGroupPKField] == contentGroupDataPK
@@ -2610,13 +2606,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
teamCanDelete(values) {
- const canInactive = this.getSettingField("teamCanInactivate").columnName;
- if (!values[canInactive]) return false;
- const children = this.getSettingField("teamLink").columnName;
- if (values[children].length > 0) return false;
- // @TODO check for any assignment
- // if (hasAssignment) return false;
- return true;
+ return (
+ values[this.getSettingField("teamCanInactivate").columnName] &&
+ // TODO (Guy): Should not save "many" value in the future. Let's fix later.
+ values[this.getSettingField("teamLink").columnName].length === 0 &&
+ values[this.getSettingField("contentField").columnName].length === 0
+ );
}
teamDelete(values, isServerSideUpdate = true) {
From 53fa0c50e76a5c8da723d91bed0f6e0e275f802b Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 22 Jan 2025 14:45:48 +0700
Subject: [PATCH 114/129] Adust assignment layouts
---
.../platform/views/viewComponent/ABViewOrgChartTeamsComponent.js | 1 +
styles/team-widget.css | 1 +
2 files changed, 2 insertions(+)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 0d2729ae..5d9e174d 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1201,6 +1201,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
element("div", "display-block"),
element("div", "display-block display-block-right"),
];
+ hardcodedDisplays[1].style.width = "40%";
const $hardcodedSpecialDisplay = element(
"div",
"team-group-record-display"
diff --git a/styles/team-widget.css b/styles/team-widget.css
index 4877596d..0ab767b7 100644
--- a/styles/team-widget.css
+++ b/styles/team-widget.css
@@ -88,6 +88,7 @@ org-chart tr.lines .downLine {
}
.team-group-record {
+ padding: 5px;
width: 100%;
border-width: 4px;
border-style: solid;
From f8ffd8866db2e1fba08a65239ecf576f46a6560f Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 22 Jan 2025 15:03:28 +0700
Subject: [PATCH 115/129] Allow blank date validation
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 5d9e174d..6d1c4248 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -558,9 +558,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
invalidMessage = `The ${field.label} must be later than the ${contentDateStartFieldLabel}.`;
rules[fieldName] = (value) =>
value >
- $$(ids.contentFormData).getValues()[
- contentDateStartFieldColumnName
- ];
+ $$(ids.contentFormData).getValues()[
+ contentDateStartFieldColumnName
+ ] || value == null;
break;
default:
rules[fieldName] = () => true;
From eabf2baf51cc3c0d26b1a0cd2acf5bd6b17856c2 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 22 Jan 2025 15:41:51 +0700
Subject: [PATCH 116/129] Only show Job Title + container when there is one
---
.../ABViewOrgChartTeamsComponent.js | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 6d1c4248..8248f89f 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1253,7 +1253,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
continue;
}
const $currentDisplay = element("div", "team-group-record-display");
-
+ const displayedFieldColumnName = displayedField.columnName;
// TODO (Guy): Now we are hardcoding for each display.
// $rowData.appendChild($currentDisplay);
switch (currentDisplayIndex) {
@@ -1261,6 +1261,19 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
hardcodedDisplays[0].appendChild($currentDisplay);
break;
case 1:
+ let i = 0;
+ while (
+ currentDataRecords.length > 0 &&
+ currentDataRecords[i] != null
+ )
+ if (
+ currentDataRecords[i][displayedFieldColumnName] == null ||
+ currentDataRecords[i][displayedFieldColumnName] === ""
+ )
+ currentDataRecords.splice(i, 1);
+ else i++;
+ if (currentDataRecords.length === 0)
+ hardcodedDisplays[2].style.display = "none";
hardcodedDisplays[2].appendChild($currentDisplay);
break;
case 2:
@@ -1275,7 +1288,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
break;
}
currentDisplayIndex++;
- const displayedFieldColumnName = displayedField.columnName;
const contentDisplayedFieldTypePrefix = `${displayedFieldKey}.${displayedFieldID}`;
const contentDisplayedFieldMappingDataObj =
JSON.parse(
From 985871a1fb30a897c3ab8fba6974cdecd4fabcf8 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 22 Jan 2025 15:57:00 +0700
Subject: [PATCH 117/129] Prevent creating assignment for the same staff on the
same team
---
.../ABViewOrgChartTeamsComponent.js | 29 ++++++++++---------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 8248f89f..305cdea4 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -113,9 +113,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
if (contentFieldLinkColumnName == null) return;
this.busy();
const $group = event.currentTarget;
+ const $content = $group.parentElement;
const newGroupDataPK = $group.dataset.pk;
const newNodeDataPK = JSON.parse(
- $group.parentElement.parentElement.dataset.source
+ $content.parentElement.dataset.source
)._rawData[nodeObjPK];
let {
source: updatedData,
@@ -130,20 +131,20 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentObj.fieldByID(contentLinkedFieldID).columnName;
const pendingPromises = [];
const newDate = new Date();
- // Employee can have multiple assignments, so don't close
+ // Employee can have multiple assignments but not the same team, so don't close
// existing
- // const $contentRecords =
- // document.getElementsByClassName("team-group-record");
- // for (const $contentRecord of $contentRecords) {
- // const contentData = JSON.parse($contentRecord.dataset.source);
- // if (contentData[contentLinkedFieldColumnName] == dataPK) {
- // contentData[contentDateEndFieldColumnName] = newDate;
- // pendingPromises.push(
- // contentModel.update(contentData.id, contentData)
- // );
- // draggedNodes.push($contentRecord);
- // }
- // }
+ const $contentRecords =
+ $content.getElementsByClassName("team-group-record");
+ for (const $contentRecord of $contentRecords) {
+ const contentData = JSON.parse($contentRecord.dataset.source);
+ if (contentData[contentLinkedFieldColumnName] == dataPK) {
+ contentData[contentDateEndFieldColumnName] = newDate;
+ pendingPromises.push(
+ contentModel.update(contentData.id, contentData)
+ );
+ draggedNodes.push($contentRecord);
+ }
+ }
updatedData = {};
updatedData[contentDateStartFieldColumnName] = newDate;
updatedData[contentLinkedFieldColumnName] =
From fdb798cee19c391bfff8903e72c9265e269050ff Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 22 Jan 2025 17:42:37 +0700
Subject: [PATCH 118/129] Fix last_updated_by field for teams and assignments
---
.../ABViewOrgChartTeamsComponent.js | 39 +++++++++++++------
styles/team-widget.css | 2 +-
2 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 305cdea4..38f81356 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -115,9 +115,8 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const $group = event.currentTarget;
const $content = $group.parentElement;
const newGroupDataPK = $group.dataset.pk;
- const newNodeDataPK = JSON.parse(
- $content.parentElement.dataset.source
- )._rawData[nodeObjPK];
+ const newNodeDataPK = JSON.parse($content.parentElement.dataset.source)
+ ._rawData[nodeObjPK];
let {
source: updatedData,
pk: dataPK,
@@ -134,9 +133,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// Employee can have multiple assignments but not the same team, so don't close
// existing
const $contentRecords =
- $content.getElementsByClassName("team-group-record");
+ $content.getElementsByClassName("team-group-record");
for (const $contentRecord of $contentRecords) {
const contentData = JSON.parse($contentRecord.dataset.source);
+ this._setUpdatedBy(contentObj, contentData);
if (contentData[contentLinkedFieldColumnName] == dataPK) {
contentData[contentDateEndFieldColumnName] = newDate;
pendingPromises.push(
@@ -164,6 +164,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
entityDC.getCursor()
);
}
+ this._setUpdatedBy(contentObj, updatedData);
pendingPromises.push(
contentModel.create(updatedData),
(async () => {
@@ -194,6 +195,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete updatedData["created_at"];
delete updatedData["updated_at"];
delete updatedData["properties"];
+ this._setUpdatedBy(contentObj, updatedData);
if (dropContentToCreate) {
const pendingPromises = [];
@@ -334,6 +336,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
] = JSON.parse(eventDetail.dropZone.dataset.source)._rawData.id;
const dc = this.datacollection;
this.busy();
+ this._setUpdatedBy(dc.datasource, dragedRecord);
try {
await dc.model.update(dragedRecord.id, dragedRecord);
} catch (err) {
@@ -757,6 +760,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete newFormData["created_at"];
delete newFormData["updated_at"];
delete newFormData["properties"];
+ this._setUpdatedBy(contentObj, newFormData);
for (const editContentFieldToCreateNew of editContentFieldsToCreateNew) {
const editContentFieldToCreateNewColumnName =
contentObj.fieldByID(
@@ -786,6 +790,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const oldData = {};
oldData[contentDateEndFieldColumnName] = new Date();
+ this._setUpdatedBy(contentObj, oldData);
pendingPromises.push(
contentModel.update(dataID, oldData)
);
@@ -1202,7 +1207,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
element("div", "display-block"),
element("div", "display-block display-block-right"),
];
- hardcodedDisplays[1].style.width = "40%";
+ hardcodedDisplays[1].style.width = "50%";
const $hardcodedSpecialDisplay = element(
"div",
"team-group-record-display"
@@ -1657,6 +1662,17 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
await this._waitDCReady(dc);
}
+ _setUpdatedBy(obj, values) {
+ values[
+ // TODO (Guy): This should be the ABDesigner setting.
+ obj.fields(
+ (field) =>
+ field.columnName.indexOf("_last_upd_by_in_app") > -1 ||
+ field.columnName.indexOf("_update_in_app") > -1
+ )[0].columnName
+ ] = this.AB.Account.email();
+ }
+
_showDataPanel() {
let $panel = $$(this.ids.dataPanelPopup);
if (!$panel) {
@@ -2503,7 +2519,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const entityDC = this._entityDC;
const teamDC = this.datacollection;
const teamObj = teamDC.datasource;
- const teamObjID = teamDC.datasource.id;
+ const teamObjID = teamObj.id;
// Add the entity value
if (entityDC) {
@@ -2523,6 +2539,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
let _rawData = values;
if (isServerSideUpdate) {
this.busy();
+ this._setUpdatedBy(teamObj, values);
try {
_rawData = await teamDC.model.create(values);
} catch (err) {
@@ -2658,13 +2675,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
async teamEdit(values, isServerSideUpdate = true) {
let _rawData = values;
+ const teamDC = this.datacollection;
+ const teamObj = teamDC.datasource;
if (isServerSideUpdate) {
this.busy();
+ this._setUpdatedBy(teamObj, values);
try {
- _rawData = await this.datacollection.model.update(
- values.id,
- values
- );
+ _rawData = await teamDC.model.update(values.id, values);
} catch (err) {
// TODO (Guy): the update error
console.error(err);
@@ -2683,7 +2700,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return;
}
const oldChartData = JSON.parse($node.dataset.source);
- const linkFieldColumnName = this.datacollection.datasource.fieldByID(
+ const linkFieldColumnName = teamObj.fieldByID(
this.getSettingField("teamLink").settings.linkColumn
).columnName;
if (
diff --git a/styles/team-widget.css b/styles/team-widget.css
index 0ab767b7..bd4caf75 100644
--- a/styles/team-widget.css
+++ b/styles/team-widget.css
@@ -99,7 +99,7 @@ org-chart tr.lines .downLine {
flex-direction: row;
align-items: center;
justify-content: center;
- gap: 5%;
+ gap: 2%;
}
.team-group-record:hover {
From cd025237d0e4f40f2b1cf84c0a30549cea822eb5 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 23 Jan 2025 17:06:33 +0700
Subject: [PATCH 119/129] Prevent drop assignment with same employees from team
to team
---
.../ABViewOrgChartTeamsComponent.js | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 38f81356..d24c4a97 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -130,6 +130,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentObj.fieldByID(contentLinkedFieldID).columnName;
const pendingPromises = [];
const newDate = new Date();
+
// Employee can have multiple assignments but not the same team, so don't close
// existing
const $contentRecords =
@@ -181,6 +182,25 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
await Promise.all(pendingPromises);
} else {
updatedData = JSON.parse(updatedData);
+ const $contentRecords =
+ $content.getElementsByClassName("team-group-record");
+ const dataPanelDCs = this._dataPanelDCs;
+ for (const dataPanelDC of dataPanelDCs) {
+ const dataPanelLinkedFieldColumnName =
+ dataPanelDC.datasource.connectFields(
+ (connectField) =>
+ connectField.datasourceLink === contentObj
+ )[0].columnName;
+ for (const $contentRecord of $contentRecords)
+ if (
+ JSON.parse($contentRecord.dataset.source)[
+ dataPanelLinkedFieldColumnName
+ ] == updatedData[dataPanelLinkedFieldColumnName]
+ ) {
+ this.ready();
+ return;
+ }
+ }
// This is move form another team node
// Move the child node to the target
From 6d291fb4f876c442cd388a51ed25cd83542e0a46 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 24 Jan 2025 11:27:22 +0700
Subject: [PATCH 120/129] Fix bug dropping assignment to leader/member in the
same team
---
.../ABViewOrgChartTeamsComponent.js | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index d24c4a97..c0aa51b6 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -191,15 +191,19 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
(connectField) =>
connectField.datasourceLink === contentObj
)[0].columnName;
- for (const $contentRecord of $contentRecords)
+ for (const $contentRecord of $contentRecords) {
+ const contentRecord = JSON.parse(
+ $contentRecord.dataset.source
+ );
if (
- JSON.parse($contentRecord.dataset.source)[
- dataPanelLinkedFieldColumnName
- ] == updatedData[dataPanelLinkedFieldColumnName]
+ updatedData.id != contentRecord.id &&
+ contentRecord[dataPanelLinkedFieldColumnName] ==
+ updatedData[dataPanelLinkedFieldColumnName]
) {
this.ready();
return;
}
+ }
}
// This is move form another team node
@@ -207,6 +211,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const $draggedNode = document.querySelector(
`#${this.contentNodeID(updatedData.id)}`
);
+ if (
+ updatedData[contentGroupByFieldColumnName] ==
+ $group.dataset.pk
+ ) {
+ this.ready();
+ return;
+ }
$draggedNode.parentNode.removeChild($draggedNode);
$group
.querySelector(".team-group-content")
From 3261ab82efbf990f5494d29478b6293a15941eac Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 24 Jan 2025 11:36:28 +0700
Subject: [PATCH 121/129] Add more condition when drop to the same team
---
.../ABViewOrgChartTeamsComponent.js | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index c0aa51b6..73176386 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -196,9 +196,12 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
$contentRecord.dataset.source
);
if (
- updatedData.id != contentRecord.id &&
- contentRecord[dataPanelLinkedFieldColumnName] ==
- updatedData[dataPanelLinkedFieldColumnName]
+ (updatedData.id != contentRecord.id &&
+ contentRecord[dataPanelLinkedFieldColumnName] ==
+ updatedData[dataPanelLinkedFieldColumnName]) ||
+ (updatedData.id == contentRecord.id &&
+ updatedData[contentGroupByFieldColumnName] ==
+ $group.dataset.pk)
) {
this.ready();
return;
@@ -211,13 +214,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const $draggedNode = document.querySelector(
`#${this.contentNodeID(updatedData.id)}`
);
- if (
- updatedData[contentGroupByFieldColumnName] ==
- $group.dataset.pk
- ) {
- this.ready();
- return;
- }
$draggedNode.parentNode.removeChild($draggedNode);
$group
.querySelector(".team-group-content")
From 1d301fa7d8c7e786485a6981bc0c0bd2f901142f Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 5 Feb 2025 13:08:32 +0700
Subject: [PATCH 122/129] Fix the connected entity field for strategy
---
.../viewComponent/ABViewOrgChartTeamsComponent.js | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 73176386..eea902b8 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -2798,18 +2798,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
],
};
- const strategyCond = {
- glue: "and",
- rules: [
- {
- key: strategyObj.connectFields(
- (f) => f.settings.linkObject === entityObjID
- )[0].columnName,
- value: entityDCCursorID,
- rule: "equals",
- },
- ],
- };
const subStrategyCol = this.getSettingField("subStrategy").columnName;
const $teamFormPopup = webix.ui({
view: "popup",
@@ -2870,7 +2858,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
"options",
(
await strategyField.getOptions(
- strategyCond,
+ null,
null,
null,
null,
From 9707ea2523bfd96270adc5e264c51e16c0d89606 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 5 Feb 2025 15:17:53 +0700
Subject: [PATCH 123/129] Limit JobTitle text
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index eea902b8..cb687975 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -1417,6 +1417,11 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
)
);
}
+
+ // TODO (Guy): Hardcode limit text.
+ if (currentDisplayIndex - 1 === 1)
+ $currentDisplay.textContent =
+ $currentDisplay.textContent.slice(0, 35);
break;
}
currentField = null;
From 4f5186bfceba8b0f0ee99cb61b4e5159993793d0 Mon Sep 17 00:00:00 2001
From: nh758 <7259@pm.me>
Date: Thu, 6 Feb 2025 13:50:56 +0700
Subject: [PATCH 124/129] Refactor team strategy input as 2 drop downs
---
.../ABViewOrgChartTeamsComponent.js | 137 ++++++++++++++----
1 file changed, 109 insertions(+), 28 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index eea902b8..5353cf9e 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -22,7 +22,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentForm: "",
contentFormData: "",
teamForm: "",
+ teamFormCode: "",
teamFormPopup: "",
+ teamFormStrategy: "",
teamFormSubmit: "",
teamFormTitle: "",
},
@@ -977,13 +979,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const ids = this.ids;
let $popup = $$(ids.filterPopup);
if (!$popup) {
- const strategyID =
- this.getSettingField("teamStrategy").settings.linkObject;
- const strategyObj = this.AB.objectByID(strategyID);
- const strategyCodeFieldID = this.getSettingField("strategyCode").id;
- const strategyCodeField = strategyObj.fields(
- (f) => f.id === strategyCodeFieldID
- )[0];
+ const self = this;
$popup = webix.ui({
view: "popup",
css: "filter-popup",
@@ -1017,9 +1013,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
try {
this.define(
"options",
- (
- await strategyCodeField.getOptions()
- ).map(fieldToOption)
+ await self.strategyCodeOptions()
);
this.refresh();
this.enable();
@@ -2780,7 +2774,6 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const entityObjID = entityDC.datasource.id;
const entityDCCursorID = entityDC.getCursor().id;
const strategyField = teamObj.fieldByID(settings.teamStrategy);
- const strategyObj = this.AB.objectByID(strategyField.settings.linkObject);
const linkField = teamObj.fieldByID(
this.getSettingField("teamLink").settings.linkColumn
);
@@ -2798,12 +2791,14 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
},
],
};
- const subStrategyCol = this.getSettingField("subStrategy").columnName;
+ const self = this;
+ const labelWidth = 110;
const $teamFormPopup = webix.ui({
view: "popup",
id: ids.teamFormPopup,
close: true,
position: "center",
+ width: 400,
css: { "border-radius": "10px" },
body: {
rows: [
@@ -2839,13 +2834,17 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
{
view: "text",
label: nameField.label,
+ labelWidth,
name: nameField.columnName,
required: true,
},
{
view: "richselect",
- label: strategyField.label,
- name: strategyField.columnName,
+ label: this.label("Strategy"),
+ labelWidth,
+ id: this.ids.teamFormCode,
+ // no name because we don't actually save this, it's
+ // used to filter strategyField options
options: [],
required: true,
on: {
@@ -2856,20 +2855,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
this.disable();
this.define(
"options",
- (
- await strategyField.getOptions(
- null,
- null,
- null,
- null,
- [subStrategyCol]
- )
- ).map((e) => ({
- id: e.id,
- value: e[`${subStrategyCol}__relation`]
- .name,
- // value: strategyObj.displayData(e),
- }))
+ await self.strategyCodeOptions()
);
this.refresh();
this.enable();
@@ -2878,11 +2864,54 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// Close popup before response or possily response fail
}
},
+ async onChange(code, previous) {
+ if (code === previous) return;
+ const opts = await self.strategyOptions(code);
+ const $strategyField = $$(
+ self.ids.teamFormStrategy
+ );
+ $strategyField.define?.("options", opts);
+ $strategyField.refresh();
+ $strategyField.enable();
+ },
+ },
+ },
+ {
+ view: "richselect",
+ label: this.label("Sub Strategy"),
+ labelWidth,
+ name: strategyField.columnName,
+ id: this.ids.teamFormStrategy,
+ options: [],
+ required: true,
+ on: {
+ async onViewShow() {
+ webix.extend(this, webix.ProgressBar);
+ this.showProgress({ type: "icon" });
+ try {
+ this.disable();
+ const value = this.getValue();
+ if (value) {
+ const { code } = (
+ await self.strategyOptions()
+ ).find((o) => o.id === value);
+ const options = self.strategyOptions(code);
+ $$(self.ids.teamFormCode).setValue(code);
+ this.define("options", options);
+ this.refresh();
+ this.enable();
+ }
+ this.hideProgress();
+ } catch {
+ // Close popup before response or possily response fail
+ }
+ },
},
},
{
view: "combo",
label: linkField.label,
+ labelWidth,
name: linkFieldColumnName,
options: [],
required: true,
@@ -3000,6 +3029,58 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return `contentnode_${id}`;
}
+ /**
+ * Get valid drop down option for strategyCode
+ * @returns {array}
+ */
+ async strategyCodeOptions() {
+ // These shouldn't change often so cache them to prevent extra requests
+ // to NetSuite
+ if (!this._strategyCodeOpts) {
+ const strategyID =
+ this.getSettingField("teamStrategy").settings.linkObject;
+ const strategyObj = this.AB.objectByID(strategyID);
+ const strategyCodeFieldID = this.getSettingField("strategyCode").id;
+ const strategyCodeField = strategyObj.fields(
+ (f) => f.id === strategyCodeFieldID
+ )[0];
+
+ const opts = await strategyCodeField.getOptions();
+ this._strategyCodeOpts = opts.map(fieldToOption).sort();
+ }
+ return this._strategyCodeOpts;
+ }
+
+ /**
+ * Get valid drop down option for teamStrategy based on strategyCode
+ * @param {string} code the id of a strategyCod
+ * @returns {array}
+ */
+ async strategyOptions(code) {
+ // These shouldn't change often so cache instead of querying Netsuite each
+ // time
+ if (!this._strategyOpts) {
+ const teamObj = this.datacollection.datasource;
+ const strategyField = teamObj.fieldByID(this.settings.teamStrategy);
+ const subStrategyCol = this.getSettingField("subStrategy").columnName;
+ const strategyCodeCol =
+ this.getSettingField("strategyCode").columnName;
+ const opts = await strategyField.getOptions(null, null, null, null, [
+ subStrategyCol,
+ ]);
+ this._strategyOpts = opts
+ .map((e) => ({
+ id: e.id,
+ value: e[`${subStrategyCol}__relation`].name,
+ code: e[strategyCodeCol],
+ }))
+ .sort();
+ }
+ return code
+ ? this._strategyOpts.filter((o) => o.code === code)
+ : this._strategyOpts;
+ }
+
/**
* generate a id for the team dom node based on it's record id
* @param {string} id record id
From 06a06828b0300fcba036b03fe545654d1653316d Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Thu, 6 Feb 2025 17:52:20 +0700
Subject: [PATCH 125/129] Prevent refresh if no changes and day condition when
drop node
---
.../ABViewOrgChartTeamsComponent.js | 119 ++++++++++++------
1 file changed, 82 insertions(+), 37 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index cb687975..bddb627b 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -123,6 +123,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentLinkedFieldID,
} = JSON.parse(dataTransfer.getData("text/plain"));
const draggedNodes = [];
+ let isRefreshed = true;
try {
if (!updatedData) {
// This is a drop from Employee list (new assignment)
@@ -135,50 +136,80 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
// existing
const $contentRecords =
$content.getElementsByClassName("team-group-record");
+ let isUpdated = false;
for (const $contentRecord of $contentRecords) {
const contentData = JSON.parse($contentRecord.dataset.source);
- this._setUpdatedBy(contentObj, contentData);
if (contentData[contentLinkedFieldColumnName] == dataPK) {
+ this._setUpdatedBy(contentObj, contentData);
+ if (!isUpdated) {
+ if (
+ contentData[contentGroupByFieldColumnName] ==
+ newGroupDataPK
+ ) {
+ isRefreshed = false;
+ isUpdated = true;
+ continue;
+ } else if (
+ this._isLessThanDay(
+ new Date(
+ contentData[contentDateStartFieldColumnName]
+ )
+ )
+ ) {
+ contentData[contentGroupByFieldColumnName] =
+ this._parseDataPK(newGroupDataPK);
+ pendingPromises.push(
+ contentModel.update(contentData.id, contentData)
+ );
+ draggedNodes.push($contentRecord);
+ isRefreshed = true;
+ isUpdated = true;
+ continue;
+ }
+ }
contentData[contentDateEndFieldColumnName] = newDate;
pendingPromises.push(
contentModel.update(contentData.id, contentData)
);
draggedNodes.push($contentRecord);
+ isRefreshed = true;
}
}
- updatedData = {};
- updatedData[contentDateStartFieldColumnName] = newDate;
- updatedData[contentLinkedFieldColumnName] =
- this._parseDataPK(dataPK);
- updatedData[contentFieldLinkColumnName] =
- this._parseDataPK(newNodeDataPK);
- updatedData[contentGroupByFieldColumnName] =
- this._parseDataPK(newGroupDataPK);
- const entityDC = this._entityDC;
- if (entityDC) {
- const entityLink = entityDC.datasource.connectFields(
- (f) => f.settings.linkObject === contentObj.id
- )[0].id;
- const entityCol =
- this.AB.definitionByID(entityLink).columnName;
- updatedData[entityCol] = this._parseDataPK(
- entityDC.getCursor()
+ if (!isUpdated) {
+ updatedData = {};
+ updatedData[contentDateStartFieldColumnName] = newDate;
+ updatedData[contentLinkedFieldColumnName] =
+ this._parseDataPK(dataPK);
+ updatedData[contentFieldLinkColumnName] =
+ this._parseDataPK(newNodeDataPK);
+ updatedData[contentGroupByFieldColumnName] =
+ this._parseDataPK(newGroupDataPK);
+ const entityDC = this._entityDC;
+ if (entityDC) {
+ const entityLink = entityDC.datasource.connectFields(
+ (f) => f.settings.linkObject === contentObj.id
+ )[0].id;
+ const entityCol =
+ this.AB.definitionByID(entityLink).columnName;
+ updatedData[entityCol] = this._parseDataPK(
+ entityDC.getCursor()
+ );
+ }
+ this._setUpdatedBy(contentObj, updatedData);
+ pendingPromises.push(
+ contentModel.create(updatedData),
+ (async () => {
+ const $draggedNode = await this._createUIContentRecord(
+ updatedData,
+ "grey"
+ );
+ $group
+ .querySelector(".team-group-content")
+ .appendChild($draggedNode);
+ draggedNodes.push($draggedNode);
+ })()
);
}
- this._setUpdatedBy(contentObj, updatedData);
- pendingPromises.push(
- contentModel.create(updatedData),
- (async () => {
- const $draggedNode = await this._createUIContentRecord(
- updatedData,
- "grey"
- );
- $group
- .querySelector(".team-group-content")
- .appendChild($draggedNode);
- draggedNodes.push($draggedNode);
- })()
- );
await Promise.all(pendingPromises);
} else {
updatedData = JSON.parse(updatedData);
@@ -223,7 +254,17 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete updatedData["updated_at"];
delete updatedData["properties"];
this._setUpdatedBy(contentObj, updatedData);
- if (dropContentToCreate) {
+ if (
+ !dropContentToCreate ||
+ (updatedData[contentFieldLinkColumnName] == newNodeDataPK &&
+ this._isLessThanDay(
+ new Date(updatedData[contentDateStartFieldColumnName])
+ ))
+ ) {
+ updatedData[contentFieldLinkColumnName] = newNodeDataPK;
+ updatedData[contentGroupByFieldColumnName] = newGroupDataPK;
+ await contentModel.update(updatedData.id, updatedData);
+ } else {
const pendingPromises = [];
// TODO (Guy): Force update Date End with a current date.
@@ -240,16 +281,16 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
updatedData[contentGroupByFieldColumnName] = newGroupDataPK;
pendingPromises.push(contentModel.create(updatedData));
await Promise.all(pendingPromises);
- } else {
- updatedData[contentFieldLinkColumnName] = newNodeDataPK;
- updatedData[contentGroupByFieldColumnName] = newGroupDataPK;
- await contentModel.update(updatedData.id, updatedData);
}
}
} catch (err) {
// TODO (Guy): The update data error.
console.log(err);
}
+ if (!isRefreshed) {
+ this.ready();
+ return;
+ }
try {
// TODO (Guy): Logic to not reload dcs.
await Promise.all([
@@ -1496,6 +1537,10 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return false;
}
+ _isLessThanDay(date) {
+ return Math.abs(new Date() - date) / 36e5 < 24;
+ }
+
_initDC(dc) {
dc.init();
if (dc.dataStatus === dc.dataStatusFlag.notInitial) dc.loadData();
From 309c6c6df8d2ede1d23a0dc780cbc5a153cb3aea Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Fri, 7 Feb 2025 12:05:59 +0700
Subject: [PATCH 126/129] Update by blank/null or within 24 hours conditions
---
.../ABViewOrgChartTeamsComponent.js | 47 ++++++++++++++-----
1 file changed, 34 insertions(+), 13 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 76d83308..9e5f24a6 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -831,21 +831,42 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete newFormData["updated_at"];
delete newFormData["properties"];
this._setUpdatedBy(contentObj, newFormData);
- for (const editContentFieldToCreateNew of editContentFieldsToCreateNew) {
- const editContentFieldToCreateNewColumnName =
- contentObj.fieldByID(
- editContentFieldToCreateNew
- )?.columnName;
- if (
- JSON.stringify(
- newFormData[editContentFieldToCreateNewColumnName] ?? ""
- ) !==
- JSON.stringify(
+ if (
+ !this._isLessThanDay(
+ new Date(
+ contentDataRecord[contentDateStartFieldColumnName]
+ )
+ )
+ ) {
+ let isCreated = false;
+ for (const editContentFieldToCreateNew of editContentFieldsToCreateNew) {
+ const editContentFieldToCreateNewColumnName =
+ contentObj.fieldByID(
+ editContentFieldToCreateNew
+ )?.columnName;
+ if (
+ !isCreated &&
contentDataRecord[
editContentFieldToCreateNewColumnName
- ] ?? ""
- )
- ) {
+ ] != null &&
+ contentDataRecord[
+ editContentFieldToCreateNewColumnName
+ ] !== "" &&
+ JSON.stringify(
+ newFormData[editContentFieldToCreateNewColumnName] ??
+ ""
+ ) !==
+ JSON.stringify(
+ contentDataRecord[
+ editContentFieldToCreateNewColumnName
+ ]
+ )
+ ) {
+ isCreated = true;
+ break;
+ }
+ }
+ if (isCreated) {
Webix.confirm({
title: this.label("Caution: Creating New Assignment"),
ok: this.label("Continue with new assignment"),
From 01004a3661babb966bb7564a67a7c45fffbad9c5 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Tue, 11 Feb 2025 15:18:45 +0700
Subject: [PATCH 127/129] Prevent date conversion by new string format
---
.../ABViewOrgChartTeamsComponent.js | 112 ++++++++++++++----
1 file changed, 87 insertions(+), 25 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 9e5f24a6..c945b0cd 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -161,7 +161,14 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
contentData[contentGroupByFieldColumnName] =
this._parseDataPK(newGroupDataPK);
pendingPromises.push(
- contentModel.update(contentData.id, contentData)
+ contentModel.update(
+ contentData.id,
+ this._parseFormValueByType(
+ contentObj,
+ contentData,
+ contentData
+ )
+ )
);
draggedNodes.push($contentRecord);
isRefreshed = true;
@@ -171,7 +178,14 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
contentData[contentDateEndFieldColumnName] = newDate;
pendingPromises.push(
- contentModel.update(contentData.id, contentData)
+ contentModel.update(
+ contentData.id,
+ this._parseFormValueByType(
+ contentObj,
+ contentData,
+ contentData
+ )
+ )
);
draggedNodes.push($contentRecord);
isRefreshed = true;
@@ -199,7 +213,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
}
this._setUpdatedBy(contentObj, updatedData);
pendingPromises.push(
- contentModel.create(updatedData),
+ contentModel.create(
+ this._parseFormValueByType(
+ contentObj,
+ updatedData,
+ updatedData
+ )
+ ),
(async () => {
const $draggedNode = await this._createUIContentRecord(
updatedData,
@@ -265,14 +285,28 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
) {
updatedData[contentFieldLinkColumnName] = newNodeDataPK;
updatedData[contentGroupByFieldColumnName] = newGroupDataPK;
- await contentModel.update(updatedData.id, updatedData);
+ await contentModel.update(
+ updatedData.id,
+ this._parseFormValueByType(
+ contentObj,
+ updatedData,
+ updatedData
+ )
+ );
} else {
const pendingPromises = [];
// TODO (Guy): Force update Date End with a current date.
updatedData[contentDateEndFieldColumnName] = new Date();
pendingPromises.push(
- contentModel.update(updatedData.id, updatedData)
+ contentModel.update(
+ updatedData.id,
+ this._parseFormValueByType(
+ contentObj,
+ updatedData,
+ updatedData
+ )
+ )
);
updatedData[contentDateStartFieldColumnName] =
updatedData[contentDateEndFieldColumnName];
@@ -281,7 +315,15 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
delete updatedData[contentDateEndFieldColumnName];
updatedData[contentFieldLinkColumnName] = newNodeDataPK;
updatedData[contentGroupByFieldColumnName] = newGroupDataPK;
- pendingPromises.push(contentModel.create(updatedData));
+ pendingPromises.push(
+ contentModel.create(
+ this._parseFormValueByType(
+ contentObj,
+ updatedData,
+ updatedData
+ )
+ )
+ );
await Promise.all(pendingPromises);
}
}
@@ -773,6 +815,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
view: "datepicker",
name: fieldName,
label: fieldLabel,
+ stringResult: true,
labelWidth,
invalidMessage,
timepicker: fieldKey === "datetime",
@@ -1641,6 +1684,22 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
const newValue = newFormData[columnName];
switch (fieldKey) {
case "date":
+ if (oldValue === undefined && newValue == null)
+ delete newFormData[columnName];
+ else {
+ newFormData[columnName] = new Date(newValue);
+ if (isNaN(newFormData[columnName]))
+ delete newFormData[columnName];
+ else
+ newFormData[columnName] = `${newFormData[
+ columnName
+ ].getFullYear()}-${String(
+ newFormData[columnName].getMonth() + 1
+ ).padStart(2, "0")}-${String(
+ newFormData[columnName].getDate()
+ ).padStart(2, "0")}`;
+ }
+ break;
case "datetime":
if (oldValue === undefined && newValue == null)
delete newFormData[columnName];
@@ -1653,20 +1712,22 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
break;
case "connectObject":
delete newFormData[`${columnName}__relation`];
- if (field.linkType() === "one")
- switch (typeof oldValue) {
- case "number":
- newFormData[columnName] = parseInt(newValue) || null;
- break;
- default:
- newFormData[columnName] = newValue?.toString() || null;
- if (
- oldValue === undefined &&
- newFormData[columnName] == null
- )
- delete newFormData[columnName];
- break;
- }
+ if (field.linkType() === "one") {
+ if (oldValue === undefined && newFormData[columnName] == null)
+ delete newFormData[columnName];
+ else
+ switch (typeof oldValue) {
+ case "number":
+ newFormData[columnName] = parseInt(newValue) || null;
+ break;
+ case "string":
+ newFormData[columnName] =
+ newValue?.toString() || null;
+ break;
+ default:
+ break;
+ }
+ }
// TODO (Guy): Many logic in the future. Now we don't have an array data changed.
else delete newFormData[columnName];
break;
@@ -3043,12 +3104,13 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
return;
this.teamEdit(newValues);
} else {
- newValues = this._parseFormValueByType(
- teamObj,
- null,
- newValues
+ this.teamAddChild(
+ this._parseFormValueByType(
+ teamObj,
+ null,
+ newValues
+ )
);
- this.teamAddChild(newValues);
}
$teamFormPopup.blockEvent();
$teamFormPopup.$view.remove();
From f4120ad60380f6675a4b516e3d6c90f94004a023 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 12 Feb 2025 11:19:33 +0700
Subject: [PATCH 128/129] Fix end date blank validation
---
.../views/viewComponent/ABViewOrgChartTeamsComponent.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index c945b0cd..68ea7f0e 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -676,7 +676,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
value >
$$(ids.contentFormData).getValues()[
contentDateStartFieldColumnName
- ] || value == null;
+ ] || value === "" || value == null;
break;
default:
rules[fieldName] = () => true;
From a4ab2872dcc7f80bc1a1178f3120940fa5f6c5b2 Mon Sep 17 00:00:00 2001
From: guyyoo
Date: Wed, 12 Feb 2025 16:38:13 +0700
Subject: [PATCH 129/129] Fix the connected self parent bug
---
.../ABViewOrgChartTeamsComponent.js | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
index 68ea7f0e..3627354c 100644
--- a/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
+++ b/AppBuilder/platform/views/viewComponent/ABViewOrgChartTeamsComponent.js
@@ -676,7 +676,9 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
value >
$$(ids.contentFormData).getValues()[
contentDateStartFieldColumnName
- ] || value === "" || value == null;
+ ] ||
+ value === "" ||
+ value == null;
break;
default:
rules[fieldName] = () => true;
@@ -2424,15 +2426,22 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
* @param {object} node the current node
* @param {number} [depth=0] a count of how many times we have recursed
*/
+ const teamLinkDef = this.getSettingField("teamLink");
+ const teamLinkDefColumnName = teamLinkDef.columnName;
+ const teamLinkedColumnDefColumnName = this.AB.definitionByID(
+ teamLinkDef.settings.linkColumn
+ ).columnName;
const pullChildData = (node, depth = 0) => {
if (depth >= TEAM_CHART_MAX_DEPTH) return;
node.children = [];
node._rawData[this.getSettingField("teamLink").columnName].forEach(
(id) => {
const childData = dc.getData((e) => e.id == id)[0];
+
// Don't show inactive teams
if (
!childData ||
+ childData[teamLinkedColumnDefColumnName] == id ||
(this.__filters?.inactive == 0 &&
childData[this.getSettingField("teamInactive").columnName])
)
@@ -2454,10 +2463,7 @@ module.exports = class ABViewOrgChartTeamsComponent extends ABViewComponent {
child.filteredOut = this.filterTeam(child);
if (child.name === "External Support")
child.className = `strategy-external`;
- if (
- childData[this.getSettingField("teamLink").columnName]
- .length > 0
- ) {
+ if (childData[teamLinkDefColumnName].length > 0) {
pullChildData(child, depth + 1);
}
// If this node is filtered we still need it if it has children