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/16] 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/16] 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/16] 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/16] 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/16] [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/16] 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/16] 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/16] [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/16] 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/16] [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/16] 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/16] [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/16] [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/16] 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 e134f7aa039d1d94fa8e67b5214b37817a8e0943 Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 20 Nov 2024 14:04:15 +0700 Subject: [PATCH 15/16] [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 a35f9c7904c7d13b1c201c27d309b6bd47dc528a Mon Sep 17 00:00:00 2001 From: nh758 <7259@pm.me> Date: Wed, 19 Feb 2025 13:59:57 +0700 Subject: [PATCH 16/16] remove orgchart view (moved to plugin) --- .../Designer/editors/EditorManager.js | 6 +- .../Designer/editors/views/ABViewOrgChart.js | 53 - .../editors/views/ABViewOrgChartTeams.js | 53 - .../Designer/properties/PropertyManager.js | 12 +- .../properties/views/ABViewOrgChart.js | 359 ------ .../properties/views/ABViewOrgChartTeams.js | 1051 ----------------- 6 files changed, 7 insertions(+), 1527 deletions(-) delete mode 100644 src/rootPages/Designer/editors/views/ABViewOrgChart.js delete mode 100644 src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js delete mode 100644 src/rootPages/Designer/properties/views/ABViewOrgChart.js delete 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 123d8856..9b6c1f57 100644 --- a/src/rootPages/Designer/editors/EditorManager.js +++ b/src/rootPages/Designer/editors/EditorManager.js @@ -6,7 +6,7 @@ */ import _ABViewDefault from "./views/_ABViewDefault"; -export default function (AB) { +export default function(AB) { const Editors = []; // {array} // All the ABField Component Inerfaces available. @@ -34,8 +34,6 @@ export default function (AB) { require("./views/ABViewLabel"), require("./views/ABViewLayout"), require("./views/ABViewMenu"), - require("./views/ABViewOrgChart"), - require("./views/ABViewOrgChartTeams"), require("./views/ABViewPage"), require("./views/ABViewPDFImporter"), require("./views/ABViewPivot"), @@ -60,7 +58,7 @@ export default function (AB) { * A filter for limiting which editor you want. * @return [{ClassUI(Editor1)}, {ClassUI(Editor2)}, ...] */ - editors: function (f = () => true) { + editors: function(f = () => true) { return Editors.filter(f); }, }; diff --git a/src/rootPages/Designer/editors/views/ABViewOrgChart.js b/src/rootPages/Designer/editors/views/ABViewOrgChart.js deleted file mode 100644 index 8ffb0774..00000000 --- a/src/rootPages/Designer/editors/views/ABViewOrgChart.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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 ABViewOrgChartEditor extends ABViewDefault { - static get key() { - return "orgchart"; - } - - constructor(view, base = "interface_editor_viewOrgChart") { - // 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/editors/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js deleted file mode 100644 index 5a568fb4..00000000 --- a/src/rootPages/Designer/editors/views/ABViewOrgChartTeams.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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 d46513a2..296684c9 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -8,7 +8,7 @@ import ABView from "./views/ABView"; var PropertyMgr = null; -export default function (AB) { +export default function(AB) { if (!PropertyMgr) { var Fields = []; // {array} @@ -110,8 +110,6 @@ export default function (AB) { require("./views/ABViewLayout"), require("./views/ABViewList"), require("./views/ABViewMenu"), - require("./views/ABViewOrgChart"), - require("./views/ABViewOrgChartTeams"), require("./views/ABViewPage"), require("./views/ABViewPDFImporter"), require("./views/ABViewPivot"), @@ -162,19 +160,19 @@ export default function (AB) { * A filter for limiting which fields you want. * @return [{ClassUI(Field1)}, {ClassUI(Field2)}, ...] */ - fields: function (f = () => true) { + fields: function(f = () => true) { return Fields.filter(f); }, - processElements: function (f = () => true) { + processElements: function(f = () => true) { return Processes.filter(f); }, - views: function (v = () => true) { + views: function(v = () => true) { return Views.filter(v); }, - mobileViews: function (v = () => true) { + mobileViews: function(v = () => true) { return MobileViews.filter(v); }, }; diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChart.js b/src/rootPages/Designer/properties/views/ABViewOrgChart.js deleted file mode 100644 index 5146e430..00000000 --- a/src/rootPages/Designer/properties/views/ABViewOrgChart.js +++ /dev/null @@ -1,359 +0,0 @@ -/* - * ABViewChart - * A Property manager for our ABViewChart definitions - */ - -import FABView from "./ABView"; - -export default function (AB) { - const BASE_ID = "properties_abview_org_chart"; - - const ABView = FABView(AB); - const uiConfig = AB.Config.uiSettings(); - const L = ABView.L(); - - class ABViewOrgChartProperty extends ABView { - constructor() { - super(BASE_ID, { - datacollectionID: "", - fields: "", - direction: "", - depth: "", - color: "", - pan: "", - zoom: "", - height: "", - export: "", - exportFilename: "", - }); - - this.AB = AB; - } - - static get key() { - return "orgchart"; - } - - 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 ABViewOrgChartProperty; -} diff --git a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js b/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js deleted file mode 100644 index b06b6ac1..00000000 --- a/src/rootPages/Designer/properties/views/ABViewOrgChartTeams.js +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * 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: "", - strategyCode: "", - teamInactive: "", - teamCanInactivate: "", - teamLink: "", - teamName: "", - teamStrategy: "", - topTeam: "", - fields: "", - direction: "", - depth: "", - draggable: "", - dropContentToCreate: "", - color: "", - pan: "", - zoom: "", - height: "", - export: "", - exportFilename: "", - groupByField: "", - showGroupTitle: "", - contentField: "", - contentFieldFilter: "", - contentFieldFilterButton: "", - contentGroupByField: "", - contentDisplayedFields: "", - contentDisplayedFieldsAdd: "", - showDataPanel: "", - dataPanelDCs: "", - dataPanelDCsAdd: "", - strategyColorPopup: "", - strategyColorForm: "", - }); - 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"; - } - - _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(), - ).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; - return super.ui([ - { - id: ids.datacollectionID, - name: "datacollectionID", - view: "richselect", - label: L("Team Data"), - labelWidth: uiConfig.labelWidthLarge, - options: [], - on: { - onChange: (value) => { - this.CurrentView.settings.datacollectionID = value; - const obj = this.CurrentView?.datacollection?.datasource; - this.populateTeamFieldOptions(obj); - 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.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: [ - { - 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, - ); - const $showGroupTitle = $$(ids.showGroupTitle); - 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(); - $showGroupTitle.show(); - } else { - contentFieldFilter.fieldsLoad([]); - $contentGroupByField.define("options", []); - $contentFieldFilterButton.disable(); - $contentDisplayedFieldsAdd.hide(); - $contentGroupByField.hide(); - $showGroupTitle.hide(); - } - $showGroupTitle.setValue(0); - $contentGroupByField.setValue(""); - 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.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, - 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(); - $contentDisplayedFields.addView( - this._uiContentDisplayedField(), - ); - }, - }, - ], - }, - { - id: ids.contentDisplayedFields, - view: "form", - 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", - 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", - view: "checkbox", - 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: "dropContentToCreate", - view: "checkbox", - label: L("Drop content to create"), - labelWidth: uiConfig.labelWidthLarge, - hidden: true, - value: 0, - on: { onChange: () => 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); - 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(), - ); - } - - deleteDataPanelDC(id) { - const $dataPanelDCs = $$(this.ids.dataPanelDCs); - $dataPanelDCs.removeView(id); - this.populateDataPanelDCs($dataPanelDCs.getValues()); - } - - 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); - const teamObj = this.CurrentView?.datacollection?.datasource; - if (teamObj) { - this.populateTeamFieldOptions(teamObj); - [ - "teamCanInactivate", - "teamInactive", - "teamLink", - "teamName", - "teamStrategy", - "topTeam", - "contentField", - "contentGroupByField", - "showGroupTitle", - "showDataPanel", - ].forEach((f) => $$(ids[f]).setValue(values[f])); - this.contentFieldFilter.setValue( - JSON.parse(values.contentFieldFilter), - ); - this.populateContentDisplayedFields(values.contentDisplayedFields); - this.populateDataPanelDCs(values.dataPanelDCs); - if (values.teamStrategy) { - this.populateStrategyOptions(values.teamStrategy); - $$(ids.strategyCode).setValue(values.strategyCode); - } - } - $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(); - } - - 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 = - object.connectFields( - (f) => f.linkType() == "one" && f.linkViaType() == "many", - ) ?? []; - $$(ids.teamStrategy).define("options", o2mFields.map(fieldToOption)); - $$(ids.teamLink).define("options", m2oFields); - const textFields = object - ?.fields((f) => f.key === "string") - .map(fieldToOption); - $$(ids.teamName).define("options", textFields); - const booleanFields = object - ?.fields((f) => f.key === "boolean") - .map(fieldToOption); - - // 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 }, - ...m2oFields, - ]); - } - - 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); - const obj = this.CurrentView.datacollection.datasource.fieldByID( - $$(ids.contentField).getValue(), - )?.datasourceLink; - if (keys.length === 0) { - $contentDisplayedFields.hide(); - return; - } - if (obj == null) { - $contentDisplayedFields.hide(); - $$(ids.contentDisplayedFieldsAdd).hide(); - return; - } - 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(); - } - - 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, - ); - 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); - - // 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 settings = (values.settings = Object.assign( - $$(ids.component).getValues(), - values.settings, - )); - // Retrive the values of your properties from Webix and store them in the view - 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.teamStrategy = $$(ids.teamStrategy).getValue(); - settings.strategyCode = $$(ids.strategyCode).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(); - settings.dataPanelDCs = $$(ids.dataPanelDCs).getValues(); - const $colorForm = $$(ids.strategyColorForm); - settings.strategyColors = $colorForm?.getValues() ?? {}; - 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_teams"); - } - } - - return ABViewOrgChartTeamsProperty; -} - -function fieldToOption(f) { - return { - id: f.id, - value: f.label, - field: f, - }; -}