From f7dbfb69021ce8486d8af5dc9b6ca5d40161e142 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Mon, 20 Feb 2023 15:45:51 +0100
Subject: [PATCH 1/8] refactor: PAB: optimise table space by moving up values
 of the basin section (length, width, ZRMB)

refs #607
---
 .../pab-table/pab-table.component.ts          | 131 +++++++-----------
 1 file changed, 50 insertions(+), 81 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index ead6072f1..8f1e259ff 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -540,58 +540,58 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         for (const cloison of this.model.children) {
             // as much rows as the greatest number of parameters among its devices
             const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison);
-            for (let i = 0; i < maxNbParams; i++) {
+            for (let r = 0; r < maxNbParams; r++) {
                 // build device params row
                 const deviceParamRow = { selectable: cloison, cells: [] };
-                // basin number and ZRAM
-                if (i === 0) {
+                // basin number, LB, BB, ZRMB and ZRAM
+                if (r === 0) {
                     // basin number
                     deviceParamRow.cells.push({
                         value: childIndex + 1,
-                        rowspan: maxNbParams + 1,
+                        rowspan: maxNbParams,
                         class: "basin_number",
                         selectable: cloison
                     });
-                    // 3 empty cells
-                    deviceParamRow.cells.push({
-                        colspan: 3,
-                        rowspan: maxNbParams - 1,
-                        selectable: cloison
-                    });
-                    // ZRAM
-                    deviceParamRow.cells.push({
-                        model: cloison.prms.ZRAM,
-                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
-                    });
-                }
-                // basin cells on the last but 1 row
-                if (i === maxNbParams - 1) {
+                    // Longueur bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.LB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB")
                     });
+                    // Largeur bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.BB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB")
                     });
+                    // Cote radier mi bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.ZRMB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB")
                     });
+                    // ZRAM
+                    deviceParamRow.cells.push({
+                        model: cloison.prms.ZRAM,
+                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
+                    });
                 }
-                // 1 empty cell below ZRAM
-                if (i === 1) {
+                else if (r === 1) {
+                    // 1 row for QA editor
+                    const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form);
+                    qaParam.radioConfig = ParamRadioConfig.VAR;
                     deviceParamRow.cells.push({
-                        rowspan: maxNbParams,
-                        selectable: cloison
+                        model: qaParam,
+                        colspan: 4,
+                        rowspan: maxNbParams - 1,
+                        qa: true,
+                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA")
                     });
                 }
                 // device param cells : 3 cells for each device
                 for (const ouvrage of cloison.structures) {
-                    const nvParam = ouvrage.getNthVisibleParam(i);
+                    const nvParam = ouvrage.getNthVisibleParam(r);
                     const nvParamTitle = nvParam ? this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol) : "";
+                    const childStructParamCount = this.nubVisibleParameterCount(ouvrage);
                     // cell 1 : device type
