|
12 | 12 | * or submit itself to any jurisdiction. |
13 | 13 | */ |
14 | 14 |
|
15 | | -import { h, iconBarChart, iconCaretRight, iconResizeBoth, iconCaretBottom, iconCircleX } from '/js/src/index.js'; |
| 15 | +import { |
| 16 | + h, |
| 17 | + iconCollapseUp, |
| 18 | + iconBarChart, |
| 19 | + iconCaretRight, |
| 20 | + iconResizeBoth, |
| 21 | + iconCaretBottom, |
| 22 | + iconCircleX, |
| 23 | +} from '/js/src/index.js'; |
16 | 24 | import { spinner } from '../common/spinner.js'; |
17 | 25 | import { draw } from '../common/object/draw.js'; |
18 | 26 | import timestampSelectForm from './../common/timestampSelectForm.js'; |
19 | 27 | import virtualTable from './virtualTable.js'; |
20 | 28 | import { defaultRowAttributes, qcObjectInfoPanel } from '../common/object/objectInfoCard.js'; |
21 | 29 | import { downloadButton } from '../common/downloadButton.js'; |
22 | 30 | import { resizableDivider } from '../common/resizableDivider.js'; |
| 31 | +import { SortDirectionsEnum } from '../common/enums/columnSort.enum.js'; |
| 32 | +import { sortableTableHead } from '../common/sortButton.js'; |
23 | 33 | import { downloadRootImageButton } from '../common/downloadRootImageButton.js'; |
24 | 34 |
|
25 | 35 | /** |
@@ -50,9 +60,15 @@ export default (model) => { |
50 | 60 | const objectsLoaded = object.list; |
51 | 61 | const objectsToDisplay = objectsLoaded.filter((qcObject) => |
52 | 62 | qcObject.name.toLowerCase().includes(searchInput.toLowerCase())); |
53 | | - return virtualTable(model, 'main', objectsToDisplay); |
| 63 | + return h('.flex-column.flex-grow', [ |
| 64 | + actionablesHeaderGroup(model.object), |
| 65 | + virtualTable(model, 'side', objectsToDisplay), |
| 66 | + ]); |
54 | 67 | } |
55 | | - return tableShow(model); |
| 68 | + return h('', [ |
| 69 | + actionablesHeaderGroup(model.object), |
| 70 | + tableShow(model), |
| 71 | + ]); |
56 | 72 | }, |
57 | 73 | Failure: () => null, // Notification is displayed |
58 | 74 | })), |
@@ -170,11 +186,75 @@ const statusBarRight = (model) => model.object.selected |
170 | 186 | * @returns {vnode} - virtual node element |
171 | 187 | */ |
172 | 188 | const tableShow = (model) => |
173 | | - h('table.table.table-sm.text-no-select', [ |
174 | | - h('thead', [h('tr', [h('th', 'Name')])]), |
175 | | - h('tbody', [treeRows(model)]), |
| 189 | + h('table.table.table-sm.text-no-select', h('tbody', [treeRows(model)])); |
| 190 | + |
| 191 | +/** |
| 192 | + * A composite header component for the actionables section. |
| 193 | + * It groups the column sorting header and the functional toolbar (search/collapse). |
| 194 | + * @param {QCObject} qcObject - The state object for Quality Control actionables. |
| 195 | + * @returns {vnode} A virtual DOM node containing the grouped header elements. |
| 196 | + */ |
| 197 | +const actionablesHeaderGroup = (qcObject) => { |
| 198 | + const { |
| 199 | + order = SortDirectionsEnum.ASC, |
| 200 | + icon = 'sort', |
| 201 | + } = qcObject.sortBy || {}; |
| 202 | + |
| 203 | + return h('.bg-gray-light.pv2', [ |
| 204 | + sortableTableHead({ |
| 205 | + order, |
| 206 | + icon, |
| 207 | + label: 'Name', |
| 208 | + sortOptions: [SortDirectionsEnum.ASC, SortDirectionsEnum.DESC], |
| 209 | + onclick: (label, order, icon) => { |
| 210 | + qcObject.sortTree(label, 'name', order, icon); |
| 211 | + }, |
| 212 | + }), |
| 213 | + actionablesContainer(qcObject), |
| 214 | + ]); |
| 215 | +}; |
| 216 | + |
| 217 | +/** |
| 218 | + * A toolbar containing interactive controls for the object tree table, |
| 219 | + * specifically the search input and the 'Collapse All' button. |
| 220 | + * @param {QCObject} qcObject - The state object for managing tree interactions. |
| 221 | + * @returns {vnode} A flex-row container with search and collapse actions. |
| 222 | + */ |
| 223 | +const actionablesContainer = (qcObject) => |
| 224 | + h('.flex-row.w-100', [ |
| 225 | + actionableSearchInput(qcObject), |
| 226 | + actionableCollapseAll(qcObject), |
176 | 227 | ]); |
177 | 228 |
|
| 229 | +/** |
| 230 | + * A button to collapse all expanded nodes in the object tree table. |
| 231 | + * Disabled when a search filter is active to prevent UI inconsistency. |
| 232 | + * @param {QCObject} qcObject - The state object containing the tree controller. |
| 233 | + * @returns {vnode} A button element with a collapse icon. |
| 234 | + */ |
| 235 | +const actionableCollapseAll = (qcObject) => |
| 236 | + h('button.btn.m2', { |
| 237 | + title: 'Close whole tree', |
| 238 | + onclick: () => qcObject.tree.closeAll(), |
| 239 | + disabled: Boolean(qcObject.searchInput), |
| 240 | + id: 'collapse-tree-button', |
| 241 | + }, iconCollapseUp()); |
| 242 | + |
| 243 | +/** |
| 244 | + * A text input for filtering the object tree table based on user queries. |
| 245 | + * @param {QCObject} qcObject - The state object managing search input and loading state. |
| 246 | + * @returns {vnode} An input element for searching. |
| 247 | + */ |
| 248 | +const actionableSearchInput = (qcObject) => |
| 249 | + h('input.form-control.form-inline.mv2.mh3.flex-grow', { |
| 250 | + id: 'searchObjectTree', |
| 251 | + placeholder: 'Search', |
| 252 | + type: 'text', |
| 253 | + value: qcObject.searchInput, |
| 254 | + disabled: qcObject.queryingObjects ? true : false, |
| 255 | + oninput: (e) => qcObject.search(e.target.value), |
| 256 | + }); |
| 257 | + |
178 | 258 | /** |
179 | 259 | * Shows a list of lines <tr> of objects |
180 | 260 | * @param {Model} model - root model of the application |
|
0 commit comments