From a1b37dd470ca1b6bf98beb29c0badc6a2498b578 Mon Sep 17 00:00:00 2001 From: roguisharcanetrickster Date: Mon, 18 May 2026 15:33:32 +0700 Subject: [PATCH 1/4] gantt --- src/plugins/index.js | 22 +- src/plugins/web_view_gantt/FNAbviewgantt.js | 224 ++++++++++++++++++ .../web_view_gantt/FNAbviewganttEditor.js | 62 +++++ .../Designer/editors/EditorManager.js | 2 +- .../Designer/properties/PropertyManager.js | 2 +- 5 files changed, 301 insertions(+), 11 deletions(-) create mode 100644 src/plugins/web_view_gantt/FNAbviewgantt.js create mode 100644 src/plugins/web_view_gantt/FNAbviewganttEditor.js diff --git a/src/plugins/index.js b/src/plugins/index.js index 02b8afe0..a06e7c8a 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -1,3 +1,5 @@ +import viewGanttProperties from "./web_view_gantt/FNAbviewgantt.js"; +import viewGanttEditor from "./web_view_gantt/FNAbviewganttEditor.js"; import viewCarouselProperties from "./web_view_carousel/FNAbviewcarousel.js"; import viewCarouselEditor from "./web_view_carousel/FNAbviewcarouselEditor.js"; import viewCommentProperties from "./web_view_comment/FNAbviewcomment.js"; @@ -19,25 +21,27 @@ import viewTextProperties from "./web_view_text/FNAbviewtext.js"; import viewTextEditor from "./web_view_text/FNAbviewtextEditor.js"; const AllPlugins = [ - viewCarouselProperties, viewCarouselEditor, - viewCommentProperties, + viewCarouselProperties, viewCommentEditor, - viewDataSelectProperties, + viewCommentProperties, viewDataSelectEditor, - viewImageProperties, + viewDataSelectProperties, + viewGanttEditor, + viewGanttProperties, viewImageEditor, - viewLabelProperties, + viewImageProperties, viewLabelEditor, - viewLayoutProperties, + viewLabelProperties, viewLayoutEditor, + viewLayoutProperties, viewListProperties, - viewPdfImporterProperties, viewPdfImporterEditor, - viewTabProperties, + viewPdfImporterProperties, viewTabEditor, - viewTextProperties, + viewTabProperties, viewTextEditor, + viewTextProperties, ]; export default { diff --git a/src/plugins/web_view_gantt/FNAbviewgantt.js b/src/plugins/web_view_gantt/FNAbviewgantt.js new file mode 100644 index 00000000..951110a0 --- /dev/null +++ b/src/plugins/web_view_gantt/FNAbviewgantt.js @@ -0,0 +1,224 @@ +// FNAbviewgantt Properties +// A properties side import for an ABView. +// +export default function FNAbviewganttProperties({ + AB, + ABViewPropertiesPlugin, + // ABUIPlugin, +}) { + const BASE_ID = "properties_abview_gantt"; + + const uiConfig = AB.Config.uiSettings(); + + const ABViewGanttWorkspaceView = FABViewGanttWorkspaceView( + AB, + `${BASE_ID}_workspaceView_gantt` + ); + + + +return class ABAbviewganttProperties extends ABViewPropertiesPlugin { + +static getPluginKey() { + return this.key; + } + +static getPluginType() { + return "properties-view"; + // properties-view : will display in the properties panel of the ABDesigner + } + + + + + constructor() { + super(BASE_ID, { + dataviewID: "", + fields: "", + }); + + this.AB = AB; + } + + static get key() { + return "gantt"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + view: "fieldset", + label: `${L("Gantt Data")}:`, + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + id: ids.dataviewID, + view: "richselect", + name: "dataviewID", + label: `${L("Datacollection")}:`, + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: (newValue, oldValue) => { + if (newValue === oldValue) return; + + ABViewGanttWorkspaceView.emit( + "dc.changed", + newValue, + this.CurrentView + ); + + this.onChange(); + }, + }, + }, + ], + }, + }, + { + view: "fieldset", + label: `${L("Gantt Fields")}:`, + labelWidth: uiConfig.labelWidthLarge, + body: { + id: ids.fields, + view: "form", + name: "fields", + borderless: true, + elements: [ABViewGanttWorkspaceView.ui()], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + this.PopupNewDataFieldComponent = FPopupNewDataField( + AB, + `${BASE_ID}_popupNewDataField` + ); + await this.PopupNewDataFieldComponent.init(AB); + this.PopupNewDataFieldComponent.on("save", (...params) => { + ABViewGanttWorkspaceView.emit("field.added", params[0]); + }); + + ABViewGanttWorkspaceView.on("dc.changed", (dcID, view) => { + const DC = this.AB.datacollectionByID(dcID); + + ABViewGanttWorkspaceView.init(DC.datasource, view); + this.PopupNewDataFieldComponent.objectLoad(DC.datasource); + }); + + ABViewGanttWorkspaceView.on("new.field", (fieldKey) => { + this.PopupNewDataFieldComponent.show(null, fieldKey, false); + }); + + await super.init(AB); + } + + populateDataview() { + // Pull data collections to options + // / NOTE: only include System Objects if the user has permission + const datacollectionFilter = this.AB.Account.isSystemDesigner() + ? (obj) => !obj.isSystemObject + : () => true; + const datacollections = + this.CurrentApplication.datacollectionsIncluded( + datacollectionFilter + ); + + // Set the objects you can choose from in the list + const $dataviewID = $$(this.ids.dataviewID); + + $dataviewID.define( + "options", + datacollections.map((e) => { + return { + id: e.id, + value: e.label, + icon: + e.sourceType == "query" + ? "fa fa-filter" + : "fa fa-database", + }; + }) + ); + $dataviewID.refresh(); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const $component = $$(ids.component); + const defaultValues = this.defaultValues(); + const values = Object.assign( + $component.getValues(), + defaultValues, + view.settings + ); + + this.populateDataview(); + + $component.setValues(values); + + let DC = this.AB.datacollectionByID(values.dataviewID); + if (DC) { + ABViewGanttWorkspaceView.init(DC.datasource, this.CurrentView); + this.PopupNewDataFieldComponent.objectLoad(DC.datasource); + } + } + + 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; + + values.settings = Object.assign( + $$(ids.component).getValues(), + $$(ids.fields).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("gantt"); + } + } + + + + +} + diff --git a/src/plugins/web_view_gantt/FNAbviewganttEditor.js b/src/plugins/web_view_gantt/FNAbviewganttEditor.js new file mode 100644 index 00000000..77dc5e13 --- /dev/null +++ b/src/plugins/web_view_gantt/FNAbviewganttEditor.js @@ -0,0 +1,62 @@ +// FNAbviewgantt Editor +// An Editor wrapper for the ABView Component. +// The Editor is displayed in the ABDesigner as a view is worked on. +// The Editor allows a widget to be moved and placed on the canvas. +// +export default function FNAbviewganttEditor({ AB, ABViewEditorPlugin }) { + const BASE_ID = "interface_editor_viewgantt"; + +return class ABAbviewganttEditor extends ABViewEditorPlugin { + +static getPluginKey() { + return this.key; + } + +/** + * @method getPluginType + * return the plugin type for this editor. + * plugin types are how our ClassManager knows how to store + * the plugin. + * @return {string} plugin type + */ + static getPluginType() { + return "editor-view"; + // editor-view : will display in the editor panel of the ABDesigner + } + + + + + static get key() { + return "gantt"; + } + + constructor(view, base = BASE_ID) { + // base: {string} unique base id reference + super(view, base, { + label: "", + }); + } + + ui() { + return this.component.ui(); + } + + async init(AB) { + this.AB = AB; + this.component.ignoreLocal = true; + // in our editor, we provide accessLv = 2 + await this.component.init(AB, 2); + } + + detatch() { + this.component.detatch?.(); + } + + onShow() { + this.component.onShow?.(); + } + }; + + +} diff --git a/src/rootPages/Designer/editors/EditorManager.js b/src/rootPages/Designer/editors/EditorManager.js index c81903b0..96210a73 100644 --- a/src/rootPages/Designer/editors/EditorManager.js +++ b/src/rootPages/Designer/editors/EditorManager.js @@ -29,7 +29,7 @@ export default function (AB) { require("./views/ABViewDocxBuilder"), require("./views/ABViewForm"), require("./views/ABViewFormUrl"), - require("./views/ABViewGantt"), + // require("./views/ABViewGantt"), require("./views/ABViewGrid"), require("./views/ABViewKanban"), // require("./views/ABViewLabel"), diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 2a0bee75..2610dff9 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -105,7 +105,7 @@ export default function (AB) { require("./views/ABViewFormTextbox"), require("./views/ABViewFormTree"), require("./views/ABViewFormUrl"), - require("./views/ABViewGantt"), + // require("./views/ABViewGantt"), require("./views/ABViewGrid"), // require("./views/ABViewImage"), require("./views/ABViewKanban"), From 73e144b1a768e785eab684ee537b063190abfbd6 Mon Sep 17 00:00:00 2001 From: roguisharcanetrickster Date: Tue, 26 May 2026 15:17:55 +0700 Subject: [PATCH 2/4] remove UIClass --- src/plugins/index.js | 11 +++++------ .../properties/workspaceViews/ABViewGantt.js | 13 +++++-------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/plugins/index.js b/src/plugins/index.js index cdd15af4..1a2b0ab8 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -42,18 +42,17 @@ const AllPlugins = [ viewDetailEditor, viewImageProperties, viewImageEditor, - viewImageProperties, - viewLabelEditor, viewLabelProperties, - viewLayoutEditor, + viewLabelEditor, viewLayoutProperties, + viewLayoutEditor, viewListProperties, - viewPdfImporterEditor, viewPdfImporterProperties, - viewTabEditor, + viewPdfImporterEditor, viewTabProperties, - viewTextEditor, + viewTabEditor, viewTextProperties, + viewTextEditor, viewPivotProperties, viewPivotEditor, ]; diff --git a/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js b/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js index 66fbfbfb..fce3b2e8 100644 --- a/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js +++ b/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js @@ -40,18 +40,15 @@ const defaultValues = { }, }; -import UI_Class from "../../ui_class"; - -export default function (AB, ibase) { - const UIClass = UI_Class(AB); - const L = UIClass.L(); +export default function (AB, ABUIPlugin, ibase) { + const L = AB.Label(); const ABFieldDate = AB.Class.ABFieldManager.fieldByKey("date"); const ABFieldNumber = AB.Class.ABFieldManager.fieldByKey("number"); const ABFieldString = AB.Class.ABFieldManager.fieldByKey("string"); const ABFieldLongText = AB.Class.ABFieldManager.fieldByKey("LongText"); - class ABObjectWorkspaceViewGantt extends UIClass { + class ABObjectWorkspaceViewGantt extends ABUIPlugin { constructor(idBase) { super(idBase, { titleFieldID: "", @@ -184,7 +181,7 @@ export default function (AB, ibase) { $$(ids.endDateFieldID).define( "value", settings.endDateFieldID || - defaultValues.settings.endDateFieldIDFieldID + defaultValues.settings.endDateFieldIDFieldID ); $$(ids.endDateFieldID).refresh(); this.syncCommonLists( @@ -197,7 +194,7 @@ export default function (AB, ibase) { $$(ids.durationFieldID).define( "value", settings.durationFieldID || - defaultValues.settings.durationFieldID + defaultValues.settings.durationFieldID ); $$(ids.durationFieldID).refresh(); this.syncCommonLists( From b3d5d589c43e3a1d885fc79b5e54b68b4e490936 Mon Sep 17 00:00:00 2001 From: roguisharcanetrickster Date: Thu, 28 May 2026 13:30:20 +0700 Subject: [PATCH 3/4] replace Workspace, adjust imports --- src/plugins/web_view_gantt/FNAbviewgantt.js | 37 +- .../web_view_gantt/FNAbviewganttEditor.js | 66 +- .../web_view_gantt/FNAbviewganttWorkspace.js | 611 ++++++++++++++++++ .../properties/workspaceViews/ABViewGantt.js | 11 +- ..._work_interface_workspace_editor_layout.js | 3 +- 5 files changed, 666 insertions(+), 62 deletions(-) create mode 100644 src/plugins/web_view_gantt/FNAbviewganttWorkspace.js diff --git a/src/plugins/web_view_gantt/FNAbviewgantt.js b/src/plugins/web_view_gantt/FNAbviewgantt.js index 951110a0..1a9581d5 100644 --- a/src/plugins/web_view_gantt/FNAbviewgantt.js +++ b/src/plugins/web_view_gantt/FNAbviewgantt.js @@ -1,36 +1,39 @@ // FNAbviewgantt Properties // A properties side import for an ABView. // +import FABViewGanttWorkspaceView from "./FNAbviewganttWorkspace.js"; + export default function FNAbviewganttProperties({ AB, ABViewPropertiesPlugin, // ABUIPlugin, }) { - const BASE_ID = "properties_abview_gantt"; - + const BASE_ID = "properties_abview_gantt"; + const L = AB.Label(); const uiConfig = AB.Config.uiSettings(); + const FPopupNewDataField = + require("../../rootPages/Designer/ui_work_object_workspace_popupNewDataField").default; + + const ABUIPopupNewDataField = FPopupNewDataField( + AB, + `${BASE_ID}_popupNewDataField` + ); const ABViewGanttWorkspaceView = FABViewGanttWorkspaceView( AB, `${BASE_ID}_workspaceView_gantt` ); - - -return class ABAbviewganttProperties extends ABViewPropertiesPlugin { - -static getPluginKey() { + return class ABAbviewganttProperties extends ABViewPropertiesPlugin { + static getPluginKey() { return this.key; } -static getPluginType() { + static getPluginType() { return "properties-view"; // properties-view : will display in the properties panel of the ABDesigner } - - - constructor() { super(BASE_ID, { dataviewID: "", @@ -101,11 +104,8 @@ static getPluginType() { async init(AB) { this.AB = AB; + this.PopupNewDataFieldComponent = ABUIPopupNewDataField; - this.PopupNewDataFieldComponent = FPopupNewDataField( - AB, - `${BASE_ID}_popupNewDataField` - ); await this.PopupNewDataFieldComponent.init(AB); this.PopupNewDataFieldComponent.on("save", (...params) => { ABViewGanttWorkspaceView.emit("field.added", params[0]); @@ -215,10 +215,5 @@ static getPluginType() { ViewClass() { return super._ViewClass("gantt"); } - } - - - - + }; } - diff --git a/src/plugins/web_view_gantt/FNAbviewganttEditor.js b/src/plugins/web_view_gantt/FNAbviewganttEditor.js index 77dc5e13..377cede7 100644 --- a/src/plugins/web_view_gantt/FNAbviewganttEditor.js +++ b/src/plugins/web_view_gantt/FNAbviewganttEditor.js @@ -3,19 +3,18 @@ // The Editor is displayed in the ABDesigner as a view is worked on. // The Editor allows a widget to be moved and placed on the canvas. // -export default function FNAbviewganttEditor({ AB, ABViewEditorPlugin }) { +export default function FNAbviewganttEditor({ ABViewEditorPlugin }) { const BASE_ID = "interface_editor_viewgantt"; -return class ABAbviewganttEditor extends ABViewEditorPlugin { - -static getPluginKey() { + return class ABAbviewganttEditor extends ABViewEditorPlugin { + static getPluginKey() { return this.key; } -/** + /** * @method getPluginType * return the plugin type for this editor. - * plugin types are how our ClassManager knows how to store + * plugin types are how our ClassManager knows how to store * the plugin. * @return {string} plugin type */ @@ -24,39 +23,34 @@ static getPluginKey() { // editor-view : will display in the editor panel of the ABDesigner } + static get key() { + return "gantt"; + } + constructor(view, base = BASE_ID) { + // base: {string} unique base id reference + super(view, base, { + label: "", + }); + } + ui() { + return this.component.ui(); + } - static get key() { - return "gantt"; - } - - constructor(view, base = BASE_ID) { - // base: {string} unique base id reference - super(view, base, { - label: "", - }); - } - - ui() { - return this.component.ui(); - } - - async init(AB) { - this.AB = AB; - this.component.ignoreLocal = true; - // in our editor, we provide accessLv = 2 - await this.component.init(AB, 2); - } - - detatch() { - this.component.detatch?.(); - } + async init(AB) { + this.AB = AB; + this.component.ignoreLocal = true; + // in our editor, we provide accessLv = 2 + await this.component.init(AB, 2); + } - onShow() { - this.component.onShow?.(); - } - }; - + detatch() { + this.component.detatch?.(); + } + onShow() { + this.component.onShow?.(); + } + }; } diff --git a/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js b/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js new file mode 100644 index 00000000..445a4613 --- /dev/null +++ b/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js @@ -0,0 +1,611 @@ +// ABObjectWorkspaceViewGantt.js +// +// Manages the settings for a Gantt Chart View in the AppBuilder Object Workspace + +const defaultValues = { + name: "Default Gantt", + filterConditions: [], // array of filters to apply to the data table + sortFields: [], + settings: { + dataviewID: "", + // {string} + // {ABDatacollection.id} of the datacollection that contains the data for + // the Gantt chart. + + titleFieldID: "", + // {string} + // {ABFieldXXX.id} of the field that contains the value of the title + // ABFieldString, ABFieldLongText + + startDateFieldID: "", + // {string} + // {ABFieldDate.id} of the field that contains the start date + + endDateFieldID: "", + // {string} + // {ABFieldDate.id} of the field that contains the end date + + durationFieldID: "", + // {string} + // {ABFieldNumber.id} of the field that contains the duration + + progressFieldID: "", + // {string} + // {ABFieldNumber.id} of the field that marks the duration + + notesFieldID: "", + // {string} + // {ABFieldXXX.id} of the field that contains the value of the notes + // ABFieldString, ABFieldLongText + }, +}; + +import UI_Class from "../../rootPages/Designer/ui_class"; + +export default function (AB, ibase) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); + + const ABFieldDate = AB.Class.ABFieldManager.fieldByKey("date"); + const ABFieldNumber = AB.Class.ABFieldManager.fieldByKey("number"); + const ABFieldString = AB.Class.ABFieldManager.fieldByKey("string"); + const ABFieldLongText = AB.Class.ABFieldManager.fieldByKey("LongText"); + + class ABObjectWorkspaceViewGantt extends UIClass { + constructor(idBase) { + super(idBase, { + titleFieldID: "", + startDateFieldID: "", + endDateFieldID: "", + durationFieldID: "", + progressFieldID: "", + notesFieldID: "", + }); + + this.on("field.added", (field) => { + // refresh our droplists with the new field. + this.refreshOptions(this.CurrentObject, this._view); + if (this._autoSelectInput) { + $$(this._autoSelectInput)?.setValue(field.id); + } + }); + + this._autoSelectInput = null; + // {string} + // contains the webix.id of the input that should be auto selected + // if we receive a "field.add" event; + + this._dateFields = []; + // {array} + // an array of webix options { id, value } that represent all the date + // fields of the CurrentObject. + } + + /** + * unique key describing this View. + * @return {string} + */ + type() { + return "gantt"; + } + + /** + * @return {string} + */ + icon() { + return "fa fa-tasks"; + } + + refreshOptions(object, settings) { + const ids = this.ids; + + const dateFields = object + .fields((f) => f instanceof ABFieldDate) + .map(({ id, label }) => ({ id, value: label })); + + // sort by value + dateFields.sort((a, b) => (a.value > b.value ? 1 : -1)); + + // Add default option + dateFields.unshift({ + id: null, + value: L("Select a date field"), + }); + this._dateFields = dateFields; + + // Start date + $$(ids.startDateFieldID).define("options", dateFields); + + // // End date + $$(ids.endDateFieldID).define("options", dateFields); + + // Duration + const numberFields = object + .fields((f) => f instanceof ABFieldNumber) + .map(({ id, label }) => ({ id, value: label })); + + // sort by value + numberFields.sort((a, b) => (a.value > b.value ? 1 : -1)); + + // Add default option + numberFields.unshift({ + id: null, + value: L("Select a number field"), + }); + this._numberFields = numberFields; + + $$(ids.durationFieldID).define("options", numberFields); + + // Progress + $$(ids.progressFieldID).define("options", numberFields); + + // Title & Notes + const stringFields = object + .fields( + (f) => f instanceof ABFieldString || f instanceof ABFieldLongText + ) + .map(({ id, label }) => ({ id, value: label })); + + // sort by value + stringFields.sort((a, b) => (a.value > b.value ? 1 : -1)); + + // Add default option + stringFields.unshift({ + id: null, + value: L("Select a string field"), + }); + this._stringFields = stringFields; + + $$(ids.titleFieldID).define("options", stringFields); + $$(ids.notesFieldID).define("options", stringFields); + + if (!settings) return; + + // Select settings's values + if (settings.titleFieldID) { + $$(ids.titleFieldID).define("value", settings.titleFieldID); + $$(ids.titleFieldID).refresh(); + this.syncCommonLists( + [ids.titleFieldID, ids.notesFieldID], + this._stringFields + ); + } + + if (settings.startDateFieldID) { + $$(ids.startDateFieldID).define("value", settings.startDateFieldID); + $$(ids.startDateFieldID).refresh(); + this.syncCommonLists( + [ids.startDateFieldID, ids.endDateFieldID], + this._dateFields + ); + } + + if (settings.endDateFieldID) { + $$(ids.endDateFieldID).define( + "value", + settings.endDateFieldID || + defaultValues.settings.endDateFieldIDFieldID + ); + $$(ids.endDateFieldID).refresh(); + this.syncCommonLists( + [ids.startDateFieldID, ids.endDateFieldID], + this._dateFields + ); + } + + if (settings.durationFieldID) { + $$(ids.durationFieldID).define( + "value", + settings.durationFieldID || + defaultValues.settings.durationFieldID + ); + $$(ids.durationFieldID).refresh(); + this.syncCommonLists( + [ids.durationFieldID, ids.progressFieldID], + this._numberFields + ); + } + + if (settings.progressFieldID) { + $$(ids.progressFieldID).define("value", settings.progressFieldID); + $$(ids.progressFieldID).refresh(); + this.syncCommonLists( + [ids.durationFieldID, ids.progressFieldID], + this._numberFields + ); + } + + if (settings.notesFieldID) { + $$(ids.notesFieldID).define("value", settings.notesFieldID); + $$(ids.notesFieldID).refresh(); + this.syncCommonLists( + [ids.titleFieldID, ids.notesFieldID], + this._stringFields + ); + } + } + + /** + * @method syncCommonLists() + * Make sure the given lists do not contain options for the other lists + * in their selections. + * In this case, we have multiple lists of fields that can be options for + * the start and end dates. However once the start date field is chosen + * we want to make sure that entry doesn't show up in the end date. + * @param {array} commonIDs + * an array of [ webix.id, webix.id ] of the lists that share the + * same values, but shouldn't show the options of the others. + * @param {array} fullOptions + * The full list of options available for those lists. + */ + syncCommonLists(commonIDs, fullOptions) { + // for each of the Other lists + + commonIDs.forEach((idCurr) => { + const otherVals = []; + const otherIDs = commonIDs.filter((i) => i != idCurr); + otherIDs.forEach((idOther) => { + otherVals.push($$(idOther).getValue()); + }); + + const $list = $$(idCurr); + const newOptions = fullOptions.filter( + (o) => otherVals.indexOf(o.id) == -1 + ); + $list.define("options", newOptions); + $list.refresh(); + }); + } + + ui() { + const ids = this.ids; + + // const labels = { + // common: App.labels, + // component: { + // titleFieldID: L("ab.add_view.gantt.title", "*Title"), + // startDateFieldID: L("ab.add_view.gantt.startDate", "*Start Date"), + // endDateFieldID: L("ab.add_view.gantt.endDate", "*End Date"), + // durationFieldID: L("ab.add_view.gantt.duration", "*Duration"), + // progressFieldID: L("ab.add_view.gantt.progress", "*Progress"), + // notesFieldID: L("ab.add_view.gantt.notes", "*Notes"), + + // datePlaceholder: L( + // "ab.add_view.gantt.datePlaceholder", + // "*Select a date field" + // ), + // numberPlaceholder: L( + // "ab.add_view.gantt.numberPlaceholder", + // "*Select a number field" + // ), + // stringPlaceholder: L( + // "ab.add_view.gantt.stringPlaceholder", + // "*Select a string field" + // ), + // }, + // }; + + // const PopupNewDataFieldComponent = new ABPopupNewDataField( + // App, + // idBase + "_gantt" + // ); + + return { + batch: "gantt", + rows: [ + { + cols: [ + { + id: ids.titleFieldID, + view: "richselect", + label: ` ${L( + "Title" + )}`, + placeholder: L("Select a string field"), + labelWidth: 130, + name: "titleFieldID", + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.titleFieldID, ids.notesFieldID], + this._stringFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.titleFieldID; + this.emit("new.field", ABFieldString.defaults().key); + }, + }, + ], + }, + { + cols: [ + { + id: ids.startDateFieldID, + view: "richselect", + label: ` ${L( + "Start Date" + )}`, + placeholder: L("Select a date field"), + labelWidth: 130, + name: "startDateFieldID", + required: true, + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.startDateFieldID, ids.endDateFieldID], + this._dateFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.startDateFieldID; + this.emit("new.field", ABFieldDate.defaults().key); + }, + }, + ], + }, + { + cols: [ + { + id: ids.endDateFieldID, + view: "richselect", + label: ` ${L( + "End Date" + )}`, + placeholder: L("Select a date field"), + labelWidth: 130, + name: "endDateFieldID", + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.startDateFieldID, ids.endDateFieldID], + this._dateFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.endDateFieldID; + this.emit("new.field", ABFieldDate.defaults().key); + }, + }, + ], + }, + { + cols: [ + { + id: ids.durationFieldID, + view: "richselect", + label: ` ${L( + "Duration" + )}`, + placeholder: L("Select a number field"), + labelWidth: 130, + name: "durationFieldID", + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.durationFieldID, ids.progressFieldID], + this._numberFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.durationFieldID; + this.emit("new.field", ABFieldNumber.defaults().key); + }, + }, + ], + }, + { + cols: [ + { + id: ids.progressFieldID, + view: "richselect", + label: ` ${L( + "Progress" + )}`, + placeholder: L("Select a number field"), + labelWidth: 130, + name: "progressFieldID", + required: false, + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.durationFieldID, ids.progressFieldID], + this._numberFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.progressFieldID; + this.emit("new.field", ABFieldNumber.defaults().key); + }, + }, + ], + }, + { + cols: [ + { + id: ids.notesFieldID, + view: "richselect", + label: ` ${L( + "Notes" + )}`, + placeholder: L("Select a string field"), + labelWidth: 130, + name: "notesFieldID", + required: false, + options: [], + on: { + onChange: (newValue, oldValue) => { + this.syncCommonLists( + [ids.titleFieldID, ids.notesFieldID], + this._stringFields + ); + }, + }, + }, + { + view: "button", + css: "webix_primary", + type: "icon", + icon: "fa fa-plus", + label: "", + width: 30, + click: () => { + this._autoSelectInput = ids.notesFieldID; + this.emit( + "new.field", + ABFieldLongText.defaults().key + ); + }, + }, + ], + }, + ], + }; + } + + init(object, view) { + this.objectLoad(object); + this._view = view; + this.refreshOptions(object, view?.settings); + } + + validate($form) { + const ids = this.ids; + const endDateFieldID = + $$(ids.endDateFieldID).getValue() || + defaultValues.settings.endDateFieldID; + const durationFieldID = + $$(ids.durationFieldID).getValue() || + defaultValues.settings.durationFieldID; + + if (!endDateFieldID && !durationFieldID) { + $form.markInvalid("endDateFieldID", "Required"); + $form.markInvalid("durationFieldID", "Required"); + + return false; + } + + return true; + } + + values() { + const ids = this.ids; + + const result = {}; + + result.titleFieldID = + $$(ids.titleFieldID).getValue() || + defaultValues.settings.titleFieldID; + result.startDateFieldID = + $$(ids.startDateFieldID).getValue() || + defaultValues.settings.startDateFieldID; + result.endDateFieldID = + $$(ids.endDateFieldID).getValue() || + defaultValues.settings.endDateFieldID; + result.durationFieldID = + $$(ids.durationFieldID).getValue() || + defaultValues.settings.durationFieldID; + result.progressFieldID = + $$(ids.progressFieldID).getValue() || + defaultValues.settings.progressFieldID; + result.notesFieldID = + $$(ids.notesFieldID).getValue() || + defaultValues.settings.notesFieldID; + + return result; + } + + /** + * @method fromObj + * take our persisted data, and properly load it + * into this object instance. + * @param {json} data the persisted data + */ + fromSettings(data) { + for (const key in defaultValues) + this[key] = data[key] || defaultValues[key]; + + this.settings = Object.assign( + {}, + defaultValues.settings, + data.settings ?? {} + ); + + this.type = this.type(); + } + + /** + * @method toObj() + * compile our current state into a {json} object + * that can be persisted. + */ + toSettings() { + const obj = {}; //super.toObj(); + + for (const key in defaultValues) + obj[key] = this[key] || defaultValues[key]; + + obj.settings = Object.assign( + {}, + defaultValues.settings, + obj.settings ?? {} + ); + obj.key = this.type(); + obj.type = this.type(); + + return obj; + } + } + + return new ABObjectWorkspaceViewGantt(ibase); +} diff --git a/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js b/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js index fce3b2e8..f906b526 100644 --- a/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js +++ b/src/rootPages/Designer/properties/workspaceViews/ABViewGantt.js @@ -40,15 +40,18 @@ const defaultValues = { }, }; -export default function (AB, ABUIPlugin, ibase) { - const L = AB.Label(); +import UI_Class from "../../ui_class"; + +export default function (AB, ibase) { + const UIClass = UI_Class(AB); + const L = UIClass.L(); const ABFieldDate = AB.Class.ABFieldManager.fieldByKey("date"); const ABFieldNumber = AB.Class.ABFieldManager.fieldByKey("number"); const ABFieldString = AB.Class.ABFieldManager.fieldByKey("string"); const ABFieldLongText = AB.Class.ABFieldManager.fieldByKey("LongText"); - class ABObjectWorkspaceViewGantt extends ABUIPlugin { + class ABObjectWorkspaceViewGantt extends UIClass { constructor(idBase) { super(idBase, { titleFieldID: "", @@ -570,7 +573,7 @@ export default function (AB, ABUIPlugin, ibase) { */ fromSettings(data) { for (const key in defaultValues) - this[v] = data[key] || defaultValues[key]; + this[key] = data[key] || defaultValues[key]; this.settings = Object.assign( {}, diff --git a/src/rootPages/Designer/ui_work_interface_workspace_editor_layout.js b/src/rootPages/Designer/ui_work_interface_workspace_editor_layout.js index 94586edc..0f797d72 100644 --- a/src/rootPages/Designer/ui_work_interface_workspace_editor_layout.js +++ b/src/rootPages/Designer/ui_work_interface_workspace_editor_layout.js @@ -287,7 +287,8 @@ export default function (AB) { } if (idDashboard) { const $dashboard = $$(idDashboard); - if ($dashboard) $dashboard.clearAll(); + if ($dashboard && typeof $dashboard.clearAll === "function") + $dashboard.clearAll(); } // add the editorUI if it is not already added From 03aa2f1b334ea0cf1c34549859765565d84fc4a3 Mon Sep 17 00:00:00 2001 From: roguisharcanetrickster Date: Tue, 2 Jun 2026 15:34:24 +0700 Subject: [PATCH 4/4] remove ui_class --- src/plugins/web_view_gantt/FNAbviewgantt.js | 3 ++- .../web_view_gantt/FNAbviewganttWorkspace.js | 13 +++++-------- src/plugins/web_view_kanban/Abkanbanworkspace.js | 8 ++------ src/plugins/web_view_kanban/FNAbviewkanban.js | 3 ++- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/plugins/web_view_gantt/FNAbviewgantt.js b/src/plugins/web_view_gantt/FNAbviewgantt.js index 1a9581d5..68d2d115 100644 --- a/src/plugins/web_view_gantt/FNAbviewgantt.js +++ b/src/plugins/web_view_gantt/FNAbviewgantt.js @@ -6,7 +6,7 @@ import FABViewGanttWorkspaceView from "./FNAbviewganttWorkspace.js"; export default function FNAbviewganttProperties({ AB, ABViewPropertiesPlugin, - // ABUIPlugin, + ABUIPlugin, }) { const BASE_ID = "properties_abview_gantt"; const L = AB.Label(); @@ -21,6 +21,7 @@ export default function FNAbviewganttProperties({ ); const ABViewGanttWorkspaceView = FABViewGanttWorkspaceView( AB, + ABUIPlugin, `${BASE_ID}_workspaceView_gantt` ); diff --git a/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js b/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js index 445a4613..5b766912 100644 --- a/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js +++ b/src/plugins/web_view_gantt/FNAbviewganttWorkspace.js @@ -40,18 +40,15 @@ const defaultValues = { }, }; -import UI_Class from "../../rootPages/Designer/ui_class"; - -export default function (AB, ibase) { - const UIClass = UI_Class(AB); - const L = UIClass.L(); +export default function (AB, ABUIPlugin, ibase) { + const L = AB.Label(); const ABFieldDate = AB.Class.ABFieldManager.fieldByKey("date"); const ABFieldNumber = AB.Class.ABFieldManager.fieldByKey("number"); const ABFieldString = AB.Class.ABFieldManager.fieldByKey("string"); const ABFieldLongText = AB.Class.ABFieldManager.fieldByKey("LongText"); - class ABObjectWorkspaceViewGantt extends UIClass { + class ABObjectWorkspaceViewGantt extends ABUIPlugin { constructor(idBase) { super(idBase, { titleFieldID: "", @@ -184,7 +181,7 @@ export default function (AB, ibase) { $$(ids.endDateFieldID).define( "value", settings.endDateFieldID || - defaultValues.settings.endDateFieldIDFieldID + defaultValues.settings.endDateFieldIDFieldID ); $$(ids.endDateFieldID).refresh(); this.syncCommonLists( @@ -197,7 +194,7 @@ export default function (AB, ibase) { $$(ids.durationFieldID).define( "value", settings.durationFieldID || - defaultValues.settings.durationFieldID + defaultValues.settings.durationFieldID ); $$(ids.durationFieldID).refresh(); this.syncCommonLists( diff --git a/src/plugins/web_view_kanban/Abkanbanworkspace.js b/src/plugins/web_view_kanban/Abkanbanworkspace.js index fc4c2e4c..d963886f 100644 --- a/src/plugins/web_view_kanban/Abkanbanworkspace.js +++ b/src/plugins/web_view_kanban/Abkanbanworkspace.js @@ -2,21 +2,17 @@ // // Manages the settings for a KanBan View in the Object Workspace -import UI_Class from "../../rootPages/Designer/ui_class"; - let classABViewKanban = null; -export default function (AB, ibase) { +export default function (AB, ABUIPlugin, ibase) { const L = AB.Label(); - const UIClass = UI_Class(AB); - const ABFieldConnect = AB.Class.ABFieldManager.fieldByKey("connectObject"); const ABFieldList = AB.Class.ABFieldManager.fieldByKey("list"); const ABFieldUser = AB.Class.ABFieldManager.fieldByKey("user"); if (!classABViewKanban) { - classABViewKanban = class ABViewKanban extends UIClass { + classABViewKanban = class ABViewKanban extends ABUIPlugin { constructor(idBase) { super(idBase, { vGroupInput: "", diff --git a/src/plugins/web_view_kanban/FNAbviewkanban.js b/src/plugins/web_view_kanban/FNAbviewkanban.js index e473cbb6..66cf8f3c 100644 --- a/src/plugins/web_view_kanban/FNAbviewkanban.js +++ b/src/plugins/web_view_kanban/FNAbviewkanban.js @@ -6,6 +6,7 @@ import FABViewKanbanWorkspace from "./Abkanbanworkspace.js"; export default function FNAbviewkanbanProperties({ AB, ABViewPropertiesPlugin, + ABUIPlugin, }) { const BASE_ID = "properties_abview_kanban"; @@ -17,7 +18,7 @@ export default function FNAbviewkanbanProperties({ const uiConfig = AB.UISettings.config(); const L = AB.Label(); - const ViewKanbanProperties = FABViewKanbanWorkspace(AB, BASE_ID); + const ViewKanbanProperties = FABViewKanbanWorkspace(AB, ABUIPlugin, BASE_ID); let PopupNewDataFieldComponent = null; return class ABAbviewkanbanProperties extends ABViewPropertiesPlugin {