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

Migrate visualizations registry/renderer/editor to React #3493

Merged
merged 52 commits into from
Apr 30, 2019
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d415506
Migrate visualizations registry/renderer/editor to React (base for fo…
kravets-levko Feb 25, 2019
8e0d8ff
Word Cloud
kravets-levko Feb 28, 2019
1a773f4
Sunburst
kravets-levko Feb 28, 2019
f9e97d3
Sankey
kravets-levko Feb 28, 2019
1b6a796
Cohort
kravets-levko Feb 28, 2019
fe43eff
Funnel
kravets-levko Feb 28, 2019
46518f0
BoxPlot (Deprecated)
kravets-levko Feb 28, 2019
962989e
Pivot
kravets-levko Mar 1, 2019
669d944
Map
kravets-levko Mar 1, 2019
5787088
Choropleth
kravets-levko Mar 1, 2019
d5668c3
Chart
kravets-levko Mar 4, 2019
8b6e065
Cleanup
kravets-levko Mar 5, 2019
78a15c7
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 5, 2019
2c614e8
Pivot editor
kravets-levko Mar 5, 2019
b53bbeb
Fix filters
kravets-levko Mar 5, 2019
7df32c6
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 5, 2019
968b70f
Refine code
kravets-levko Mar 5, 2019
ce74b08
Avoid infinite sync loop when map bounds updated
kravets-levko Mar 5, 2019
34705c7
Remove redundant code
kravets-levko Mar 5, 2019
f6c6d80
Optimize Pivot table updates
kravets-levko Mar 5, 2019
3ceea26
Word Cloud: editor in React; Box plot: fix rendering, editor in React
kravets-levko Mar 5, 2019
c2ee55b
EditVisualizationDialog fixes
kravets-levko Mar 5, 2019
7e28ab5
Fix ColorBox component
kravets-levko Mar 5, 2019
5c35f1a
Fix Pivot, Sankey and Sunburst errors
kravets-levko Mar 6, 2019
ab3a7ea
Move grid optsettings from options to visualization config; fix auto-…
kravets-levko Mar 6, 2019
c63f481
Fix Sunburst error; fix editors
kravets-levko Mar 6, 2019
1325785
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 7, 2019
46e2a5f
Fix Word Cloud rendering bug
kravets-levko Mar 7, 2019
cc47139
Word Cloud: predictive words sizes
kravets-levko Mar 7, 2019
bfd92c4
Visualization Editor improvements
kravets-levko Mar 10, 2019
5981c07
Update dashboard-level filters when widget added/removed
kravets-levko Mar 10, 2019
0085ed9
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 10, 2019
3a350f0
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 25, 2019
25d8828
Edit Visualization Dialog tests
kravets-levko Mar 25, 2019
0b76bd5
Tests: Sunburst, Sankey
kravets-levko Mar 25, 2019
114aa73
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 26, 2019
bfbec29
Test: refactoring
kravets-levko Mar 26, 2019
cb23ce7
Tests: fix errors
kravets-levko Mar 26, 2019
e9ecd91
Tests: more precise selectors
kravets-levko Mar 26, 2019
bc09795
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 26, 2019
aa81662
Tests: Pivot
kravets-levko Mar 27, 2019
9dac277
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Mar 28, 2019
04aba81
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Apr 1, 2019
4ea94b3
Fix markup; allow searching filter values
kravets-levko Apr 15, 2019
d9c56e5
Fix filters behavior on Query page and in Edit visualization dialog
kravets-levko Apr 15, 2019
cabb247
Fix bugs in Word Cound and Funnel
kravets-levko Apr 17, 2019
a0ff04e
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Apr 17, 2019
5bb3d01
Remove unused function
kravets-levko Apr 17, 2019
a771ef5
Fix linter errors
kravets-levko Apr 17, 2019
03057dc
Restore missing component
kravets-levko Apr 17, 2019
ddbd162
Fix tests
kravets-levko Apr 17, 2019
d510aa4
Merge branch 'master' into feature/migrate-visualizations
kravets-levko Apr 30, 2019
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
68 changes: 54 additions & 14 deletions client/app/assets/less/ant.less
Original file line number Diff line number Diff line change
Expand Up @@ -221,21 +221,61 @@
}
}

