diff --git a/src/model/metaData/Collapsible.ts b/src/model/metaData/Collapsible.ts new file mode 100644 index 0000000..ea86695 --- /dev/null +++ b/src/model/metaData/Collapsible.ts @@ -0,0 +1,51 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/******************************************************************************* + ** Meta-Data to define Collapsible state, e.g., for a section or widget + ** + *******************************************************************************/ +export class Collapsible +{ + isCollapsible: boolean; + initiallyOpen: boolean; + + constructor(object: any) + { + //////////////////////////////////////////////////////////////////////////// + // use value === true to let undefined (or any other) values become false // + //////////////////////////////////////////////////////////////////////////// + this.isCollapsible = object.isCollapsible === true; + this.initiallyOpen = object.initiallyOpen === true; + } + + + /*************************************************************************** + * + ***************************************************************************/ + public clone(): Collapsible + { + const clone = new Collapsible({ + ...this + }); + return (clone); + } +} diff --git a/src/model/metaData/QTableSection.ts b/src/model/metaData/QTableSection.ts index b427fa4..9657741 100644 --- a/src/model/metaData/QTableSection.ts +++ b/src/model/metaData/QTableSection.ts @@ -19,6 +19,7 @@ * along with this program. If not, see . */ +import {Collapsible} from "./Collapsible"; import {QHelpContent} from "./QHelpContent"; /******************************************************************************* @@ -37,6 +38,7 @@ export class QTableSection gridColumns?: number; helpContents?: QHelpContent[]; alternatives?: Map; + collapsible?: Collapsible; /******************************************************************************* @@ -68,6 +70,11 @@ export class QTableSection this.alternatives.set(type, new QTableSection(object.alternatives[type])); } } + + if (object.collapsible) + { + this.collapsible = new Collapsible(object.collapsible); + } } /*************************************************************************** @@ -97,11 +104,14 @@ export class QTableSection alternativesClone.set(key, value.clone())); } + const collapsibleClone: Collapsible | undefined = (this.collapsible ? this.collapsible.clone() : undefined); + const clone = new QTableSection({...this}); clone.fieldNames = fieldNamesClone; clone.helpContents = helpContentsClone; clone.alternatives = alternativesClone; + clone.collapsible = collapsibleClone; return (clone); } diff --git a/src/model/metaData/QWidgetMetaData.ts b/src/model/metaData/QWidgetMetaData.ts index 17c6b78..6b910ad 100644 --- a/src/model/metaData/QWidgetMetaData.ts +++ b/src/model/metaData/QWidgetMetaData.ts @@ -19,6 +19,7 @@ * along with this program. If not, see . */ +import {Collapsible} from "./Collapsible"; import {QHelpContent} from "./QHelpContent"; import {QIcon} from "./QIcon"; @@ -51,6 +52,7 @@ export class QWidgetMetaData helpContent?: Map; defaultValues?: Map; + collapsible?: Collapsible; constructor(object: any) { @@ -89,5 +91,9 @@ export class QWidgetMetaData } } + if (object.collapsible) + { + this.collapsible = new Collapsible(object.collapsible); + } } } diff --git a/tests/model/metaData/Collapsible.test.ts b/tests/model/metaData/Collapsible.test.ts new file mode 100644 index 0000000..c1655c6 --- /dev/null +++ b/tests/model/metaData/Collapsible.test.ts @@ -0,0 +1,64 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2025. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Collapsible} from "../../../src/model/metaData/Collapsible"; + +describe("Collapsible", () => +{ + describe("constructor", () => + { + it("should construct with all properties from object", () => + { + const collapsible = new Collapsible({ + isCollapsible: true, + initiallyOpen: true + }); + + expect(collapsible.isCollapsible).toBe(true); + expect(collapsible.initiallyOpen).toBe(true); + }); + + it("should handle empty object", () => + { + const collapsible = new Collapsible({}); + + ////////////////////////////////////// + // both attributes default to false // + ////////////////////////////////////// + expect(collapsible.isCollapsible).toBe(false); + expect(collapsible.initiallyOpen).toBe(false); + }); + + it("should treat non-true values as false", () => + { + const collapsible = new Collapsible({ + isCollapsible: 1, + initiallyOpen: "true" + }); + + ////////////////////////////////////// + // both attributes default to false // + ////////////////////////////////////// + expect(collapsible.isCollapsible).toBe(false); + expect(collapsible.initiallyOpen).toBe(false); + }); + }); +}); diff --git a/tests/model/metaData/QTableSection.test.ts b/tests/model/metaData/QTableSection.test.ts new file mode 100644 index 0000000..38b94d2 --- /dev/null +++ b/tests/model/metaData/QTableSection.test.ts @@ -0,0 +1,105 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2025. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {QTableSection} from "../../../src/model/metaData/QTableSection"; + +describe("QTableSection", () => +{ + describe("constructor", () => + { + it("should construct with collapsible object if set in source object", () => + { + const section = new QTableSection({ + name: "section1", + collapsible: { + isCollapsible: true, + initiallyOpen: false + } + }); + + expect(section.name).toBe("section1"); + expect(section.collapsible?.isCollapsible).toBe(true); + expect(section.collapsible?.initiallyOpen).toBe(false); + }); + + it("should construct with undefined collapsible object if not present in source object", () => + { + const section = new QTableSection({ + name: "section2" + }); + + expect(section.name).toBe("section2"); + expect(section.collapsible).toBeUndefined(); + }); + + it("should construct with collapsible object with null values if empty collapsible object is in source", () => + { + const section = new QTableSection({ + name: "section3", + collapsible: {} + }); + + expect(section.name).toBe("section3"); + expect(section.collapsible?.isCollapsible).toBe(false); + expect(section.collapsible?.initiallyOpen).toBe(false); + }); + + it("should deeply clone a collapsible", () => + { + const section = new QTableSection({ + name: "section4", + collapsible: { + isCollapsible: true, + initiallyOpen: true + } + }); + + expect(section.name).toBe("section4"); + expect(section.collapsible?.isCollapsible).toBe(true); + expect(section.collapsible?.initiallyOpen).toBe(true); + + const clone = section.clone(); + expect(clone.collapsible?.isCollapsible).toBe(true); + expect(clone.collapsible?.initiallyOpen).toBe(true); + + if(clone.collapsible) + { + clone.collapsible.initiallyOpen = false; + } + expect(section.collapsible?.initiallyOpen).toBe(true); + expect(clone.collapsible?.initiallyOpen).toBe(false); + }); + + it("should handle an undefined collapsible during cloning", () => + { + const section = new QTableSection({ + name: "section5" + }); + + expect(section.name).toBe("section5"); + expect(section.collapsible).toBeUndefined(); + + const clone = section.clone(); + expect(clone.collapsible).toBeUndefined(); + }); + }); + +}); diff --git a/tests/model/metaData/QWidgetMetaData.test.ts b/tests/model/metaData/QWidgetMetaData.test.ts new file mode 100644 index 0000000..32c9440 --- /dev/null +++ b/tests/model/metaData/QWidgetMetaData.test.ts @@ -0,0 +1,67 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2025. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {QWidgetMetaData} from "../../../src/model/metaData/QWidgetMetaData"; + +describe("QWidgetMetaData", () => +{ + describe("constructor", () => + { + it("should construct with collapsible object if set in source object", () => + { + const widget = new QWidgetMetaData({ + name: "widget1", + collapsible: { + isCollapsible: true, + initiallyOpen: false + } + }); + + expect(widget.name).toBe("widget1"); + expect(widget.collapsible?.isCollapsible).toBe(true); + expect(widget.collapsible?.initiallyOpen).toBe(false); + }); + + it("should construct with undefined collapsible object if not present in source object", () => + { + const widget = new QWidgetMetaData({ + name: "widget2" + }); + + expect(widget.name).toBe("widget2"); + expect(widget.collapsible).toBeUndefined(); + }); + + it("should construct with collapsible object with null values if empty collapsible object is in source", () => + { + const widget = new QWidgetMetaData({ + name: "widget3", + collapsible: {} + }); + + expect(widget.name).toBe("widget3"); + expect(widget.collapsible?.isCollapsible).toBe(false); + expect(widget.collapsible?.initiallyOpen).toBe(false); + }); + + }); + +});