Skip to content

Commit

Permalink
Table viz: editor UI
Browse files Browse the repository at this point in the history
  • Loading branch information
kravets-levko committed Dec 1, 2017
1 parent 127b45a commit 8fc3af7
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 82 deletions.
7 changes: 0 additions & 7 deletions client/app/filters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import moment from 'moment';
import _capitalize from 'underscore.string/capitalize';
import { isEmpty } from 'underscore';

// eslint-disable-next-line
const urlPattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;

export function durationHumanize(duration) {
let humanized = '';

Expand Down Expand Up @@ -67,10 +64,6 @@ export function capitalize(text) {
return null;
}

export function linkify(text) {
return text.replace(urlPattern, "$1<a href='$2' target='_blank'>$2</a>");
}

export function remove(items, item) {
if (items === undefined) {
return items;
Expand Down
1 change: 1 addition & 0 deletions client/app/lib/sortable.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ angular.module('ui.sortable', [])
// ng-repeat items
// if the user uses
items: '> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]',
cancel: 'input, textarea, button, select, option, .ui-sortable-bypass',
})
.directive('uiSortable', [
'uiSortableConfig', '$timeout', '$log',
Expand Down
6 changes: 0 additions & 6 deletions client/app/pages/queries/query.html
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,6 @@ <h3>
</div>
<div class="row">
<div class="col-lg-12">
<div ng-show="selectedTab == 'table'">
<filters filters="filters"></filters>
<div class="scrollbox">
<grid-renderer query-result="queryResult" items-per-page="50"></grid-renderer>
</div>
</div>
<div ng-if="selectedTab == vis.id" ng-repeat="vis in query.visualizations">
<visualization-renderer visualization="vis" query-result="queryResult"></visualization-renderer>
<div class="p-15">
Expand Down
10 changes: 6 additions & 4 deletions client/app/pages/queries/view.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { pick, any, some, find, values } from 'underscore';
import { pick, any, some, find, values, first } from 'underscore';
import template from './query.html';

function QueryViewCtrl(
$scope, Events, $route, $routeParams, $location, $window, $q,
KeyboardShortcuts, Title, AlertDialog, Notifications, clientConfig, toastr, $uibModal,
currentUser, Query, DataSource,
) {
const DEFAULT_TAB = 'table';

$scope.$watch('query', (query) => {
if (query) {
query.visualizations = values(query.visualizations).reverse();
Expand Down Expand Up @@ -366,7 +364,11 @@ function QueryViewCtrl(

$scope.$watch(
() => $location.hash(),
(hash) => { $scope.selectedTab = hash || DEFAULT_TAB; },
(hash) => {
// eslint-disable-next-line eqeqeq
const exists = find($scope.query.visualizations, item => item.id == hash);
$scope.selectedTab = exists ? hash : first($scope.query.visualizations).id;
},
);

$scope.showManagePermissionsModal = () => {
Expand Down
60 changes: 60 additions & 0 deletions client/app/visualizations/table/formats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import moment from 'moment/moment';
import numeral from 'numeral';
import _ from 'underscore';

// eslint-disable-next-line
const urlPattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;

function createDefaultFormatter(highlightLinks) {
if (highlightLinks) {
return (value) => {
if (_.isString(value)) {
value = value.replace(urlPattern, '$1<a href="$2" target="_blank">$2</a>');
}
return value;
};
}
return value => value;
}

function createDateTimeFormatter(format) {
if (_.isString(format) && (format !== '')) {
return (value) => {
if (value && moment.isMoment(value)) {
return value.format(format);
}
return value;
};
}
return value => value;
}

function createBooleanFormatter(values) {
if (_.isArray(values)) {
if (values.length >= 2) {
// Both `true` and `false` specified
return value => '' + values[value ? 1 : 0];
} else if (values.length === 1) {
// Only `true`
return value => (value ? values[0] : '');
}
}
return value => (value ? 'true' : 'false');
}

function createNumberFormatter(format) {
if (_.isString(format) && (format !== '')) {
const n = numeral(0); // cache `numeral` instance
return value => n.set(value).format(format);
}
return value => value;
}

export default function createFormatter(column) {
switch (column.displayAs) {
case 'number': return createNumberFormatter(column.numberFormat);
case 'boolean': return createBooleanFormatter(column.booleanValues);
case 'datetime': return createDateTimeFormatter(column.dateTimeFormat);
default: return createDefaultFormatter(column.allowHTML && column.highlightLinks);
}
}
99 changes: 54 additions & 45 deletions client/app/visualizations/table/index.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,52 @@
import moment from 'moment';
import _ from 'underscore';
import { getColumnCleanName } from '@/services/query-result';
import createFormatter from './formats';
import template from './table.html';
import editorTemplate from './table-editor.html';
import './table-editor.less';

function formatValue($filter, clientConfig, value, type) {
let formattedValue = value;
switch (type) {
case 'integer':
formattedValue = $filter('number')(value, 0);
break;
case 'float':
formattedValue = $filter('number')(value, 2);
break;
case 'boolean':
if (value !== undefined) {
formattedValue = String(value);
}
break;
case 'date':
if (value && moment.isMoment(value)) {
formattedValue = value.format(clientConfig.dateFormat);
}
break;
case 'datetime':
if (value && moment.isMoment(value)) {
formattedValue = value.format(clientConfig.dateTimeFormat);
}
break;
default:
if (_.isString(value)) {
formattedValue = $filter('linkify')(value);
}
break;
}

return formattedValue;
}

function getColumnContentAlignment(type) {
return ['integer', 'float', 'boolean', 'date', 'datetime'].indexOf(type) >= 0 ? 'right' : 'left';
}

function getDefaultColumnsOptions(columns) {
const displayAs = {
integer: 'number',
float: 'number',
boolean: 'boolean',
date: 'datetime',
datetime: 'datetime',
};

return _.map(columns, (col, index) => ({
name: col.name,
type: col.type,
displayAs: displayAs[col.type] || 'string',
visible: true,
order: 100000 + index,
title: getColumnCleanName(col.name),
allowHTML: false,
highlightLinks: false,
alignContent: getColumnContentAlignment(col.type),
}));
}

function getDefaultFormatOptions(column, clientConfig) {
const dateTimeFormat = {
date: clientConfig.dateFormat || 'DD/MM/YY',
datetime: clientConfig.dateTimeFormat || 'DD/MM/YY HH:mm',
};
const numberFormat = {
integer: clientConfig.integerFormat || '0,0',
float: clientConfig.floatFormat || '0,0.00',
};
return {
dateTimeFormat: dateTimeFormat[column.type],
numberFormat: numberFormat[column.type],
booleanValues: clientConfig.booleanValues || ['false', 'true'],
};
}

function getColumnsOptions(columns, visualizationColumns) {
const options = getDefaultColumnsOptions(columns);
visualizationColumns = _.object(_.map(
Expand All @@ -67,11 +59,18 @@ function getColumnsOptions(columns, visualizationColumns) {
return _.sortBy(options, 'order');
}

function getColumnsToDisplay(columns, options, $filter, clientConfig) {
function getColumnsToDisplay(columns, options, clientConfig) {
columns = _.object(_.map(columns, col => [col.name, col]));
const result = _.map(options, col => _.extend({}, col, columns[col.name], {
formatFunction: _.partial(formatValue, $filter, clientConfig, _, col.type),
let result = _.map(options, col => _.extend(
getDefaultFormatOptions(col, clientConfig),
col,
columns[col.name],
));

result = _.map(result, col => _.extend(col, {
formatFunction: createFormatter(col),
}));

return _.sortBy(_.filter(result, 'visible'), 'order');
}

Expand All @@ -84,7 +83,7 @@ function GridRenderer(clientConfig) {
},
template,
replace: false,
controller($scope, $filter) {
controller($scope) {
$scope.gridColumns = [];
$scope.gridRows = [];

Expand All @@ -101,7 +100,7 @@ function GridRenderer(clientConfig) {
columns,
_.extend({}, $scope.options).columns,
);
$scope.gridColumns = getColumnsToDisplay(columns, columnsOptions, $filter, clientConfig);
$scope.gridColumns = getColumnsToDisplay(columns, columnsOptions, clientConfig);
}
}

Expand All @@ -120,13 +119,23 @@ function GridRenderer(clientConfig) {
};
}

function GridEditor() {
function GridEditor(clientConfig) {
return {
restrict: 'E',
template: editorTemplate,
link: ($scope) => {
$scope.allowedItemsPerPage = [5, 10, 15, 20, 25];
$scope.allowedContentAlignment = ['left', 'center', 'right'];
$scope.displayAsOptions = [
{ name: 'Text', value: 'string' },
{ name: 'Number', value: 'number' },
{ name: 'Date/Time', value: 'datetime' },
{ name: 'Boolean', value: 'boolean' },
];

$scope.currentTab = 'grid';
$scope.setCurrentTab = (tab) => {
$scope.currentTab = tab;
};

$scope.$watch('queryResult && queryResult.getData()', (queryResult) => {
if (!queryResult) {
Expand All @@ -136,9 +145,9 @@ function GridEditor() {
$scope.visualization.options.columns = [];
} else {
const columns = $scope.queryResult.getColumns();
$scope.visualization.options.columns = getColumnsOptions(
columns,
$scope.visualization.options.columns,
$scope.visualization.options.columns = _.map(
getColumnsOptions(columns, $scope.visualization.options.columns),
col => _.extend(getDefaultFormatOptions(col, clientConfig), col),
);
}
});
Expand Down
Loading

0 comments on commit 8fc3af7

Please sign in to comment.