-                    if (i === 0) { // 1st row
+                    if (r === 0) { // 1st row
                         deviceParamRow.cells.push({
                             model: ouvrage,
                             modelValue: ouvrage.getPropValue("loiDebit"),
@@ -600,75 +600,42 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                         });
                     }
                     // fill space below device type selector
-                    if (i === 1) {
+                    else if (r === 1) {
                         deviceParamRow.cells.push({
                             rowspan: (maxNbParams - 1),
                             selectable: ouvrage
                         });
                     }
-                    // cell 2 : param name
                     if (nvParam) {
+                        // cell 2 : param name
                         deviceParamRow.cells.push({
                             value: nvParam.symbol,
                             title: nvParamTitle,
                             selectable: ouvrage
                         });
-                    } else {
-                        deviceParamRow.cells.push({
-                            selectable: ouvrage
-                        });
-                    }
-                    // cell 3 : param value
-                    if (nvParam) {
+                        // cell 3 : param value
                         deviceParamRow.cells.push({
                             model: nvParam,
                             title: nvParamTitle,
                             selectable: ouvrage
                         });
-                    } else {
-                        deviceParamRow.cells.push({
-                            selectable: ouvrage
-                        });
                     }
-                }
-                // fill horizontal space
-                const devDiff =  (maxNbDevices - cloison.structures.length);
-                if (i === 0) {
-                    for (let j = 0; j < devDiff; j++) {
-                        deviceParamRow.cells.push({
-                            colspan: 3,
-                            rowspan: maxNbParams,
-                            selectable: cloison,
-                            selectableColumn: cloison.structures.length + j
-                        });
+                    else if (r === childStructParamCount) {
+                        // fill remaining space
+                        const remaining = maxNbParams - childStructParamCount;
+                        if (remaining > 0) {
+                            deviceParamRow.cells.push({
+                                colspan: 2,
+                                rowspan: remaining,
+                                selectable: cloison
+                            });
+                        }
                     }
                 }
                 // done !
                 this.rows.push(deviceParamRow);
             }
-            // 1 row for QA editor
-            const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form);
-            qaParam.radioConfig = ParamRadioConfig.VAR;
-            const qaRow: { selectable: any, cells: any[] } = {
-                selectable: undefined,
-                cells: [
-                    {
-                        model: qaParam,
-                        colspan: 3,
-                        qa: true,
-                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA")
-                    }
-                ]
-            };
-            // as many pairs of columns as the maximum number of devices
-            qaRow.cells.push({
-                colspan: maxNbDevices * 3,
-                // selectable: cloison @TODO oui ou non ?
-            });
-            // done !
-            this.rows.push(qaRow);
-
-            childIndex ++;
+            childIndex++;
         }
 
         // B.2 many rows for downwall
@@ -790,18 +757,20 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         return maxNbDevices;
     }
 
+    private nubVisibleParameterCount(n: Nub) {
+        let res = 0;
+        for (const p of n.parameterIterator) {
+            if (p.visible) {
+                res++;
+            }
+        }
+        return res;
+    }
+
     private findMaxNumberOfDeviceParameters(struct: ParallelStructure): number {
         let maxNbParams = 1;
-        for (const d of struct.getChildren()) {
-            let nbParams = 0;
-            for (const p of d.parameterIterator) {
-                if (p.visible) {
-                    // console.log("(counting)", p.symbol);
-                    nbParams ++;
-                }
-            }
-            // console.log(">>> child params: ", nbParams);
-            maxNbParams = Math.max(maxNbParams, nbParams);
+        for (const child of struct.getChildren()) {
+            maxNbParams = Math.max(maxNbParams, this.nubVisibleParameterCount(child));
         }
         return maxNbParams;
     }
-- 
GitLab


From fc7d6b4c693a5e1208787b9f0e65563c0d828243 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Tue, 21 Feb 2023 13:22:25 +0100
Subject: [PATCH 2/8] refactor: PAB: modify table: move type over parameters
 and values fields

refs #607
---
 .../pab-table/pab-table.component.html        | 11 +++--
 .../pab-table/pab-table.component.ts          | 48 ++++++++++++-------
 2 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html
index b68a85d56..3f2722eb2 100644
--- a/src/app/components/pab-table/pab-table.component.html
+++ b/src/app/components/pab-table/pab-table.component.html
@@ -65,12 +65,13 @@
                     {{ h.title }}
                 </th>
             </tr>
-            <tr>
-                <th *ngFor="let col of columns" (click)="toggleSelection(col, $event)"
-                    (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(col)"
-                    [class.selected-cell]="isSelected(col)">
+            <tr *ngFor="let col of columns">
+                <th *ngFor="let cell of col.cells" (click)="toggleSelection(col, $event)"
+                    (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(cell)"
+                    [class.selected-cell]="isSelected(cell)" [attr.rowspan]="rowSpan(cell)"
+                    [attr.colspan]="colSpan(cell)" [title]="cellTitle(cell)">
 
-                    {{ col.title }}
+                    {{ cell.title }}
                 </th>
             </tr>
         </ng-template>
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 8f1e259ff..db19cdb9d 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -477,7 +477,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         for (let i = 0; i < maxNbDevices; i++) {
             this.headers.push({
                 title: sprintf(this.i18nService.localizeText("INFO_PAB_CLOISON_OUVRAGE_N"), (i + 1)),
-                colspan: 3,
+                colspan: 2,
                 selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
                 selectableColumn: i
             });
@@ -485,43 +485,55 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
 
         // A. build columns set
         this.cols = [];
+        const headerRow1 = { cells: [] };
+        const headerRow2 = { cells: [] };
+        this.cols.push(headerRow1);
+        this.cols.push(headerRow2);
+
         // 5 cols for basin
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"),
-            selectable: bs
+            selectable: bs,
+            rowspan: 2
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB"),
-            selectable: bs
+            selectable: bs,
+            rowspan: 2
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB"),
-            selectable: bs
+            selectable: bs,
+            rowspan: 2
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB"),
-            selectable: bs
+            selectable: bs,
+            rowspan: 2
         });
-        this.cols.push({
+        headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM"),
-            selectable: bs
+            selectable: bs,
+            rowspan: 2
         });
         // no col for wall type (defined by rowspan-2 header above)
         // 3 cols for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
-            this.cols.push({
+            const sel = this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]);
+            headerRow1.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_TYPE"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
-                selectableColumn: i
+                selectable: sel,
+                selectableColumn: i,
+                colspan: 2
             });
