From 3569bcebe7c045f344a0248c0659510ef51e9b59 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Mon, 9 Sep 2024 13:06:49 +0700 Subject: [PATCH 01/32] add complex teams widget --- .../Designer/editors/EditorManager.js | 1 + .../editors/views/ABViewOrgChartTeams.js | 53 +++ .../Designer/properties/PropertyManager.js | 1 + .../properties/views/ABViewOrgChartTeams.js | 359 ++++++++++++++++++ 4 files changed, 414 insertions(+) create mode 100644 src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js create mode 100644 src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js diff --git a/src/rootPages/Designer/editors/EditorManager.js b/src/rootPages/Designer/editors/EditorManager.js index 6afb1ef0..f7b82266 100644 --- a/src/rootPages/Designer/editors/EditorManager.js +++ b/src/rootPages/Designer/editors/EditorManager.js @@ -32,6 +32,7 @@ export default function (AB) { require("./views/ABViewLayout"), require("./views/ABViewMenu"), require("./views/ABViewOrgChart"), + require("./views/ABViewOrgChartTeams"), require("./views/ABViewPage"), require("./views/ABViewPDFImporter"), require("./views/ABViewPivot"), diff --git a/src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js new file mode 100644 index 00000000..5a568fb4 --- /dev/null +++ b/src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js @@ -0,0 +1,53 @@ +/** + * ABViewOrgChartEditor + * The widget that displays the UI Editor Component on the screen + * when designing the UI. + */ +var myClass = null; +// {singleton} +// we will want to call this factory fn() repeatedly in our imports, +// but we only want to define 1 Class reference. + +import FABViewDefault from "./_ABViewDefault"; + +export default function (AB) { + if (!myClass) { + const ABViewDefault = FABViewDefault(AB); + // var L = UIClass.L(); + // var L = ABViewContainer.L(); + + myClass = class ABViewOrgChartTeamsEditor extends ABViewDefault { + static get key() { + return "orgchart_teams"; + } + + constructor(view, base = "interface_editor_viewOrgChartTeans") { + // base: {string} unique base id reference + + super(view, base); + + // this.component = this.view.component(); + } + + ui() { + let _ui = super.ui(); + return _ui; + } + + init(AB) { + this.AB = AB; + return super.init(AB); + } + + detatch() { + this.component?.detatch?.(); + } + + onShow() { + this.component?.onShow?.(); + } + }; + } + + return myClass; +} diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 8608b548..b497faaa 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -109,6 +109,7 @@ export default function (AB) { require("./views/ABViewList"), require("./views/ABViewMenu"), require("./views/ABViewOrgChart"), + require("./views/ABViewOrgChartTeams"), require("./views/ABViewPage"), require("./views/ABViewPDFImporter"), require("./views/ABViewPivot"), diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js new file mode 100644 index 00000000..891acda6 --- /dev/null +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -0,0 +1,359 @@ +/* + * ABViewChartTeams + * A Property manager for our ABViewChartTeams definitions + */ + +import FABView from "./ABView"; + +export default function (AB) { + const BASE_ID = "properties_abview_org_chart_teams"; + + const ABView = FABView(AB); + const uiConfig = AB.Config.uiSettings(); + const L = ABView.L(); + + class ABViewOrgChartTeamsProperty extends ABView { + constructor() { + super(BASE_ID, { + datacollectionID: "", + fields: "", + direction: "", + depth: "", + color: "", + pan: "", + zoom: "", + height: "", + export: "", + exportFilename: "", + }); + + this.AB = AB; + } + + static get key() { + return "orgchart_teams"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + id: ids.datacollectionID, + name: "datacollectionID", + view: "richselect", + label: L("Data Collection"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: (value) => { + this.CurrentView.settings.datacollectionID = value; + this.populateSubValueFieldOptions( + this.CurrentView?.datacollection?.datasource + ); + this.onChange(); + }, + }, + }, + { + cols: [ + { + view: "label", + label: "Fields", + width: uiConfig.labelWidthLarge, + }, + { + id: ids.fields, + name: "fields", + view: "tree", + template: + "{common.icon()} {common.checkbox()} #value#", + select: false, + height: 200, + data: [], + on: { + onItemCheck: () => { + const fieldValues = $$(this.ids.fields).getChecked(); + this.refreshValueFieldOptions(fieldValues); + this.onChange(); + }, + }, + }, + ], + }, + { + id: ids.direction, + name: "direction", + view: "richselect", + label: L("Direction"), + labelWidth: uiConfig.labelWidthLarge, + options: [ + { id: "t2b", value: L("Top to Bottom") }, + { id: "b2t", value: L("Bottom to Top") }, + { id: "l2r", value: L("Left to Right") }, + { id: "r2l", value: L("Right to Left") }, + ], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.depth, + name: "depth", + hidden: true, // NOTE: use choose Connect Fields option + view: "counter", + label: L("Depth"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.color, + name: "color", + view: "colorpicker", + label: L("Color"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + hidden: true, // NOTE: does not support + id: ids.pan, + name: "pan", + view: "checkbox", + label: L("Pan"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + hidden: true, // NOTE: does not support + id: ids.zoom, + name: "zoom", + view: "checkbox", + label: L("Zoom"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.height, + view: "counter", + name: "height", + label: L("Height"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + hidden: true, // NOTE: does not support + view: "fieldset", + label: L("Export"), + body: { + view: "layout", + borderless: true, + rows: [ + { + id: ids.export, + name: "export", + view: "checkbox", + label: L("Is Exportable"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.exportFilename, + view: "text", + name: "exportFilename", + label: L("File name"), + placeholder: L("Enter file name"), + labelWidth: uiConfig.labelWidthLarge, + }, + ], + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + + webix.extend($$(this.ids.component), webix.ProgressBar); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const $component = $$(ids.component); + const defaultValues = this.defaultValues(); + const values = Object.assign( + $component.getValues(), + Object.assign(defaultValues, view.settings) + ); + + const $fieldList = $$(ids.fields); + $fieldList.clearAll(); + + this.populateDatacollection(values.datacollectionId); + // this.populateDescriptionFieldOptions(values.columnDescription); + + const fieldValues = (view.settings?.fields ?? "").split(","); + this.refreshValueFieldOptions(fieldValues); + + $component.setValues(values); + } + + populateDatacollection(datacollectionId) { + const $dataCollection = $$(this.ids.datacollectionID); + + // Pull data collections to options + const dcOptions = this.CurrentView.application + .datacollectionsIncluded() + .map((d) => { + return { id: d.id, value: d.label }; + }); + $dataCollection.define("options", dcOptions); + $dataCollection.define("value", datacollectionId); + $dataCollection.refresh(); + } + + refreshValueFieldOptions(fieldValues = []) { + const ids = this.ids; + const view = this.CurrentView; + const $fieldList = $$(ids.fields); + + $fieldList.clearAll(); + + // Populate 1:M fields option of the root object + this.populateSubValueFieldOptions(view.datacollection?.datasource); + + // Populate sub 1:M fields option of each fields + fieldValues.forEach((fId) => { + if (!fId) return; + + const $fieldItem = $fieldList.getItem(fId); + if ($fieldItem) { + const abField = $fieldItem.field; + this.populateSubValueFieldOptions(abField.datasourceLink, fId); + } + }); + + // Set check items + $fieldList.blockEvent(); + fieldValues.forEach((fId) => { + if ($fieldList.exists(fId)) $fieldList.checkItem(fId); + }); + $fieldList.unblockEvent(); + } + + populateSubValueFieldOptions(object, parentFieldId) { + const view = this.CurrentView; + const $fields = $$(this.ids.fields); + + view.getValueFields(object).forEach((f, index) => { + if ($fields.exists(f.id)) return; + $fields.add( + { + id: f.id, + value: f.label, + field: f, + }, + index, + parentFieldId + ); + }); + + $fields.openAll(); + } + + // populateDescriptionFieldOptions(fieldId) { + // const valueField = this.CurrentView.valueField(); + // const $columnDescription = $$(this.ids.columnDescription); + + // const connectFieldOpts = + // valueField?.datasourceLink + // ?.fields?.((f) => f.key != "connectObject") + // .map?.((f) => { + // return { + // id: f.id, + // value: f.label, + // }; + // }) ?? []; + // $columnDescription.define("options", connectFieldOpts); + // $columnDescription.define("value", fieldId); + // $columnDescription.refresh(); + // } + + defaultValues() { + const ViewClass = this.ViewClass(); + + let values = null; + + if (ViewClass) { + values = ViewClass.defaultValues(); + } + + return values; + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const values = super.values(); + const ids = this.ids; + const $component = $$(ids.component); + + values.settings = Object.assign( + $component.getValues(), + values.settings + ); + + // Retrive the values of your properties from Webix and store them in the view + values.settings.fields = $$(ids.fields).getChecked().join(","); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("orgchart"); + } + } + + return ABViewOrgChartTeamsProperty; +} From 1e4f0e26e3989c2033e173e47e91c6b80b384d92 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Tue, 10 Sep 2024 11:10:27 +0700 Subject: [PATCH 02/32] add options for node name and top node selection --- .../properties/views/ABViewOrgChartTeams.js | 131 +++++++++++------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 891acda6..8f682101 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -16,6 +16,9 @@ export default function (AB) { constructor() { super(BASE_ID, { datacollectionID: "", + teamLink: "", + teamName: "", + topTeam: "", fields: "", direction: "", depth: "", @@ -42,44 +45,47 @@ export default function (AB) { id: ids.datacollectionID, name: "datacollectionID", view: "richselect", - label: L("Data Collection"), + label: L("Team Data"), labelWidth: uiConfig.labelWidthLarge, options: [], on: { onChange: (value) => { this.CurrentView.settings.datacollectionID = value; - this.populateSubValueFieldOptions( - this.CurrentView?.datacollection?.datasource - ); + const obj = this.CurrentView?.datacollection?.datasource; + this.populateTeamFieldOptions(obj); this.onChange(); }, }, }, { - cols: [ - { - view: "label", - label: "Fields", - width: uiConfig.labelWidthLarge, - }, - { - id: ids.fields, - name: "fields", - view: "tree", - template: - "{common.icon()} {common.checkbox()} #value#", - select: false, - height: 200, - data: [], - on: { - onItemCheck: () => { - const fieldValues = $$(this.ids.fields).getChecked(); - this.refreshValueFieldOptions(fieldValues); - this.onChange(); - }, - }, - }, - ], + id: ids.teamLink, + view: "richselect", + label: L("Team Link"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.teamName, + view: "richselect", + label: L("Team Name"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.topTeam, + view: "richselect", + label: L("Top Team"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: () => this.onChange(), + }, }, { id: ids.direction, @@ -219,14 +225,16 @@ export default function (AB) { Object.assign(defaultValues, view.settings) ); - const $fieldList = $$(ids.fields); - $fieldList.clearAll(); - + // const $fieldList = $$(ids.fields); + // $fieldList.clearAll(); this.populateDatacollection(values.datacollectionId); - // this.populateDescriptionFieldOptions(values.columnDescription); - - const fieldValues = (view.settings?.fields ?? "").split(","); - this.refreshValueFieldOptions(fieldValues); + const teamObj = this.CurrentView?.datacollection?.datasource; + if (teamObj) { + this.populateTeamFieldOptions(teamObj); + $$(this.ids.teamLink).setValue(values.teamLink); + $$(this.ids.teamName).setValue(values.teamName); + $$(this.ids.topTeam).setValue(values.topTeam); + } $component.setValues(values); } @@ -274,24 +282,40 @@ export default function (AB) { $fieldList.unblockEvent(); } - populateSubValueFieldOptions(object, parentFieldId) { + populateTeamFieldOptions(object) { const view = this.CurrentView; - const $fields = $$(this.ids.fields); + const linkFields = view.getValueFields(object).map((f) => { + return { + id: f.id, + value: f.label, + field: f, + }; + }); + $$(this.ids.teamLink).define("options", linkFields); - view.getValueFields(object).forEach((f, index) => { - if ($fields.exists(f.id)) return; - $fields.add( - { + const textFields = object + ?.fields((f) => f.key === "string") + .map((f) => { + return { id: f.id, value: f.label, field: f, - }, - index, - parentFieldId - ); - }); + }; + }); + $$(this.ids.teamName).define("options", textFields); - $fields.openAll(); + const booleanFields = object + ?.fields((f) => f.key === "boolean") + .map((f) => { + return { + id: f.id, + value: f.label, + field: f, + }; + }); + // Add an empty option as this is an optional setting. + booleanFields.unshift({ id: "", value: "", $empty: true }); + $$(this.ids.topTeam).define("options", booleanFields); } // populateDescriptionFieldOptions(fieldId) { @@ -332,15 +356,16 @@ export default function (AB) { values() { const values = super.values(); const ids = this.ids; - const $component = $$(ids.component); - + // values.settings = values.setttings ?? {}; values.settings = Object.assign( - $component.getValues(), + $$(ids.component).getValues(), values.settings ); - // Retrive the values of your properties from Webix and store them in the view - values.settings.fields = $$(ids.fields).getChecked().join(","); + values.settings.teamLink = $$(ids.teamLink).getValue(); + values.settings.teamName = $$(ids.teamName).getValue(); + values.settings.topTeam = $$(ids.topTeam).getValue(); + values.settings.dataCollectionId = $$(ids.datacollectionID).getValue(); return values; } @@ -351,7 +376,7 @@ export default function (AB) { * NOTE: Must be overwritten by the Child Class */ ViewClass() { - return super._ViewClass("orgchart"); + return super._ViewClass("orgchart_teams"); } } From dc09c403025e93e86c7d502d6f2b85aaf96dce41 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Tue, 10 Sep 2024 12:46:21 +0700 Subject: [PATCH 03/32] add drag & drop setting --- .../properties/views/ABViewOrgChartTeams.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 8f682101..6e0c0bb9 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -22,6 +22,7 @@ export default function (AB) { fields: "", direction: "", depth: "", + draggable: "", color: "", pan: "", zoom: "", @@ -87,6 +88,19 @@ export default function (AB) { onChange: () => this.onChange(), }, }, + { + id: ids.draggable, + name: "draggable", + view: "checkbox", + label: L("Drag & Drop"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, { id: ids.direction, name: "direction", From 91ee7389c410d7d3aa8de39bc1324f877b038227 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Thu, 3 Oct 2024 13:39:03 +0700 Subject: [PATCH 04/32] add setting fields for inactive, canInactivate --- .../properties/views/ABViewOrgChartTeams.js | 76 ++++++++----------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 6e0c0bb9..ff111fb9 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -16,6 +16,8 @@ export default function (AB) { constructor() { super(BASE_ID, { datacollectionID: "", + teamInactive: "", + teamCanInactivate: "", teamLink: "", teamName: "", topTeam: "", @@ -64,9 +66,7 @@ export default function (AB) { label: L("Team Link"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, }, { id: ids.teamName, @@ -74,9 +74,7 @@ export default function (AB) { label: L("Team Name"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, }, { id: ids.topTeam, @@ -84,9 +82,23 @@ export default function (AB) { label: L("Top Team"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, + }, + { + id: ids.teamInactive, + view: "richselect", + label: L("Team Inactive"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { onChange: () => this.onChange() }, + }, + { + id: ids.teamCanInactivate, + view: "richselect", + label: L("Can Inactivate"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { onChange: () => this.onChange() }, }, { id: ids.draggable, @@ -95,11 +107,7 @@ export default function (AB) { label: L("Drag & Drop"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.direction, @@ -113,11 +121,7 @@ export default function (AB) { { id: "l2r", value: L("Left to Right") }, { id: "r2l", value: L("Right to Left") }, ], - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.depth, @@ -127,11 +131,7 @@ export default function (AB) { label: L("Depth"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.color, @@ -139,11 +139,7 @@ export default function (AB) { view: "colorpicker", label: L("Color"), labelWidth: uiConfig.labelWidthLarge, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -153,11 +149,7 @@ export default function (AB) { label: L("Pan"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -167,11 +159,7 @@ export default function (AB) { label: L("Zoom"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.height, @@ -179,11 +167,7 @@ export default function (AB) { name: "height", label: L("Height"), labelWidth: uiConfig.labelWidthLarge, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -330,6 +314,8 @@ export default function (AB) { // Add an empty option as this is an optional setting. booleanFields.unshift({ id: "", value: "", $empty: true }); $$(this.ids.topTeam).define("options", booleanFields); + $$(this.ids.teamInactive).define("options", booleanFields); + $$(this.ids.teamCanInactivate).define("options", booleanFields); } // populateDescriptionFieldOptions(fieldId) { @@ -379,6 +365,8 @@ export default function (AB) { values.settings.teamLink = $$(ids.teamLink).getValue(); values.settings.teamName = $$(ids.teamName).getValue(); values.settings.topTeam = $$(ids.topTeam).getValue(); + values.settings.teamInactive = $$(ids.teamInactive).getValue(); + values.settings.teamCanInactivate = $$(ids.teamCanInactivate).getValue(); values.settings.dataCollectionId = $$(ids.datacollectionID).getValue(); return values; From 1f0abaa6bf545fec1b2cb403823ffd70d3bd1942 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 11 Oct 2024 15:42:33 -0500 Subject: [PATCH 05/32] [wip] initial Netsuite object definitions --- .../Designer/ui_work_object_list_newObject.js | 13 +- ...object_list_newObject_api_read_response.js | 8 +- .../ui_work_object_list_newObject_netsuite.js | 404 +++++++++++++++++ ...ect_list_newObject_netsuite_connections.js | 409 +++++++++++++++++ ...ect_list_newObject_netsuite_credentials.js | 317 +++++++++++++ ...object_list_newObject_netsuite_dataTest.js | 390 ++++++++++++++++ ...k_object_list_newObject_netsuite_fields.js | 419 ++++++++++++++++++ ...k_object_list_newObject_netsuite_tables.js | 374 ++++++++++++++++ 8 files changed, 2328 insertions(+), 6 deletions(-) create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite_credentials.js create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite_dataTest.js create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite_fields.js create mode 100644 src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js diff --git a/src/rootPages/Designer/ui_work_object_list_newObject.js b/src/rootPages/Designer/ui_work_object_list_newObject.js index 16a6cc11..94b870fa 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject.js @@ -22,6 +22,7 @@ import UIBlankObject from "./ui_work_object_list_newObject_blank"; import UICsvObject from "./ui_work_object_list_newObject_csv"; import UIApiObject from "./ui_work_object_list_newObject_api"; import UIImportObject from "./ui_work_object_list_newObject_import"; +import UINetsuiteObject from "./ui_work_object_list_newObject_netsuite"; // const ABImportExternal = require("./ab_work_object_list_newObject_external"); export default function (AB) { const UIClass = UI_Class(AB); @@ -42,6 +43,7 @@ export default function (AB) { this.CsvTab = UICsvObject(AB); this.ApiTab = UIApiObject(AB); this.ImportTab = UIImportObject(AB); + this.NetsuiteTab = UINetsuiteObject(AB); /* this.ExternalTab = new ABImportExternal(AB); */ @@ -86,10 +88,11 @@ export default function (AB) { view: "tabview", id: this.ids.tab, cells: [ - this.BlankTab.ui() /*, this.ImportTab.ui(), this.ExternalTab.ui() */, + this.BlankTab.ui() /* this.ExternalTab.ui() */, this.CsvTab.ui(), this.ApiTab.ui(), this.ImportTab.ui(), + this.NetsuiteTab.ui(), ], tabbar: { on: { @@ -129,7 +132,9 @@ export default function (AB) { "BlankTab", "CsvTab", "ApiTab", - "ImportTab" /*, "ExternalTab"*/, + "ImportTab", + "NetsuiteTab", + /*, "ExternalTab"*/ ].forEach((k) => { allInits.push(this[k].init(AB)); this[k].on("cancel", () => { @@ -161,6 +166,7 @@ export default function (AB) { this.CsvTab.applicationLoad(application); this.ApiTab.applicationLoad(application); this.ImportTab.applicationLoad(application); + this.NetsuiteTab.applicationLoad(application); } /** @@ -285,6 +291,9 @@ export default function (AB) { case this.ExternalTab?.ids.form: this.ExternalTab?.onShow?.(this.CurrentApplicationID); break; + case this.NetsuiteTab?.ids.form: + this.NetsuiteTab?.onShow?.(this.CurrentApplicationID); + break; } } } diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js b/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js index 2d0275d0..147f9e85 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_api_read_response.js @@ -79,7 +79,7 @@ export default function (AB) { label: L("Data Key"), placeholder: "data.example", bottomLabel: L( - "* JSON key containing the relevant data from the resonse object. Can be left blank to use the root level data." + "* JSON key containing the relevant data from the response object. Can be left blank to use the root level data." ), suggest: [], on: { @@ -261,12 +261,12 @@ export default function (AB) { _addFieldItem(key, type) { const uiItem = this._fieldItem(key, type); - $$(this.ids.fields).addView(uiItem); + $$(this.ids.connections).addView(uiItem); } _clearFieldItems() { - const $fields = $$(this.ids.fields); - AB.Webix.ui([], $fields); + const $connections = $$(this.ids.connections); + AB.Webix.ui([], $connections); } _populateDataKeys() { diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js new file mode 100644 index 00000000..377a49b6 --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js @@ -0,0 +1,404 @@ +/* + * ui_work_object_list_newObject_netsuite + * + * Display the form for creating a new ABObject that connects to a Netsuite + * instance. + */ +import UI_Class from "./ui_class"; +import UI_Credentials from "./ui_work_object_list_newObject_netsuite_credentials"; +import UI_Tables from "./ui_work_object_list_newObject_netsuite_tables"; +import UI_Fields from "./ui_work_object_list_newObject_netsuite_fields"; +import UI_Connections from "./ui_work_object_list_newObject_netsuite_connections"; +import UI_FieldTest from "./ui_work_object_list_newObject_netsuite_dataTest"; + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + class UI_Work_Object_List_NewObject_Netsuite extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite", { + // component: base, + + form: "", + buttonSave: "", + buttonCancel: "", + }); + + this.UI_Credentials = UI_Credentials(AB); + this.UI_Tables = UI_Tables(AB); + this.UI_Fields = UI_Fields(AB); + this.UI_FieldTest = UI_FieldTest(AB); + this.UI_Connections = UI_Connections(AB); + } + + ui() { + // Our webix UI definition: + return { + id: this.ids.component, + header: L("Netsuite"), + body: { + view: "form", + id: this.ids.form, + width: 820, + height: 650, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + { + rows: [ + { + view: "text", + label: L("Name"), + name: "name", + required: true, + placeholder: L("Object name"), + labelWidth: 70, + }, + { + view: "checkbox", + label: L("Read Only"), + name: "readonly", + value: 0, + // disabled: true, + }, + ], + }, + { + view: "tabview", + cells: [ + this.UI_Credentials.ui(), + this.UI_Tables.ui(), + this.UI_Fields.ui(), + this.UI_Connections.ui(), + this.UI_FieldTest.ui(), + ], + }, + { fillspace: true }, + { + cols: [ + { fillspace: true }, + { + view: "button", + id: this.ids.buttonCancel, + value: L("Cancel"), + css: "ab-cancel-button", + autowidth: true, + click: () => { + this.cancel(); + }, + }, + { + view: "button", + id: this.ids.buttonSave, + css: "webix_primary", + value: L("Save"), + autowidth: true, + type: "form", + click: () => { + return this.save(); + }, + disabled: true, + }, + ], + }, + ], + }, + }; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + AB.Webix.extend(this.$form, webix.ProgressBar); + + this.UI_Credentials.init(AB); + this.UI_Tables.init(AB); + this.UI_Fields.init(AB); + this.UI_Connections.init(AB); + this.UI_FieldTest.init(AB); + + this.UI_Credentials.show(); + this.UI_Tables.disable(); + this.UI_Fields.disable(); + this.UI_Connections.disable(); + this.UI_FieldTest.disable(); + + // "verified" is triggered on the credentials tab once we verify + // the entered data is successful. + this.UI_Credentials.on("verified", () => { + this.UI_Tables.enable(); + let creds = this.UI_Credentials.credentials(); + this.UI_Tables.setCredentials(creds); + this.UI_Fields.setCredentials(creds); + this.UI_FieldTest.setCredentials(creds); + // this.UI_Tables.loadTables(); + this.UI_Tables.show(); + }); + + this.UI_Credentials.on("notverified", () => { + this.UI_Tables.disable(); + }); + + this.UI_Tables.on("table.selected", (table) => { + this.UI_Fields.enable(); + this.UI_Fields.loadFields(table); + this.UI_Fields.show(); + + this.UI_Connections.setTable(table); + this.UI_FieldTest.setTable(table); + }); + + this.UI_Fields.on("connections", (list) => { + this.UI_Connections.loadConnections(list); + this.UI_Connections.enable(); + }); + + this.UI_Fields.on("fields.ready", (config) => { + this.UI_FieldTest.enable(); + this.UI_FieldTest.loadConfig(config); + }); + + this.UI_FieldTest.on("data.verfied", () => { + $$(this.ids.buttonSave).enable(); + }); + + // "save.error" is triggered by the ui_work_object_list_newObject + // if there was an error saving the values from our form. + this.on("save.error", (err) => { + this.onError(err); + }); + + // "save.successful" is triggered by the ui_work_object_list_newObject + // if the values we provided were successfully saved. + this.on("save.successful", async (obj) => { + this.onSuccess(); + + // try { + // await obj.fetchData(); + + // webix.message({ + // type: "success", + // text: L("Successfully fetching data."), + // }); + // } catch (err) { + // webix.message({ + // type: "error", + // text: L("Error fetching data."), + // }); + // this.AB.notify.developer(err, { + // context: "ABObjectAPI.fetchData()", + // object: obj.toObj(), + // }); + // } + }); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + cancel() { + this.formClear(); + this.emit("cancel"); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + + this.UI_Credentials.formClear(); + this.UI_Tables.formClear(); + this.UI_Fields.formClear(); + this.UI_Connections.formClear(); + this.UI_FieldTest.formClear(); + + $$(this.ids.buttonSave).disable(); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + onError(err) { + if (err) { + console.error(err); + let message = L("the entered data is invalid"); + // if this was our Validation() object: + if (err.updateForm) { + err.updateForm(this.$form); + } else { + if (err.code && err.data) { + message = err.data?.sqlMessage ?? message; + } else { + message = err?.message ?? message; + } + } + + const values = this.$form.getValues(); + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: message, + type: "alert-error", + }); + } + // get notified if there was an error saving. + $$(this.ids.buttonSave).enable(); + } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + onSuccess() { + this.formClear(); + $$(this.ids.buttonSave).enable(); + } + + /** + * @function save + * + * verify the current info is ok, package it, and return it to be + * added to the application.createModel() method. + */ + async save() { + this.busy(); + + const Form = this.$form; + + Form.clearValidation(); + + // if it doesn't pass the basic form validation, return: + if (!Form.validate()) { + this.ready(); + return false; + } + + let values = Form.getValues(); + + values.credentials = this.UI_Credentials.getValues(); + values.tableName = this.UI_Tables.getValues(); + + let allFields = this.UI_Fields.getValues(); + + // allConnectFields = allFields.concat(this.UI_Connections.getValues()); + /* + linkCol = linkObject.fieldNew({ + // id: OP.Util.uuid(), + + key: field.key, + + columnName: linkColumnName, + label: this.CurrentObject.label, + + settings: { + showIcon: field.settings.showIcon, + + linkObject: field.object.id, + linkType: field.settings.linkViaType, + linkViaType: field.settings.linkType, + isCustomFK: field.settings.isCustomFK, + indexField: field.settings.indexField, + indexField2: field.settings.indexField2, + isSource: 0, + width: width, + }, + }); + */ + + // Pick out our special columns: pk, created_at, updated_at + let pkField = allFields.find((f) => f.pk); + if (!pkField) { + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: L("No primary key specified."), + type: "alert-error", + }); + return; + } + values.primaryColumnName = pkField.column; + + values.columnRef = { created_at: null, updated_at: null }; + + ["created_at", "updated_at"].forEach((field) => { + let foundField = allFields.find((f) => f[field]); + if (foundField) { + values.columnRef[field] = foundField.column; + } + }); + + // Create a new Object + const object = AB.objectNew( + Object.assign({ isNetsuite: true }, values) + ); + + try { + // Add fields + + for (const f of allFields) { + let def = { + name: f.title, + label: f.title, + columnName: f.column, + key: f.abType, + }; + if (f.default) { + def.settings = {}; + def.settings.default = f.default; + } + const field = AB.fieldNew(def, object); + await field.save(true); + + // values.fieldIDs.push(field.id); + } + // values.id = object.id; + + this.emit("save", object.toObj()); + + this.ready(); + } catch (err) { + console.error(err); + } + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + } + + busy() { + const $form = $$(this.ids.form); + const $saveButton = $$(this.ids.buttonSave); + + $form.showProgress({ type: "icon" }); + $saveButton.disable(); + } + + ready() { + const $form = $$(this.ids.form); + const $saveButton = $$(this.ids.buttonSave); + + $form.hideProgress(); + $saveButton.enable(); + } + } + return new UI_Work_Object_List_NewObject_Netsuite(); +} diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js new file mode 100644 index 00000000..eb811400 --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js @@ -0,0 +1,409 @@ +/* + * ui_work_object_list_newObject_netsuite_connections + * + * Display the tab/form for selecting which of the available conections we + * want to create for this table. + */ +import UI_Class from "./ui_class"; + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + const uiConfig = AB.Config.uiSettings(); + + class UI_Work_Object_List_NewObject_Netsuite_Connections extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite_connections", { + // component: base, + + form: "", + + fieldSelector: "", + connections: "", + displayConnections: "", + displayNoConnections: "", + + fieldGrid: "", + buttonVerify: "", + buttonLookup: "", + tableName: "", + }); + + this.credentials = {}; + // { CRED_KEY : CRED_VAL } + // The entered credential references necessary to perform our Netsuite + // operations. + + this.connectionList = null; + // {array} + // Holds an array of connection descriptions + + this.connections = null; + // {array} + // Holds the array of chosen/verified connections + } + + ui() { + // Our webix UI definition: + return { + id: this.ids.component, + header: L("Connections"), + body: { + view: "form", + id: this.ids.form, + width: 800, + height: 450, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + { + view: "layout", + padding: 10, + rows: [ + { + id: this.ids.tableName, + label: L("Selected Table: {0}", [this.table]), + view: "label", + height: 40, + }, + ], + }, + + // Field Selector + { + view: "multiview", + animate: false, + borderless: true, + rows: [ + { + id: this.ids.displayNoConnections, + rows: [ + { + maxHeight: uiConfig.xxxLargeSpacer, + hidden: uiConfig.hideMobile, + }, + { + view: "label", + align: "center", + height: 200, + label: "
", + }, + { + // id: ids.error_msg, + view: "label", + align: "center", + label: L( + "You have no other Netwuite Objects imported" + ), + }, + { + // id: ids.error_msg, + view: "label", + align: "center", + label: L( + "Continue creating this object now, then create the connections on the other objects you import." + ), + }, + { + maxHeight: uiConfig.xxxLargeSpacer, + hidden: uiConfig.hideMobile, + }, + ], + }, + { + id: this.ids.displayConnections, + rows: [ + { + // id: ids.tabFields, + view: "layout", + padding: 10, + rows: [ + { + cols: [ + { + label: L("Connections"), + view: "label", + }, + { + icon: "wxi-plus", + view: "icon", + width: 38, + click: () => { + this._addConnection(); + }, + }, + ], + }, + { + view: "scrollview", + scroll: "y", + borderless: true, + padding: 0, + margin: 0, + body: { + id: this.ids.connections, + view: "layout", + padding: 0, + margin: 0, + rows: [], + }, + }, + ], + }, + + { + cols: [ + { fillspace: true }, + // { + // view: "button", + // id: this.ids.buttonCancel, + // value: L("Cancel"), + // css: "ab-cancel-button", + // autowidth: true, + // click: () => { + // this.cancel(); + // }, + // }, + { + view: "button", + id: this.ids.buttonVerify, + css: "webix_primary", + value: L("Verify"), + autowidth: true, + type: "form", + click: () => { + return this.verify(); + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + }; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + + this.$fieldSelector = $$(this.ids.fieldSelector); + AB.Webix.extend(this.$form, webix.ProgressBar); + AB.Webix.extend(this.$fieldSelector, webix.ProgressBar); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + disable() { + $$(this.ids.form).disable(); + } + + enable() { + $$(this.ids.form).enable(); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + this.disable(); + } + + getValues() { + return []; // TODO: + } + + setTable(table) { + this.table = table; + $$(this.ids.tableName).setValue( + `${this.table}` + ); + } + + loadConnections(allConnections) { + this.connectionList = allConnections; + // refresh more often than on init(); + this.listNetsuiteObjects = this.AB.objects((o) => o.isNetsuite); + if (this.listNetsuiteObjects.length == 0) { + $$(this.ids.displayNoConnections)?.show(); + } else { + $$(this.ids.displayConnections)?.show(); + } + } + + _fieldItem(key, type) { + const self = this; + const fieldTypes = this.AB.Class.ABFieldManager.allFields(); + const fieldKeys = ["string", "LongText", "number", "date", "boolean"]; + + const linkTypes = ["one:one", "one:many", "many:one", "many:many"]; + return { + cols: [ + { + rows: [ + { + label: L("Field"), + view: "label", + }, + { + placeholder: "Type", + options: this.connectionList.map((conn) => { + return { + id: conn.column, + value: conn.column, + }; + }), + view: "select", + // value: type, + }, + ], + }, + { + rows: [ + { + placeholder: "Existing Netsuite Object", + options: this.listNetsuiteObjects.map((nObj) => { + return { + id: nObj.id, + value: nObj.label, + }; + }), + view: "select", + // value: type, + }, + { + placeholder: "Link Column", + options: [], + view: "select", + // value: type, + }, + { + placeholder: "Link Type", + options: linkTypes.map((l) => { + return { + id: l, + value: l, + }; + }), + view: "select", + // value: type, + }, + ], + }, + + { + icon: "wxi-trash", + view: "icon", + width: 38, + click: function () { + const $item = this.getParentView(); + $$(self.ids.fields).removeView($item); + }, + }, + ], + }; + } + + _addConnection(key, type) { + const uiItem = this._fieldItem(key, type); + $$(this.ids.connections).addView(uiItem); + } + + _clearFieldItems() { + const $connections = $$(this.ids.connections); + AB.Webix.ui([], $connections); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + onError(err) { + if (err) { + console.error(err); + let message = L("the entered data is invalid"); + // if this was our Validation() object: + if (err.updateForm) { + err.updateForm(this.$form); + } else { + if (err.code && err.data) { + message = err.data?.sqlMessage ?? message; + } else { + message = err?.message ?? message; + } + } + + const values = this.$form.getValues(); + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: message, + type: "alert-error", + }); + } + // get notified if there was an error saving. + $$(this.ids.buttonVerify).enable(); + } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + onSuccess() { + this.formClear(); + $$(this.ids.buttonVerify).enable(); + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + } + + busy() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$fieldSelector.showProgress({ type: "icon" }); + $verifyButton.disable(); + } + + ready() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$fieldSelector.hideProgress(); + $verifyButton.enable(); + } + + // setCredentials(creds) { + // this.credentials = creds; + // } + + // verify() { + // this.emit("fields.ready", { + // credentials: this.credentials, + // table: this.table, + // fieldList: this.fieldList, + // }); + // } + } + return new UI_Work_Object_List_NewObject_Netsuite_Connections(); +} diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_credentials.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_credentials.js new file mode 100644 index 00000000..e4fbf138 --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_credentials.js @@ -0,0 +1,317 @@ +/* + * ui_work_object_list_newObject_netsuite_credentials + * + * Display the tab/form for entering the Netsuite credentials for our + * connection. + */ +import UI_Class from "./ui_class"; + +const KeysCredentials = [ + "NETSUITE_CONSUMER_KEY", + "NETSUITE_CONSUMER_SECRET", + "NETSUITE_TOKEN_KEY", + "NETSUITE_TOKEN_SECRET", +]; +const KeysAPI = [ + "NETSUITE_REALM", + "NETSUITE_BASE_URL", + "NETSUITE_QUERY_BASE_URL", +]; + +const KeysALL = KeysCredentials.concat(KeysAPI); + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + class UI_Work_Object_List_NewObject_Netsuite_Credentials extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite_credentials", { + // component: base, + + form: "", + buttonVerify: "", + labelVerified: "", + }); + + this.entries = {}; + } + + ui() { + // Our webix UI definition: + let ui = { + id: this.ids.component, + header: L("Credentials"), + body: { + view: "form", + id: this.ids.form, + width: 820, + height: 700, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + { + rows: [], + }, + { + cols: [ + { fillspace: true }, + // { + // view: "button", + // id: this.ids.buttonCancel, + // value: L("Cancel"), + // css: "ab-cancel-button", + // autowidth: true, + // click: () => { + // this.cancel(); + // }, + // }, + { + view: "button", + id: this.ids.buttonVerify, + css: "webix_primary", + value: L("Verify"), + autowidth: true, + type: "form", + click: () => { + return this.verify(); + }, + }, + ], + }, + { + cols: [ + { fillspace: true }, + { + id: this.ids.labelVerified, + view: "label", + label: L( + "All parameters are valid. Continue on to select a Table to work with." + ), + hidden: true, + }, + ], + }, + ], + }, + }; + + let rows = ui.body.elements[0].rows; + let fsOauth = { + view: "fieldset", + label: L("Netsuite OAuth 1.0 Credentials"), + body: { + rows: [], + }, + }; + + let EnvInput = (k) => { + return { + cols: [ + { + id: k, + view: "text", + label: k, + name: k, + required: true, + placeholder: `ENV:${k}`, + value: `ENV:${k}`, + labelWidth: 230, + on: { + onChange: (nV, oV) => { + this.envVerify(k, nV); + }, + }, + }, + { + id: `${k}_verified`, + view: "label", + width: 20, + label: '', + hidden: true, + }, + ], + }; + }; + + KeysCredentials.forEach((k) => { + fsOauth.body.rows.push(EnvInput(k)); + }); + rows.push(fsOauth); + rows.push({ height: 15 }); + + let fsAPI = { + view: "fieldset", + label: L("Netsuite API Config"), + body: { + rows: [], + }, + }; + + KeysAPI.forEach((k) => { + fsAPI.body.rows.push(EnvInput(k)); + }); + rows.push(fsAPI); + + return ui; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + AB.Webix.extend(this.$form, webix.ProgressBar); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + + KeysALL.forEach((k) => { + $$(k).setValue(`ENV:${k}`); + }); + } + + getValues() { + return this.credentials(); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + onError(err) { + if (err) { + console.error(err); + let message = L("the entered data is invalid"); + // if this was our Validation() object: + if (err.updateForm) { + err.updateForm(this.$form); + } else { + if (err.code && err.data) { + message = err.data?.sqlMessage ?? message; + } else { + message = err?.message ?? message; + } + } + + const values = this.$form.getValues(); + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: message, + type: "alert-error", + }); + } + // get notified if there was an error saving. + $$(this.ids.buttonVerify).enable(); + } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + onSuccess() { + this.formClear(); + $$(this.ids.buttonVerify).enable(); + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + console.log("SHOW, Baby! SHOW!"); + } + + busy() { + const $form = $$(this.ids.form); + const $saveButton = $$(this.ids.buttonVerify); + + $form.showProgress({ type: "icon" }); + $saveButton.disable(); + } + + credentials() { + let creds = {}; + KeysALL.forEach((k) => { + let $input = $$(k); + if ($input) { + creds[k] = $input.getValue(); + } + }); + + return creds; + } + + envVerify(k, nV) { + let envKey = nV.replace("ENV:", ""); + return this.AB.Network.get({ + url: `/env/verify/${envKey}`, + }) + .then((result) => { + console.log(result); + if (result.status == "success") { + $$(`${k}_verified`).show(); + this.entries[k] = true; + } else { + $$(`${k}_verified`).hide(); + this.entries[k] = false; + } + }) + .catch((err) => { + console.error(err); + $$(`${k}_verified`).hide(); + this.entries[k] = false; + }); + } + + ready() { + const $form = $$(this.ids.form); + const $saveButton = $$(this.ids.buttonVerify); + + $form.hideProgress(); + $saveButton.enable(); + } + + async verify() { + let isVerified = true; + let AllVerifies = []; + KeysALL.forEach((k) => { + let nV = $$(k).getValue(); + AllVerifies.push(this.envVerify(k, nV)); + }); + await Promise.all(AllVerifies); + + KeysALL.forEach((k) => { + isVerified = isVerified && this.entries[k]; + }); + + if (isVerified) { + this.emit("verified"); + $$(this.ids.labelVerified)?.show(); + } else { + this.emit("notverified"); + $$(this.ids.labelVerified)?.hide(); + } + } + } + return new UI_Work_Object_List_NewObject_Netsuite_Credentials(); +} diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_dataTest.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_dataTest.js new file mode 100644 index 00000000..a258d31f --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_dataTest.js @@ -0,0 +1,390 @@ +/* + * ui_work_object_list_newObject_netsuite_dataTest + * + * Display the tab/form to review what the current Definitions look like + * working with the data from Netsuite. + */ +import UI_Class from "./ui_class"; + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + class UI_Work_Object_List_NewObject_Netsuite_DataTest extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite_dataTest", { + // component: base, + form: "", + network: "", + dataView: "", + + buttonVerify: "", + tableName: "", + }); + + this.credentials = {}; + // { CRED_KEY : CRED_VAL } + // The entered credential references necessary to perform our Netsuite + // operations. + + this.fieldKeys = [ + "string", + "LongText", + "number", + "date", + "boolean", + "json", + "list", + ]; + // {array} of types of ABFields we can translate into. + + this.fieldList = null; + // {array} + // Holds an array of field descriptions + + this.table = null; + // {string} + // name of the table we are working with + } + + ui() { + // Our webix UI definition: + return { + id: this.ids.component, + header: L("Data Verification"), + body: { + view: "form", + id: this.ids.form, + width: 800, + height: 400, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + // Field Selector + { + view: "layout", + padding: 10, + rows: [ + { + cols: [ + { + id: this.ids.tableName, + label: L("Selected Table: {0}", [this.table]), + view: "label", + height: 40, + }, + {}, + ], + }, + { + view: "multiview", + // keepViews: true, + cells: [ + // Select Table indicator + { + id: this.ids.network, + rows: [ + {}, + { + view: "label", + align: "center", + height: 200, + label: "
", + }, + { + view: "label", + align: "center", + label: L( + "Gathering data from Netsuite." + ), + }, + {}, + ], + }, + { + id: this.ids.dataView, + rows: [ + {}, + { + view: "label", + label: "Waiting for response", + }, + {}, + ], + // hidden: true, + }, + ], + }, + + // { + // id: this.ids.fieldGrid, + // view: "datatable", + // resizeColumn: true, + // height: 300, + // columns: [ + // { + // id: "title", + // header: L("title"), + // editor: "text", + // }, + // { id: "column", header: L("column") }, + + // { id: "nullable", header: L("nullable") }, + // { id: "readOnly", header: L("read only") }, + // { + // id: "pk", + // header: L("is primary key"), + // template: "{common.radio()}", + // }, + // // { + // // id: "description", + // // header: L("description"), + // // fillspace: true, + // // }, + // { + // id: "abType", + // header: L("AB Field Type"), + // editor: "select", + // options: [" "].concat(this.fieldKeys), + // }, + // { + // id: "delme", + // header: "", + // template: "{common.trashIcon()}", + // }, + // ], + // editable: true, + // scroll: "y", + // onClick: { + // "wxi-trash": (e, id) => { + // debugger; + // $$(this.ids.fieldGrid).remove(id); + // }, + // }, + // }, + ], + }, + + { + cols: [ + { fillspace: true }, + // { + // view: "button", + // id: this.ids.buttonCancel, + // value: L("Cancel"), + // css: "ab-cancel-button", + // autowidth: true, + // click: () => { + // this.cancel(); + // }, + // }, + { + view: "button", + id: this.ids.buttonVerify, + css: "webix_primary", + value: L("Verify"), + autowidth: true, + type: "form", + click: () => { + return this.verify(); + }, + }, + ], + }, + ], + }, + }; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + AB.Webix.extend(this.$form, webix.ProgressBar); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + disable() { + $$(this.ids.form).disable(); + } + + enable() { + $$(this.ids.form).enable(); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + + // reset the data view to blank + let table = { + id: this.ids.dataView, + rows: [ + {}, + { + view: "label", + label: "Waiting for response", + }, + {}, + ], + // hidden: true, + }; + webix.ui(table, $$(this.ids.dataView)); + this.disable(); + } + setTableName() { + $$(this.ids.tableName).setValue( + `${this.table}` + ); + } + + setTable(table) { + this.table = table; + this.setTableName(); + + // this is called when a table name has been selected. + // but we need to be disabled until they have verified the + // fields. + this.formClear(); + } + + async loadConfig(config) { + this.credentials = config.credentials; + this.setTable(config.table); + this.fieldList = config.fieldList; + + $$(this.ids.network).show(); + this.busy(); + + let result = await this.AB.Network.get({ + url: `/netsuite/dataVerify/${this.table}`, + params: { + credentials: JSON.stringify(this.credentials), + }, + }); + + this.data = result; + // this.ids.dataView, + + // convert all the json types to strings for display: + this.fieldList + .filter((f) => f.abType == "json") + .forEach((f) => { + this.data.forEach((d) => { + try { + d[f.column] = JSON.stringify(d[f.column]); + } catch (e) { + console.log(e); + } + }); + }); + + this.showTable(); + this.enable(); + this.ready(); + } + + showTable() { + let table = { + id: this.ids.dataView, + view: "datatable", + columns: this.fieldList.map((f) => { + return { + id: f.column, + header: f.title, + }; + }), + data: this.data, + }; + + webix.ui(table, $$(this.ids.dataView)); + $$(this.ids.dataView).show(); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + // onError(err) { + // if (err) { + // console.error(err); + // let message = L("the entered data is invalid"); + // // if this was our Validation() object: + // if (err.updateForm) { + // err.updateForm(this.$form); + // } else { + // if (err.code && err.data) { + // message = err.data?.sqlMessage ?? message; + // } else { + // message = err?.message ?? message; + // } + // } + + // const values = this.$form.getValues(); + // webix.alert({ + // title: L("Error creating Object: {0}", [values.name]), + // ok: L("fix it"), + // text: message, + // type: "alert-error", + // }); + // } + // // get notified if there was an error saving. + // $$(this.ids.buttonVerify).enable(); + // } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + // onSuccess() { + // this.formClear(); + // $$(this.ids.buttonVerify).enable(); + // } + + verify() { + this.emit("data.verfied"); + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + } + + busy() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$form.showProgress({ type: "icon" }); + $verifyButton.disable(); + } + + ready() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$form.hideProgress(); + $verifyButton.enable(); + } + + setCredentials(creds) { + this.credentials = creds; + } + } + return new UI_Work_Object_List_NewObject_Netsuite_DataTest(); +} diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_fields.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_fields.js new file mode 100644 index 00000000..08caf392 --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_fields.js @@ -0,0 +1,419 @@ +/* + * ui_work_object_list_newObject_netsuite_fields + * + * Display the tab/form for selecting which of the available tables we are + * working with. + */ +import UI_Class from "./ui_class"; + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + class UI_Work_Object_List_NewObject_Netsuite_Fields extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite_fields", { + // component: base, + + form: "", + + tableName: "", + // tableList: "", + fieldSelector: "", + // fields: "", + fieldGrid: "", + buttonVerify: "", + // buttonLookup: "", + }); + + this.credentials = {}; + // { CRED_KEY : CRED_VAL } + // The entered credential references necessary to perform our Netsuite + // operations. + + this.fieldKeys = [ + "string", + "LongText", + "number", + "date", + "datetime", + "boolean", + "json", + "list", + // "connectObject", + ]; + // {array} of types of ABFields we can translate into. + + this.fieldList = null; + // {array} + // Holds an array of field descriptions + + this.fields = null; + // {array} + // Holds the array of chosen/verified fields + } + + ui() { + // Our webix UI definition: + return { + id: this.ids.component, + header: L("Fields"), + body: { + view: "form", + id: this.ids.form, + width: 800, + height: 450, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + // Field Selector + { + id: this.ids.fieldSelector, + view: "layout", + padding: 10, + rows: [ + { + rows: [ + { + id: this.ids.tableName, + label: L("Selected Table: {0}", [this.table]), + view: "label", + height: 40, + }, + {}, + ], + }, + // { + // view: "scrollview", + // scroll: "y", + // borderless: true, + // padding: 0, + // margin: 0, + // body: { + // id: this.ids.fields, + // view: "layout", + // padding: 0, + // margin: 0, + // rows: [], + // }, + // }, + { + id: this.ids.fieldGrid, + view: "datatable", + resizeColumn: true, + height: 300, + columns: [ + { + id: "title", + header: L("title"), + editor: "text", + }, + { id: "column", header: L("column") }, + + { id: "nullable", header: L("nullable") }, + { id: "readOnly", header: L("read only") }, + { + id: "default", + header: L("Default Value"), + editor: "text", + }, + { + id: "pk", + header: L("is primary key"), + template: "{common.radio()}", + }, + { + id: "created_at", + header: L("Created At"), + template: "{common.radio()}", + }, + { + id: "updated_at", + header: L("Updated At"), + template: "{common.radio()}", + }, + // { + // id: "description", + // header: L("description"), + // fillspace: true, + // }, + { + id: "abType", + header: L("AB Field Type"), + editor: "select", + options: [" "].concat(this.fieldKeys), + on: { + onChange: (newValue, oldValue) => { + debugger; + }, + }, + }, + { + id: "delme", + header: "", + template: "{common.trashIcon()}", + }, + ], + editable: true, + scroll: "xy", + onClick: { + "wxi-trash": (e, id) => { + $$(this.ids.fieldGrid).remove(id); + this.fields = this.fields.filter( + (f) => f.id != id.row + ); + }, + }, + }, + { + cols: [ + { fillspace: true }, + // { + // view: "button", + // id: this.ids.buttonCancel, + // value: L("Cancel"), + // css: "ab-cancel-button", + // autowidth: true, + // click: () => { + // this.cancel(); + // }, + // }, + { + view: "button", + id: this.ids.buttonVerify, + css: "webix_primary", + value: L("Verify"), + autowidth: true, + type: "form", + click: () => { + return this.verify(); + }, + }, + ], + }, + ], + }, + ], + }, + }; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + + this.$fieldSelector = $$(this.ids.fieldSelector); + AB.Webix.extend(this.$form, webix.ProgressBar); + AB.Webix.extend(this.$fieldSelector, webix.ProgressBar); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + disable() { + $$(this.ids.form).disable(); + } + + enable() { + $$(this.ids.form).enable(); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + + $$(this.ids.fieldGrid)?.clearAll(); + this.disable(); + $$(this.ids.buttonVerify).disable(); + } + + addABType(f) { + switch (f.type) { + case "array": + // this is most likely a MANY:x connection. + // Q:what do we default this to? + f.abType = "json"; + break; + + case "object": + // this is most likely a ONE:X[ONE,MANY] connection. + // // lets scan the properties of the dest obj, + // // find a property with title = "Internal Identifier" + // // and make this ABType == that property.type + + // if (f.properties) { + // Object.keys(f.properties).forEach((k) => { + // if (f.properties[k].title == "Internal Identifier") { + // f.abType = f.properties[k].type; + // } + // }); + // } + // // default to "string" if an Internal Identifier isn't found. + // if (!f.abType) { + // f.abType = "string"; + // } + f.abType = "connectObject"; + break; + + case "boolean": + f.abType = "boolean"; + break; + + default: + f.abType = "string"; + } + + // just in case: + // lets see if this looks like a date field instead + + if (f.abType == "string") { + let lcTitle = f.title?.toLowerCase(); + if (lcTitle) { + let indxDate = lcTitle.indexOf("date") > -1; + let indxDay = lcTitle.indexOf("day") > -1; + if (indxDate || indxDay) { + f.abType = "date"; + } + } + + if (f.format == "date-time") { + f.abType = "datetime"; + } + } + + // Seems like the PKs have title == "Internal ID" + if (f.title == "Internal ID") { + f.pk = true; + } + } + + getValues() { + return this.fields; + } + + setTableName() { + $$(this.ids.tableName).setValue( + `${this.table}` + ); + } + async loadFields(table) { + $$(this.ids.fieldGrid)?.clearAll(); + this.table = table; + $$(this.ids.fieldSelector).show(); + this.busy(); + this.setTableName(); + + let result = await this.AB.Network.get({ + url: `/netsuite/table/${table}`, + params: { credentials: JSON.stringify(this.credentials) }, + }); + + this.fieldList = result; + (result || []).forEach((f) => { + this.addABType(f); + }); + + // ok, in this pane, we are just looking at the base fields + // leave the connections to the next pane: + this.fields = result.filter((r) => r.type != "object"); + + // let our other pane know about it's connections + this.emit( + "connections", + result.filter((r) => r.type == "object") + ); + + $$(this.ids.fieldGrid).parse(this.fields); + this.ready(); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + onError(err) { + if (err) { + console.error(err); + let message = L("the entered data is invalid"); + // if this was our Validation() object: + if (err.updateForm) { + err.updateForm(this.$form); + } else { + if (err.code && err.data) { + message = err.data?.sqlMessage ?? message; + } else { + message = err?.message ?? message; + } + } + + const values = this.$form.getValues(); + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: message, + type: "alert-error", + }); + } + // get notified if there was an error saving. + $$(this.ids.buttonVerify).enable(); + } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + onSuccess() { + this.formClear(); + $$(this.ids.buttonVerify).enable(); + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + } + + busy() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$fieldSelector.showProgress({ type: "icon" }); + $verifyButton.disable(); + } + + ready() { + const $verifyButton = $$(this.ids.buttonVerify); + + this.$fieldSelector.hideProgress(); + $verifyButton.enable(); + } + + setCredentials(creds) { + this.credentials = creds; + } + + verify() { + this.emit("fields.ready", { + credentials: this.credentials, + table: this.table, + fieldList: this.fields, + }); + } + } + return new UI_Work_Object_List_NewObject_Netsuite_Fields(); +} diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js new file mode 100644 index 00000000..f5481169 --- /dev/null +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js @@ -0,0 +1,374 @@ +/* + * ui_work_object_list_newObject_netsuite_tables + * + * Display the tab/form for selecting which of the available tables we are + * working with. + */ +import UI_Class from "./ui_class"; + +export default function (AB) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + class UI_Work_Object_List_NewObject_Netsuite_Tables extends UIClass { + constructor() { + super("ui_work_object_list_newObject_netsuite_tables", { + // component: base, + + form: "", + + searchText: "", + tableList: "", + // fieldSelector: "", + fields: "", + buttonVerify: "", + buttonLookup: "", + }); + + this.credentials = {}; + // { CRED_KEY : CRED_VAL } + // The entered credential references necessary to perform our Netsuite + // operations. + + this.lastSelectedTable = null; + // {string} + // the table name of the last selected table. + } + + ui() { + // Our webix UI definition: + return { + id: this.ids.component, + header: L("Tables"), + body: { + view: "form", + id: this.ids.form, + width: 800, + height: 400, + rules: { + // TODO: + // name: inputValidator.rules.validateObjectName + }, + elements: [ + { + cols: [ + // The Table Selector Column + { + rows: [ + { + cols: [ + { + view: "label", + align: "left", + label: L( + "Use the provided credentials to request a list of tables to work with." + ), + }, + { + view: "button", + id: this.ids.buttonLookup, + value: L("Load Catalog"), + // css: "ab-cancel-button", + autowidth: true, + click: () => { + this.loadCatalog(); + }, + }, + ], + }, + { + id: this.ids.searchText, + view: "search", + icon: "fa fa-search", + label: L("Search"), + labelWidth: 80, + placeholder: L("tablename"), + height: 35, + keyPressTimeout: 100, + on: { + onAfterRender() { + AB.ClassUI.CYPRESS_REF(this); + }, + onTimedKeyPress: () => { + let searchText = $$(this.ids.searchText) + .getValue() + .toLowerCase(); + + this.$list.filter(function (item) { + return ( + !item.value || + item.value + .toLowerCase() + .indexOf(searchText) > -1 + ); + }); + }, + }, + }, + { + id: this.ids.tableList, + view: "list", + select: 1, + height: 400, + on: { + onItemClick: (id, e) => { + if (id != this.lastSelectedTable) { + this.lastSelectedTable = id; + this.emit("table.selected", id); + } + }, + }, + }, + ], + }, + + // Select Table indicator + { + rows: [ + {}, + { + view: "label", + align: "center", + height: 200, + label: "
", + }, + { + view: "label", + align: "center", + label: L("Select an table to work with."), + }, + {}, + ], + }, + ], + }, + // { + // cols: [ + // { fillspace: true }, + // // { + // // view: "button", + // // id: this.ids.buttonCancel, + // // value: L("Cancel"), + // // css: "ab-cancel-button", + // // autowidth: true, + // // click: () => { + // // this.cancel(); + // // }, + // // }, + // { + // view: "button", + // id: this.ids.buttonVerify, + // css: "webix_primary", + // value: L("Verify"), + // autowidth: true, + // type: "form", + // click: () => { + // return this.verify(); + // }, + // }, + // ], + // }, + ], + }, + }; + } + + async init(AB) { + this.AB = AB; + + this.$form = $$(this.ids.form); + this.$list = $$(this.ids.tableList); + // this.$fieldSelector = $$(this.ids.fieldSelector); + AB.Webix.extend(this.$form, webix.ProgressBar); + AB.Webix.extend(this.$list, webix.ProgressBar); + // AB.Webix.extend(this.$fieldSelector, webix.ProgressBar); + + // init() routines are always considered async so: + return Promise.resolve(); + } + + disable() { + $$(this.ids.form).disable(); + } + + enable() { + $$(this.ids.form).enable(); + } + + formClear() { + this.$form.clearValidation(); + this.$form.clear(); + + $$(this.ids.searchText).setValue(""); + this.$list.filter(() => true); + this.lastSelectedTable = null; + } + getValues() { + return this.lastSelectedTable; + } + + async loadCatalog() { + this.busy(); + let result = await this.AB.Network.get({ + url: "/netsuite/metadata", + params: { credentials: JSON.stringify(this.credentials) }, + }); + + let data = []; + result.forEach((r) => { + data.push({ id: r, value: r }); + }); + let $table = $$(this.ids.tableList); + $table.clearAll(); + $table.parse(data); + + console.error(data); + } + + _fieldItem(def) { + const self = this; + const fieldTypes = this.AB.Class.ABFieldManager.allFields(); + const fieldKeys = ["string", "LongText", "number", "date", "boolean"]; + + let key = def.column || def.title; + let type = def.type; + + return { + cols: [ + { + view: "text", + value: key, + placeholder: "key", + }, + { + placeholder: "Type", + options: fieldKeys.map((fKey) => { + return { + id: fKey, + value: fieldTypes + .filter((f) => f.defaults().key == fKey)[0] + ?.defaults().menuName, + }; + }), + view: "select", + value: type, + }, + { + icon: "wxi-trash", + view: "icon", + width: 38, + click: function () { + const $item = this.getParentView(); + $$(self.ids.fields).removeView($item); + }, + }, + ], + }; + } + + async loadFields(table) { + // $$(this.ids.fieldSelector).show(); + this.busyFields(); + + let result = await this.AB.Network.get({ + url: `/netsuite/table/${table}`, + params: { credentials: JSON.stringify(this.credentials) }, + }); + + this.fieldList = result; + (result || []).forEach((f) => { + const uiItem = this._fieldItem(f); + $$(this.ids.fields).addView(uiItem); + }); + this.readyFields(); + } + + /** + * @method onError() + * Our Error handler when the data we provided our parent + * ui_work_object_list_newObject object had an error saving + * the values. + * @param {Error|ABValidation|other} err + * The error information returned. This can be several + * different types of objects: + * - A javascript Error() object + * - An ABValidation object returned from our .isValid() + * method + * - An error response from our API call. + */ + onError(err) { + if (err) { + console.error(err); + let message = L("the entered data is invalid"); + // if this was our Validation() object: + if (err.updateForm) { + err.updateForm(this.$form); + } else { + if (err.code && err.data) { + message = err.data?.sqlMessage ?? message; + } else { + message = err?.message ?? message; + } + } + + const values = this.$form.getValues(); + webix.alert({ + title: L("Error creating Object: {0}", [values.name]), + ok: L("fix it"), + text: message, + type: "alert-error", + }); + } + // get notified if there was an error saving. + $$(this.ids.buttonVerify).enable(); + } + + /** + * @method onSuccess() + * Our success handler when the data we provided our parent + * ui_work_object_list_newObject successfully saved the values. + */ + onSuccess() { + this.formClear(); + $$(this.ids.buttonVerify).enable(); + } + + /** + * @function show() + * + * Show this component. + */ + show() { + $$(this.ids.component)?.show(); + } + + busy() { + const $list = $$(this.ids.tableList); + // const $verifyButton = $$(this.ids.buttonVerify); + + $list.showProgress({ type: "icon" }); + // $verifyButton.disable(); + } + + // busyFields() { + // this.$fieldSelector.showProgress({ type: "icon" }); + // } + + ready() { + const $form = $$(this.ids.form); + // const $verifyButton = $$(this.ids.buttonVerify); + + $form.hideProgress(); + // $verifyButton.enable(); + } + + // readyFields() { + // this.$fieldSelector.hideProgress(); + // } + + setCredentials(creds) { + this.credentials = creds; + } + } + return new UI_Work_Object_List_NewObject_Netsuite_Tables(); +} From e3540da4b24be1fc0c9bdedcc96bf2b4f4bc40d2 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 15 Oct 2024 15:05:13 +0700 Subject: [PATCH 06/32] Add node content and display --- .../properties/views/ABViewOrgChartTeams.js | 411 +++++++++++++++++- 1 file changed, 388 insertions(+), 23 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 6e0c0bb9..1e3398b9 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -29,18 +29,143 @@ export default function (AB) { height: "", export: "", exportFilename: "", + groupByField: "", + contentField: "", + contentFieldFilter: "", + contentFieldFilterButton: "", + contentGroupByField: "", + contentDisplayedFields: "", + contentDisplayedFieldsAdd: "", }); - this.AB = AB; + const contentFieldFilter = (this.contentFieldFilter = + AB.filterComplexNew(this.ids.contentFieldFilter)); + contentFieldFilter.on("save", () => { + if ( + !contentFieldFilter.isConditionComplete( + contentFieldFilter.getValue() + ) + ) + contentFieldFilter.setValue({ glue: "and", rules: [] }); + this.onChange(); + }); } static get key() { return "orgchart_teams"; } + _uiContentDisplayedField(fieldID = "", obj, atDisplay) { + const self = this; + const ids = self.ids; + const datasource = this.CurrentView.datacollection.datasource; + const datasourceID = datasource.id; + const parentObj = datasource.fieldByID( + $$(ids.contentField).getValue() + ).datasourceLink; + const parentObjID = parentObj.id; + const objID = obj?.id || parentObjID; + const $contentDisplayedFields = $$(ids.contentDisplayedFields); + const filterFields = (f) => { + const linkedObjID = f.datasourceLink?.id; + return linkedObjID !== datasourceID && linkedObjID !== parentObjID; + }; + const mapFields = (f) => ({ + id: f.id, + value: f.label, + field: f, + }); + const getOnSelectChangeFn = + (currentObj, currentAtDisplay) => (newValue) => { + const field = currentObj.fieldByID(newValue); + if (field.key === "connectObject") { + $contentDisplayedFields.addView( + this._uiContentDisplayedField( + "", + field.datasourceLink, + currentAtDisplay + ) + ); + } + this.populateContentDisplayedFields( + $contentDisplayedFields.getValues() + ); + this.onChange(); + }; + if (objID === parentObjID) { + const rootAtDisplay = Object.keys( + $contentDisplayedFields.elements + ).filter((key) => key.includes(objID)).length; + return { + cols: [ + { + view: "richselect", + name: `${rootAtDisplay}.${parentObjID}`, + label: `${L("Display")} ${rootAtDisplay + 1}`, + labelWidth: uiConfig.labelWidthMedium, + options: + parentObj.fields(filterFields).map(mapFields) || [], + value: fieldID, + on: { + onChange: getOnSelectChangeFn(parentObj, rootAtDisplay), + }, + }, + { + view: "button", + css: "webix_danger", + type: "icon", + icon: "wxi-close", + width: uiConfig.buttonWidthExtraSmall, + click() { + self.deleteContentDisplayedField( + this.getParentView().getChildViews()[0].config.id + ); + self.onChange(); + }, + }, + ], + }; + } + return { + cols: [ + { + view: "richselect", + name: `${atDisplay}.${objID}`, + label: "->", + labelWidth: uiConfig.labelWidthMedium, + options: obj.fields(filterFields).map(mapFields) || [], + value: fieldID, + on: { + onChange: getOnSelectChangeFn(obj, atDisplay), + }, + }, + { + view: "button", + css: "webix_danger", + type: "icon", + icon: "wxi-close", + width: uiConfig.buttonWidthExtraSmall, + click() { + self.deleteContentDisplayedField( + this.getParentView().getChildViews()[0].config.id + ); + self.onChange(); + }, + }, + ], + }; + } + ui() { const ids = this.ids; - + const contentFieldFilter = this.contentFieldFilter; + contentFieldFilter.myPopup = webix.ui({ + view: "popup", + height: 240, + width: 480, + hidden: true, + body: contentFieldFilter.ui, + }); return super.ui([ { id: ids.datacollectionID, @@ -88,6 +213,139 @@ export default function (AB) { onChange: () => this.onChange(), }, }, + { + cols: [ + { + view: "label", + label: L("Content Field"), + width: uiConfig.labelWidthLarge, + }, + { + id: ids.contentField, + name: "contentField", + view: "richselect", + options: [], + on: { + onChange: (newValue) => { + const $contentDisplayedFieldsAdd = $$( + ids.contentDisplayedFieldsAdd + ); + const $contentFieldFilterButton = $$( + ids.contentFieldFilterButton + ); + const $contentGroupByField = $$( + ids.contentGroupByField + ); + contentFieldFilter.init(); + contentFieldFilter.setValue({ + glue: "and", + rules: [], + }); + if (newValue != null && newValue !== "") { + const contentObj = + this.CurrentView.datacollection.datasource.fieldByID( + newValue + ).datasourceLink; + contentFieldFilter.fieldsLoad( + contentObj.fields() + ); + $contentGroupByField.setValue(""); + $contentGroupByField.define("options", [ + { id: "", value: "", $empty: true }, + ...contentObj + .fields( + (f) => + f.key === "list" && + f.settings.isMultiple === 0 + ) + .map((f) => ({ + id: f.id, + value: f.label, + field: f, + })), + ]); + $contentFieldFilterButton.enable(); + $contentDisplayedFieldsAdd.show(); + $contentGroupByField.show(); + } else { + contentFieldFilter.fieldsLoad([]); + $contentGroupByField.setValue(""); + $contentGroupByField.define("options", []); + $contentFieldFilterButton.disable(); + $contentDisplayedFieldsAdd.hide(); + $contentGroupByField.hide(); + } + this.populateContentDisplayedFields({}); + this.onChange(); + }, + }, + }, + { + id: ids.contentFieldFilterButton, + view: "button", + type: "icon", + icon: "fa fa-filter", + css: "webix_primary", + disabled: true, + width: uiConfig.buttonWidthExtraSmall, + click() { + contentFieldFilter.popUp(this.$view, null, { + pos: "top", + }); + }, + }, + ], + }, + { + id: ids.contentGroupByField, + hidden: true, + view: "richselect", + label: L("Content Group By Field"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: (newValue) => { + this.onChange(); + }, + }, + }, + { + id: ids.contentDisplayedFieldsAdd, + hidden: true, + cols: [ + { + view: "label", + label: L("Content Displayed Fields"), + }, + { + view: "button", + type: "icon", + icon: "fa fa-plus", + css: "webix_primary", + width: uiConfig.buttonWidthExtraSmall, + click: () => { + const $contentDisplayedFields = $$( + ids.contentDisplayedFields + ); + if (!$contentDisplayedFields.isVisible()) + $contentDisplayedFields.show(); + const values = $contentDisplayedFields.getValues(); + for (const key in values) { + } + Object.keys($contentDisplayedFields.elements); + $contentDisplayedFields.addView( + this._uiContentDisplayedField() + ); + }, + }, + ], + }, + { + id: ids.contentDisplayedFields, + view: "form", + hidden: true, + elements: [], + }, { id: ids.draggable, name: "draggable", @@ -222,15 +480,44 @@ export default function (AB) { async init(AB) { this.AB = AB; - await super.init(AB); - webix.extend($$(this.ids.component), webix.ProgressBar); + this.contentFieldFilter.queriesLoad( + this.CurrentApplication?.queriesIncluded() + ); + } + + deleteContentDisplayedField(id) { + const ids = this.ids; + const $contentDisplayedFields = $$(ids.contentDisplayedFields); + const $elements = $contentDisplayedFields.elements; + const $richselect = $$(id); + const deletedElementKey = $richselect.config.name; + if ( + deletedElementKey.includes( + this.CurrentView.datacollection.datasource.fieldByID( + $$(ids.contentField).getValue() + ).datasourceLink.id + ) + ) { + const deletedAtDisplay = deletedElementKey.split(".")[0]; + for (const key in $elements) { + if (!key.includes(`${deletedAtDisplay}.`)) continue; + $contentDisplayedFields.removeView( + $elements[key].getParentView().config.id + ); + } + } else + $contentDisplayedFields.removeView( + $richselect.getParentView().config.id + ); + this.populateContentDisplayedFields( + $contentDisplayedFields.getValues() + ); } populate(view) { super.populate(view); - const ids = this.ids; const $component = $$(ids.component); const defaultValues = this.defaultValues(); @@ -238,18 +525,22 @@ export default function (AB) { $component.getValues(), Object.assign(defaultValues, view.settings) ); - // const $fieldList = $$(ids.fields); // $fieldList.clearAll(); this.populateDatacollection(values.datacollectionId); const teamObj = this.CurrentView?.datacollection?.datasource; if (teamObj) { this.populateTeamFieldOptions(teamObj); - $$(this.ids.teamLink).setValue(values.teamLink); - $$(this.ids.teamName).setValue(values.teamName); - $$(this.ids.topTeam).setValue(values.topTeam); + $$(ids.teamLink).setValue(values.teamLink); + $$(ids.teamName).setValue(values.teamName); + $$(ids.topTeam).setValue(values.topTeam); + $$(ids.contentField).setValue(values.contentField); + $$(ids.contentGroupByField).setValue(values.contentGroupByField); + this.contentFieldFilter.setValue( + JSON.parse(values.contentFieldFilter) + ); + this.populateContentDisplayedFields(values.contentDisplayedFields); } - $component.setValues(values); } @@ -305,8 +596,8 @@ export default function (AB) { field: f, }; }); - $$(this.ids.teamLink).define("options", linkFields); - + const ids = this.ids; + $$(ids.teamLink).define("options", linkFields); const textFields = object ?.fields((f) => f.key === "string") .map((f) => { @@ -316,8 +607,7 @@ export default function (AB) { field: f, }; }); - $$(this.ids.teamName).define("options", textFields); - + $$(ids.teamName).define("options", textFields); const booleanFields = object ?.fields((f) => f.key === "boolean") .map((f) => { @@ -327,9 +617,78 @@ export default function (AB) { field: f, }; }); + // Add an empty option as this is an optional setting. booleanFields.unshift({ id: "", value: "", $empty: true }); - $$(this.ids.topTeam).define("options", booleanFields); + $$(ids.topTeam).define("options", booleanFields); + $$(ids.contentField).define("options", [ + { id: "", value: "", $empty: true }, + ...linkFields, + ]); + } + + populateContentDisplayedFields(values) { + const ids = this.ids; + const $contentDisplayedFields = $$(ids.contentDisplayedFields); + const elements = $contentDisplayedFields.elements; + for (const key in elements) + $contentDisplayedFields.removeView( + elements[key].getParentView().config.id + ); + const keys = Object.keys(values); + if (keys.length === 0) { + $contentDisplayedFields.hide(); + return; + } + const obj = this.CurrentView.datacollection.datasource.fieldByID( + $$(ids.contentField).getValue() + ).datasourceLink; + const objID = obj.id; + const parentKeys = []; + const childKeys = []; + while (keys.length > 0) { + const key = keys.pop(); + (key.includes(objID) && parentKeys.push(key)) || + childKeys.push(key); + } + while (parentKeys.length > 0) { + const parentKey = parentKeys.pop(); + const parentFieldID = values[parentKey] ?? ""; + $contentDisplayedFields.addView( + this._uiContentDisplayedField(parentFieldID) + ); + if ( + parentFieldID === "" || + obj.fieldByID(parentFieldID).key !== "connectObject" + ) + continue; + const currentAtDisplay = + Object.keys($contentDisplayedFields.getValues()).filter( + (currentKey) => currentKey.includes(objID) + ).length - 1; + while ( + childKeys.findIndex((childKey) => + childKey.includes(`${parentKey.split(".")[0]}.`) + ) > -1 + ) { + const childKey = childKeys.pop(); + const childObj = this.AB.objectByID(childKey.split(".")[1]); + const childFieldID = values[childKey] ?? ""; + $contentDisplayedFields.addView( + this._uiContentDisplayedField( + childFieldID, + childObj, + currentAtDisplay + ) + ); + if ( + childFieldID === "" || + childObj.fieldByID(childFieldID).key !== "connectObject" + ) + break; + } + } + $contentDisplayedFields.show(); } // populateDescriptionFieldOptions(fieldId) { @@ -370,17 +729,23 @@ export default function (AB) { values() { const values = super.values(); const ids = this.ids; - // values.settings = values.setttings ?? {}; - values.settings = Object.assign( + const settings = (values.settings = Object.assign( $$(ids.component).getValues(), values.settings - ); + )); // Retrive the values of your properties from Webix and store them in the view - values.settings.teamLink = $$(ids.teamLink).getValue(); - values.settings.teamName = $$(ids.teamName).getValue(); - values.settings.topTeam = $$(ids.topTeam).getValue(); - values.settings.dataCollectionId = $$(ids.datacollectionID).getValue(); - + settings.teamLink = $$(ids.teamLink).getValue(); + settings.teamName = $$(ids.teamName).getValue(); + settings.topTeam = $$(ids.topTeam).getValue(); + settings.dataCollectionId = $$(ids.datacollectionID).getValue(); + settings.contentField = $$(ids.contentField).getValue(); + settings.contentGroupByField = $$(ids.contentGroupByField).getValue(); + settings.contentFieldFilter = JSON.stringify( + this.contentFieldFilter.getValue() + ); + settings.contentDisplayedFields = $$( + ids.contentDisplayedFields + ).getValues(); return values; } From 976c20833786d2693703c58e390c4d08f6528305 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Thu, 17 Oct 2024 11:56:09 +0700 Subject: [PATCH 07/32] Merge nh branch --- .../properties/views/ABViewOrgChartTeams.js | 78 ++++++++----------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 1e3398b9..15ec8488 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -16,6 +16,8 @@ export default function (AB) { constructor() { super(BASE_ID, { datacollectionID: "", + teamInactive: "", + teamCanInactivate: "", teamLink: "", teamName: "", topTeam: "", @@ -189,9 +191,7 @@ export default function (AB) { label: L("Team Link"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, }, { id: ids.teamName, @@ -199,9 +199,7 @@ export default function (AB) { label: L("Team Name"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, }, { id: ids.topTeam, @@ -209,9 +207,23 @@ export default function (AB) { label: L("Top Team"), labelWidth: uiConfig.labelWidthLarge, options: [], - on: { - onChange: () => this.onChange(), - }, + on: { onChange: () => this.onChange() }, + }, + { + id: ids.teamInactive, + view: "richselect", + label: L("Team Inactive"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { onChange: () => this.onChange() }, + }, + { + id: ids.teamCanInactivate, + view: "richselect", + label: L("Can Inactivate"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { onChange: () => this.onChange() }, }, { cols: [ @@ -353,11 +365,7 @@ export default function (AB) { label: L("Drag & Drop"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.direction, @@ -371,11 +379,7 @@ export default function (AB) { { id: "l2r", value: L("Left to Right") }, { id: "r2l", value: L("Right to Left") }, ], - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.depth, @@ -385,11 +389,7 @@ export default function (AB) { label: L("Depth"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.color, @@ -397,11 +397,7 @@ export default function (AB) { view: "colorpicker", label: L("Color"), labelWidth: uiConfig.labelWidthLarge, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -411,11 +407,7 @@ export default function (AB) { label: L("Pan"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -425,11 +417,7 @@ export default function (AB) { label: L("Zoom"), labelWidth: uiConfig.labelWidthLarge, value: 0, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { id: ids.height, @@ -437,11 +425,7 @@ export default function (AB) { name: "height", label: L("Height"), labelWidth: uiConfig.labelWidthLarge, - on: { - onChange: () => { - this.onChange(); - }, - }, + on: { onChange: () => this.onChange() }, }, { hidden: true, // NOTE: does not support @@ -533,6 +517,8 @@ export default function (AB) { this.populateTeamFieldOptions(teamObj); $$(ids.teamLink).setValue(values.teamLink); $$(ids.teamName).setValue(values.teamName); + $$(ids.teamInactive).setValue(values.teamInactive); + $$(ids.teamCanInactivate).setValue(values.teamCanInactivate); $$(ids.topTeam).setValue(values.topTeam); $$(ids.contentField).setValue(values.contentField); $$(ids.contentGroupByField).setValue(values.contentGroupByField); @@ -621,6 +607,8 @@ export default function (AB) { // Add an empty option as this is an optional setting. booleanFields.unshift({ id: "", value: "", $empty: true }); $$(ids.topTeam).define("options", booleanFields); + $$(ids.teamInactive).define("options", booleanFields); + $$(ids.teamCanInactivate).define("options", booleanFields); $$(ids.contentField).define("options", [ { id: "", value: "", $empty: true }, ...linkFields, @@ -737,6 +725,8 @@ export default function (AB) { settings.teamLink = $$(ids.teamLink).getValue(); settings.teamName = $$(ids.teamName).getValue(); settings.topTeam = $$(ids.topTeam).getValue(); + settings.teamInactive = $$(ids.teamInactive).getValue(); + settings.teamCanInactivate = $$(ids.teamCanInactivate).getValue(); settings.dataCollectionId = $$(ids.datacollectionID).getValue(); settings.contentField = $$(ids.contentField).getValue(); settings.contentGroupByField = $$(ids.contentGroupByField).getValue(); From 6b338d44a97b0f7eb28e43341946311895b0c39e Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 17 Oct 2024 22:10:15 -0500 Subject: [PATCH 08/32] [wip] initial connection declarations --- .../ui_work_object_list_newObject_netsuite.js | 101 ++++++--- ...ect_list_newObject_netsuite_connections.js | 195 ++++++++++++------ ...work_object_workspace_popupNewDataField.js | 4 +- 3 files changed, 208 insertions(+), 92 deletions(-) diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js index 377a49b6..70822ea3 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js @@ -135,7 +135,7 @@ export default function (AB) { this.UI_Tables.setCredentials(creds); this.UI_Fields.setCredentials(creds); this.UI_FieldTest.setCredentials(creds); - // this.UI_Tables.loadTables(); + this.UI_Connections.setCredentials(creds); this.UI_Tables.show(); }); @@ -294,31 +294,6 @@ export default function (AB) { let allFields = this.UI_Fields.getValues(); - // allConnectFields = allFields.concat(this.UI_Connections.getValues()); - /* - linkCol = linkObject.fieldNew({ - // id: OP.Util.uuid(), - - key: field.key, - - columnName: linkColumnName, - label: this.CurrentObject.label, - - settings: { - showIcon: field.settings.showIcon, - - linkObject: field.object.id, - linkType: field.settings.linkViaType, - linkViaType: field.settings.linkType, - isCustomFK: field.settings.isCustomFK, - indexField: field.settings.indexField, - indexField2: field.settings.indexField2, - isSource: 0, - width: width, - }, - }); - */ - // Pick out our special columns: pk, created_at, updated_at let pkField = allFields.find((f) => f.pk); if (!pkField) { @@ -366,13 +341,79 @@ export default function (AB) { // values.fieldIDs.push(field.id); } // values.id = object.id; - - this.emit("save", object.toObj()); - - this.ready(); } catch (err) { console.error(err); } + + let allConnectFields = this.UI_Connections.getValues(); + for (var i = 0; i < allConnectFields.length; i++) { + let f = allConnectFields[i]; + /* f = + { + "thisField": "_this_object_", + "thatObject": "b7c7cca2-b919-4a90-b199-650a7a4693c1", + "thatObjectField": "custrecord_whq_teams_strategy_strtgy_cod", + "linkType": "many:one" + } + */ + + let linkObject = this.AB.objectByID(f.thatObject); + if (!linkObject) continue; + + let linkType = f.linkType; + let parts = linkType.split(":"); + let link = parts[0]; + let linkVia = parts[1]; + + let colName = ""; + if (f.thisField != "_this_object_") { + colName = f.thisField; + } else if (f.thatObjectField != "_that_object_") { + colName = f.thatObjectField; + } + + let thisField = { + key: "connectObject", + columnName: f.thisField, + label: linkObject.label, + settings: { + showIcon: "1", + + linkObject: linkObject.id, + linkType: link, + linkViaType: linkVia, + isCustomFK: 0, + indexField: "", + indexField2: "", + isSource: 0, + width: 100, + }, + }; + + let linkField = this.AB.cloneDeep(thisField); + linkField.columnName = f.thatObjectField; + linkField.label = object.label || object.name; + linkField.settings.linkObject = object.id; + linkField.settings.linkType = linkVia; + linkField.settings.linkViaType = link; + + // create an initial LinkColumn + let fieldLink = linkObject.fieldNew(linkField); + await fieldLink.save(true); // should get an .id now + + // make sure I can reference field => linkColumn + thisField.settings.linkColumn = fieldLink.id; + let field = object.fieldNew(thisField); + await field.save(); + + // now update reference linkColumn => field + fieldLink.settings.linkColumn = field.id; + await fieldLink.save(); + } + + this.emit("save", object.toObj()); + + this.ready(); } /** diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js index eb811400..22eb68fd 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js @@ -18,7 +18,7 @@ export default function (AB) { form: "", - fieldSelector: "", + // fieldSelector: "", connections: "", displayConnections: "", displayNoConnections: "", @@ -193,9 +193,11 @@ export default function (AB) { this.$form = $$(this.ids.form); - this.$fieldSelector = $$(this.ids.fieldSelector); AB.Webix.extend(this.$form, webix.ProgressBar); - AB.Webix.extend(this.$fieldSelector, webix.ProgressBar); + + // this.$fieldSelector = $$(this.ids.fieldSelector); + // if (this.$fieldSelector) + // AB.Webix.extend(this.$fieldSelector, webix.ProgressBar); // init() routines are always considered async so: return Promise.resolve(); @@ -243,69 +245,130 @@ export default function (AB) { const fieldKeys = ["string", "LongText", "number", "date", "boolean"]; const linkTypes = ["one:one", "one:many", "many:one", "many:many"]; + + // For the Base Object, let's include all fields that are clearly + // objects. + let fieldOptions = this.connectionList.map((conn) => { + return { + id: conn.column, + value: conn.column, + }; + }); + // we also need to include "_this_object_" reference so that + // we can make many:xxx connections (we don't store the value, the + // other object does) + fieldOptions.unshift({ + id: "_this_object_", + value: L("This Object"), + }); + return { - cols: [ + view: "form", + elements: [ { - rows: [ + cols: [ { - label: L("Field"), - view: "label", + rows: [ + { + label: L("Field"), + view: "label", + }, + { + placeholder: "Type", + options: fieldOptions, + view: "select", + // value: type, + name: "thisField", + }, + ], }, { - placeholder: "Type", - options: this.connectionList.map((conn) => { - return { - id: conn.column, - value: conn.column, - }; - }), - view: "select", - // value: type, - }, - ], - }, - { - rows: [ - { - placeholder: "Existing Netsuite Object", - options: this.listNetsuiteObjects.map((nObj) => { - return { - id: nObj.id, - value: nObj.label, - }; - }), - view: "select", - // value: type, - }, - { - placeholder: "Link Column", - options: [], - view: "select", - // value: type, + rows: [ + { + placeholder: L("Existing Netsuite Object"), + options: this.listNetsuiteObjects.map((nObj) => { + return { + id: nObj.id, + value: nObj.label, + }; + }), + view: "select", + name: "thatObject", + // value: type, + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + let connObj = self.AB.objectByID(newVal); + if (connObj) { + let result = await self.AB.Network.get({ + url: `/netsuite/table/${connObj.tableName}`, + params: { + credentials: JSON.stringify( + self.credentials + ), + }, + }); + let fields = result.filter( + (r) => r.type == "object" + ); + let options = fields.map((f) => { + return { + id: f.column, + value: f.column, + }; + }); + + // include a "_that_object_" incase this is a one:xxx + // connection. + options.unshift({ + id: "_that_object_", + value: L("That Object"), + }); + let $linkColumn = + this.getParentView().getChildViews()[1]; + + $linkColumn.define("options", options); + $linkColumn.refresh(); + } + }, + }, + }, + { + placeholder: "Link Column", + options: [], + view: "select", + // value: type, + name: "thatObjectField", + }, + { + placeholder: "Link Type", + options: linkTypes.map((l) => { + return { + id: l, + value: l, + }; + }), + view: "select", + name: "linkType", + // value: type, + }, + ], }, + { - placeholder: "Link Type", - options: linkTypes.map((l) => { - return { - id: l, - value: l, - }; - }), - view: "select", - // value: type, + icon: "wxi-trash", + view: "icon", + width: 38, + click: function () { + const $item = this.getParentView().getParentView(); + $$(self.ids.connections).removeView($item); + }, }, ], }, - - { - icon: "wxi-trash", - view: "icon", - width: 38, - click: function () { - const $item = this.getParentView(); - $$(self.ids.fields).removeView($item); - }, - }, ], }; } @@ -382,20 +445,30 @@ export default function (AB) { busy() { const $verifyButton = $$(this.ids.buttonVerify); - this.$fieldSelector.showProgress({ type: "icon" }); + // this.$fieldSelector.showProgress({ type: "icon" }); $verifyButton.disable(); } ready() { const $verifyButton = $$(this.ids.buttonVerify); - this.$fieldSelector.hideProgress(); + // this.$fieldSelector.hideProgress(); $verifyButton.enable(); } - // setCredentials(creds) { - // this.credentials = creds; - // } + setCredentials(creds) { + this.credentials = creds; + } + + getValues() { + let values = []; + $$(this.ids.connections) + .getChildViews() + .forEach(($row) => { + values.push($row.getValues()); + }); + return values; + } // verify() { // this.emit("fields.ready", { diff --git a/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js b/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js index 46a42248..15a8797e 100644 --- a/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js +++ b/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js @@ -420,7 +420,9 @@ export default function (AB, ibase) { field.columnName === "" ) { this.AB.Webix.message({ - text: "The column name can't contain special characters.", + text: L( + "The column name can't contain special characters." + ), type: "error", }); From aa0e664bb433588ecfe3796232cbea1e00e7d56b Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Fri, 11 Oct 2024 10:27:44 +0700 Subject: [PATCH 09/32] add properties to color team node by strategy --- .../properties/views/ABViewOrgChartTeams.js | 160 +++++++++++++++--- 1 file changed, 134 insertions(+), 26 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index ff111fb9..7cd10e2a 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -16,10 +16,12 @@ export default function (AB) { constructor() { super(BASE_ID, { datacollectionID: "", + strategyCode: "", teamInactive: "", teamCanInactivate: "", teamLink: "", teamName: "", + teamStrategy: "", topTeam: "", fields: "", direction: "", @@ -31,6 +33,8 @@ export default function (AB) { height: "", export: "", exportFilename: "", + strategyColorPopup: "", + strategyColorForm: "", }); this.AB = AB; @@ -100,6 +104,42 @@ export default function (AB) { options: [], on: { onChange: () => this.onChange() }, }, + { + id: ids.teamStrategy, + view: "richselect", + label: L("Strategy"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: (value) => { + this.populateStrategyOptions(value); + this.onChange(); + }, + }, + }, + { + cols: [ + { + id: ids.strategyCode, + view: "richselect", + label: L("Strategy Code"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: () => { + this.onChange(); + $$(this.ids.strategyColorPopup)?.close(); + }, + }, + }, + { + view: "icon", + icon: "fa fa-paint-brush", + allign: "right", + click: () => this.strategyColorPopup(), + }, + ], + }, { id: ids.draggable, name: "draggable", @@ -229,9 +269,18 @@ export default function (AB) { const teamObj = this.CurrentView?.datacollection?.datasource; if (teamObj) { this.populateTeamFieldOptions(teamObj); - $$(this.ids.teamLink).setValue(values.teamLink); - $$(this.ids.teamName).setValue(values.teamName); - $$(this.ids.topTeam).setValue(values.topTeam); + [ + "teamCanInactivate", + "teamInactive", + "teamLink", + "teamName", + "teamStrategy", + "topTeam", + ].forEach((f) => $$(this.ids[f]).setValue(values[f])); + if (values.teamStrategy) { + this.populateStrategyOptions(values.teamStrategy); + $$(this.ids.strategyCode).setValue(values.strategyCode); + } } $component.setValues(values); @@ -282,35 +331,25 @@ export default function (AB) { populateTeamFieldOptions(object) { const view = this.CurrentView; - const linkFields = view.getValueFields(object).map((f) => { - return { - id: f.id, - value: f.label, - field: f, - }; - }); - $$(this.ids.teamLink).define("options", linkFields); + const m2oFields = view.getValueFields(object).map(fieldToOption); + $$(this.ids.teamLink).define("options", m2oFields); + const o2mFields = + object.connectFields( + (f) => f.linkType() == "one" && f.linkViaType() == "many" + ) ?? []; + $$(this.ids.teamStrategy).define( + "options", + o2mFields.map(fieldToOption) + ); const textFields = object ?.fields((f) => f.key === "string") - .map((f) => { - return { - id: f.id, - value: f.label, - field: f, - }; - }); + .map(fieldToOption); $$(this.ids.teamName).define("options", textFields); const booleanFields = object ?.fields((f) => f.key === "boolean") - .map((f) => { - return { - id: f.id, - value: f.label, - field: f, - }; - }); + .map(fieldToOption); // Add an empty option as this is an optional setting. booleanFields.unshift({ id: "", value: "", $empty: true }); $$(this.ids.topTeam).define("options", booleanFields); @@ -318,6 +357,61 @@ export default function (AB) { $$(this.ids.teamCanInactivate).define("options", booleanFields); } + populateStrategyOptions(fieldID) { + const strategyObj = this.AB.objectByID( + this.AB.definitionByID(fieldID).settings.linkObject + ); + const listFields = strategyObj + .fields((f) => f.key === "list") + .map(fieldToOption); + $$(this.ids.strategyCode).define("options", listFields); + } + + strategyColorPopup() { + const codeFieldID = $$(this.ids.strategyCode).getValue(); + if (!codeFieldID) return; + + let $popup = $$(this.ids.strategyColorPopup); + + if (!$popup) { + const values = this.CurrentView.settings.strategyColors ?? {}; + const strategyTypes = this.AB.definitionByID( + codeFieldID + ).settings.options.map((strategy) => { + return { + view: "colorpicker", + label: strategy.text, + name: strategy.id, + value: values[strategy.id] ?? "#111111", + }; + }); + + $popup = this.AB.Webix.ui({ + view: "window", + id: this.ids.strategyColorPopup, + close: true, + title: L("Set Colors"), + position: "center", + body: { + view: "form", + id: this.ids.strategyColorForm, + elements: [ + ...strategyTypes, + { + view: "button", + label: L("Apply"), + click: () => { + this.onChange(); + $$(this.ids.strategyColorPopup).hide(); + }, + }, + ], + }, + }); + } + $popup.show(); + } + // populateDescriptionFieldOptions(fieldId) { // const valueField = this.CurrentView.valueField(); // const $columnDescription = $$(this.ids.columnDescription); @@ -366,8 +460,14 @@ export default function (AB) { values.settings.teamName = $$(ids.teamName).getValue(); values.settings.topTeam = $$(ids.topTeam).getValue(); values.settings.teamInactive = $$(ids.teamInactive).getValue(); - values.settings.teamCanInactivate = $$(ids.teamCanInactivate).getValue(); + values.settings.teamCanInactivate = $$( + ids.teamCanInactivate + ).getValue(); + values.settings.teamStrategy = $$(ids.teamStrategy).getValue(); + values.settings.strategyCode = $$(ids.strategyCode).getValue(); values.settings.dataCollectionId = $$(ids.datacollectionID).getValue(); + const $colorForm = $$(ids.strategyColorForm); + values.settings.strategyColors = $colorForm?.getValues() ?? {}; return values; } @@ -384,3 +484,11 @@ export default function (AB) { return ABViewOrgChartTeamsProperty; } + +function fieldToOption(f) { + return { + id: f.id, + value: f.label, + field: f, + }; +} From 39e2a88eada7a78f8df84e242a6b420ec8ae4c17 Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 22 Oct 2024 03:00:20 -0500 Subject: [PATCH 10/32] [wip] modify existing Object workspace add connect field to work with Netsuite objects. --- .../properties/dataFields/ABFieldConnect.js | 107 +++++++++++++++++- ...work_object_workspace_popupNewDataField.js | 11 +- 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/rootPages/Designer/properties/dataFields/ABFieldConnect.js b/src/rootPages/Designer/properties/dataFields/ABFieldConnect.js index c6ac0f7d..c981e262 100644 --- a/src/rootPages/Designer/properties/dataFields/ABFieldConnect.js +++ b/src/rootPages/Designer/properties/dataFields/ABFieldConnect.js @@ -31,6 +31,12 @@ export default function (AB) { indexField: "", indexField2: "", + netsuite_one: "", + netsuiteOneLabel: "", + netsuiteOneColumn: "", + + netsuite_many: "", + connectDataPopup: "", }); } @@ -237,6 +243,37 @@ export default function (AB) { }, }, }, + { + view: "layout", + id: ids.netsuite_one, + hidden: true, + cols: [ + { + id: ids.netsuiteOneLabel, + view: "label", + label: L(" [Select object]'s field"), + width: 300, + }, + { + id: ids.netsuiteOneColumn, + name: "netsuiteOneColumn", + disallowEdit: true, + view: "richselect", + // value: FC.defaultValues().linkViaType, + // width: 200, + fillspace: true, + options: [], + on: { + // onChange: (newV, oldV) => { + // this.selectLinkViaType(newV, oldV); + // }, + onAfterRender: function () { + ABField.CYPRESS_REF(this); + }, + }, + }, + ], + }, ]); } @@ -295,6 +332,7 @@ export default function (AB) { $fieldLink2.refresh(); this.updateCustomIndex(); + this.checkNetsuiteObjects(); } show() { @@ -387,13 +425,19 @@ export default function (AB) { const options = []; // if an ABApplication is set then load in the related objects const application = this.CurrentApplication; + + // if this is a Netsuite Object, just gather other Netsuite Objs + let objFilter = () => true; + if (this.CurrentObject.isNetsuite) { + objFilter = (o) => o.isNetsuite; + } if (application) { - application.objectsIncluded().forEach((o) => { + application.objectsIncluded(objFilter).forEach((o) => { options.push({ id: o.id, value: o.label }); }); } else { // else load in all the ABObjects - this.AB.objects().forEach((o) => { + this.AB.objects(objFilter).forEach((o) => { options.push({ id: o.id, value: o.label }); }); } @@ -449,6 +493,7 @@ export default function (AB) { $field.refresh(); this.updateCustomIndex(); + this.checkNetsuiteObjects(); } selectObjectTo(newValue, oldValue) { @@ -474,6 +519,8 @@ export default function (AB) { $$(ids.link2).show(); this.updateCustomIndex(); + + this.checkNetsuiteObjects(); } updateCustomIndex() { @@ -578,6 +625,62 @@ export default function (AB) { this.checkCustomFK(); } + + async checkNetsuiteObjects() { + let ids = this.ids; + if (!this.CurrentObject.isNetsuite) { + $$(ids.netsuite_one)?.hide(); + $$(ids.netsuite_many)?.hide(); + return; + } + + let linkType = $$(ids.linkType).getValue(); + let linkViaType = $$(ids.linkViaType).getValue(); + + if (linkType == "one") { + await this.updateNetsuiteOneUI(this.CurrentObject); + $$(ids.netsuite_one)?.show(); + $$(ids.netsuite_many)?.hide(); + } else if (linkViaType == "one") { + // fill label and Drop list with object in Droplist + let objID = $$(ids.linkObject).getValue(); + let connObj = this.AB.objectByID(objID); + if (!connObj) return; + await this.updateNetsuiteOneUI(connObj); + $$(ids.netsuite_one)?.show(); + $$(ids.netsuite_many)?.hide(); + } else { + // this is many:many + $$(ids.netsuite_one)?.hide(); + $$(ids.netsuite_many)?.show(); + } + } + + async updateNetsuiteOneUI(object) { + let ids = this.ids; + + // fill label and Drop list with Current Object + $$(ids.netsuiteOneLabel).setValue( + L(" {0}'s field", [object.label]) + ); + + let result = await this.AB.Network.get({ + url: `/netsuite/table/${object.tableName}`, + params: { + credentials: JSON.stringify(object.credentials), + }, + }); + let fields = result.filter((r) => r.type == "object"); + let options = fields.map((f) => { + return { + id: f.column, + value: f.column, + }; + }); + + $$(ids.netsuiteOneColumn).define("options", options); + $$(ids.netsuiteOneColumn).refresh(); + } } return ABFieldConnectProperty; diff --git a/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js b/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js index 15a8797e..ec83732e 100644 --- a/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js +++ b/src/rootPages/Designer/ui_work_object_workspace_popupNewDataField.js @@ -410,6 +410,12 @@ export default function (AB, ibase) { let linkCol; + if (this.CurrentObject.isNetsuite) { + if (vals.settings?.netsuiteOneColumn) { + vals.columnName = vals.settings.netsuiteOneColumn; + } + } + // if this is an ADD operation, (_editField will be undefined) if (!this._editField) { // get a new instance of a field: @@ -579,7 +585,10 @@ export default function (AB, ibase) { await field.save(); // when add new link fields, then run create migrate fields here - if (!this._editField) { + if ( + !this._editField && + !this.CurrentObject.isNetsuite + ) { await field.migrateCreate(); await linkCol.migrateCreate(); } From 4dcfdb2ead6cefa56cc7eb55ee48573d1b0e2e32 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Mon, 28 Oct 2024 10:28:34 +0700 Subject: [PATCH 11/32] The option for content to update exist data/create new data --- .../properties/views/ABViewOrgChartTeams.js | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 15ec8488..f801061d 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -25,6 +25,7 @@ export default function (AB) { direction: "", depth: "", draggable: "", + dropContentToCreate: "", color: "", pan: "", zoom: "", @@ -161,13 +162,6 @@ export default function (AB) { ui() { const ids = this.ids; const contentFieldFilter = this.contentFieldFilter; - contentFieldFilter.myPopup = webix.ui({ - view: "popup", - height: 240, - width: 480, - hidden: true, - body: contentFieldFilter.ui, - }); return super.ui([ { id: ids.datacollectionID, @@ -365,6 +359,25 @@ export default function (AB) { label: L("Drag & Drop"), labelWidth: uiConfig.labelWidthLarge, value: 0, + on: { + onChange: (newValue) => { + const $dropContentToCreate = $$(ids.dropContentToCreate); + if (newValue === 0) { + $dropContentToCreate.setValue(0); + $dropContentToCreate.hide(); + } else $dropContentToCreate.show(); + this.onChange(); + }, + }, + }, + { + id: ids.dropContentToCreate, + name: "dropContentToCreateNew", + view: "checkbox", + label: L("Drop content to create"), + labelWidth: uiConfig.labelWidthLarge, + hidden: true, + value: 0, on: { onChange: () => this.onChange() }, }, { From 3f042ec3eb21dee467f0bb7183efd4e4e02ea386 Mon Sep 17 00:00:00 2001 From: Johnny Date: Sat, 2 Nov 2024 23:53:42 -0500 Subject: [PATCH 12/32] [wip] capturing information about many:many connections --- .../ui_work_object_list_newObject_netsuite.js | 44 +- ...ect_list_newObject_netsuite_connections.js | 483 +++++++++++++++++- ...k_object_list_newObject_netsuite_tables.js | 5 +- 3 files changed, 515 insertions(+), 17 deletions(-) diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js index 70822ea3..5536a8f3 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js @@ -143,6 +143,10 @@ export default function (AB) { this.UI_Tables.disable(); }); + this.UI_Tables.on("tables", (tables) => { + this.UI_Connections.setAllTables(tables); + }); + this.UI_Tables.on("table.selected", (table) => { this.UI_Fields.enable(); this.UI_Fields.loadFields(table); @@ -365,16 +369,9 @@ export default function (AB) { let link = parts[0]; let linkVia = parts[1]; - let colName = ""; - if (f.thisField != "_this_object_") { - colName = f.thisField; - } else if (f.thatObjectField != "_that_object_") { - colName = f.thatObjectField; - } - let thisField = { key: "connectObject", - columnName: f.thisField, + // columnName: f.thisField, label: linkObject.label, settings: { showIcon: "1", @@ -391,12 +388,41 @@ export default function (AB) { }; let linkField = this.AB.cloneDeep(thisField); - linkField.columnName = f.thatObjectField; + // linkField.columnName = f.thatObjectField; linkField.label = object.label || object.name; linkField.settings.linkObject = object.id; linkField.settings.linkType = linkVia; linkField.settings.linkViaType = link; + switch (linkType) { + case "one:one": + if (f.whichSource == "_this_") { + thisField.settings.isSource = 1; + } else { + linkField.settings.isSource = 1; + } + thisField.columnName = f.sourceField; + linkField.columnName = f.sourceField; + break; + + case "one:many": + case "many:one": + thisField.columnName = f.thatField; + linkField.columnName = f.thatField; + break; + + case "many:many": + thisField.settings.joinTable = f.joinTable; + linkField.settings.joinTable = f.joinTable; + + thisField.settings.joinTableReference = f.thisObjReference; + linkField.settings.joinTableReference = f.thatObjReference; + + thisField.settings.joinTablePK = f.joinTablePK; + linkField.settings.joinTablePK = f.joinTablePK; + break; + } + // create an initial LinkColumn let fieldLink = linkObject.fieldNew(linkField); await fieldLink.save(true); // should get an .id now diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js index 22eb68fd..d48c7944 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js @@ -29,6 +29,12 @@ export default function (AB) { tableName: "", }); + this.allTables = []; + // [ { id, name }, ... ] + // A list of all the available tables. This is used for identifying the + // join tables in many:many connections. + // We get this list from the Tables interface tab. + this.credentials = {}; // { CRED_KEY : CRED_VAL } // The entered credential references necessary to perform our Netsuite @@ -245,6 +251,10 @@ export default function (AB) { const fieldKeys = ["string", "LongText", "number", "date", "boolean"]; const linkTypes = ["one:one", "one:many", "many:one", "many:many"]; + const linkOptions = linkTypes.map((l) => { + return { id: l, value: l }; + }); + linkOptions.unshift({ id: "_choose", value: L("choose link type") }); // For the Base Object, let's include all fields that are clearly // objects. @@ -254,14 +264,458 @@ export default function (AB) { value: conn.column, }; }); - // we also need to include "_this_object_" reference so that - // we can make many:xxx connections (we don't store the value, the - // other object does) - fieldOptions.unshift({ - id: "_this_object_", - value: L("This Object"), + + let thisObjectFields = fieldOptions; + let thatObjectFields = []; + + let listOtherObjects = this.listNetsuiteObjects.map((nObj) => { + return { + id: nObj.id, + value: nObj.label, + }; }); + listOtherObjects.unshift({ id: "_choose", value: L("Choose Object") }); + return { + view: "form", + elements: [ + { + cols: [ + // object and type + { + rows: [ + { + placeholder: L("Existing Netsuite Object"), + options: listOtherObjects, + view: "select", + name: "thatObject", + label: L("To:"), + // value: type, + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + let connObj = self.AB.objectByID(newVal); + if (connObj) { + let result = await self.AB.Network.get({ + url: `/netsuite/table/${connObj.tableName}`, + params: { + credentials: JSON.stringify( + self.credentials + ), + }, + }); + let fields = result.filter( + (r) => r.type == "object" + ); + let options = fields.map((f) => { + return { + id: f.column, + value: f.column, + }; + }); + + // include a "_that_object_" incase this is a one:xxx + // connection. + // options.unshift({ + // id: "_that_object_", + // value: L("That Object"), + // }); + + thatObjectFields = options; + /* + let $linkColumn = + this.getParentView().getChildViews()[1]; + + $linkColumn.define("options", options); + $linkColumn.refresh(); + */ + let $rowsFieldsets = this.getParentView() + .getParentView() + .getChildViews()[1]; + + // update one:one ThatObject: + let whichOptions = $rowsFieldsets + .getChildViews()[0] + .getChildViews()[0] + .getChildViews()[1]; + let newOptions = [ + { id: "_choose", value: L("Choose") }, + { + id: "_this_", + value: L("This Object"), + }, + ]; + newOptions.push({ + id: connObj.id, + value: connObj.label, + }); + whichOptions.define( + "options", + newOptions + ); + whichOptions.refresh(); + } + }, + }, + }, + { + placeholder: "Link Type", + options: linkOptions, + view: "select", + name: "linkType", + label: L("link type"), + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + let $toObj = + this.getParentView().getChildViews()[0]; + let $linkColumn = + this.getParentView().getChildViews()[1]; + + let objID = $toObj.getValue(); + let Obj = self.AB.objectByID(objID); + + let linkVal = $linkColumn.getValue(); + let links = linkVal.split(":"); + let messageA = self.message( + L("This object"), + links[0], + Obj.label + ); + + let messageB = self.message( + Obj.label, + links[1], + L("This object") + ); + + if (newVal == "_choose") { + messageA = messageB = ""; + } + + let $linkTextA = + this.getParentView().getChildViews()[2]; + let $linkTextB = + this.getParentView().getChildViews()[3]; + + $linkTextA.define("label", messageA); + $linkTextA.refresh(); + + $linkTextB.define("label", messageB); + $linkTextB.refresh(); + + let $rowsFieldsets = this.getParentView() + .getParentView() + .getChildViews()[1]; + + let $thatFieldOptions; + + switch (linkVal) { + case "one:one": + $rowsFieldsets + .getChildViews()[0] + .show(); + break; + + case "one:many": + // This Object's fields must be in field picker: + $thatFieldOptions = $rowsFieldsets + .getChildViews()[1] + .getChildViews()[0] + .getChildViews()[1]; + $thatFieldOptions.define( + "options", + thisObjectFields + ); + $thatFieldOptions.refresh(); + $rowsFieldsets + .getChildViews()[1] + .show(); + break; + + case "many:one": + // This Object's fields must be in field picker: + $thatFieldOptions = $rowsFieldsets + .getChildViews()[1] + .getChildViews()[0] + .getChildViews()[1]; + $thatFieldOptions.define( + "options", + thatObjectFields + ); + $thatFieldOptions.refresh(); + $rowsFieldsets + .getChildViews()[1] + .show(); + break; + + case "many:many": + $rowsFieldsets + .getChildViews()[2] + .show(); + break; + } + }, + }, + // value: type, + }, + { + // this to that + // id: ids.fieldLink2, + view: "label", + // width: 200, + }, + { + // that to this + view: "label", + // width: 200, + }, + ], + }, + { + rows: [ + { + view: "fieldset", + label: L("one to one"), + hidden: true, + body: { + rows: [ + { + view: "label", + label: L( + "which object holds the connection value?" + ), + }, + { + view: "select", + options: [ + { + id: "_choose", + value: L("Choose Object"), + }, + { + id: "_this_", + value: L("This Object"), + }, + { + id: "_that_", + value: L("That Object"), + }, + ], + name: "whichSource", + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + if (newVal == "_choose") return; + + let $fieldPicker = + this.getParentView().getChildViews()[2]; + + if (newVal == "_this_") { + $fieldPicker.define( + "options", + thisObjectFields + ); + } else { + $fieldPicker.define( + "options", + thatObjectFields + ); + } + $fieldPicker.refresh(); + $fieldPicker.show(); + }, + }, + }, + { + view: "select", + label: L("which field"), + name: "sourceField", + options: [], + hidden: true, + }, + ], + }, + }, + { + view: "fieldset", + label: L("one:X"), + hidden: true, + body: { + rows: [ + { + view: "label", + label: L( + "which field defines the connection?" + ), + }, + { + view: "select", + // label: L("which field"), + name: "thatField", + options: [], + // hidden: false, + }, + ], + }, + }, + { + view: "fieldset", + label: L("many:many"), + hidden: true, + body: { + rows: [ + { + view: "label", + label: L( + "which table is the join table?" + ), + }, + { + view: "combo", + name: "joinTable", + options: { + filter: (item, value) => { + return ( + item.value + .toLowerCase() + .indexOf( + value.toLowerCase() + ) > -1 + ); + }, + body: { + // template: "#value#", + data: this.allTables, + }, + }, + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + let result = + await self.AB.Network.get({ + url: `/netsuite/table/${newVal}`, + params: { + credentials: + JSON.stringify( + self.credentials + ), + }, + }); + // let fields = result.filter( + // (r) => r.type == "object" + // ); + let options = result.map((f) => { + return { + id: f.column, + value: f.column, + }; + }); + + let $thisObjRef = + this.getParentView().getChildViews()[2]; + $thisObjRef.define( + "options", + options + ); + $thisObjRef.refresh(); + $thisObjRef.show(); + + let $thatObjRef = + this.getParentView().getChildViews()[3]; + $thatObjRef.define( + "options", + options + ); + $thatObjRef.refresh(); + $thatObjRef.show(); + + let $objectPK = + this.getParentView().getChildViews()[4]; + $objectPK.define( + "options", + options + ); + + let pkField = result.find( + (r) => r.title == "Internal ID" + ); + if (pkField) { + $objectPK.setValue( + pkField.column + ); + } + $objectPK.refresh(); + $objectPK.show(); + }, + }, + }, + + { + view: "select", + label: L("This Object's reference"), + labelPosition: "top", + options: [], + name: "thisObjReference", + hidden: true, + }, + { + view: "select", + label: L("That Object's reference"), + labelPosition: "top", + options: [], + name: "thatObjReference", + hidden: true, + }, + { + view: "select", + label: L("Join Table Primary Key:"), + labelPosition: "top", + options: [], + name: "joinTablePK", + hidden: true, + }, + ], + }, + }, + ], + }, + { + // Delete Column + rows: [ + {}, + { + icon: "wxi-trash", + view: "icon", + width: 38, + click: function () { + const $item = this.getParentView() + .getParentView() + .getParentView(); + $$(self.ids.connections).removeView($item); + }, + }, + {}, + ], + // delete Row Icon + }, + ], + }, + ], + }; + /* return { view: "form", elements: [ @@ -371,6 +825,7 @@ export default function (AB) { }, ], }; + */ } _addConnection(key, type) { @@ -383,6 +838,17 @@ export default function (AB) { AB.Webix.ui([], $connections); } + message(a, link, b) { + let msg; + if (link == "many") { + msg = L("{0} has many {1} entities", [a, b]); + } else { + msg = L("{0} has one {1} entity", [a, b]); + } + + return msg; + } + /** * @method onError() * Our Error handler when the data we provided our parent @@ -460,6 +926,11 @@ export default function (AB) { this.credentials = creds; } + setAllTables(tables) { + this.allTables = this.AB.cloneDeep(tables); + this.allTables.unshift({ id: "_choose", value: L("Choose") }); + } + getValues() { let values = []; $$(this.ids.connections) diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js index f5481169..e3a62781 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_tables.js @@ -44,7 +44,7 @@ export default function (AB) { view: "form", id: this.ids.form, width: 800, - height: 400, + height: 700, rules: { // TODO: // name: inputValidator.rules.validateObjectName @@ -222,7 +222,8 @@ export default function (AB) { $table.clearAll(); $table.parse(data); - console.error(data); + // console.error(data); + this.emit("tables", data); } _fieldItem(def) { From cd8e54ec6d88d8700d676b50e01bcf5e807fe7ba Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 5 Nov 2024 21:08:23 -0600 Subject: [PATCH 13/32] [wip] additional info for many:many connections --- .../ui_work_object_list_newObject_netsuite.js | 10 ++++ ...ect_list_newObject_netsuite_connections.js | 56 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js index 5536a8f3..33c2578d 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js @@ -420,6 +420,16 @@ export default function (AB) { thisField.settings.joinTablePK = f.joinTablePK; linkField.settings.joinTablePK = f.joinTablePK; + + if (f.joinActiveField != "_none_") { + thisField.settings.joinActiveField = f.joinActiveField; + thisField.settings.joinActiveValue = f.joinActiveValue; + thisField.settings.joinInActiveValue = f.joinInActiveValue; + + linkField.settings.joinActiveField = f.joinActiveField; + linkField.settings.joinActiveValue = f.joinActiveValue; + linkField.settings.joinInActiveValue = f.joinInActiveValue; + } break; } diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js index d48c7944..9ad7f3e0 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js @@ -659,6 +659,21 @@ export default function (AB) { } $objectPK.refresh(); $objectPK.show(); + + let fOptions = + self.AB.cloneDeep(options); + fOptions.unshift({ + id: "_none_", + value: "", + }); + let $activeField = + this.getParentView().getChildViews()[5]; + $activeField.define( + "options", + fOptions + ); + $activeField.refresh(); + $activeField.show(); }, }, }, @@ -687,6 +702,47 @@ export default function (AB) { name: "joinTablePK", hidden: true, }, + { + view: "select", + label: L("Join Table isActive Field:"), + labelPosition: "top", + options: [], + name: "joinActiveField", + hidden: true, + on: { + onChange: async function ( + newVal, + oldVal, + config + ) { + if (newVal != "_none_") { + // show the active/inactive value + let siblings = + this.getParentView().getChildViews(); + siblings[ + siblings.length - 2 + ].show(); + siblings[ + siblings.length - 1 + ].show(); + } + }, + }, + }, + { + view: "text", + label: L("Active Value"), + name: "joinActiveValue", + hidden: true, + value: "", + }, + { + view: "text", + label: L("InActive Value"), + name: "joinInActiveValue", + hidden: true, + value: "", + }, ], }, }, From 76067536c07671bbf2f83a3b2ff8b70cce0c08dd Mon Sep 17 00:00:00 2001 From: guyyoo Date: Wed, 13 Nov 2024 16:21:34 +0700 Subject: [PATCH 14/32] Data panel settings and group title settings --- .../properties/views/ABViewOrgChartTeams.js | 276 +++++++++++++++--- 1 file changed, 228 insertions(+), 48 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index ecb2c34f..b06b6ac1 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -35,12 +35,16 @@ export default function (AB) { export: "", exportFilename: "", groupByField: "", + showGroupTitle: "", contentField: "", contentFieldFilter: "", contentFieldFilterButton: "", contentGroupByField: "", contentDisplayedFields: "", contentDisplayedFieldsAdd: "", + showDataPanel: "", + dataPanelDCs: "", + dataPanelDCsAdd: "", strategyColorPopup: "", strategyColorForm: "", }); @@ -50,7 +54,7 @@ export default function (AB) { contentFieldFilter.on("save", () => { if ( !contentFieldFilter.isConditionComplete( - contentFieldFilter.getValue() + contentFieldFilter.getValue(), ) ) contentFieldFilter.setValue({ glue: "and", rules: [] }); @@ -62,13 +66,94 @@ export default function (AB) { return "orgchart_teams"; } + _uiDataPanelDC(labelValue = "", dcID = "") { + const self = this; + const ids = self.ids; + const $dataPanelDCs = $$(ids.dataPanelDCs); + const validOBJIDs = this.CurrentView.datacollection.datasource + .fieldByID($$(ids.contentField).getValue()) + .datasourceLink.connectFields( + (connectField) => connectField.linkType() === "one", + ) + .map((connectField) => connectField.datasourceLink.id); + const dcs = this.AB.datacollections( + (dc) => validOBJIDs.indexOf(dc.datasource.id) > -1, + ); + const dcOptions = dcs.map((dc) => ({ + id: dc.id, + value: dc.label, + dc, + })); + const getUILabel = (dcID, elementIndex) => ({ + view: "text", + name: `${elementIndex}.${dcID}`, + // label: L("Name"), + // labelWidth: uiConfig.labelWidthMedium, + on: { + onChange: () => { + this.onChange(); + }, + onViewShow() { + this.setValue(labelValue); + }, + }, + }); + return { + cols: [ + { + view: "richselect", + label: `${L("Panel")} ${ + $dataPanelDCs.getChildViews().length + 1 + }`, + labelWidth: uiConfig.labelWidthMedium, + options: dcOptions, + on: { + onChange(newValue) { + const $parentView = this.getParentView(); + const sameLevelViews = $parentView.getChildViews(); + if ($parentView.getChildViews().length === 3) + $parentView.removeView(sameLevelViews[1].config.id); + $parentView.addView( + getUILabel( + newValue, + $dataPanelDCs + .getChildViews() + .findIndex( + ($dataPanelDCsChild) => + $dataPanelDCsChild === $parentView, + ), + ), + 1, + ); + }, + onViewShow() { + if (dcID == null || dcID === "") return; + this.setValue(dcID); + }, + }, + }, + { + view: "button", + css: "webix_danger", + type: "icon", + icon: "wxi-close", + width: uiConfig.buttonWidthExtraSmall, + click() { + self.deleteDataPanelDC(this.getParentView().config.id); + self.onChange(); + }, + }, + ], + }; + } + _uiContentDisplayedField(fieldID = "", obj, atDisplay) { const self = this; const ids = self.ids; const datasource = this.CurrentView.datacollection.datasource; const datasourceID = datasource.id; const parentObj = datasource.fieldByID( - $$(ids.contentField).getValue() + $$(ids.contentField).getValue(), ).datasourceLink; const parentObjID = parentObj.id; const objID = obj?.id || parentObjID; @@ -90,18 +175,18 @@ export default function (AB) { this._uiContentDisplayedField( "", field.datasourceLink, - currentAtDisplay - ) + currentAtDisplay, + ), ); } this.populateContentDisplayedFields( - $contentDisplayedFields.getValues() + $contentDisplayedFields.getValues(), ); this.onChange(); }; if (objID === parentObjID) { const rootAtDisplay = Object.keys( - $contentDisplayedFields.elements + $contentDisplayedFields.elements, ).filter((key) => key.includes(objID)).length; return { cols: [ @@ -125,7 +210,7 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click() { self.deleteContentDisplayedField( - this.getParentView().getChildViews()[0].config.id + this.getParentView().getChildViews()[0].config.id, ); self.onChange(); }, @@ -154,7 +239,7 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click() { self.deleteContentDisplayedField( - this.getParentView().getChildViews()[0].config.id + this.getParentView().getChildViews()[0].config.id, ); self.onChange(); }, @@ -238,14 +323,15 @@ export default function (AB) { on: { onChange: (newValue) => { const $contentDisplayedFieldsAdd = $$( - ids.contentDisplayedFieldsAdd + ids.contentDisplayedFieldsAdd, ); const $contentFieldFilterButton = $$( - ids.contentFieldFilterButton + ids.contentFieldFilterButton, ); const $contentGroupByField = $$( - ids.contentGroupByField + ids.contentGroupByField, ); + const $showGroupTitle = $$(ids.showGroupTitle); contentFieldFilter.init(); contentFieldFilter.setValue({ glue: "and", @@ -254,10 +340,10 @@ export default function (AB) { if (newValue != null && newValue !== "") { const contentObj = this.CurrentView.datacollection.datasource.fieldByID( - newValue + newValue, ).datasourceLink; contentFieldFilter.fieldsLoad( - contentObj.fields() + contentObj.fields(), ); $contentGroupByField.setValue(""); $contentGroupByField.define("options", [ @@ -266,7 +352,7 @@ export default function (AB) { .fields( (f) => f.key === "list" && - f.settings.isMultiple === 0 + f.settings.isMultiple === 0, ) .map((f) => ({ id: f.id, @@ -277,14 +363,17 @@ export default function (AB) { $contentFieldFilterButton.enable(); $contentDisplayedFieldsAdd.show(); $contentGroupByField.show(); + $showGroupTitle.show(); } else { contentFieldFilter.fieldsLoad([]); - $contentGroupByField.setValue(""); $contentGroupByField.define("options", []); $contentFieldFilterButton.disable(); $contentDisplayedFieldsAdd.hide(); $contentGroupByField.hide(); + $showGroupTitle.hide(); } + $showGroupTitle.setValue(0); + $contentGroupByField.setValue(""); this.populateContentDisplayedFields({}); this.onChange(); }, @@ -319,6 +408,20 @@ export default function (AB) { }, }, }, + { + id: ids.showGroupTitle, + hidden: true, + name: "showGroupTitle", + view: "checkbox", + label: L("Show Group Title"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: (newValue) => { + this.onChange(); + }, + }, + }, { id: ids.contentDisplayedFieldsAdd, hidden: true, @@ -335,16 +438,12 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click: () => { const $contentDisplayedFields = $$( - ids.contentDisplayedFields + ids.contentDisplayedFields, ); if (!$contentDisplayedFields.isVisible()) $contentDisplayedFields.show(); - const values = $contentDisplayedFields.getValues(); - for (const key in values) { - } - Object.keys($contentDisplayedFields.elements); $contentDisplayedFields.addView( - this._uiContentDisplayedField() + this._uiContentDisplayedField(), ); }, }, @@ -356,6 +455,51 @@ export default function (AB) { hidden: true, elements: [], }, + { + id: ids.showDataPanel, + name: "showDataPanel", + view: "checkbox", + label: L("Show Data Panel"), + labelWidth: uiConfig.labelWidthLarge, + value: 0, + on: { + onChange: (newValue) => { + const $dataPanelDCsAdd = $$(ids.dataPanelDCsAdd); + if (newValue === 1) $dataPanelDCsAdd.show(); + else $dataPanelDCsAdd.hide(); + this.populateDataPanelDCs({}); + this.onChange(); + }, + }, + }, + { + id: ids.dataPanelDCsAdd, + hidden: true, + cols: [ + { + view: "label", + label: L("Data Panel DCs"), + }, + { + view: "button", + type: "icon", + icon: "fa fa-plus", + css: "webix_primary", + width: uiConfig.buttonWidthExtraSmall, + click: () => { + const $dataPanelDCs = $$(ids.dataPanelDCs); + if (!$dataPanelDCs.isVisible()) $dataPanelDCs.show(); + $dataPanelDCs.addView(this._uiDataPanelDC()); + }, + }, + ], + }, + { + id: ids.dataPanelDCs, + view: "form", + hidden: true, + elements: [], + }, { id: ids.teamStrategy, view: "richselect", @@ -520,7 +664,7 @@ export default function (AB) { await super.init(AB); webix.extend($$(this.ids.component), webix.ProgressBar); this.contentFieldFilter.queriesLoad( - this.CurrentApplication?.queriesIncluded() + this.CurrentApplication?.queriesIncluded(), ); } @@ -533,26 +677,32 @@ export default function (AB) { if ( deletedElementKey.includes( this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue() - ).datasourceLink.id + $$(ids.contentField).getValue(), + ).datasourceLink.id, ) ) { const deletedAtDisplay = deletedElementKey.split(".")[0]; for (const key in $elements) { if (!key.includes(`${deletedAtDisplay}.`)) continue; $contentDisplayedFields.removeView( - $elements[key].getParentView().config.id + $elements[key].getParentView().config.id, ); } } else $contentDisplayedFields.removeView( - $richselect.getParentView().config.id + $richselect.getParentView().config.id, ); this.populateContentDisplayedFields( - $contentDisplayedFields.getValues() + $contentDisplayedFields.getValues(), ); } + deleteDataPanelDC(id) { + const $dataPanelDCs = $$(this.ids.dataPanelDCs); + $dataPanelDCs.removeView(id); + this.populateDataPanelDCs($dataPanelDCs.getValues()); + } + populate(view) { super.populate(view); const ids = this.ids; @@ -560,7 +710,7 @@ export default function (AB) { const defaultValues = this.defaultValues(); const values = Object.assign( $component.getValues(), - Object.assign(defaultValues, view.settings) + Object.assign(defaultValues, view.settings), ); // const $fieldList = $$(ids.fields); // $fieldList.clearAll(); @@ -577,11 +727,14 @@ export default function (AB) { "topTeam", "contentField", "contentGroupByField", + "showGroupTitle", + "showDataPanel", ].forEach((f) => $$(ids[f]).setValue(values[f])); this.contentFieldFilter.setValue( - JSON.parse(values.contentFieldFilter) + JSON.parse(values.contentFieldFilter), ); this.populateContentDisplayedFields(values.contentDisplayedFields); + this.populateDataPanelDCs(values.dataPanelDCs); if (values.teamStrategy) { this.populateStrategyOptions(values.teamStrategy); $$(ids.strategyCode).setValue(values.strategyCode); @@ -640,12 +793,9 @@ export default function (AB) { const m2oFields = view.getValueFields(object).map(fieldToOption); const o2mFields = object.connectFields( - (f) => f.linkType() == "one" && f.linkViaType() == "many" + (f) => f.linkType() == "one" && f.linkViaType() == "many", ) ?? []; - $$(ids.teamStrategy).define( - "options", - o2mFields.map(fieldToOption) - ); + $$(ids.teamStrategy).define("options", o2mFields.map(fieldToOption)); $$(ids.teamLink).define("options", m2oFields); const textFields = object ?.fields((f) => f.key === "string") @@ -672,16 +822,21 @@ export default function (AB) { const elements = $contentDisplayedFields.elements; for (const key in elements) $contentDisplayedFields.removeView( - elements[key].getParentView().config.id + elements[key].getParentView().config.id, ); const keys = Object.keys(values); + const obj = this.CurrentView.datacollection.datasource.fieldByID( + $$(ids.contentField).getValue(), + )?.datasourceLink; if (keys.length === 0) { $contentDisplayedFields.hide(); return; } - const obj = this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue() - ).datasourceLink; + if (obj == null) { + $contentDisplayedFields.hide(); + $$(ids.contentDisplayedFieldsAdd).hide(); + return; + } const objID = obj.id; const parentKeys = []; const childKeys = []; @@ -694,7 +849,7 @@ export default function (AB) { const parentKey = parentKeys.pop(); const parentFieldID = values[parentKey] ?? ""; $contentDisplayedFields.addView( - this._uiContentDisplayedField(parentFieldID) + this._uiContentDisplayedField(parentFieldID), ); if ( parentFieldID === "" || @@ -703,11 +858,11 @@ export default function (AB) { continue; const currentAtDisplay = Object.keys($contentDisplayedFields.getValues()).filter( - (currentKey) => currentKey.includes(objID) + (currentKey) => currentKey.includes(objID), ).length - 1; while ( childKeys.findIndex((childKey) => - childKey.includes(`${parentKey.split(".")[0]}.`) + childKey.includes(`${parentKey.split(".")[0]}.`), ) > -1 ) { const childKey = childKeys.pop(); @@ -717,8 +872,8 @@ export default function (AB) { this._uiContentDisplayedField( childFieldID, childObj, - currentAtDisplay - ) + currentAtDisplay, + ), ); if ( childFieldID === "" || @@ -730,9 +885,33 @@ export default function (AB) { $contentDisplayedFields.show(); } + populateDataPanelDCs(values) { + const ids = this.ids; + const $dataPanelDCs = $$(ids.dataPanelDCs); + const dataPanelDCsChidren = $dataPanelDCs.getChildViews(); + while (dataPanelDCsChidren.length > 0) + $dataPanelDCs.removeView(dataPanelDCsChidren[0].config.id); + $dataPanelDCs.hide(); + const contentFieldValue = $$(ids.contentField).getValue(); + const keys = Object.keys(values); + if ( + contentFieldValue == null || + contentFieldValue === "" || + keys.length === 0 + ) + return; + while (keys.length > 0) { + const key = keys.shift(); + $dataPanelDCs.addView( + this._uiDataPanelDC(values[key] ?? "", key.split(".")[1] ?? ""), + ); + } + $dataPanelDCs.show(); + } + populateStrategyOptions(fieldID) { const strategyObj = this.AB.objectByID( - this.AB.definitionByID(fieldID).settings.linkObject + this.AB.definitionByID(fieldID).settings.linkObject, ); const listFields = strategyObj .fields((f) => f.key === "list") @@ -749,7 +928,7 @@ export default function (AB) { if (!$popup) { const values = this.CurrentView.settings.strategyColors ?? {}; const strategyTypes = this.AB.definitionByID( - codeFieldID + codeFieldID, ).settings.options.map((strategy) => { return { view: "colorpicker", @@ -825,7 +1004,7 @@ export default function (AB) { const ids = this.ids; const settings = (values.settings = Object.assign( $$(ids.component).getValues(), - values.settings + values.settings, )); // Retrive the values of your properties from Webix and store them in the view settings.teamLink = $$(ids.teamLink).getValue(); @@ -839,11 +1018,12 @@ export default function (AB) { settings.contentField = $$(ids.contentField).getValue(); settings.contentGroupByField = $$(ids.contentGroupByField).getValue(); settings.contentFieldFilter = JSON.stringify( - this.contentFieldFilter.getValue() + this.contentFieldFilter.getValue(), ); settings.contentDisplayedFields = $$( - ids.contentDisplayedFields + ids.contentDisplayedFields, ).getValues(); + settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); const $colorForm = $$(ids.strategyColorForm); settings.strategyColors = $colorForm?.getValues() ?? {}; return values; From ccda766c5a67f2c4ceed8ca04102e76ed0fd413b Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 19 Nov 2024 17:39:21 +0700 Subject: [PATCH 15/32] Team Widget can edit assignments --- .../properties/views/ABViewOrgChartTeams.js | 61 +++++++++++++------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index b06b6ac1..29e57aff 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -36,6 +36,7 @@ export default function (AB) { exportFilename: "", groupByField: "", showGroupTitle: "", + editContentFieldsToCreateNew: "", contentField: "", contentFieldFilter: "", contentFieldFilterButton: "", @@ -162,11 +163,6 @@ export default function (AB) { const linkedObjID = f.datasourceLink?.id; return linkedObjID !== datasourceID && linkedObjID !== parentObjID; }; - const mapFields = (f) => ({ - id: f.id, - value: f.label, - field: f, - }); const getOnSelectChangeFn = (currentObj, currentAtDisplay) => (newValue) => { const field = currentObj.fieldByID(newValue); @@ -196,7 +192,7 @@ export default function (AB) { label: `${L("Display")} ${rootAtDisplay + 1}`, labelWidth: uiConfig.labelWidthMedium, options: - parentObj.fields(filterFields).map(mapFields) || [], + parentObj.fields(filterFields).map(fieldToOption) || [], value: fieldID, on: { onChange: getOnSelectChangeFn(parentObj, rootAtDisplay), @@ -225,7 +221,7 @@ export default function (AB) { name: `${atDisplay}.${objID}`, label: "->", labelWidth: uiConfig.labelWidthMedium, - options: obj.fields(filterFields).map(mapFields) || [], + options: obj.fields(filterFields).map(fieldToOption) || [], value: fieldID, on: { onChange: getOnSelectChangeFn(obj, atDisplay), @@ -322,6 +318,9 @@ export default function (AB) { options: [], on: { onChange: (newValue) => { + const $editContentFieldsToCreateNew = $$( + ids.editContentFieldsToCreateNew, + ); const $contentDisplayedFieldsAdd = $$( ids.contentDisplayedFieldsAdd, ); @@ -342,36 +341,45 @@ export default function (AB) { this.CurrentView.datacollection.datasource.fieldByID( newValue, ).datasourceLink; - contentFieldFilter.fieldsLoad( - contentObj.fields(), + const contentObjFields = contentObj.fields(); + $editContentFieldsToCreateNew.define( + "options", + // contentObjFields.map(fieldToOption), + contentObjFields.map((contentObjField) => ({ + id: contentObjField.id, + value: contentObjField.label, + })), ); - $contentGroupByField.setValue(""); + contentFieldFilter.fieldsLoad(contentObjFields); $contentGroupByField.define("options", [ { id: "", value: "", $empty: true }, - ...contentObj - .fields( + ...contentObjFields + .filter( (f) => f.key === "list" && f.settings.isMultiple === 0, ) - .map((f) => ({ - id: f.id, - value: f.label, - field: f, - })), + .map(fieldToOption), ]); + $editContentFieldsToCreateNew.enable(); $contentFieldFilterButton.enable(); $contentDisplayedFieldsAdd.show(); $contentGroupByField.show(); $showGroupTitle.show(); } else { + $editContentFieldsToCreateNew.define( + "options", + [], + ); contentFieldFilter.fieldsLoad([]); $contentGroupByField.define("options", []); + $editContentFieldsToCreateNew.enable(); $contentFieldFilterButton.disable(); $contentDisplayedFieldsAdd.hide(); $contentGroupByField.hide(); $showGroupTitle.hide(); } + $editContentFieldsToCreateNew.setValue([]); $showGroupTitle.setValue(0); $contentGroupByField.setValue(""); this.populateContentDisplayedFields({}); @@ -422,6 +430,20 @@ export default function (AB) { }, }, }, + { + id: ids.editContentFieldsToCreateNew, + view: "multicombo", + value: [], + options: [], + placeholder: L("Choose content fields to create new by editing"), + labelAlign: "left", + stringResult: false /* returns data as an array of [id] */, + on: { + onChange: (newValue) => { + this.onChange(); + }, + }, + }, { id: ids.contentDisplayedFieldsAdd, hidden: true, @@ -727,6 +749,7 @@ export default function (AB) { "topTeam", "contentField", "contentGroupByField", + "editContentFieldsToCreateNew", "showGroupTitle", "showDataPanel", ].forEach((f) => $$(ids[f]).setValue(values[f])); @@ -788,7 +811,6 @@ export default function (AB) { populateTeamFieldOptions(object) { const view = this.CurrentView; - // const linkFields = view.getValueFields(object).map(fieldToOption); const ids = this.ids; const m2oFields = view.getValueFields(object).map(fieldToOption); const o2mFields = @@ -1017,6 +1039,9 @@ export default function (AB) { settings.dataCollectionId = $$(ids.datacollectionID).getValue(); settings.contentField = $$(ids.contentField).getValue(); settings.contentGroupByField = $$(ids.contentGroupByField).getValue(); + settings.editContentFieldsToCreateNew = $$( + ids.editContentFieldsToCreateNew, + ).getValue(); settings.contentFieldFilter = JSON.stringify( this.contentFieldFilter.getValue(), ); From e134f7aa039d1d94fa8e67b5214b37817a8e0943 Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 20 Nov 2024 14:04:15 +0700 Subject: [PATCH 16/32] [wip] enable labels on api objects, fill out missing many:many information --- .../ui_work_object_list_newObject_netsuite.js | 3 + ...ect_list_newObject_netsuite_connections.js | 176 ++++-------------- .../Designer/ui_work_object_workspace.js | 37 ++-- 3 files changed, 60 insertions(+), 156 deletions(-) diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js index 33c2578d..32018fb8 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite.js @@ -421,6 +421,9 @@ export default function (AB) { thisField.settings.joinTablePK = f.joinTablePK; linkField.settings.joinTablePK = f.joinTablePK; + thisField.settings.joinTableEntity = f.joinTableEntity; + linkField.settings.joinTableEntity = f.joinTableEntity; + if (f.joinActiveField != "_none_") { thisField.settings.joinActiveField = f.joinActiveField; thisField.settings.joinActiveValue = f.joinActiveValue; diff --git a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js index 9ad7f3e0..bdae1a56 100644 --- a/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js +++ b/src/rootPages/Designer/ui_work_object_list_newObject_netsuite_connections.js @@ -158,33 +158,6 @@ export default function (AB) { }, ], }, - - { - cols: [ - { fillspace: true }, - // { - // view: "button", - // id: this.ids.buttonCancel, - // value: L("Cancel"), - // css: "ab-cancel-button", - // autowidth: true, - // click: () => { - // this.cancel(); - // }, - // }, - { - view: "button", - id: this.ids.buttonVerify, - css: "webix_primary", - value: L("Verify"), - autowidth: true, - type: "form", - click: () => { - return this.verify(); - }, - }, - ], - }, ], }, ], @@ -660,6 +633,32 @@ export default function (AB) { $objectPK.refresh(); $objectPK.show(); + let $entityField = + this.getParentView().getChildViews()[5]; + $entityField.define( + "options", + options + ); + + let fieldEntity = result.find( + (r) => { + if (!r.column) return false; + + return ( + r.column.indexOf( + "entity" + ) > -1 + ); + } + ); + if (fieldEntity) { + $entityField.setValue( + fieldEntity.column + ); + } + $entityField.refresh(); + $entityField.show(); + let fOptions = self.AB.cloneDeep(options); fOptions.unshift({ @@ -667,7 +666,7 @@ export default function (AB) { value: "", }); let $activeField = - this.getParentView().getChildViews()[5]; + this.getParentView().getChildViews()[6]; $activeField.define( "options", fOptions @@ -702,6 +701,16 @@ export default function (AB) { name: "joinTablePK", hidden: true, }, + { + view: "select", + label: L( + "Which field holds the Entity:" + ), + labelPosition: "top", + options: [], + name: "joinTableEntity", + hidden: true, + }, { view: "select", label: L("Join Table isActive Field:"), @@ -771,117 +780,6 @@ export default function (AB) { }, ], }; - /* - return { - view: "form", - elements: [ - { - cols: [ - { - rows: [ - { - label: L("Field"), - view: "label", - }, - { - placeholder: "Type", - options: fieldOptions, - view: "select", - // value: type, - name: "thisField", - }, - ], - }, - { - rows: [ - { - placeholder: L("Existing Netsuite Object"), - options: this.listNetsuiteObjects.map((nObj) => { - return { - id: nObj.id, - value: nObj.label, - }; - }), - view: "select", - name: "thatObject", - // value: type, - on: { - onChange: async function ( - newVal, - oldVal, - config - ) { - let connObj = self.AB.objectByID(newVal); - if (connObj) { - let result = await self.AB.Network.get({ - url: `/netsuite/table/${connObj.tableName}`, - params: { - credentials: JSON.stringify( - self.credentials - ), - }, - }); - let fields = result.filter( - (r) => r.type == "object" - ); - let options = fields.map((f) => { - return { - id: f.column, - value: f.column, - }; - }); - - // include a "_that_object_" incase this is a one:xxx - // connection. - options.unshift({ - id: "_that_object_", - value: L("That Object"), - }); - let $linkColumn = - this.getParentView().getChildViews()[1]; - - $linkColumn.define("options", options); - $linkColumn.refresh(); - } - }, - }, - }, - { - placeholder: "Link Column", - options: [], - view: "select", - // value: type, - name: "thatObjectField", - }, - { - placeholder: "Link Type", - options: linkTypes.map((l) => { - return { - id: l, - value: l, - }; - }), - view: "select", - name: "linkType", - // value: type, - }, - ], - }, - - { - icon: "wxi-trash", - view: "icon", - width: 38, - click: function () { - const $item = this.getParentView().getParentView(); - $$(self.ids.connections).removeView($item); - }, - }, - ], - }, - ], - }; - */ } _addConnection(key, type) { diff --git a/src/rootPages/Designer/ui_work_object_workspace.js b/src/rootPages/Designer/ui_work_object_workspace.js index 94527dd0..9513c00c 100644 --- a/src/rootPages/Designer/ui_work_object_workspace.js +++ b/src/rootPages/Designer/ui_work_object_workspace.js @@ -179,15 +179,18 @@ export default function (AB, ibase, init_settings) { this.callbackHeaderEditorMenu(action, field, node); }); - if (!this.isReadOnly) { - this.PopupDefineLabelComponent = new FPopupDefineLabel( - AB, - `${base}_defineLabel` - ); - this.PopupDefineLabelComponent.on("changed", () => { - this.callbackDefineLabel(); - }); - } + // NOTE: label information is only concerning how we display the info + // from this Object. It doesn't impact the data. So we can go ahead + // and allow users to modify the Label data. + // if (!this.isReadOnly) { + this.PopupDefineLabelComponent = new FPopupDefineLabel( + AB, + `${base}_defineLabel` + ); + this.PopupDefineLabelComponent.on("changed", () => { + this.callbackDefineLabel(); + }); + // } this.PopupFilterDataTableComponent = new FPopupFilterDataTable( AB, @@ -437,7 +440,7 @@ export default function (AB, ibase, init_settings) { icon: "fa fa-crosshairs", css: "webix_transparent", type: "icon", - hidden: this.isReadOnly, + // hidden: this.isReadOnly, click: function () { _logic.toolbarDefineLabel(this.$view); }, @@ -707,9 +710,9 @@ export default function (AB, ibase, init_settings) { allInits.push(this.PopupHeaderEditMenu.init(AB)); - if (!this.isReadOnly) { - allInits.push(this.PopupDefineLabelComponent.init(AB)); - } + // if (!this.isReadOnly) { + allInits.push(this.PopupDefineLabelComponent.init(AB)); + // } allInits.push(this.PopupFilterDataTableComponent.init(AB)); this.PopupFilterDataTableComponent.on("save", (...params) => { @@ -1391,8 +1394,8 @@ export default function (AB, ibase, init_settings) { if (!this.isReadOnly) { this.PopupNewDataFieldComponent.objectLoad(object); - this.PopupDefineLabelComponent.objectLoad(object); } + this.PopupDefineLabelComponent.objectLoad(object); this.PopupFilterDataTableComponent.objectLoad(object); this.PopupFrozenColumnsComponent.objectLoad(object); @@ -1782,7 +1785,7 @@ export default function (AB, ibase, init_settings) { const ids = this.ids; const $buttonAddField = $$(ids.buttonAddField), $spaceAddField = $$(ids.spaceAddField), - $buttonLabel = $$(ids.buttonLabel), + // $buttonLabel = $$(ids.buttonLabel), $spaceLabel = $$(ids.spaceLabel), $buttonImport = $$(ids.buttonImport), $spaceImport = $$(ids.spaceImport), @@ -1792,7 +1795,7 @@ export default function (AB, ibase, init_settings) { if (this._isReadOnly) { $buttonAddField?.hide(); $spaceAddField?.hide(); - $buttonLabel?.hide(); + // $buttonLabel?.hide(); $spaceLabel?.hide(); $buttonImport?.hide(); $spaceImport?.hide(); @@ -1801,7 +1804,7 @@ export default function (AB, ibase, init_settings) { } else { $buttonAddField?.show(); $spaceAddField?.show(); - $buttonLabel?.show(); + // $buttonLabel?.show(); $spaceLabel?.show(); $buttonImport?.show(); $spaceImport?.show(); From 5dfeab48c0883ab67f88e3c4f6b41527ec261adb Mon Sep 17 00:00:00 2001 From: guyyoo Date: Wed, 20 Nov 2024 15:01:34 +0700 Subject: [PATCH 17/32] Fix layout --- .../properties/views/ABViewOrgChartTeams.js | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 29e57aff..e7dfb9ba 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -431,18 +431,28 @@ export default function (AB) { }, }, { - id: ids.editContentFieldsToCreateNew, - view: "multicombo", - value: [], - options: [], - placeholder: L("Choose content fields to create new by editing"), - labelAlign: "left", - stringResult: false /* returns data as an array of [id] */, - on: { - onChange: (newValue) => { - this.onChange(); + rows: [ + { + view: "label", + label: L("Create new by editing content fields"), }, - }, + { + id: ids.editContentFieldsToCreateNew, + view: "multicombo", + value: [], + options: [], + placeholder: L( + "Choose content fields to create new by editing", + ), + labelAlign: "left", + stringResult: false /* returns data as an array of [id] */, + on: { + onChange: (newValue) => { + this.onChange(); + }, + }, + }, + ], }, { id: ids.contentDisplayedFieldsAdd, From a5c7c43b73f128794e0b4300f2b5622d2aa6670e Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Fri, 22 Nov 2024 13:02:51 +0700 Subject: [PATCH 18/32] fix data types to match real data --- .../properties/views/ABViewOrgChartTeams.js | 116 +++++++++--------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 29e57aff..45a2c4d5 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -55,7 +55,7 @@ export default function (AB) { contentFieldFilter.on("save", () => { if ( !contentFieldFilter.isConditionComplete( - contentFieldFilter.getValue(), + contentFieldFilter.getValue() ) ) contentFieldFilter.setValue({ glue: "and", rules: [] }); @@ -74,11 +74,11 @@ export default function (AB) { const validOBJIDs = this.CurrentView.datacollection.datasource .fieldByID($$(ids.contentField).getValue()) .datasourceLink.connectFields( - (connectField) => connectField.linkType() === "one", + (connectField) => connectField.linkType() === "one" ) .map((connectField) => connectField.datasourceLink.id); const dcs = this.AB.datacollections( - (dc) => validOBJIDs.indexOf(dc.datasource.id) > -1, + (dc) => validOBJIDs.indexOf(dc.datasource.id) > -1 ); const dcOptions = dcs.map((dc) => ({ id: dc.id, @@ -121,10 +121,10 @@ export default function (AB) { .getChildViews() .findIndex( ($dataPanelDCsChild) => - $dataPanelDCsChild === $parentView, - ), + $dataPanelDCsChild === $parentView + ) ), - 1, + 1 ); }, onViewShow() { @@ -154,7 +154,7 @@ export default function (AB) { const datasource = this.CurrentView.datacollection.datasource; const datasourceID = datasource.id; const parentObj = datasource.fieldByID( - $$(ids.contentField).getValue(), + $$(ids.contentField).getValue() ).datasourceLink; const parentObjID = parentObj.id; const objID = obj?.id || parentObjID; @@ -171,18 +171,18 @@ export default function (AB) { this._uiContentDisplayedField( "", field.datasourceLink, - currentAtDisplay, - ), + currentAtDisplay + ) ); } this.populateContentDisplayedFields( - $contentDisplayedFields.getValues(), + $contentDisplayedFields.getValues() ); this.onChange(); }; if (objID === parentObjID) { const rootAtDisplay = Object.keys( - $contentDisplayedFields.elements, + $contentDisplayedFields.elements ).filter((key) => key.includes(objID)).length; return { cols: [ @@ -206,7 +206,7 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click() { self.deleteContentDisplayedField( - this.getParentView().getChildViews()[0].config.id, + this.getParentView().getChildViews()[0].config.id ); self.onChange(); }, @@ -235,7 +235,7 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click() { self.deleteContentDisplayedField( - this.getParentView().getChildViews()[0].config.id, + this.getParentView().getChildViews()[0].config.id ); self.onChange(); }, @@ -319,16 +319,16 @@ export default function (AB) { on: { onChange: (newValue) => { const $editContentFieldsToCreateNew = $$( - ids.editContentFieldsToCreateNew, + ids.editContentFieldsToCreateNew ); const $contentDisplayedFieldsAdd = $$( - ids.contentDisplayedFieldsAdd, + ids.contentDisplayedFieldsAdd ); const $contentFieldFilterButton = $$( - ids.contentFieldFilterButton, + ids.contentFieldFilterButton ); const $contentGroupByField = $$( - ids.contentGroupByField, + ids.contentGroupByField ); const $showGroupTitle = $$(ids.showGroupTitle); contentFieldFilter.init(); @@ -339,25 +339,20 @@ export default function (AB) { if (newValue != null && newValue !== "") { const contentObj = this.CurrentView.datacollection.datasource.fieldByID( - newValue, + newValue ).datasourceLink; const contentObjFields = contentObj.fields(); $editContentFieldsToCreateNew.define( "options", - // contentObjFields.map(fieldToOption), - contentObjFields.map((contentObjField) => ({ - id: contentObjField.id, - value: contentObjField.label, - })), + contentObjFields.map(fieldToOption) ); contentFieldFilter.fieldsLoad(contentObjFields); $contentGroupByField.define("options", [ { id: "", value: "", $empty: true }, ...contentObjFields .filter( - (f) => - f.key === "list" && - f.settings.isMultiple === 0, + (f) => f.key === "connectObject" //&& + // f.settings.isMultiple === 0 ) .map(fieldToOption), ]); @@ -369,7 +364,7 @@ export default function (AB) { } else { $editContentFieldsToCreateNew.define( "options", - [], + [] ); contentFieldFilter.fieldsLoad([]); $contentGroupByField.define("options", []); @@ -411,7 +406,7 @@ export default function (AB) { labelWidth: uiConfig.labelWidthLarge, options: [], on: { - onChange: (newValue) => { + onChange: (/*newValue*/) => { this.onChange(); }, }, @@ -425,7 +420,7 @@ export default function (AB) { labelWidth: uiConfig.labelWidthLarge, value: 0, on: { - onChange: (newValue) => { + onChange: (/*newValue*/) => { this.onChange(); }, }, @@ -439,7 +434,7 @@ export default function (AB) { labelAlign: "left", stringResult: false /* returns data as an array of [id] */, on: { - onChange: (newValue) => { + onChange: (/*newValue*/) => { this.onChange(); }, }, @@ -460,12 +455,12 @@ export default function (AB) { width: uiConfig.buttonWidthExtraSmall, click: () => { const $contentDisplayedFields = $$( - ids.contentDisplayedFields, + ids.contentDisplayedFields ); if (!$contentDisplayedFields.isVisible()) $contentDisplayedFields.show(); $contentDisplayedFields.addView( - this._uiContentDisplayedField(), + this._uiContentDisplayedField() ); }, }, @@ -686,7 +681,7 @@ export default function (AB) { await super.init(AB); webix.extend($$(this.ids.component), webix.ProgressBar); this.contentFieldFilter.queriesLoad( - this.CurrentApplication?.queriesIncluded(), + this.CurrentApplication?.queriesIncluded() ); } @@ -699,23 +694,23 @@ export default function (AB) { if ( deletedElementKey.includes( this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue(), - ).datasourceLink.id, + $$(ids.contentField).getValue() + ).datasourceLink.id ) ) { const deletedAtDisplay = deletedElementKey.split(".")[0]; for (const key in $elements) { if (!key.includes(`${deletedAtDisplay}.`)) continue; $contentDisplayedFields.removeView( - $elements[key].getParentView().config.id, + $elements[key].getParentView().config.id ); } } else $contentDisplayedFields.removeView( - $richselect.getParentView().config.id, + $richselect.getParentView().config.id ); this.populateContentDisplayedFields( - $contentDisplayedFields.getValues(), + $contentDisplayedFields.getValues() ); } @@ -732,7 +727,7 @@ export default function (AB) { const defaultValues = this.defaultValues(); const values = Object.assign( $component.getValues(), - Object.assign(defaultValues, view.settings), + Object.assign(defaultValues, view.settings) ); // const $fieldList = $$(ids.fields); // $fieldList.clearAll(); @@ -754,7 +749,7 @@ export default function (AB) { "showDataPanel", ].forEach((f) => $$(ids[f]).setValue(values[f])); this.contentFieldFilter.setValue( - JSON.parse(values.contentFieldFilter), + JSON.parse(values.contentFieldFilter) ); this.populateContentDisplayedFields(values.contentDisplayedFields); this.populateDataPanelDCs(values.dataPanelDCs); @@ -815,7 +810,7 @@ export default function (AB) { const m2oFields = view.getValueFields(object).map(fieldToOption); const o2mFields = object.connectFields( - (f) => f.linkType() == "one" && f.linkViaType() == "many", + (f) => f.linkType() == "one" && f.linkViaType() == "many" ) ?? []; $$(ids.teamStrategy).define("options", o2mFields.map(fieldToOption)); $$(ids.teamLink).define("options", m2oFields); @@ -844,11 +839,11 @@ export default function (AB) { const elements = $contentDisplayedFields.elements; for (const key in elements) $contentDisplayedFields.removeView( - elements[key].getParentView().config.id, + elements[key].getParentView().config.id ); const keys = Object.keys(values); const obj = this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue(), + $$(ids.contentField).getValue() )?.datasourceLink; if (keys.length === 0) { $contentDisplayedFields.hide(); @@ -871,7 +866,7 @@ export default function (AB) { const parentKey = parentKeys.pop(); const parentFieldID = values[parentKey] ?? ""; $contentDisplayedFields.addView( - this._uiContentDisplayedField(parentFieldID), + this._uiContentDisplayedField(parentFieldID) ); if ( parentFieldID === "" || @@ -880,11 +875,11 @@ export default function (AB) { continue; const currentAtDisplay = Object.keys($contentDisplayedFields.getValues()).filter( - (currentKey) => currentKey.includes(objID), + (currentKey) => currentKey.includes(objID) ).length - 1; while ( childKeys.findIndex((childKey) => - childKey.includes(`${parentKey.split(".")[0]}.`), + childKey.includes(`${parentKey.split(".")[0]}.`) ) > -1 ) { const childKey = childKeys.pop(); @@ -894,8 +889,8 @@ export default function (AB) { this._uiContentDisplayedField( childFieldID, childObj, - currentAtDisplay, - ), + currentAtDisplay + ) ); if ( childFieldID === "" || @@ -925,7 +920,7 @@ export default function (AB) { while (keys.length > 0) { const key = keys.shift(); $dataPanelDCs.addView( - this._uiDataPanelDC(values[key] ?? "", key.split(".")[1] ?? ""), + this._uiDataPanelDC(values[key] ?? "", key.split(".")[1] ?? "") ); } $dataPanelDCs.show(); @@ -933,15 +928,15 @@ export default function (AB) { populateStrategyOptions(fieldID) { const strategyObj = this.AB.objectByID( - this.AB.definitionByID(fieldID).settings.linkObject, + this.AB.definitionByID(fieldID).settings.linkObject ); const listFields = strategyObj - .fields((f) => f.key === "list") + .fields((f) => f.key === "connectObject") .map(fieldToOption); $$(this.ids.strategyCode).define("options", listFields); } - strategyColorPopup() { + async strategyColorPopup() { const codeFieldID = $$(this.ids.strategyCode).getValue(); if (!codeFieldID) return; @@ -949,12 +944,13 @@ export default function (AB) { if (!$popup) { const values = this.CurrentView.settings.strategyColors ?? {}; - const strategyTypes = this.AB.definitionByID( - codeFieldID, - ).settings.options.map((strategy) => { + const link = + this.AB.definitionByID(codeFieldID).settings.linkObject; + const strategies = await this.AB.objectByID(link).model().findAll(); + const strategyTypes = strategies.data.map((strategy) => { return { view: "colorpicker", - label: strategy.text, + label: strategy.name, name: strategy.id, value: values[strategy.id] ?? "#111111", }; @@ -1026,7 +1022,7 @@ export default function (AB) { const ids = this.ids; const settings = (values.settings = Object.assign( $$(ids.component).getValues(), - values.settings, + values.settings )); // Retrive the values of your properties from Webix and store them in the view settings.teamLink = $$(ids.teamLink).getValue(); @@ -1040,13 +1036,13 @@ export default function (AB) { settings.contentField = $$(ids.contentField).getValue(); settings.contentGroupByField = $$(ids.contentGroupByField).getValue(); settings.editContentFieldsToCreateNew = $$( - ids.editContentFieldsToCreateNew, + ids.editContentFieldsToCreateNew ).getValue(); settings.contentFieldFilter = JSON.stringify( - this.contentFieldFilter.getValue(), + this.contentFieldFilter.getValue() ); settings.contentDisplayedFields = $$( - ids.contentDisplayedFields, + ids.contentDisplayedFields ).getValues(); settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); const $colorForm = $$(ids.strategyColorForm); From 351e48138c4253f638c9b74d86b70e3a774243a5 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Fri, 22 Nov 2024 15:43:28 +0700 Subject: [PATCH 19/32] Content filter's feature settings --- .../properties/views/ABViewOrgChartTeams.js | 143 +++++++++++++++--- 1 file changed, 125 insertions(+), 18 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index e7dfb9ba..217038f8 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -43,6 +43,8 @@ export default function (AB) { contentGroupByField: "", contentDisplayedFields: "", contentDisplayedFieldsAdd: "", + contentDisplayedFieldFilters: "", + contentDisplayedFieldFiltersSet: "", showDataPanel: "", dataPanelDCs: "", dataPanelDCsAdd: "", @@ -159,6 +161,9 @@ export default function (AB) { const parentObjID = parentObj.id; const objID = obj?.id || parentObjID; const $contentDisplayedFields = $$(ids.contentDisplayedFields); + const $contentDisplayedFieldFilters = $$( + ids.contentDisplayedFieldFilters, + ); const filterFields = (f) => { const linkedObjID = f.datasourceLink?.id; return linkedObjID !== datasourceID && linkedObjID !== parentObjID; @@ -177,6 +182,7 @@ export default function (AB) { } this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), + $contentDisplayedFieldFilters.getValues(), ); this.onChange(); }; @@ -487,6 +493,21 @@ export default function (AB) { hidden: true, elements: [], }, + { + id: ids.contentDisplayedFieldFiltersSet, + hidden: false, + rows: [ + { + view: "label", + label: L("Set content displayed filters by field"), + }, + { + id: ids.contentDisplayedFieldFilters, + view: "form", + elements: [], + }, + ], + }, { id: ids.showDataPanel, name: "showDataPanel", @@ -766,7 +787,10 @@ export default function (AB) { this.contentFieldFilter.setValue( JSON.parse(values.contentFieldFilter), ); - this.populateContentDisplayedFields(values.contentDisplayedFields); + this.populateContentDisplayedFields( + values.contentDisplayedFields, + values.contentDisplayedFieldFilters, + ); this.populateDataPanelDCs(values.dataPanelDCs); if (values.teamStrategy) { this.populateStrategyOptions(values.teamStrategy); @@ -848,30 +872,99 @@ export default function (AB) { ]); } - populateContentDisplayedFields(values) { + populateContentDisplayedFields(values = {}, filters = {}) { + const self = this; const ids = this.ids; const $contentDisplayedFields = $$(ids.contentDisplayedFields); - const elements = $contentDisplayedFields.elements; - for (const key in elements) + const contentDisplayedFieldsElements = + $contentDisplayedFields.elements; + for (const key in contentDisplayedFieldsElements) $contentDisplayedFields.removeView( - elements[key].getParentView().config.id, + contentDisplayedFieldsElements[key].getParentView().config.id, + ); + const $contentDisplayedFieldFilters = $$( + ids.contentDisplayedFieldFilters, + ); + const contentDisplayedFieldFiltersElements = + $contentDisplayedFieldFilters.elements; + const $contentDisplayedFieldFiltersSet = $$( + ids.contentDisplayedFieldFiltersSet, + ); + for (const key in contentDisplayedFieldFiltersElements) + $contentDisplayedFieldFilters.removeView( + contentDisplayedFieldFiltersElements[key].getParentView().config + .id, ); + $contentDisplayedFieldFiltersSet.hide(); const keys = Object.keys(values); - const obj = this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue(), - )?.datasourceLink; if (keys.length === 0) { $contentDisplayedFields.hide(); return; } + const obj = this.CurrentView.datacollection.datasource.fieldByID( + $$(ids.contentField).getValue(), + )?.datasourceLink; if (obj == null) { $contentDisplayedFields.hide(); $$(ids.contentDisplayedFieldsAdd).hide(); return; } + const filterKeys = Object.keys(filters); const objID = obj.id; const parentKeys = []; const childKeys = []; + const createOptionsView = (key, field) => { + const filterPrefix = `${key}.${field.id}`; + const filterValue = parseInt( + filterKeys + .find((filterKey) => filterKey.indexOf(filterPrefix) > -1) + ?.split(".")[3], + ); + $contentDisplayedFieldFilters.addView({ + cols: [ + { + view: "checkbox", + label: field.label, + labelWidth: uiConfig.labelWidthMedium, + value: isNaN(filterValue) ? 0 : filterValue, + on: { + onChange: (newValue, oldValue) => { + const oldFilters = + $contentDisplayedFieldFilters.getValues(); + const oldFilterEntries = Object.entries(oldFilters); + const newFilters = {}; + const oldFilterKey = `${filterPrefix}.${oldValue}`; + for (const [key, value] of oldFilterEntries) + if (key === oldFilterKey) + newFilters[`${filterPrefix}.${newValue}`] = ""; + else newFilters[key] = value; + this.populateContentDisplayedFields( + $contentDisplayedFields.getValues(), + newFilters, + ); + this.onChange(); + }, + onViewShow() { + const checkboxValue = this.getValue(); + const filterKey = `${filterPrefix}.${checkboxValue}`; + this.getParentView().addView({ + view: "text", + placeholder: L("Add the new field label."), + name: filterKey, + value: filters[filterKey], + disabled: checkboxValue === 1 ? false : true, + on: { + onChange: () => { + self.onChange(); + }, + }, + }); + }, + }, + }, + ], + }); + }; while (keys.length > 0) { const key = keys.pop(); (key.includes(objID) && parentKeys.push(key)) || @@ -883,11 +976,16 @@ export default function (AB) { $contentDisplayedFields.addView( this._uiContentDisplayedField(parentFieldID), ); - if ( - parentFieldID === "" || - obj.fieldByID(parentFieldID).key !== "connectObject" - ) - continue; + const parentField = obj.fieldByID(parentFieldID); + if (parentField == null) continue; + switch (parentField.key) { + case "connectObject": + case "user": + break; + default: + createOptionsView(parentKey, parentField); + continue; + } const currentAtDisplay = Object.keys($contentDisplayedFields.getValues()).filter( (currentKey) => currentKey.includes(objID), @@ -907,14 +1005,20 @@ export default function (AB) { currentAtDisplay, ), ); - if ( - childFieldID === "" || - childObj.fieldByID(childFieldID).key !== "connectObject" - ) - break; + const childField = childObj.fieldByID(childFieldID); + if (childField == null) continue; + switch (childField.key) { + case "connectObject": + case "user": + break; + default: + createOptionsView(parentKey, childField); + continue; + } } } $contentDisplayedFields.show(); + $contentDisplayedFieldFiltersSet.show(); } populateDataPanelDCs(values) { @@ -1058,6 +1162,9 @@ export default function (AB) { settings.contentDisplayedFields = $$( ids.contentDisplayedFields, ).getValues(); + settings.contentDisplayedFieldFilters = $$( + ids.contentDisplayedFieldFilters, + ).getValues(); settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); const $colorForm = $$(ids.strategyColorForm); settings.strategyColors = $colorForm?.getValues() ?? {}; From 76675435595b20d467b6d3be0c0e5ff73ddbf94f Mon Sep 17 00:00:00 2001 From: guyyoo Date: Mon, 25 Nov 2024 11:47:48 +0700 Subject: [PATCH 20/32] Content filter settings and [WIP] maping field data types --- .../properties/views/ABViewOrgChartTeams.js | 189 ++++++++++++++++-- 1 file changed, 175 insertions(+), 14 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 28e346e8..278c65ee 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -45,6 +45,8 @@ export default function (AB) { contentDisplayedFieldsAdd: "", contentDisplayedFieldFilters: "", contentDisplayedFieldFiltersSet: "", + contentDisplayedFieldTypes: "", + contentDisplayedFieldTypesSet: "", showDataPanel: "", dataPanelDCs: "", dataPanelDCsAdd: "", @@ -161,6 +163,7 @@ export default function (AB) { const parentObjID = parentObj.id; const objID = obj?.id || parentObjID; const $contentDisplayedFields = $$(ids.contentDisplayedFields); + const $contentDisplayedFieldTypes = $$(ids.contentDisplayedFieldTypes); const $contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ); @@ -182,6 +185,7 @@ export default function (AB) { } this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), + $contentDisplayedFieldTypes.getValues(), $contentDisplayedFieldFilters.getValues() ); this.onChange(); @@ -350,7 +354,11 @@ export default function (AB) { const contentObjFields = contentObj.fields(); $editContentFieldsToCreateNew.define( "options", - contentObjFields.map(fieldToOption) + // contentObjFields.map(fieldToOption) + contentObjFields.map((contentObjField) => ({ + id: contentObjField.id, + value: contentObjField.label, + })) ); contentFieldFilter.fieldsLoad(contentObjFields); $contentGroupByField.define("options", [ @@ -383,7 +391,7 @@ export default function (AB) { $editContentFieldsToCreateNew.setValue([]); $showGroupTitle.setValue(0); $contentGroupByField.setValue(""); - this.populateContentDisplayedFields({}); + this.populateContentDisplayedFields(); this.onChange(); }, }, @@ -488,9 +496,26 @@ export default function (AB) { hidden: true, elements: [], }, + { + id: ids.contentDisplayedFieldTypesSet, + hidden: true, + rows: [ + { + view: "label", + label: L( + "Set content active displays and displayed types" + ), + }, + { + id: ids.contentDisplayedFieldTypes, + view: "form", + elements: [], + }, + ], + }, { id: ids.contentDisplayedFieldFiltersSet, - hidden: false, + hidden: true, rows: [ { view: "label", @@ -784,6 +809,7 @@ export default function (AB) { ); this.populateContentDisplayedFields( values.contentDisplayedFields, + values.contentDisplayedFieldTypes, values.contentDisplayedFieldFilters ); this.populateDataPanelDCs(values.dataPanelDCs); @@ -867,7 +893,7 @@ export default function (AB) { ]); } - populateContentDisplayedFields(values = {}, filters = {}) { + populateContentDisplayedFields(values = {}, types = {}, filters = {}) { const self = this; const ids = this.ids; const $contentDisplayedFields = $$(ids.contentDisplayedFields); @@ -877,6 +903,16 @@ export default function (AB) { $contentDisplayedFields.removeView( contentDisplayedFieldsElements[key].getParentView().config.id ); + const $contentDisplayedFieldTypes = $$(ids.contentDisplayedFieldTypes); + const contentDisplayedFieldTypesElements = + $contentDisplayedFieldTypes.elements; + const $contentDisplayedFieldTypesSet = $$( + ids.contentDisplayedFieldTypesSet + ); + for (const key in contentDisplayedFieldTypesElements) + $contentDisplayedFieldTypes.removeView( + contentDisplayedFieldTypesElements[key].getParentView().config.id + ); const $contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ); @@ -890,6 +926,7 @@ export default function (AB) { contentDisplayedFieldFiltersElements[key].getParentView().config .id ); + $contentDisplayedFieldTypesSet.hide(); $contentDisplayedFieldFiltersSet.hide(); const keys = Object.keys(values); if (keys.length === 0) { @@ -904,50 +941,170 @@ export default function (AB) { $$(ids.contentDisplayedFieldsAdd).hide(); return; } + const typeKeys = Object.keys(types); const filterKeys = Object.keys(filters); const objID = obj.id; const parentKeys = []; const childKeys = []; const createOptionsView = (key, field) => { - const filterPrefix = `${key}.${field.id}`; - const filterValue = parseInt( + const optionPrefix = `${key}.${field.id}`; + const fieldLabel = field.label; + const typeKeyIndex = typeKeys.findIndex( + (typeKey) => typeKey.indexOf(optionPrefix) > -1 + ); + const typeKeyParts = + typeKeys + .find((typeKey) => typeKey.indexOf(optionPrefix) > -1) + ?.split(".") || []; + const typeSwitchValue = parseInt(typeKeyParts[3]); + const isTypeKeyIndexFound = typeKeyIndex > -1; + const typeSelectedValue = + (isTypeKeyIndexFound && typeKeyParts[4]) || "text"; + const typeOptions = [ + { id: "icon", value: "Icon" }, + { id: "image", value: "Image" }, + { id: "text", value: "Text" }, + ]; + $contentDisplayedFieldTypes.addView({ + cols: [ + { + view: "switch", + label: fieldLabel, + labelWidth: uiConfig.labelWidthMedium, + value: isNaN(typeSwitchValue) ? 1 : typeSwitchValue, + on: { + onChange: (newValue, oldValue) => { + const oldTypes = + $contentDisplayedFieldTypes.getValues(); + const oldTypeEntries = Object.entries(oldTypes); + const newTypes = {}; + const oldTypePrefix = `${optionPrefix}.${oldValue}`; + for (const [key, value] of oldTypeEntries) + if (key.indexOf(oldTypePrefix) > -1) + newTypes[`${optionPrefix}.${newValue}.${key.split(".")[4]}`] = ""; + else newTypes[key] = value; + this.populateContentDisplayedFields( + $contentDisplayedFields.getValues(), + newTypes, + $contentDisplayedFieldFilters.getValues() + ); + this.onChange(); + }, + onViewShow() { + const $parentView = this.getParentView(); + $parentView.addView({ + view: "richselect", + options: typeOptions, + value: typeSelectedValue, + on: { + onChange: (newValue, oldValue) => { + const currentTypeSwitchValue = this.getValue(); + const typePrefix = `${optionPrefix}.${currentTypeSwitchValue}`; + const key = `${typePrefix}.${newValue}`; + switch (newValue) { + case "image": + $parentView.addView({ + view: "textarea", + name: key, + placeholder: L("Image base 64 data."), + value: types[`${typePrefix}.${oldValue}`] ?? "", + on: { + onChange: () => { + self.onChange(); + }, + }, + }) + break; + default: + $parentView.addView({ + view: "text", + name: key, + placeholder: L("No data need to fill up."), + disabled: true, + value: "", + }); + break; + } + self.populateContentDisplayedFields( + $contentDisplayedFields.getValues(), + $contentDisplayedFieldTypes.getValues(), + $contentDisplayedFieldFilters.getValues() + ); + self.onChange(); + }, + }, + }); + const key = `${optionPrefix}.${this.getValue()}.${typeSelectedValue}`; + switch (typeSelectedValue) { + case "image": + $parentView.addView({ + view: "textarea", + name: key, + placeholder: L("Image base 64 data."), + value: types[key] ?? "", + on: { + onChange: () => { + self.onChange(); + }, + }, + }); + break; + default: + $parentView.addView({ + view: "text", + name: key, + placeholder: L("No data need to fill up."), + disabled: true, + value: "", + }); + break; + } + }, + }, + }, + ], + }); + const filterCheckboxValue = parseInt( filterKeys - .find((filterKey) => filterKey.indexOf(filterPrefix) > -1) + .find((filterKey) => filterKey.indexOf(optionPrefix) > -1) ?.split(".")[3] ); $contentDisplayedFieldFilters.addView({ cols: [ { view: "checkbox", - label: field.label, + label: fieldLabel, labelWidth: uiConfig.labelWidthMedium, - value: isNaN(filterValue) ? 0 : filterValue, + value: isNaN(filterCheckboxValue) + ? 0 + : filterCheckboxValue, on: { onChange: (newValue, oldValue) => { const oldFilters = $contentDisplayedFieldFilters.getValues(); const oldFilterEntries = Object.entries(oldFilters); const newFilters = {}; - const oldFilterKey = `${filterPrefix}.${oldValue}`; + const oldFilterKey = `${optionPrefix}.${oldValue}`; for (const [key, value] of oldFilterEntries) if (key === oldFilterKey) - newFilters[`${filterPrefix}.${newValue}`] = ""; + newFilters[`${optionPrefix}.${newValue}`] = ""; else newFilters[key] = value; this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), + $contentDisplayedFieldTypes.getValues(), newFilters ); this.onChange(); }, onViewShow() { - const checkboxValue = this.getValue(); - const filterKey = `${filterPrefix}.${checkboxValue}`; + const filterKey = `${optionPrefix}.${this.getValue()}`; this.getParentView().addView({ view: "text", placeholder: L("Add the new field label."), name: filterKey, value: filters[filterKey], - disabled: checkboxValue === 1 ? false : true, + disabled: + filterCheckboxValue === 1 ? false : true, on: { onChange: () => { self.onChange(); @@ -1013,6 +1170,7 @@ export default function (AB) { } } $contentDisplayedFields.show(); + $contentDisplayedFieldTypesSet.show(); $contentDisplayedFieldFiltersSet.show(); } @@ -1158,6 +1316,9 @@ export default function (AB) { settings.contentDisplayedFields = $$( ids.contentDisplayedFields ).getValues(); + settings.contentDisplayedFieldTypes = $$( + ids.contentDisplayedFieldTypes + ).getValues(); settings.contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ).getValues(); From c3196de1d2f3e706c286fd87857054920fb19d5a Mon Sep 17 00:00:00 2001 From: guyyoo Date: Mon, 25 Nov 2024 13:19:17 +0700 Subject: [PATCH 21/32] Fix filter default labels --- .../properties/views/ABViewOrgChartTeams.js | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 278c65ee..c39817de 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -980,8 +980,12 @@ export default function (AB) { const newTypes = {}; const oldTypePrefix = `${optionPrefix}.${oldValue}`; for (const [key, value] of oldTypeEntries) - if (key.indexOf(oldTypePrefix) > -1) - newTypes[`${optionPrefix}.${newValue}.${key.split(".")[4]}`] = ""; + if (key.indexOf(oldTypePrefix) > -1) + newTypes[ + `${optionPrefix}.${newValue}.${ + key.split(".")[4] + }` + ] = ""; else newTypes[key] = value; this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), @@ -998,7 +1002,8 @@ export default function (AB) { value: typeSelectedValue, on: { onChange: (newValue, oldValue) => { - const currentTypeSwitchValue = this.getValue(); + const currentTypeSwitchValue = + this.getValue(); const typePrefix = `${optionPrefix}.${currentTypeSwitchValue}`; const key = `${typePrefix}.${newValue}`; switch (newValue) { @@ -1006,20 +1011,27 @@ export default function (AB) { $parentView.addView({ view: "textarea", name: key, - placeholder: L("Image base 64 data."), - value: types[`${typePrefix}.${oldValue}`] ?? "", + placeholder: L( + "Image base 64 data." + ), + value: + types[ + `${typePrefix}.${oldValue}` + ] ?? "", on: { onChange: () => { self.onChange(); }, }, - }) + }); break; default: $parentView.addView({ view: "text", name: key, - placeholder: L("No data need to fill up."), + placeholder: L( + "No data need to fill up." + ), disabled: true, value: "", }); @@ -1097,14 +1109,17 @@ export default function (AB) { this.onChange(); }, onViewShow() { - const filterKey = `${optionPrefix}.${this.getValue()}`; + const currentFilterCheckboxValue = this.getValue(); + const filterKey = `${optionPrefix}.${currentFilterCheckboxValue}`; this.getParentView().addView({ view: "text", placeholder: L("Add the new field label."), name: filterKey, - value: filters[filterKey], + value: filters[filterKey] || fieldLabel, disabled: - filterCheckboxValue === 1 ? false : true, + currentFilterCheckboxValue === 1 + ? false + : true, on: { onChange: () => { self.onChange(); From d368a4a5ef128e234073cb0b059529fb8e987fd1 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 26 Nov 2024 18:08:16 +0700 Subject: [PATCH 22/32] Fix content mapping data and type --- .../properties/views/ABViewOrgChartTeams.js | 244 ++++++++++++------ 1 file changed, 169 insertions(+), 75 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index c39817de..12a5c807 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -47,6 +47,8 @@ export default function (AB) { contentDisplayedFieldFiltersSet: "", contentDisplayedFieldTypes: "", contentDisplayedFieldTypesSet: "", + contentDisplayedFieldMappingData: "", + contentDisplayedFieldMappingDataSet: "", showDataPanel: "", dataPanelDCs: "", dataPanelDCsAdd: "", @@ -164,6 +166,9 @@ export default function (AB) { const objID = obj?.id || parentObjID; const $contentDisplayedFields = $$(ids.contentDisplayedFields); const $contentDisplayedFieldTypes = $$(ids.contentDisplayedFieldTypes); + const $contentDisplayedFieldMappingData = $$( + ids.contentDisplayedFieldMappingData + ); const $contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ); @@ -186,6 +191,7 @@ export default function (AB) { this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), $contentDisplayedFieldTypes.getValues(), + $contentDisplayedFieldMappingData.getValues(), $contentDisplayedFieldFilters.getValues() ); this.onChange(); @@ -513,6 +519,21 @@ export default function (AB) { }, ], }, + { + id: ids.contentDisplayedFieldMappingDataSet, + hidden: true, + rows: [ + { + view: "label", + label: L("Set content mapping displayed data"), + }, + { + id: ids.contentDisplayedFieldMappingData, + view: "form", + elements: [], + }, + ], + }, { id: ids.contentDisplayedFieldFiltersSet, hidden: true, @@ -810,6 +831,7 @@ export default function (AB) { this.populateContentDisplayedFields( values.contentDisplayedFields, values.contentDisplayedFieldTypes, + values.contentDisplayedFieldMappingData, values.contentDisplayedFieldFilters ); this.populateDataPanelDCs(values.dataPanelDCs); @@ -865,6 +887,7 @@ export default function (AB) { } populateTeamFieldOptions(object) { + const webix = this.AB.Webix; const view = this.CurrentView; const ids = this.ids; const m2oFields = view.getValueFields(object).map(fieldToOption); @@ -893,8 +916,14 @@ export default function (AB) { ]); } - populateContentDisplayedFields(values = {}, types = {}, filters = {}) { + populateContentDisplayedFields( + values = {}, + types = {}, + mappingDataValues = {}, + filters = {} + ) { const self = this; + const webix = this.AB.Webix; const ids = this.ids; const $contentDisplayedFields = $$(ids.contentDisplayedFields); const contentDisplayedFieldsElements = @@ -913,9 +942,22 @@ export default function (AB) { $contentDisplayedFieldTypes.removeView( contentDisplayedFieldTypesElements[key].getParentView().config.id ); + const $contentDisplayedFieldMappingData = $$( + ids.contentDisplayedFieldMappingData + ); + const contentDisplayedFieldMappingDataElements = + $contentDisplayedFieldMappingData.elements; + const $contentDisplayedFieldMappingDataSet = $$( + ids.contentDisplayedFieldMappingDataSet + ); const $contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ); + for (const key in contentDisplayedFieldMappingDataElements) + $contentDisplayedFieldMappingData.removeView( + contentDisplayedFieldMappingDataElements[key].getParentView() + .config.id + ); const contentDisplayedFieldFiltersElements = $contentDisplayedFieldFilters.elements; const $contentDisplayedFieldFiltersSet = $$( @@ -927,6 +969,7 @@ export default function (AB) { .id ); $contentDisplayedFieldTypesSet.hide(); + $contentDisplayedFieldMappingDataSet.hide(); $contentDisplayedFieldFiltersSet.hide(); const keys = Object.keys(values); if (keys.length === 0) { @@ -960,11 +1003,6 @@ export default function (AB) { const isTypeKeyIndexFound = typeKeyIndex > -1; const typeSelectedValue = (isTypeKeyIndexFound && typeKeyParts[4]) || "text"; - const typeOptions = [ - { id: "icon", value: "Icon" }, - { id: "image", value: "Image" }, - { id: "text", value: "Text" }, - ]; $contentDisplayedFieldTypes.addView({ cols: [ { @@ -990,92 +1028,143 @@ export default function (AB) { this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), newTypes, + $contentDisplayedFieldMappingData.getValues(), $contentDisplayedFieldFilters.getValues() ); this.onChange(); }, onViewShow() { - const $parentView = this.getParentView(); - $parentView.addView({ + this.getParentView().addView({ view: "richselect", - options: typeOptions, + options: [ + { id: "icon", value: "Icon" }, + { id: "image", value: "Image" }, + { id: "text", value: "Text" }, + ], + name: `${optionPrefix}.${this.getValue()}`, value: typeSelectedValue, on: { - onChange: (newValue, oldValue) => { - const currentTypeSwitchValue = - this.getValue(); - const typePrefix = `${optionPrefix}.${currentTypeSwitchValue}`; - const key = `${typePrefix}.${newValue}`; - switch (newValue) { - case "image": - $parentView.addView({ - view: "textarea", - name: key, - placeholder: L( - "Image base 64 data." - ), - value: - types[ - `${typePrefix}.${oldValue}` - ] ?? "", - on: { - onChange: () => { - self.onChange(); - }, - }, - }); - break; - default: - $parentView.addView({ - view: "text", - name: key, - placeholder: L( - "No data need to fill up." - ), - disabled: true, - value: "", - }); - break; - } - self.populateContentDisplayedFields( - $contentDisplayedFields.getValues(), - $contentDisplayedFieldTypes.getValues(), - $contentDisplayedFieldFilters.getValues() - ); + onChange: () => { self.onChange(); }, }, }); - const key = `${optionPrefix}.${this.getValue()}.${typeSelectedValue}`; - switch (typeSelectedValue) { - case "image": - $parentView.addView({ - view: "textarea", - name: key, - placeholder: L("Image base 64 data."), - value: types[key] ?? "", - on: { - onChange: () => { - self.onChange(); - }, - }, - }); - break; - default: - $parentView.addView({ - view: "text", - name: key, - placeholder: L("No data need to fill up."), - disabled: true, - value: "", - }); - break; - } }, }, }, ], }); + const mappingDataValue = mappingDataValues[optionPrefix]; + $contentDisplayedFieldMappingData.addView({ + cols: [ + { + view: "label", + label: fieldLabel, + width: uiConfig.labelWidthMedium, + }, + { + view: "button", + label: "Set", + width: uiConfig.buttonWidthExtraSmall, + click: () => { + const getValueViewUI = (key = "", value = "") => ({ + cols: [ + { view: "text", value: key }, + { + view: "label", + label: L("to"), + align: "center", + width: uiConfig.labelWidthSmall, + }, + { view: "text", value }, + { + view: "button", + css: "webix_danger", + type: "icon", + icon: "wxi-close", + width: uiConfig.buttonWidthExtraSmall, + click() { + const $childView = this.getParentView(); + $childView + .getParentView() + .removeView($childView.config.id); + }, + }, + ], + }); + const $popup = webix.ui({ + view: "window", + close: true, + title: L("Map Data"), + position: "center", + body: { + view: "form", + elements: [ + { + view: "button", + label: L("Add a value"), + click() { + this.getParentView() + .getChildViews()[1] + .addView(getValueViewUI()); + }, + }, + { + rows: [], + }, + { + view: "button", + label: L("Apply"), + click() { + const $valueView = + this.getParentView().getChildViews()[1]; + const mapingValues = {}; + const valueChildViews = + $valueView.getChildViews(); + for (const $valueChildView of valueChildViews) { + const valueChildViewElements = + $valueChildView.getChildViews(); + mapingValues[ + valueChildViewElements[0].getValue() + ] = + valueChildViewElements[2].getValue(); + } + $contentDisplayedFieldMappingData.elements[ + optionPrefix + ]?.setValue(JSON.stringify(mapingValues)); + $popup.hide(); + self.onChange(); + }, + }, + ], + }, + on: { + onHide() { + this.destructor(); + }, + }, + }); + try { + const $valueView = $popup + .getChildViews()[1] + .getChildViews()[1]; + const mappingDataObj = JSON.parse( + mappingDataValue + ); + for (const key in mappingDataObj) + $valueView.addView(getValueViewUI(key, mappingDataObj[key])); + } catch {} + $popup.show(); + }, + }, + { + view: "text", + name: optionPrefix, + disabled: true, + value: mappingDataValue || {}, + }, + ], + }); const filterCheckboxValue = parseInt( filterKeys .find((filterKey) => filterKey.indexOf(optionPrefix) > -1) @@ -1104,6 +1193,7 @@ export default function (AB) { this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), $contentDisplayedFieldTypes.getValues(), + $contentDisplayedFieldMappingData.getValues(), newFilters ); this.onChange(); @@ -1186,6 +1276,7 @@ export default function (AB) { } $contentDisplayedFields.show(); $contentDisplayedFieldTypesSet.show(); + $contentDisplayedFieldMappingDataSet.show(); $contentDisplayedFieldFiltersSet.show(); } @@ -1334,6 +1425,9 @@ export default function (AB) { settings.contentDisplayedFieldTypes = $$( ids.contentDisplayedFieldTypes ).getValues(); + settings.contentDisplayedFieldMappingData = $$( + ids.contentDisplayedFieldMappingData + ).getValues(); settings.contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ).getValues(); From 2944973c20e1ba57e80b3ca584ee543425a35880 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 26 Nov 2024 18:47:56 +0700 Subject: [PATCH 23/32] Fix the populating mapping field bug --- src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 12a5c807..236a1802 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1161,7 +1161,7 @@ export default function (AB) { view: "text", name: optionPrefix, disabled: true, - value: mappingDataValue || {}, + value: mappingDataValue || JSON.stringify({}), }, ], }); From a33a40ff6b34df82bf948248443b39a6ab510aef Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 26 Nov 2024 19:29:25 +0700 Subject: [PATCH 24/32] Fix getting the wrong key bug --- src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 236a1802..39c17432 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1269,7 +1269,7 @@ export default function (AB) { case "user": break; default: - createOptionsView(parentKey, childField); + createOptionsView(childKey, childField); continue; } } From 0803c337524b8743cf780f9e0bd505cd1d2ab510 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Tue, 26 Nov 2024 16:38:08 +0700 Subject: [PATCH 25/32] add entity dc setting --- .../properties/views/ABViewOrgChartTeams.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 45a2c4d5..25f71959 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -28,7 +28,6 @@ export default function (AB) { depth: "", draggable: "", dropContentToCreate: "", - color: "", pan: "", zoom: "", height: "", @@ -48,6 +47,7 @@ export default function (AB) { dataPanelDCsAdd: "", strategyColorPopup: "", strategyColorForm: "", + entityDatacollection: "", }); this.AB = AB; const contentFieldFilter = (this.contentFieldFilter = @@ -595,6 +595,17 @@ export default function (AB) { ], on: { onChange: () => this.onChange() }, }, + { + id: ids.entityDatacollection, + name: "entityDatacollection", + view: "richselect", + label: L("Entity"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { + onChange: () => this.onChange(), + }, + }, { id: ids.depth, name: "depth", @@ -605,14 +616,6 @@ export default function (AB) { value: 0, on: { onChange: () => this.onChange() }, }, - { - id: ids.color, - name: "color", - view: "colorpicker", - label: L("Color"), - labelWidth: uiConfig.labelWidthLarge, - on: { onChange: () => this.onChange() }, - }, { hidden: true, // NOTE: does not support id: ids.pan, @@ -773,6 +776,8 @@ export default function (AB) { $dataCollection.define("options", dcOptions); $dataCollection.define("value", datacollectionId); $dataCollection.refresh(); + $$(this.ids.entityDatacollection).define("options", dcOptions); + $$(this.ids.entityDatacollection).refresh(); } refreshValueFieldOptions(fieldValues = []) { From 4b20439a526900a48b5189a3ef784ca0c11a30a6 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Wed, 27 Nov 2024 16:03:26 +0700 Subject: [PATCH 26/32] Add the SVG field type and placeholder --- .../properties/views/ABViewOrgChartTeams.js | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index bfa2dda4..b53e34d4 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1044,6 +1044,7 @@ export default function (AB) { options: [ { id: "icon", value: "Icon" }, { id: "image", value: "Image" }, + { id: "svg", value: "SVG" }, { id: "text", value: "Text" }, ], name: `${optionPrefix}.${this.getValue()}`, @@ -1074,14 +1075,34 @@ export default function (AB) { click: () => { const getValueViewUI = (key = "", value = "") => ({ cols: [ - { view: "text", value: key }, + { + view: "text", + placeholder: L("The value need to map."), + value: key, + }, { view: "label", label: L("to"), align: "center", width: uiConfig.labelWidthSmall, }, - { view: "text", value }, + { + view: "text", + placeholder: (() => { + switch (value) { + case "icon": + return L("Icon class text."); + case "image": + case "svg": + return L( + "Base64 image url (ex. data:image/png;base64,AAABBBCCC)." + ); + default: + return L("New text."); + } + })(), + value, + }, { view: "button", css: "webix_danger", @@ -1136,7 +1157,9 @@ export default function (AB) { } $contentDisplayedFieldMappingData.elements[ optionPrefix - ]?.setValue(JSON.stringify(mapingValues)); + ]?.setValue( + JSON.stringify(mapingValues) + ); $popup.hide(); self.onChange(); }, @@ -1153,11 +1176,11 @@ export default function (AB) { const $valueView = $popup .getChildViews()[1] .getChildViews()[1]; - const mappingDataObj = JSON.parse( - mappingDataValue - ); + const mappingDataObj = JSON.parse(mappingDataValue); for (const key in mappingDataObj) - $valueView.addView(getValueViewUI(key, mappingDataObj[key])); + $valueView.addView( + getValueViewUI(key, mappingDataObj[key]) + ); } catch {} $popup.show(); }, From c0b3a431977f4cf9f7e05cdcae7524aec348a767 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Wed, 27 Nov 2024 16:24:03 +0700 Subject: [PATCH 27/32] Fix setting type bug --- .../properties/views/ABViewOrgChartTeams.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index b53e34d4..b54e42cf 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1000,14 +1000,11 @@ export default function (AB) { const typeKeyIndex = typeKeys.findIndex( (typeKey) => typeKey.indexOf(optionPrefix) > -1 ); - const typeKeyParts = + const typeSwitchValue = parseInt( typeKeys .find((typeKey) => typeKey.indexOf(optionPrefix) > -1) - ?.split(".") || []; - const typeSwitchValue = parseInt(typeKeyParts[3]); - const isTypeKeyIndexFound = typeKeyIndex > -1; - const typeSelectedValue = - (isTypeKeyIndexFound && typeKeyParts[4]) || "text"; + ?.split(".")[3] + ); $contentDisplayedFieldTypes.addView({ cols: [ { @@ -1025,10 +1022,8 @@ export default function (AB) { for (const [key, value] of oldTypeEntries) if (key.indexOf(oldTypePrefix) > -1) newTypes[ - `${optionPrefix}.${newValue}.${ - key.split(".")[4] - }` - ] = ""; + `${optionPrefix}.${newValue}` + ] = value; else newTypes[key] = value; this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), @@ -1048,7 +1043,10 @@ export default function (AB) { { id: "text", value: "Text" }, ], name: `${optionPrefix}.${this.getValue()}`, - value: typeSelectedValue, + value: + (typeKeyIndex > -1 && + types[typeKeys[typeKeyIndex]]) || + "text", on: { onChange: () => { self.onChange(); From 6c8a50122b2533fcfcae4ce0ea32d4f1735fb22d Mon Sep 17 00:00:00 2001 From: guyyoo Date: Thu, 28 Nov 2024 10:13:33 +0700 Subject: [PATCH 28/32] Fix placeholder text --- .../Designer/properties/views/ABViewOrgChartTeams.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index b54e42cf..5583f564 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1021,9 +1021,8 @@ export default function (AB) { const oldTypePrefix = `${optionPrefix}.${oldValue}`; for (const [key, value] of oldTypeEntries) if (key.indexOf(oldTypePrefix) > -1) - newTypes[ - `${optionPrefix}.${newValue}` - ] = value; + newTypes[`${optionPrefix}.${newValue}`] = + value; else newTypes[key] = value; this.populateContentDisplayedFields( $contentDisplayedFields.getValues(), @@ -1093,7 +1092,7 @@ export default function (AB) { case "image": case "svg": return L( - "Base64 image url (ex. data:image/png;base64,AAABBBCCC)." + "Image url or Base64 (ex. data:image/png;base64,AAABBBCCC) url." ); default: return L("New text."); From 2c17a59a1a771d177b43e49c6e21d34fe3f1d66a Mon Sep 17 00:00:00 2001 From: guyyoo Date: Tue, 3 Dec 2024 09:57:10 +0700 Subject: [PATCH 29/32] Add start date and end date fields --- .../properties/views/ABViewOrgChartTeams.js | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 5583f564..03974264 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -38,6 +38,8 @@ export default function (AB) { editContentFieldsToCreateNew: "", contentField: "", contentFieldFilter: "", + contentFieldDateStart: "", + contentFieldDateEnd: "", contentFieldFilterButton: "", contentGroupByField: "", contentDisplayedFields: "", @@ -346,6 +348,12 @@ export default function (AB) { const $contentGroupByField = $$( ids.contentGroupByField ); + const $contentFieldDateStart = $$( + ids.contentFieldDateStart + ); + const $contentFieldDateEnd = $$( + ids.contentFieldDateEnd + ); const $showGroupTitle = $$(ids.showGroupTitle); contentFieldFilter.init(); contentFieldFilter.setValue({ @@ -358,6 +366,19 @@ export default function (AB) { newValue ).datasourceLink; const contentObjFields = contentObj.fields(); + const contentDateFiels = contentObjFields.filter( + (field) => + field.key === "date" || + field.key === "datetime" + ); + $contentFieldDateStart.define( + "options", + contentDateFiels.map(fieldToOption) + ); + $contentFieldDateEnd.define( + "options", + contentDateFiels.map(fieldToOption) + ); $editContentFieldsToCreateNew.define( "options", // contentObjFields.map(fieldToOption) @@ -379,6 +400,8 @@ export default function (AB) { $editContentFieldsToCreateNew.enable(); $contentFieldFilterButton.enable(); $contentDisplayedFieldsAdd.show(); + $contentFieldDateStart.show(); + $contentFieldDateEnd.show(); $contentGroupByField.show(); $showGroupTitle.show(); } else { @@ -391,6 +414,8 @@ export default function (AB) { $editContentFieldsToCreateNew.enable(); $contentFieldFilterButton.disable(); $contentDisplayedFieldsAdd.hide(); + $contentFieldDateStart.hide(); + $contentFieldDateEnd.hide(); $contentGroupByField.hide(); $showGroupTitle.hide(); } @@ -418,6 +443,32 @@ export default function (AB) { }, ], }, + { + id: ids.contentFieldDateStart, + name: "contentFieldDateStart", + label: L("Date Start"), + labelWidth: uiConfig.labelWidthLarge, + view: "richselect", + options: [], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.contentFieldDateEnd, + name: "contentFieldDateEnd", + label: L("Date End"), + labelWidth: uiConfig.labelWidthLarge, + view: "richselect", + options: [], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, { id: ids.contentGroupByField, hidden: true, @@ -892,7 +943,6 @@ export default function (AB) { } populateTeamFieldOptions(object) { - const webix = this.AB.Webix; const view = this.CurrentView; const ids = this.ids; const m2oFields = view.getValueFields(object).map(fieldToOption); @@ -1456,6 +1506,10 @@ export default function (AB) { settings.contentDisplayedFieldFilters = $$( ids.contentDisplayedFieldFilters ).getValues(); + settings.contentFieldDateStart = $$( + ids.contentFieldDateStart + ).getValue(); + settings.contentFieldDateEnd = $$(ids.contentFieldDateEnd).getValue(); settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); const $colorForm = $$(ids.strategyColorForm); settings.strategyColors = $colorForm?.getValues() ?? {}; From d4986dfc9bc27d481fe401817a6037029029fde8 Mon Sep 17 00:00:00 2001 From: guyyoo Date: Fri, 6 Dec 2024 15:09:53 +0700 Subject: [PATCH 30/32] Limit edit form's fields --- .../properties/views/ABViewOrgChartTeams.js | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index 03974264..bb8c27b8 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -36,6 +36,7 @@ export default function (AB) { groupByField: "", showGroupTitle: "", editContentFieldsToCreateNew: "", + setEditableContentFields: "", contentField: "", contentFieldFilter: "", contentFieldDateStart: "", @@ -339,6 +340,9 @@ export default function (AB) { const $editContentFieldsToCreateNew = $$( ids.editContentFieldsToCreateNew ); + const $setEditableContentFields = $$( + ids.setEditableContentFields + ); const $contentDisplayedFieldsAdd = $$( ids.contentDisplayedFieldsAdd ); @@ -379,13 +383,19 @@ export default function (AB) { "options", contentDateFiels.map(fieldToOption) ); - $editContentFieldsToCreateNew.define( - "options", - // contentObjFields.map(fieldToOption) + const contentObjMappedFields = + // contentObjFields.map(fieldToOption) *** (Guy) this makes my chrome browser crash (Only multi-selection) it is because { field: f } *** contentObjFields.map((contentObjField) => ({ id: contentObjField.id, value: contentObjField.label, - })) + })); + $editContentFieldsToCreateNew.define( + "options", + contentObjMappedFields + ); + $setEditableContentFields.define( + "options", + contentObjMappedFields ); contentFieldFilter.fieldsLoad(contentObjFields); $contentGroupByField.define("options", [ @@ -500,7 +510,9 @@ export default function (AB) { rows: [ { view: "label", - label: L("Create new by editing content fields"), + label: L( + "Force the creation of a new row of data by editing the content fields" + ), }, { id: ids.editContentFieldsToCreateNew, @@ -508,12 +520,30 @@ export default function (AB) { value: [], options: [], placeholder: L( - "Choose content fields to create new by editing" + "Choose the content fields to create a new entry through editing" ), labelAlign: "left", stringResult: false /* returns data as an array of [id] */, on: { - onChange: (newValue) => { + onChange: () => { + this.onChange(); + }, + }, + }, + { + view: "label", + label: L("Set the editable content fields"), + }, + { + id: ids.setEditableContentFields, + view: "multicombo", + value: [], + options: [], + placeholder: L("Choose the editable content fields"), + labelAlign: "left", + stringResult: false /* returns data as an array of [id] */, + on: { + onChange: () => { this.onChange(); }, }, @@ -876,6 +906,7 @@ export default function (AB) { "contentField", "contentGroupByField", "editContentFieldsToCreateNew", + "setEditableContentFields", "showGroupTitle", "showDataPanel", ].forEach((f) => $$(ids[f]).setValue(values[f])); @@ -1491,6 +1522,9 @@ export default function (AB) { settings.editContentFieldsToCreateNew = $$( ids.editContentFieldsToCreateNew ).getValue(); + settings.setEditableContentFields = $$( + ids.setEditableContentFields + ).getValue(); settings.contentFieldFilter = JSON.stringify( this.contentFieldFilter.getValue() ); From 932bc5a2c22049c7fb8f593554a457c04b537e4e Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Mon, 9 Dec 2024 09:19:57 +0700 Subject: [PATCH 31/32] add substrategy field setting --- .../Designer/properties/views/ABViewOrgChartTeams.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index bb8c27b8..de317bd0 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -17,6 +17,7 @@ export default function (AB) { super(BASE_ID, { datacollectionID: "", strategyCode: "", + subStrategy: "", teamInactive: "", teamCanInactivate: "", teamLink: "", @@ -711,6 +712,14 @@ export default function (AB) { }, ], }, + { + id: ids.subStrategy, + view: "richselect", + label: L("Sub Strategy"), + labelWidth: uiConfig.labelWidthLarge, + options: [], + on: { onChange: () => this.onChange() }, + }, { id: ids.draggable, name: "draggable", @@ -923,6 +932,7 @@ export default function (AB) { if (values.teamStrategy) { this.populateStrategyOptions(values.teamStrategy); $$(ids.strategyCode).setValue(values.strategyCode); + $$(ids.subStrategy).setValue(values.subStrategy); } } $component.setValues(values); @@ -1418,6 +1428,7 @@ export default function (AB) { .fields((f) => f.key === "connectObject") .map(fieldToOption); $$(this.ids.strategyCode).define("options", listFields); + $$(this.ids.subStrategy).define("options", listFields); } async strategyColorPopup() { @@ -1515,6 +1526,7 @@ export default function (AB) { settings.teamInactive = $$(ids.teamInactive).getValue(); settings.teamCanInactivate = $$(ids.teamCanInactivate).getValue(); settings.teamStrategy = $$(ids.teamStrategy).getValue(); + settings.subStrategy = $$(ids.subStrategy).getValue(); settings.strategyCode = $$(ids.strategyCode).getValue(); settings.dataCollectionId = $$(ids.datacollectionID).getValue(); settings.contentField = $$(ids.contentField).getValue(); From 53daa8def958ef331150fbd388c4b5e89d4ecaa8 Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Fri, 3 Jan 2025 15:02:07 +0700 Subject: [PATCH 32/32] Fix save colors and allow custom colors --- .../Designer/properties/views/ABViewOrgChartTeams.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js index de317bd0..e2f1acbe 100644 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js @@ -1448,6 +1448,12 @@ export default function (AB) { label: strategy.name, name: strategy.id, value: values[strategy.id] ?? "#111111", + suggest: { + type: "colorselect", + body: { + button: true, + }, + }, }; }); @@ -1558,7 +1564,8 @@ export default function (AB) { settings.contentFieldDateEnd = $$(ids.contentFieldDateEnd).getValue(); settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); const $colorForm = $$(ids.strategyColorForm); - settings.strategyColors = $colorForm?.getValues() ?? {}; + settings.strategyColors = + $colorForm?.getValues() ?? settings.strategyColors; return values; }