Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace dynamic-table renderer with ag-grid #2104

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/app/assets/css/redash.css
Original file line number Diff line number Diff line change
Expand Up @@ -731,5 +731,5 @@ div.table-name:hover {
}

visualization-renderer .pagination {
margin: 0;
margin: 5px 0;
}
2 changes: 1 addition & 1 deletion client/app/assets/less/inc/visualizations/misc.less
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
visualization-renderer .pagination {
margin: 0;
margin: 5px 0;
}
3 changes: 0 additions & 3 deletions client/app/components/dynamic-table/dynamic-table.css

This file was deleted.

45 changes: 16 additions & 29 deletions client/app/components/dynamic-table/dynamic-table.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
<div>
<table class="table table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="column in $ctrl.columns" ng-click="$ctrl.orderBy(column)" class="sortable-column">
{{column.title}} <span ng-if="$ctrl.sortIcon(column)"><i class="fa fa-sort-{{$ctrl.sortIcon(column)}}"></i></span>
</th>
</tr>

</thead>
<tbody>
<tr ng-repeat="row in $ctrl.rowsToDisplay">
<td ng-repeat="column in $ctrl.columns" ng-bind-html="$ctrl.sanitize(column.formatFunction(row[column.name]))">
</td>
</tr>
</tbody>
</table>
</div>
<div class="text-center" ng-if="$ctrl.rowsCount > $ctrl.itemsPerPage">
<ul uib-pagination total-items="$ctrl.rowsCount"
items-per-page="$ctrl.itemsPerPage"
ng-model="$ctrl.page"
max-size="6"
class="pagination"
boundary-link-numbers="true"
rotate="false"
next-text='&#8594;'
previous-text='&#8592;'
ng-change="$ctrl.pageChanged()"></ul>
<div class="dynamic-table-container">
<div class="ag-grid-container">
<div ag-grid="$ctrl.gridOptions" class="ag-theme-material"></div>
</div>
<div class="text-center" ng-if="$ctrl.rowsCount > $ctrl.itemsPerPage">
<ul uib-pagination total-items="$ctrl.rowsCount"
items-per-page="$ctrl.itemsPerPage"
ng-model="$ctrl.page"
max-size="6"
class="pagination"
boundary-link-numbers="true"
rotate="false"
next-text='&#8594;'
previous-text='&#8592;'
ng-change="$ctrl.pageChanged()"></ul>
</div>
</div>
18 changes: 18 additions & 0 deletions client/app/components/dynamic-table/dynamic-table.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.dynamic-table-container {
display: flex;
flex-direction: column;
height: 600px;

.ag-grid-container {
flex-grow: 1;
position: relative;

[ag-grid] {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
}
}
102 changes: 60 additions & 42 deletions client/app/components/dynamic-table/index.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,84 @@
import { sortBy } from 'underscore';
import * as _ from 'underscore';
import 'ag-grid/dist/styles/ag-grid.css';
import 'ag-grid/dist/styles/ag-theme-material.css';
import template from './dynamic-table.html';
import './dynamic-table.css';
import './dynamic-table.less';

function DynamicTable($sanitize) {
'ngInject';

this.itemsPerPage = this.count = 15;
this.itemsPerPage = 10;
this.page = 1;
this.rowsCount = 0;
this.orderByField = undefined;
this.orderByReverse = false;

this.pageChanged = () => {
const first = this.count * (this.page - 1);
const last = this.count * (this.page);

this.rowsToDisplay = this.rows.slice(first, last);
this.gridOptions = {
columnDefs: [],
rowData: [],
enableColResize: true,
// suppressMovableColumns: true,
suppressFieldDotNotation: true,
enableSorting: true,
suppressRowClickSelection: true,
suppressCellSelection: true,
suppressClickEdit: true,
pagination: true,
suppressPaginationPanel: true,
paginationPageSize: this.itemsPerPage,
suppressScrollOnNewData: true,
suppressDragLeaveHidesColumns: true,
suppressFocusAfterRefresh: true,
// domLayout: 'autoHeight',
};

this.$onChanges = (changes) => {
if (changes.columns) {
this.columns = changes.columns.currentValue;
}
const isNumericColumns = column => _.includes(
['integer', 'float', 'boolean', 'date', 'datetime'],
column.type,
);

if (changes.rows) {
this.rows = changes.rows.currentValue;
const updateColumns = (columns) => {
if (this.gridOptions.api) {
this.gridOptions.api.setRowData(null);
this.gridOptions.api.setColumnDefs(_.map(columns, col => ({
headerName: col.title,
field: col.name,
type: isNumericColumns(col) ? 'numericColumn' : '',
cellRenderer: params => $sanitize(params.value),
valueFormatter: params => (col.formatFunction
? col.formatFunction(params.value, col.type)
: params.value
),
})));
if (columns.length <= 4) {
setTimeout(() => {
this.gridOptions.api.sizeColumnsToFit();
}, 50);
}
}

this.rowsCount = this.rows.length;

this.pageChanged();
};

this.orderBy = (column) => {
if (column === this.orderByField) {
this.orderByReverse = !this.orderByReverse;
} else {
this.orderByField = column;
this.orderByReverse = false;
const updateData = (rows) => {
if (this.gridOptions.api) {
this.gridOptions.api.setRowData(rows);
}
};

if (this.orderByField) {
this.rows = sortBy(this.rows, this.orderByField.name);
if (this.orderByReverse) {
this.rows = this.rows.reverse();
}
this.pageChanged();
this.pageChanged = () => {
if (this.gridOptions.api) {
this.gridOptions.api.paginationGoToPage(this.page - 1);
}
};

this.sanitize = value => $sanitize(value);

this.sortIcon = (column) => {
if (column !== this.orderByField) {
return null;
this.$onChanges = (changes) => {
if (changes.columns) {
updateColumns(changes.columns.currentValue);
}

if (this.orderByReverse) {
return 'desc';
if (changes.rows) {
updateData(changes.rows.currentValue);
this.page = 1;
this.pageChanged();
}

return 'asc';
this.rowsCount = this.rows.length;
this.pageChanged();
};
}

Expand Down
4 changes: 4 additions & 0 deletions client/app/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'brace';
import 'angular-ui-ace';
import 'angular-resizable';
import ngGridster from 'angular-gridster';
import { initialiseAgGridWithAngular1 } from 'ag-grid';
import { each } from 'underscore';

import '@/lib/sortable';
Expand All @@ -30,6 +31,8 @@ import dashboardGridOptions from './dashboard-grid-options';

const logger = debug('redash:config');

initialiseAgGridWithAngular1(angular);

const requirements = [
ngRoute,
ngResource,
Expand All @@ -45,6 +48,7 @@ const requirements = [
vsRepeat,
'ui.sortable',
ngGridster.name,
'agGrid',
];

const ngModule = angular.module('app', requirements);
Expand Down
5 changes: 4 additions & 1 deletion client/app/visualizations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ function VisualizationRenderer(Visualization) {
// TODO: using switch here (and in the options editor) might introduce errors and bad
// performance wise. It's better to eventually show the correct template based on the
// visualization type and not make the browser render all of them.
template: `<filters filters="filters"></filters>\n${Visualization.renderVisualizationsTemplate}`,
template: `
<filters filters="filters"></filters>
${Visualization.renderVisualizationsTemplate}
`,
replace: false,
link(scope) {
scope.$watch('queryResult && queryResult.getFilters()', (filters) => {
Expand Down
Loading