1// Copyright (C) 2021 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import * as m from 'mithril'; 16import {isStackPivot} from '../common/pivot_table_common'; 17 18import {globals} from './globals'; 19import {hideModel} from './modal'; 20import { 21 PivotTableHelper, 22} from './pivot_table_helper'; 23 24interface PivotTableEditorAttrs { 25 helper: PivotTableHelper; 26} 27 28export class ColumnPicker implements m.ClassComponent<PivotTableEditorAttrs> { 29 view(vnode: m.Vnode<PivotTableEditorAttrs>) { 30 const {helper} = vnode.attrs; 31 32 // Fills available aggregations options in aggregation select. 33 const aggregationOptions = []; 34 for (const aggregation of helper.availableAggregations) { 35 aggregationOptions.push( 36 m('option', {value: aggregation, key: aggregation}, aggregation)); 37 } 38 39 // Fills available columns options divided according to their table in 40 // column select. 41 const columnOptionGroup = []; 42 for (const {tableName, columns} of helper.availableColumns) { 43 const options = []; 44 for (const column of columns) { 45 // We can't aggregate a stack column. 46 const hidden = !helper.isPivot && isStackPivot(tableName, column); 47 options.push(m('option', {value: column, key: column, hidden}, column)); 48 } 49 columnOptionGroup.push(m('optgroup', {label: tableName}, options)); 50 } 51 52 return m( 53 'div', 54 m( 55 'section', 56 m('h2', 'Select column type: '), 57 // Pivot radio button. 58 m( 59 'span', 60 m(`input[type=radio][name=type][id=pivot]`, { 61 checked: helper.isPivot, 62 onchange: () => { 63 helper.togglePivotSelection(); 64 globals.rafScheduler.scheduleFullRedraw(); 65 } 66 }), 67 m(`label[for=pivot]`, 'Pivot'), 68 ), 69 // Aggregation radio button. 70 m('span', m(`input[type=radio][name=type][id=aggregation]`, { 71 checked: !helper.isPivot, 72 onchange: () => { 73 helper.togglePivotSelection(); 74 globals.rafScheduler.scheduleFullRedraw(); 75 } 76 })), 77 m(`label[for=aggregation]`, 'Aggregation'), 78 ), 79 m( 80 'section', 81 m('h2', 'Select a column: '), 82 // Aggregation select. 83 m('select', 84 { 85 disabled: helper.isPivot, 86 selectedIndex: helper.selectedAggregationIndex, 87 onchange: (e: InputEvent) => { 88 helper.setSelectedPivotTableAggregationIndex( 89 (e.target as HTMLSelectElement).selectedIndex); 90 } 91 }, 92 aggregationOptions), 93 ' ', 94 // Column select. 95 m('select', 96 { 97 selectedIndex: helper.selectedColumnIndex, 98 onchange: (e: InputEvent) => { 99 helper.setSelectedPivotTableColumnIndex( 100 (e.target as HTMLSelectElement).selectedIndex); 101 } 102 }, 103 columnOptionGroup), 104 ), 105 m('section.button-group', 106 // Button to toggle selected column. 107 m('button', 108 { 109 onclick: () => { 110 helper.updatePivotTableColumnOnSelectedIndex(); 111 globals.rafScheduler.scheduleFullRedraw(); 112 } 113 }, 114 'Add/Remove'), 115 // Button to clear table and all selected columns. 116 m('button', 117 { 118 onclick: () => { 119 helper.clearPivotTableColumns(); 120 globals.rafScheduler.scheduleFullRedraw(); 121 } 122 }, 123 'Clear'))); 124 } 125} 126 127export class ColumnDisplay implements m.ClassComponent<PivotTableEditorAttrs> { 128 view(vnode: m.Vnode<PivotTableEditorAttrs>) { 129 const {helper} = vnode.attrs; 130 const selectedPivotsDisplay = []; 131 const selectedAggregationsDisplay = []; 132 133 for (let i = 0; i < helper.selectedPivots.length; ++i) { 134 const columnAttrs = helper.selectedPivots[i]; 135 selectedPivotsDisplay.push(m( 136 'tr', 137 m('td', 138 { 139 draggable: true, 140 ondragstart: (e: DragEvent) => { 141 helper.selectedColumnOnDrag(e, true, i); 142 }, 143 ondrop: (e: DragEvent) => { 144 helper.removeHighlightFromDropLocation(e); 145 helper.selectedColumnOnDrop(e, true, i); 146 globals.rafScheduler.scheduleFullRedraw(); 147 }, 148 onclick: () => { 149 helper.selectPivotTableColumn(columnAttrs); 150 globals.rafScheduler.scheduleFullRedraw(); 151 }, 152 ondragenter: (e: DragEvent) => { 153 helper.highlightDropLocation(e, true); 154 }, 155 ondragleave: (e: DragEvent) => { 156 helper.removeHighlightFromDropLocation(e); 157 } 158 }, 159 m('i.material-icons', 160 { 161 onclick: () => { 162 helper.updatePivotTableColumnOnColumnAttributes(columnAttrs); 163 globals.rafScheduler.scheduleFullRedraw(); 164 }, 165 }, 166 'remove'), 167 ' ', 168 `${columnAttrs.tableName} ${columnAttrs.columnName}`))); 169 } 170 171 for (let i = 0; i < helper.selectedAggregations.length; ++i) { 172 const columnAttrs = helper.selectedAggregations[i]; 173 const sortIcon = helper.selectedAggregations[i].order === 'DESC' ? 174 'arrow_drop_down' : 175 'arrow_drop_up'; 176 selectedAggregationsDisplay.push(m( 177 'tr', 178 m('td', 179 { 180 draggable: 'true', 181 ondragstart: (e: DragEvent) => { 182 helper.selectedColumnOnDrag(e, false, i); 183 }, 184 ondrop: (e: DragEvent) => { 185 helper.removeHighlightFromDropLocation(e); 186 helper.selectedColumnOnDrop(e, false, i); 187 globals.rafScheduler.scheduleFullRedraw(); 188 }, 189 onclick: () => { 190 helper.selectPivotTableColumn(columnAttrs); 191 globals.rafScheduler.scheduleFullRedraw(); 192 }, 193 ondragenter: (e: DragEvent) => { 194 helper.highlightDropLocation(e, false); 195 }, 196 ondragleave: (e: DragEvent) => { 197 helper.removeHighlightFromDropLocation(e); 198 } 199 }, 200 m('i.material-icons', 201 { 202 onclick: () => { 203 helper.updatePivotTableColumnOnColumnAttributes(columnAttrs); 204 globals.rafScheduler.scheduleFullRedraw(); 205 }, 206 }, 207 'remove'), 208 ' ', 209 `${columnAttrs.tableName} ${columnAttrs.columnName} (${ 210 columnAttrs.aggregation})`, 211 m('i.material-icons', 212 { 213 onclick: () => { 214 helper.togglePivotTableAggregationSorting(i); 215 globals.rafScheduler.scheduleFullRedraw(); 216 } 217 }, 218 sortIcon)))); 219 } 220 221 return m( 222 'div', 223 m('section.table-group', 224 // Table that displays selected pivots. 225 m('table', 226 m('thead', m('tr', m('th', 'Selected Pivots'))), 227 m('div.scroll', m('tbody', selectedPivotsDisplay))), 228 // Table that displays selected aggregations. 229 m('table', 230 m('thead', m('tr', m('th', 'Selected Aggregations'))), 231 m('div.scroll', m('tbody', selectedAggregationsDisplay)))), 232 m('section.button-group', 233 // Button to toggle selected column. 234 m('button', 235 { 236 onclick: () => { 237 helper.queryPivotTableChanges(); 238 hideModel(); 239 } 240 }, 241 'Query'), 242 // Button to clear table and all selected columns. 243 m('button', 244 { 245 onclick: () => { 246 hideModel(); 247 } 248 }, 249 'Cancel'))); 250 } 251} 252