// Copyright (C) 2021 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import * as m from 'mithril'; import {isStackPivot} from '../common/pivot_table_common'; import {globals} from './globals'; import {hideModel} from './modal'; import { PivotTableHelper, } from './pivot_table_helper'; interface PivotTableEditorAttrs { helper: PivotTableHelper; } export class ColumnPicker implements m.ClassComponent { view(vnode: m.Vnode) { const {helper} = vnode.attrs; // Fills available aggregations options in aggregation select. const aggregationOptions = []; for (const aggregation of helper.availableAggregations) { aggregationOptions.push( m('option', {value: aggregation, key: aggregation}, aggregation)); } // Fills available columns options divided according to their table in // column select. const columnOptionGroup = []; for (const {tableName, columns} of helper.availableColumns) { const options = []; for (const column of columns) { // We can't aggregate a stack column. const hidden = !helper.isPivot && isStackPivot(tableName, column); options.push(m('option', {value: column, key: column, hidden}, column)); } columnOptionGroup.push(m('optgroup', {label: tableName}, options)); } return m( 'div', m( 'section', m('h2', 'Select column type: '), // Pivot radio button. m( 'span', m(`input[type=radio][name=type][id=pivot]`, { checked: helper.isPivot, onchange: () => { helper.togglePivotSelection(); globals.rafScheduler.scheduleFullRedraw(); } }), m(`label[for=pivot]`, 'Pivot'), ), // Aggregation radio button. m('span', m(`input[type=radio][name=type][id=aggregation]`, { checked: !helper.isPivot, onchange: () => { helper.togglePivotSelection(); globals.rafScheduler.scheduleFullRedraw(); } })), m(`label[for=aggregation]`, 'Aggregation'), ), m( 'section', m('h2', 'Select a column: '), // Aggregation select. m('select', { disabled: helper.isPivot, selectedIndex: helper.selectedAggregationIndex, onchange: (e: InputEvent) => { helper.setSelectedPivotTableAggregationIndex( (e.target as HTMLSelectElement).selectedIndex); } }, aggregationOptions), ' ', // Column select. m('select', { selectedIndex: helper.selectedColumnIndex, onchange: (e: InputEvent) => { helper.setSelectedPivotTableColumnIndex( (e.target as HTMLSelectElement).selectedIndex); } }, columnOptionGroup), ), m('section.button-group', // Button to toggle selected column. m('button', { onclick: () => { helper.updatePivotTableColumnOnSelectedIndex(); globals.rafScheduler.scheduleFullRedraw(); } }, 'Add/Remove'), // Button to clear table and all selected columns. m('button', { onclick: () => { helper.clearPivotTableColumns(); globals.rafScheduler.scheduleFullRedraw(); } }, 'Clear'))); } } export class ColumnDisplay implements m.ClassComponent { view(vnode: m.Vnode) { const {helper} = vnode.attrs; const selectedPivotsDisplay = []; const selectedAggregationsDisplay = []; for (let i = 0; i < helper.selectedPivots.length; ++i) { const columnAttrs = helper.selectedPivots[i]; selectedPivotsDisplay.push(m( 'tr', m('td', { draggable: true, ondragstart: (e: DragEvent) => { helper.selectedColumnOnDrag(e, true, i); }, ondrop: (e: DragEvent) => { helper.removeHighlightFromDropLocation(e); helper.selectedColumnOnDrop(e, true, i); globals.rafScheduler.scheduleFullRedraw(); }, onclick: () => { helper.selectPivotTableColumn(columnAttrs); globals.rafScheduler.scheduleFullRedraw(); }, ondragenter: (e: DragEvent) => { helper.highlightDropLocation(e, true); }, ondragleave: (e: DragEvent) => { helper.removeHighlightFromDropLocation(e); } }, m('i.material-icons', { onclick: () => { helper.updatePivotTableColumnOnColumnAttributes(columnAttrs); globals.rafScheduler.scheduleFullRedraw(); }, }, 'remove'), ' ', `${columnAttrs.tableName} ${columnAttrs.columnName}`))); } for (let i = 0; i < helper.selectedAggregations.length; ++i) { const columnAttrs = helper.selectedAggregations[i]; const sortIcon = helper.selectedAggregations[i].order === 'DESC' ? 'arrow_drop_down' : 'arrow_drop_up'; selectedAggregationsDisplay.push(m( 'tr', m('td', { draggable: 'true', ondragstart: (e: DragEvent) => { helper.selectedColumnOnDrag(e, false, i); }, ondrop: (e: DragEvent) => { helper.removeHighlightFromDropLocation(e); helper.selectedColumnOnDrop(e, false, i); globals.rafScheduler.scheduleFullRedraw(); }, onclick: () => { helper.selectPivotTableColumn(columnAttrs); globals.rafScheduler.scheduleFullRedraw(); }, ondragenter: (e: DragEvent) => { helper.highlightDropLocation(e, false); }, ondragleave: (e: DragEvent) => { helper.removeHighlightFromDropLocation(e); } }, m('i.material-icons', { onclick: () => { helper.updatePivotTableColumnOnColumnAttributes(columnAttrs); globals.rafScheduler.scheduleFullRedraw(); }, }, 'remove'), ' ', `${columnAttrs.tableName} ${columnAttrs.columnName} (${ columnAttrs.aggregation})`, m('i.material-icons', { onclick: () => { helper.togglePivotTableAggregationSorting(i); globals.rafScheduler.scheduleFullRedraw(); } }, sortIcon)))); } return m( 'div', m('section.table-group', // Table that displays selected pivots. m('table', m('thead', m('tr', m('th', 'Selected Pivots'))), m('div.scroll', m('tbody', selectedPivotsDisplay))), // Table that displays selected aggregations. m('table', m('thead', m('tr', m('th', 'Selected Aggregations'))), m('div.scroll', m('tbody', selectedAggregationsDisplay)))), m('section.button-group', // Button to toggle selected column. m('button', { onclick: () => { helper.queryPivotTableChanges(); hideModel(); } }, 'Query'), // Button to clear table and all selected columns. m('button', { onclick: () => { hideModel(); } }, 'Cancel'))); } }