// styling for short modals (no lines)
.@{dialog-prefix-cls}.shortModal {
.@{dialog-prefix-cls} {
&-header,
&-footer {
border: none;
padding: 16px;
}
&-body {
padding: 10px 16px;
.@{dialog-prefix-cls} {
// styling for short modals (no lines)
&.shortModal {
.@{dialog-prefix-cls} {
&-header,
&-footer {
border: none;
padding: 16px;
}

&-body {
padding: 10px 16px;
}

&-close-x {
width: 46px;
height: 46px;
line-height: 46px;
}
}
&-close-x {
width: 46px;
height: 46px;
line-height: 46px;
}

// fullscreen modals
&-fullscreen {
.@{dialog-prefix-cls} {
position: absolute;
left: 15px;
top: 15px;
right: 15px;
bottom: 15px;
width: auto !important;
height: auto !important;
max-width: none;
max-height: none;
margin: 0;
padding: 0;

.@{dialog-prefix-cls}-content {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
}

.@{dialog-prefix-cls}-body {
flex: 1 1 auto;
overflow: auto;
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions client/app/assets/less/inc/visualizations/misc.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
visualization-renderer {
display: block;

.pagination,
.ant-pagination {
margin: 0;
Expand Down
2 changes: 1 addition & 1 deletion client/app/assets/less/inc/visualizations/pivot-table.less
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
.pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
overflow: auto;
}
4 changes: 2 additions & 2 deletions client/app/assets/less/redash/query.less
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ edit-in-place p.editable:hover {

.widget-wrapper {
.body-container {
filters {
.filters-wrapper {
display: block;
padding-left: 15px;
}
Expand Down Expand Up @@ -336,7 +336,7 @@ a.label-tag {
border-bottom: 1px solid #efefef;
}

pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
.pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
overflow: visible;
}

Expand Down
23 changes: 23 additions & 0 deletions client/app/components/ColorBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';

import './color-box.less';

export function ColorBox({ color }) {
return <span style={{ backgroundColor: color }} />;
}

ColorBox.propTypes = {
color: PropTypes.string,
};

ColorBox.defaultProps = {
color: 'transparent',
};

export default function init(ngModule) {
ngModule.component('colorBox', react2angular(ColorBox));
}

init.init = true;
122 changes: 122 additions & 0 deletions client/app/components/Filters.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { isArray, map, includes, every, some } from 'lodash';
import moment from 'moment';
import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import Select from 'antd/lib/select';

const ALL_VALUES = '###Redash::Filters::SelectAll###';
const NONE_VALUES = '###Redash::Filters::Clear###';

export const FilterType = PropTypes.shape({
name: PropTypes.string.isRequired,
friendlyName: PropTypes.string.isRequired,
multiple: PropTypes.bool,
current: PropTypes.oneOfType([
PropTypes.any,
PropTypes.arrayOf(PropTypes.any),
]).isRequired,
values: PropTypes.arrayOf(PropTypes.any).isRequired,
});

export const FiltersType = PropTypes.arrayOf(FilterType);

function createFilterChangeHandler(filters, onChange) {
return (filter, value) => {
if (filter.multiple && includes(value, ALL_VALUES)) {
value = [...filter.values];
}
if (filter.multiple && includes(value, NONE_VALUES)) {
value = [];
}
filters = map(filters, f => (f.name === filter.name ? { ...filter, current: value } : f));
onChange(filters);
};
}

export function filterData(rows, filters = []) {
if (!isArray(rows)) {
return [];
}

let result = rows;

if (isArray(filters) && (filters.length > 0)) {
// "every" field's value should match "some" of corresponding filter's values
result = result.filter(row => every(
filters,
(filter) => {
const rowValue = row[filter.name];
const filterValues = isArray(filter.current) ? filter.current : [filter.current];
return some(filterValues, (filterValue) => {
if (moment.isMoment(rowValue)) {
return rowValue.isSame(filterValue);
}
// We compare with either the value or the String representation of the value,
// because Select2 casts true/false to "true"/"false".
return (filterValue === rowValue) || (String(rowValue) === filterValue);
});
},
));
}

return result;
}

export function Filters({ filters, onChange }) {
if (filters.length === 0) {
return null;
}

onChange = createFilterChangeHandler(filters, onChange);

return (
<div className="filters-wrapper">
<div className="parameter-container container bg-white">
<div className="row">
{map(filters, (filter) => {
const options = map(filter.values, value => (
<Select.Option key={value}>{value}</Select.Option>
));

return (
<div key={filter.name} className="col-sm-6 p-l-0 filter-container">
<label>{filter.friendlyName}</label>
<Select
className="w-100"
mode={filter.multiple ? 'multiple' : 'default'}
value={filter.current}
allowClear={filter.multiple}
showSearch
onChange={value => onChange(filter, value)}
>
{!filter.multiple && options}
{filter.multiple && [
<Select.Option key={NONE_VALUES}><i className="fa fa-square-o m-r-5" />Clear</Select.Option>,
<Select.Option key={ALL_VALUES}><i className="fa fa-check-square-o m-r-5" />Select All</Select.Option>,
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
<Select.OptGroup key="Values" title="Values">{options}</Select.OptGroup>,
]}
</Select>
</div>
);
})}
</div>
</div>
</div>
);
}

Filters.propTypes = {
filters: FiltersType.isRequired,
onChange: PropTypes.func, // (name, value) => void
};

Filters.defaultProps = {
onChange: () => {},
};

export default function init(ngModule) {
ngModule.component('filters', react2angular(Filters));
}

init.init = true;
8 changes: 8 additions & 0 deletions client/app/components/color-box.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
color-box {
span {
width: 12px !important;
height: 12px !important;
display: inline-block !important;
margin-right: 5px;
}
}
6 changes: 5 additions & 1 deletion client/app/components/dashboards/widget.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@
<div class="alert alert-danger m-5" ng-show="$ctrl.widget.getQueryResult().getError()">Error running query: <strong>{{$ctrl.widget.getQueryResult().getError()}}</strong></div>
</div>
<div ng-switch-when="done" class="body-row-auto scrollbox">
<visualization-renderer visualization="$ctrl.widget.visualization" query-result="$ctrl.widget.getQueryResult()" class="t-body"></visualization-renderer>
<visualization-renderer class="t-body"
visualization="$ctrl.widget.visualization"
query-result="$ctrl.widget.getQueryResult()"
filters="$ctrl.filters"
></visualization-renderer>
</div>
<div ng-switch-default class="body-row-auto spinner-container">
<div class="spinner">
Expand Down
1 change: 1 addition & 0 deletions client/app/components/dashboards/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export default function init(ngModule) {
widget: '<',
public: '<',
dashboard: '<',
filters: '<',
deleted: '&onDelete',
},
});
Expand Down
44 changes: 0 additions & 44 deletions client/app/components/filters.html

This file was deleted.

30 changes: 0 additions & 30 deletions client/app/components/filters.js

This file was deleted.

30 changes: 30 additions & 0 deletions client/app/lib/hooks/useQueryResult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useState, useEffect } from 'react';

function getQueryResultData(queryResult) {
return {
columns: queryResult ? queryResult.getColumns() : [],
rows: queryResult ? queryResult.getData() : [],
filters: queryResult ? queryResult.getFilters() : [],
};
}

export default function useQueryResult(queryResult) {
const [data, setData] = useState(getQueryResultData(queryResult));
let isCancelled = false;
useEffect(() => {
if (queryResult) {
queryResult.toPromise()
.then(() => {
if (!isCancelled) {
setData(getQueryResultData(queryResult));
}
});
} else {
setData(getQueryResultData(queryResult));
}
return () => {
isCancelled = true;
};
}, [queryResult]);
return data;
}
Loading