-            this.cols.push({
+            headerRow2.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_PARAMETERS"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
+                selectable: sel,
                 selectableColumn: i
             });
-            this.cols.push({
+            headerRow2.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_VALUES"),
-                selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]),
+                selectable: sel,
                 selectableColumn: i
             });
         }
-- 
GitLab


From 925304e90c09d465643a3168c89148663ad45a42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Tue, 21 Feb 2023 14:44:38 +0100
Subject: [PATCH 3/8] refactor: PAB: table data: move type over parameter name
 and value

refs #607
---
 .../pab-table/pab-table.component.ts          | 169 ++++++------------
 1 file changed, 59 insertions(+), 110 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index db19cdb9d..c07ae0282 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -84,7 +84,6 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         private i18nService: I18nService,
         private formService: FormulaireService,
         private editPabDialog: MatDialog,
-        private appSetupService: ApplicationSetupService,
         private notifService: NotificationsService
     ) {
         this.selectedItems = [];
@@ -552,7 +551,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         for (const cloison of this.model.children) {
             // as much rows as the greatest number of parameters among its devices
             const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison);
-            for (let r = 0; r < maxNbParams; r++) {
+            for (let r = 0; r <= maxNbParams; r++) {
                 // build device params row
                 const deviceParamRow = { selectable: cloison, cells: [] };
                 // basin number, LB, BB, ZRMB and ZRAM
@@ -560,7 +559,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     // basin number
                     deviceParamRow.cells.push({
                         value: childIndex + 1,
-                        rowspan: maxNbParams,
+                        rowspan: maxNbParams + 1,
                         class: "basin_number",
                         selectable: cloison
                     });
@@ -592,60 +591,14 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     deviceParamRow.cells.push({
                         model: qaParam,
                         colspan: 4,
-                        rowspan: maxNbParams - 1,
+                        rowspan: maxNbParams,
                         qa: true,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA")
                     });
                 }
-                // device param cells : 3 cells for each device
-                for (const ouvrage of cloison.structures) {
-                    const nvParam = ouvrage.getNthVisibleParam(r);
-                    const nvParamTitle = nvParam ? this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol) : "";
-                    const childStructParamCount = this.nubVisibleParameterCount(ouvrage);
-                    // cell 1 : device type
-                    if (r === 0) { // 1st row
-                        deviceParamRow.cells.push({
-                            model: ouvrage,
-                            modelValue: ouvrage.getPropValue("loiDebit"),
-                            options: loisCloisons,
-                            selectable: ouvrage
-                        });
-                    }
-                    // fill space below device type selector
-                    else if (r === 1) {
-                        deviceParamRow.cells.push({
-                            rowspan: (maxNbParams - 1),
-                            selectable: ouvrage
-                        });
-                    }
-                    if (nvParam) {
-                        // cell 2 : param name
-                        deviceParamRow.cells.push({
-                            value: nvParam.symbol,
-                            title: nvParamTitle,
-                            selectable: ouvrage
-                        });
-                        // cell 3 : param value
-                        deviceParamRow.cells.push({
-                            model: nvParam,
-                            title: nvParamTitle,
-                            selectable: ouvrage
-                        });
-                    }
-                    else if (r === childStructParamCount) {
-                        // fill remaining space
-                        const remaining = maxNbParams - childStructParamCount;
-                        if (remaining > 0) {
-                            deviceParamRow.cells.push({
-                                colspan: 2,
-                                rowspan: remaining,
-                                selectable: cloison
-                            });
-                        }
-                    }
-                }
-                // done !
-                this.rows.push(deviceParamRow);
+
+                // devices
+                this.fillParallelStructureCells(deviceParamRow, r, maxNbParams, loisCloisons);
             }
             childIndex++;
         }
@@ -660,21 +613,21 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         });
         // as much rows as the greatest number of parameters among its devices
         const maxNbParamsDW = this.findMaxNumberOfDeviceParameters(this.model.downWall);
-        for (let i = 0; i < maxNbParamsDW; i++) {
+        for (let r = 0; r <= maxNbParamsDW; r++) {
             // build device params row
             const deviceParamRowDW = { selectable: this.model.downWall, cells: [] };
-            // basin number
-            if (i === 0) {
+            if (r === 0) {
+                // "downstream"
                 deviceParamRowDW.cells.push({
                     value: "Aval",
-                    rowspan: maxNbParamsDW,
+                    rowspan: maxNbParamsDW + 1,
                     class: "basin_number",
                     selectable: this.model.downWall
                 });
                 // 3 empty cells
                 deviceParamRowDW.cells.push({
                     colspan: 3,
-                    rowspan: maxNbParamsDW ,
+                    rowspan: maxNbParamsDW + 1,
                     selectable: this.model.downWall
                 });
                 // ZRAM
@@ -683,74 +636,70 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
                 });
             }
-            if (i === 1) {
-                // 1 empty cell
+            if (r === 1) {
+                // 1 empty cell (in place of the QA editor)
                 deviceParamRowDW.cells.push({
-                    rowspan: maxNbParamsDW - 1,
+                    rowspan: maxNbParamsDW,
                     selectable: this.model.downWall
                 });
             }
-            // downwall device param cells : 3 cells for each device
-            for (const ouvrage of this.model.downWall.structures) {
-                const nvParam = ouvrage.getNthVisibleParam(i);
-                const nvParamTitle = nvParam ? this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol) : "";
-                // cell 1 : device type
-                if (i === 0) { // 1st row
-                    deviceParamRowDW.cells.push({
-                        model: ouvrage,
-                        modelValue: ouvrage.getPropValue("loiDebit"),
-                        options: loisAval
-                    });
-                }
-                // fill space
-                if (i === 1) {
-                    deviceParamRowDW.cells.push({
-                        rowspan: (maxNbParamsDW - 1),
-                        selectable: ouvrage
+
+            // devices
+            this.fillParallelStructureCells(deviceParamRowDW, r, maxNbParamsDW, loisAval);
+        }
+
+        this.updateValidity();
+    }
+
+    private fillParallelStructureCells(tableRow: any, rowIndex: number, maxParamCount: number, loisAdmissibles: any[]) {
+        // device param cells : 3 cells for each device
+
+        const ps: ParallelStructure = tableRow.selectable;
+
+        for (const struct of ps.structures) {
+            const childStructParamCount = this.nubVisibleParameterCount(struct);
+            // cell 1 : device type
+            if (rowIndex === 0) { // 1st row
+                tableRow.cells.push({
+                    model: struct,
+                    modelValue: struct.getPropValue("loiDebit"),
+                    options: loisAdmissibles,
+                    selectable: struct,
+                    colspan: 2
+                });
+            }
+            else if (rowIndex === childStructParamCount + 1) {
+                // fill remaining space
+                const remaining = maxParamCount - childStructParamCount;
+                if (remaining > 0) {
+                    tableRow.cells.push({
+                        colspan: 2,
+                        rowspan: remaining,
+                        selectable: ps
                     });
                 }
-                // cell 2 : param name
+            }
+            else {
+                const nvParam = struct.getNthVisibleParam(rowIndex - 1);
                 if (nvParam) {
-                    deviceParamRowDW.cells.push({
+                    const nvParamTitle = this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol);
+                    // cell 2 : param name
+                    tableRow.cells.push({
                         value: nvParam.symbol,
                         title: nvParamTitle,
-                        selectable: ouvrage
-                    });
-                } else {
-                    deviceParamRowDW.cells.push({
-                        selectable: ouvrage
+                        selectable: struct
                     });
-                }
-                // cell 3 : param value
-                if (nvParam) {
-                    deviceParamRowDW.cells.push({
+                    // cell 3 : param value
+                    tableRow.cells.push({
                         model: nvParam,
                         title: nvParamTitle,
-                        selectable: ouvrage
-                    });
-                } else {
-                    deviceParamRowDW.cells.push({
-                        selectable: ouvrage
+                        selectable: struct
                     });
                 }
             }
-            // fill horizontal space
-            const devDiff =  (maxNbDevices - this.model.downWall.structures.length);
-            if (i === 0) {
-                for (let j = 0; j < devDiff; j++) {
-                    deviceParamRowDW.cells.push({
-                        colspan: 3,
-                        rowspan: maxNbParamsDW,
-                        selectable: this.model.downWall,
-                        selectableColumn: this.model.downWall.structures.length + j
-                    });
-                }
-            }
-            // done !
-            this.rows.push(deviceParamRowDW);
         }
-
-        this.updateValidity();
+        // done !
+        this.rows.push(tableRow);
     }
 
     /**
-- 
GitLab


From 12635d844f42e2c0be790fbc091b4e452a015eab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 2 Mar 2023 10:58:29 +0100
Subject: [PATCH 4/8] fix: PAB table: column selection not working on header
 second line (type, parameters, value)

refs #607
---
 src/app/components/pab-table/pab-table.component.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html
index 3f2722eb2..d3b0c017e 100644
--- a/src/app/components/pab-table/pab-table.component.html
+++ b/src/app/components/pab-table/pab-table.component.html
@@ -66,7 +66,7 @@
                 </th>
             </tr>
             <tr *ngFor="let col of columns">
-                <th *ngFor="let cell of col.cells" (click)="toggleSelection(col, $event)"
+                <th *ngFor="let cell of col.cells" (click)="toggleSelection(cell, $event)"
                     (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(cell)"
                     [class.selected-cell]="isSelected(cell)" [attr.rowspan]="rowSpan(cell)"
                     [attr.colspan]="colSpan(cell)" [title]="cellTitle(cell)">
-- 
GitLab


From f6f4548a1fbe8673cf47913da69cf1b826f18926 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 2 Mar 2023 11:32:38 +0100
Subject: [PATCH 5/8] fix: PAB table: copy button not working

refs #607
---
 src/app/components/pab-table/pab-table.component.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index c07ae0282..f06c1b536 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -969,7 +969,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         for (let i = 0; i < this.childrenToAdd; i++) {
             for (const si of this.selectedItems) {
                 const newChild = Session.getInstance().createNub(
-                    si.properties.clone(),
+                    si,
                     si.parent
                 );
                 // copy parameter values
@@ -982,7 +982,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 if (si instanceof ParallelStructure) {
                     for (const c of si.getChildren()) {
                         const newGrandChild = Session.getInstance().createNub(
-                            c.properties.clone(),
+                            c,
                             newChild
                         );
                         // copy children parameters values
-- 
GitLab


From cf18931f24dc418fd54aeff1f97e267da62c17d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Mon, 3 Apr 2023 14:37:23 +0200
Subject: [PATCH 6/8] refactor: PAB table: rename first column

refs #615
---
 src/locale/messages.en.json | 2 +-
 src/locale/messages.fr.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index b7b836bd0..b31fc6330 100755
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -470,7 +470,7 @@
     "INFO_PAB_OUVRAGES": "Devices",
     "INFO_PAB_EDIT_VALUES": "Modify values",
     "INFO_CALCULATE_FIRST": "Calculate this module first",
-    "INFO_PAB_NUM_BASSIN": "Basin #",
+    "INFO_PAB_NUM_BASSIN": "Basin/wall #",
     "INFO_PAB_HEADER_TYPE": "Type",
     "INFO_PAB_HEADER_PARAMETERS": "Parameters",
     "INFO_PAB_HEADER_VALUES": "Values",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 1b2892173..21aca059b 100755
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -471,7 +471,7 @@
     "INFO_PAB_OUVRAGES": "Ouvrages",
     "INFO_PAB_EDIT_VALUES": "Modifier les valeurs",
     "INFO_CALCULATE_FIRST": "Calculer ce module d'abord",
-    "INFO_PAB_NUM_BASSIN": "N° de bassin",
+    "INFO_PAB_NUM_BASSIN": "N° de bassin/cloison",
     "INFO_PAB_HEADER_TYPE": "Type",
     "INFO_PAB_HEADER_PARAMETERS": "Paramètres",
     "INFO_PAB_HEADER_VALUES": "Valeurs",
-- 
GitLab


From 0be34bb23fc3fca1ea14bc22e033522be87f9d8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Tue, 4 Apr 2023 10:53:44 +0200
Subject: [PATCH 7/8] refactor: PAB table: reshape cells, move ZRAM parameter
 out of basin columns

refs #615
---
 .../pab-table/pab-table.component.ts          | 142 ++++++++++--------
 1 file changed, 82 insertions(+), 60 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index a3919284b..c835b87b4 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -464,14 +464,24 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
 
         // 0. build spanned headers over real columns
         this.headers = [];
-        // 1 header for basin
+        // 1 column for basin number
         let bs: any[] = this.model.children;
         bs = bs.concat(this.model.downWall);
+        this.headers.push({
+            title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"),
+            selectable: bs,
+            rowspan: 2
+        });
+        // 3 columns for basin information
         this.headers.push({
             title: this.i18nService.localizeText("INFO_PAB_BASSIN"),
-            colspan: 5,
+            colspan: 3,
             selectable: bs
         });
+        // 1 col for wall
+        this.headers.push({
+            title: this.i18nService.localizeText("INFO_PB_CLOISON"),
+        });
         // 1 header for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
             this.headers.push({
@@ -489,48 +499,35 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         this.cols.push(headerRow1);
         this.cols.push(headerRow2);
 
-        // 5 cols for basin
-        headerRow1.cells.push({
-            title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"),
-            selectable: bs,
-            rowspan: 2
-        });
+        // 3 cols for basin information
         headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB"),
-            selectable: bs,
-            rowspan: 2
+            selectable: bs
         });
         headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB"),
-            selectable: bs,
-            rowspan: 2
+            selectable: bs
         });
         headerRow1.cells.push({
             title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB"),
-            selectable: bs,
-            rowspan: 2
-        });
-        headerRow1.cells.push({
-            title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM"),
-            selectable: bs,
-            rowspan: 2
+            selectable: bs
         });
-        // no col for wall type (defined by rowspan-2 header above)
-        // 3 cols for each device of the wall having the most devices (including downwall)
+
+        // 2 cols for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
             const sel = this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]);
+            if (i == 0) {
+                headerRow1.cells.push({
+                    title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM"),
+                    selectable: bs,
+                });
+            }
             headerRow1.cells.push({
-                title: this.i18nService.localizeText("INFO_PAB_HEADER_TYPE"),
-                selectable: sel,
-                selectableColumn: i,
-                colspan: 2
-            });
-            headerRow2.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_PARAMETERS"),
                 selectable: sel,
                 selectableColumn: i
             });
-            headerRow2.cells.push({
+            headerRow1.cells.push({
                 title: this.i18nService.localizeText("INFO_PAB_HEADER_VALUES"),
                 selectable: sel,
                 selectableColumn: i
@@ -546,23 +543,50 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 value: l
             };
         });
+
+        // NOTE : EB = empty cell (3 columns wide) for LB,BB,ZRMB
+        //        EZRAM = empty cell below ZRAM value (QA editor height + 1)
+
+        const minQAEditorRowCount: number = 1;
+
         // B.1 many rows for each wall
         let childIndex = 0;
         for (const cloison of this.model.children) {
-            // as much rows as the greatest number of parameters among its devices
-            const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison);
-            for (let r = 0; r <= maxNbParams; r++) {
-                // build device params row
+            // maximum device parameter count for all devices in this wall
+            const maxDeviceParamCount = this.findMaxNumberOfDeviceParameters(cloison);
+
+            // total row count for this wall = max device parameter row count + 1 line for device type
+            // minimum = 1 row (EB) + 1 row (LB,BB,ZRMB cells) + QA editor
+            const totalRowCount = Math.max(maxDeviceParamCount + 1, 1 + 1 + minQAEditorRowCount);
+
+            // QA editor row count : total row count - 1 (LB,BB,ZRMB cells) - 1 (EB, see note)
+            const QAEditorRowCount = Math.max(totalRowCount - 2, minQAEditorRowCount);
+
+            // total parameter rows (all parameters without device type) = total row count - 1
+            const paramRowCount = totalRowCount - 1;
+
+            for (let r = 0; r < totalRowCount; r++) {
                 const deviceParamRow = { selectable: cloison, cells: [] };
-                // basin number, LB, BB, ZRMB and ZRAM
                 if (r === 0) {
                     // basin number
                     deviceParamRow.cells.push({
                         value: childIndex + 1,
-                        rowspan: maxNbParams + 1,
+                        rowspan: totalRowCount,
                         class: "basin_number",
                         selectable: cloison
                     });
+                    // empty line (EB cell, see note)
+                    deviceParamRow.cells.push({
+                        colspan: 3
+                    });
+                    // ZRAM
+                    deviceParamRow.cells.push({
+                        model: cloison.prms.ZRAM,
+                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
+                    });
+                }
+                // LB, BB, ZRMB, EZRAM cell (see note)
+                else if (r === 1) {
                     // Longueur bassin
                     deviceParamRow.cells.push({
                         model: cloison.prms.LB,
@@ -578,27 +602,26 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                         model: cloison.prms.ZRMB,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB")
                     });
-                    // ZRAM
+                    // empty cell (EZRAM cell, see note)
                     deviceParamRow.cells.push({
-                        model: cloison.prms.ZRAM,
-                        title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM")
+                        rowspan: paramRowCount
                     });
                 }
-                else if (r === 1) {
-                    // 1 row for QA editor
+                else if (r === 2) {
+                    // rows for QA editor
                     const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form);
                     qaParam.radioConfig = ParamRadioConfig.VAR;
                     deviceParamRow.cells.push({
                         model: qaParam,
-                        colspan: 4,
-                        rowspan: maxNbParams,
+                        colspan: 3,
+                        rowspan: QAEditorRowCount,
                         qa: true,
                         title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA")
                     });
                 }
 
                 // devices
-                this.fillParallelStructureCells(deviceParamRow, r, maxNbParams, loisCloisons);
+                this.fillParallelStructureCells(deviceParamRow, r, paramRowCount, loisCloisons);
             }
             childIndex++;
         }
@@ -612,22 +635,23 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
             };
         });
         // as much rows as the greatest number of parameters among its devices
-        const maxNbParamsDW = this.findMaxNumberOfDeviceParameters(this.model.downWall);
-        for (let r = 0; r <= maxNbParamsDW; r++) {
+        const dwParamCount = this.findMaxNumberOfDeviceParameters(this.model.downWall); // device parameter count
+        const paramRowCount = dwParamCount + 1; // max line number for parameters (without device type)
+        for (let r = 0; r < paramRowCount; r++) {
             // build device params row
             const deviceParamRowDW = { selectable: this.model.downWall, cells: [] };
             if (r === 0) {
                 // "downstream"
                 deviceParamRowDW.cells.push({
                     value: "Aval",
-                    rowspan: maxNbParamsDW + 1,
+                    rowspan: paramRowCount,
                     class: "basin_number",
                     selectable: this.model.downWall
                 });
                 // 3 empty cells
                 deviceParamRowDW.cells.push({
                     colspan: 3,
-                    rowspan: maxNbParamsDW + 1,
+                    rowspan: paramRowCount,
                     selectable: this.model.downWall
                 });
                 // ZRAM
@@ -639,27 +663,24 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
             if (r === 1) {
                 // 1 empty cell (in place of the QA editor)
                 deviceParamRowDW.cells.push({
-                    rowspan: maxNbParamsDW,
+                    rowspan: dwParamCount,
                     selectable: this.model.downWall
                 });
             }
 
             // devices
-            this.fillParallelStructureCells(deviceParamRowDW, r, maxNbParamsDW, loisAval);
+            this.fillParallelStructureCells(deviceParamRowDW, r, paramRowCount, loisAval);
         }
 
         this.updateValidity();
     }
 
-    private fillParallelStructureCells(tableRow: any, rowIndex: number, maxParamCount: number, loisAdmissibles: any[]) {
-        // device param cells : 3 cells for each device
-
+    private fillParallelStructureCells(tableRow: any, rowIndex: number, maxStructParamRowCount: number, loisAdmissibles: any[]) {
         const ps: ParallelStructure = tableRow.selectable;
-
-        for (const struct of ps.structures) {
-            const childStructParamCount = this.nubVisibleParameterCount(struct);
-            // cell 1 : device type
-            if (rowIndex === 0) { // 1st row
+        for (const struct of ps.structures) { // for each device
+            const structParamCount = this.nubVisibleParameterCount(struct);
+            if (rowIndex === 0) {
+                // 1st row : device type
                 tableRow.cells.push({
                     model: struct,
                     modelValue: struct.getPropValue("loiDebit"),
@@ -668,9 +689,9 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     colspan: 2
                 });
             }
-            else if (rowIndex === childStructParamCount + 1) {
+            else if (rowIndex === structParamCount + 1) {
                 // fill remaining space
-                const remaining = maxParamCount - childStructParamCount;
+                const remaining = maxStructParamRowCount - structParamCount;
                 if (remaining > 0) {
                     tableRow.cells.push({
                         colspan: 2,
@@ -680,16 +701,17 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 }
             }
             else {
+                // parameter row
                 const nvParam = struct.getNthVisibleParam(rowIndex - 1);
                 if (nvParam) {
                     const nvParamTitle = this.formService.expandVariableNameAndUnit(CalculatorType.Pab, nvParam.symbol);
-                    // cell 2 : param name
+                    // parameter name
                     tableRow.cells.push({
                         value: nvParam.symbol,
                         title: nvParamTitle,
                         selectable: struct
                     });
-                    // cell 3 : param value
+                    // parameter value
                     tableRow.cells.push({
                         model: nvParam,
                         title: nvParamTitle,
-- 
GitLab


From f70b4d5bea623b80d2bb62b4e2a1d6da93550494 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Tue, 4 Apr 2023 11:37:31 +0200
Subject: [PATCH 8/8] fix: PAB table: selected areas when clicking on various
 cells

refs #615
---
 src/app/components/pab-table/pab-table.component.ts | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index c835b87b4..8d48ab20a 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -481,6 +481,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
         // 1 col for wall
         this.headers.push({
             title: this.i18nService.localizeText("INFO_PB_CLOISON"),
+            selectable: bs
         });
         // 1 header for each device of the wall having the most devices (including downwall)
         for (let i = 0; i < maxNbDevices; i++) {
@@ -577,7 +578,8 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     });
                     // empty line (EB cell, see note)
                     deviceParamRow.cells.push({
-                        colspan: 3
+                        colspan: 3,
+                        selectable: cloison
                     });
                     // ZRAM
                     deviceParamRow.cells.push({
@@ -604,7 +606,8 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     });
                     // empty cell (EZRAM cell, see note)
                     deviceParamRow.cells.push({
-                        rowspan: paramRowCount
+                        rowspan: paramRowCount,
+                        selectable: cloison
                     });
                 }
                 else if (r === 2) {
@@ -696,7 +699,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     tableRow.cells.push({
                         colspan: 2,
                         rowspan: remaining,
-                        selectable: ps
+                        selectable: struct
                     });
                 }
             }
-- 
GitLab