Merge branch 'master' into design/refinements-2

# Conflicts:
#	client/app/pages/dashboards/public-dashboard-page.html
This commit is contained in:
Zsolt Kocsmarszky 2017-11-25 06:27:52 +01:00
commit a488de22c4
19 changed files with 456 additions and 416 deletions

View File

@ -1,282 +1,282 @@
/* -------------------------------------------------------- /* --------------------------------------------------------
Paths Paths
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@imgpath: ~'../img'; @imgpath: ~'../img';
@fontpath: ~'../fonts'; @fontpath: ~'../fonts';
/* -------------------------------------------------------- /* --------------------------------------------------------
Container Container
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@container-tablet: 100%; @container-tablet: 100%;
@container-desktop: 100%; @container-desktop: 100%;
@container-large-desktop: 100%; @container-large-desktop: 100%;
/* -------------------------------------------------------- /* --------------------------------------------------------
Template Variables Template Variables
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@header-height: 50px; @header-height: 60px;
@footer-height: 95px; @footer-height: 95px;
@sidebar-left-width: 240px; @sidebar-left-width: 240px;
@sidebar-left-mid-width: 64px; @sidebar-left-mid-width: 64px;
@logo-width: @sidebar-left-width; @logo-width: @sidebar-left-width;
@logo-height: @header-height; @logo-height: @header-height;
@boxed-width: 1170px; @boxed-width: 1170px;
@body-bg: #edecec; @body-bg: #edecec;
/* -------------------------------------------------------- /* --------------------------------------------------------
Branding Branding
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@brand-bg: #191C22; @brand-bg: #191C22;
@sidebar: @brand-bg; @sidebar: @brand-bg;
@sidebar-active-bg: #121419; @sidebar-active-bg: #121419;
@color-dark: #9BA1B1; @color-dark: #9BA1B1;
/* -------------------------------------------------------- /* --------------------------------------------------------
Font Font
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@font-icon: 'Material-Design-Iconic-Font'; @font-icon: 'Material-Design-Iconic-Font';
@font-family-sans-serif: 'Roboto', sans-serif; @font-family-sans-serif: 'Roboto', sans-serif;
@font-size-base: 13px; @font-size-base: 13px;
/* -------------------------------------------------------- /* --------------------------------------------------------
Typograpgy Typograpgy
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@text-color: #767676; @text-color: #767676;
@link: #02a4c4; @link: #02a4c4;
@link-hover-decoration: none; @link-hover-decoration: none;
@headings-color: #333; @headings-color: #333;
/* -------------------------------------------------------- /* --------------------------------------------------------
Form Form
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@input-color-placeholder: #b4b4b4; @input-color-placeholder: #b4b4b4;
@input-border: #e8e8e8; @input-border: #e8e8e8;
@input-border-radius: 0; @input-border-radius: 0;
@input-border-radius-large: 0px; @input-border-radius-large: 0px;
@input-height-large: 40px; @input-height-large: 40px;
@input-height-base: 35px; @input-height-base: 35px;
@input-height-small: 30px; @input-height-small: 30px;
@input-border-focus: #79c2ff; @input-border-focus: #79c2ff;
@input-group-addon-bg: @light-gray; @input-group-addon-bg: @light-gray;
/* -------------------------------------------------------- /* --------------------------------------------------------
Colors Colors
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@white: #ffffff; @white: #ffffff;
@black: #000000; @black: #000000;
@blue: #2196F3; @blue: #2196F3;
@red: #F44336; @red: #F44336;
@purple: #9C27B0; @purple: #9C27B0;
@deeppurple: #673AB7; @deeppurple: #673AB7;
@lightblue: #03A9F4; @lightblue: #03A9F4;
@cyan: #00BCD4; @cyan: #00BCD4;
@teal: #009688; @teal: #009688;
@green: #4CAF50; @green: #4CAF50;
@lightgreen: #8BC34A; @lightgreen: #8BC34A;
@lime: #CDDC39; @lime: #CDDC39;
@yellow: #FFEB3B; @yellow: #FFEB3B;
@amber: #FFC107; @amber: #FFC107;
@orange: #FF9800; @orange: #FF9800;
@deeporange: #FF5722; @deeporange: #FF5722;
@gray: #9E9E9E; @gray: #9E9E9E;
@bluegray: #607D8B; @bluegray: #607D8B;
@indigo: #3F51B5; @indigo: #3F51B5;
@pink: #E91E63; @pink: #E91E63;
@brown: #795548; @brown: #795548;
@light-gray: #FCFCFC; @light-gray: #FCFCFC;
@gray-light: #828282; @gray-light: #828282;
@ace: #f8f8f8; @ace: #f8f8f8;
/** Form States **/ /** Form States **/
@state-success-text: @green; @state-success-text: @green;
@state-info-text: @blue; @state-info-text: @blue;
@state-danger-text: lighten(@red, 5%); @state-danger-text: lighten(@red, 5%);
@state-warning-text: @orange; @state-warning-text: @orange;
/* -------------------------------------------------------- /* --------------------------------------------------------
Alert Alert
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@alert-success-border: transparent; @alert-success-border: transparent;
@alert-info-border: transparent; @alert-info-border: transparent;
@alert-warning-border: transparent; @alert-warning-border: transparent;
@alert-danger-border: transparent; @alert-danger-border: transparent;
@alert-inverse-border: transparent; @alert-inverse-border: transparent;
@alert-success-bg: fade(@green, 70%); @alert-success-bg: fade(@green, 70%);
@alert-info-bg: fade(@blue, 70%); @alert-info-bg: fade(@blue, 70%);
@alert-warning-bg: fade(@amber, 70%); @alert-warning-bg: fade(@amber, 70%);
@alert-danger-bg: fade(@red, 70%); @alert-danger-bg: fade(@red, 70%);
@alert-inverse-bg: #333; @alert-inverse-bg: #333;
@alert-success-text: #fff; @alert-success-text: #fff;
@alert-info-text: #fff; @alert-info-text: #fff;
@alert-warning-text: #fff; @alert-warning-text: #fff;
@alert-danger-text: #fff; @alert-danger-text: #fff;
@alert-inverse-text: #fff; @alert-inverse-text: #fff;
/* -------------------------------------------------------- /* --------------------------------------------------------
Bootstrap Brands Bootstrap Brands
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@brand-default: #eee; @brand-default: #eee;
@brand-primary: @blue; @brand-primary: @blue;
@brand-info: @cyan; @brand-info: @cyan;
@brand-success: @green; @brand-success: @green;
@brand-warning: @orange; @brand-warning: @orange;
@brand-danger: @red; @brand-danger: @red;
/* -------------------------------------------------------- /* --------------------------------------------------------
Border Radius Border Radius
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@border-radius-base: 2px; @border-radius-base: 2px;
@border-radius-large: 2px; @border-radius-large: 2px;
@border-radius-small: 2px; @border-radius-small: 2px;
/* -------------------------------------------------------- /* --------------------------------------------------------
Dropdown Dropdown
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@dropdown-fallback-border: transparent; @dropdown-fallback-border: transparent;
@dropdown-border: transparent; @dropdown-border: transparent;
@dropdown-divider-bg: ''; @dropdown-divider-bg: '';
@dropdown-link-hover-bg: rgba(0,0,0,0.075); @dropdown-link-hover-bg: rgba(0,0,0,0.075);
@dropdown-link-color: #333; @dropdown-link-color: #333;
@dropdown-link-hover-color: #333; @dropdown-link-hover-color: #333;
@dropdown-link-disabled-color: #e4e4e4; @dropdown-link-disabled-color: #e4e4e4;
@dropdown-divider-bg: rgba(0,0,0,0.08); @dropdown-divider-bg: rgba(0,0,0,0.08);
@dropdown-link-active-color: #333; @dropdown-link-active-color: #333;
@dropdown-link-active-bg: rgba(0, 0, 0, 0.075); @dropdown-link-active-bg: rgba(0, 0, 0, 0.075);
@zindex-dropdown: 9; @zindex-dropdown: 9;
@dropdown-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); @dropdown-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
/* -------------------------------------------------------- /* --------------------------------------------------------
Page Header Page Header
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@page-header-border-color: transparent; @page-header-border-color: transparent;
/* -------------------------------------------------------- /* --------------------------------------------------------
Buttons Buttons
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@btn-default-border: @input-border; @btn-default-border: @input-border;
@btn-font-weight: 400; @btn-font-weight: 400;
/* -------------------------------------------------------- /* --------------------------------------------------------
Tables Tables
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@table-bg: #fff; @table-bg: #fff;
@table-border-color: #f0f0f0; @table-border-color: #f0f0f0;
@table-cell-padding: 10px; @table-cell-padding: 10px;
@table-condensed-cell-padding: 7px; @table-condensed-cell-padding: 7px;
@table-bg-accent: @light-gray; @table-bg-accent: @light-gray;
@table-bg-active: #FFFCBE; @table-bg-active: #FFFCBE;
@table-bg-hover: lighten(@light-gray, 2%); @table-bg-hover: lighten(@light-gray, 2%);
/* -------------------------------------------------------- /* --------------------------------------------------------
Pagination Pagination
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@pagination-bg: #E2E2E2; @pagination-bg: #E2E2E2;
@pagination-border: #fff; @pagination-border: #fff;
@pagination-color: #7E7E7E; @pagination-color: #7E7E7E;
@pagination-active-bg: @lightblue; @pagination-active-bg: @lightblue;
@pagination-active-border: @pagination-border; @pagination-active-border: @pagination-border;
@pagination-disabled-bg: #E2E2E2; @pagination-disabled-bg: #E2E2E2;
@pagination-disabled-border: @pagination-border; @pagination-disabled-border: @pagination-border;
@pagination-hover-color: #333; @pagination-hover-color: #333;
@pagination-hover-bg: #d7d7d7; @pagination-hover-bg: #d7d7d7;
@pagination-hover-border: @pagination-border; @pagination-hover-border: @pagination-border;
@pager-border-radius: 5px; @pager-border-radius: 5px;
/* -------------------------------------------------------- /* --------------------------------------------------------
Thumbnail Thumbnail
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@thumbnail-bg: #fff; @thumbnail-bg: #fff;
@thumbnail-border: #eee; @thumbnail-border: #eee;
/* -------------------------------------------------------- /* --------------------------------------------------------
Carousel Carousel
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@carousel-caption-color: #fff; @carousel-caption-color: #fff;
/* -------------------------------------------------------- /* --------------------------------------------------------
Modal Modal
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@modal-content-fallback-border-color: transparent; @modal-content-fallback-border-color: transparent;
@modal-content-border-color: transparent; @modal-content-border-color: transparent;
@modal-backdrop-bg: #000; @modal-backdrop-bg: #000;
@modal-header-border-color: transparent; @modal-header-border-color: transparent;
@modal-title-line-height: transparent; @modal-title-line-height: transparent;
@modal-footer-border-color: transparent; @modal-footer-border-color: transparent;
@zindex-modal-background: 10; @zindex-modal-background: 10;
/* -------------------------------------------------------- /* --------------------------------------------------------
Tooltips Tooltips
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@tooltip-bg: #333; @tooltip-bg: #333;
@tooltip-opacity: 1; @tooltip-opacity: 1;
/* -------------------------------------------------------- /* --------------------------------------------------------
Popobver Popobver
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@zindex-popover: 9; @zindex-popover: 9;
@popover-title-bg: #fff; @popover-title-bg: #fff;
@popover-border-color: #fff; @popover-border-color: #fff;
@popover-fallback-border-color: #fff; @popover-fallback-border-color: #fff;
/* -------------------------------------------------------- /* --------------------------------------------------------
Breacrumb Breacrumb
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@breadcrumb-bg: transparent; @breadcrumb-bg: transparent;
@breadcrumb-padding-horizontal: 20px; @breadcrumb-padding-horizontal: 20px;
@breadcrumb-active-color: #7c7c7c; @breadcrumb-active-color: #7c7c7c;
/* -------------------------------------------------------- /* --------------------------------------------------------
Jumbotron Jumbotron
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@jumbotron-bg: #F7F7F7; @jumbotron-bg: #F7F7F7;
/* -------------------------------------------------------- /* --------------------------------------------------------
List Group List Group
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@list-group-border: #f4f4f4; @list-group-border: #f4f4f4;
@list-group-active-color: #000; @list-group-active-color: #000;
@list-group-active-bg: #f5f5f5; @list-group-active-bg: #f5f5f5;
@list-group-active-border: @list-group-border; @list-group-active-border: @list-group-border;
@list-group-disabled-color: #B5B4B4; @list-group-disabled-color: #B5B4B4;
@list-group-disabled-bg: #fff; @list-group-disabled-bg: #fff;
@list-group-disabled-text-color: #B5B4B4; @list-group-disabled-text-color: #B5B4B4;
/* -------------------------------------------------------- /* --------------------------------------------------------
Badges Badges
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@badge-color: #fff; @badge-color: #fff;
@badge-bg: @brand-primary; @badge-bg: @brand-primary;
@badge-border-radius: 2px; @badge-border-radius: 2px;
@badge-font-weight: 400; @badge-font-weight: 400;
@badge-active-color: #fff; @badge-active-color: #fff;
@badge-active-bg: @brand-primary; @badge-active-bg: @brand-primary;
/* -------------------------------------------------------- /* --------------------------------------------------------
Misc Misc
-----------------------------------------------------------*/ -----------------------------------------------------------*/
@code-bg: transparent; @code-bg: transparent;
@tile-shadow: 0 1px 1px rgba(0,0,0,0.07); @tile-shadow: 0 1px 1px rgba(0,0,0,0.07);

View File

@ -0,0 +1,10 @@
cohort-renderer {
display: block;
text-align: center;
}
.cornelius-container {
display: inline-block;
padding: 0;
margin: 0 10px;
}

View File

@ -7,6 +7,7 @@ counter-renderer {
counter-renderer counter { counter-renderer counter {
margin: 0; margin: 0;
padding: 0;
display: block; display: block;
font-size: 80px; font-size: 80px;
overflow: hidden; overflow: hidden;

View File

@ -12,3 +12,8 @@
stroke: #000; stroke: #000;
stroke-opacity: .2; stroke-opacity: .2;
} }
.sankey-visualization-container {
height: 500px;
overflow: hidden;
}

View File

@ -0,0 +1,36 @@
.sunburst-visualization-container {
height: 400px;
display: flex;
flex-direction: column;
> div {
position: relative;
&:first-child {
flex-grow: 0;
}
&:last-child {
flex-grow: 1;
}
}
.sunburst-container,
.summary-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.summary-container {
font-size: 11px;
color: #666;
}
}

View File

@ -61,6 +61,8 @@
@import 'inc/visualizations/pivot-table'; @import 'inc/visualizations/pivot-table';
@import 'inc/visualizations/map'; @import 'inc/visualizations/map';
@import 'inc/visualizations/chart'; @import 'inc/visualizations/chart';
@import 'inc/visualizations/sunburst';
@import 'inc/visualizations/cohort';
@import 'inc/visualizations/misc'; @import 'inc/visualizations/misc';
/** VENDOR OVERRIDES **/ /** VENDOR OVERRIDES **/
@ -71,4 +73,4 @@
@import 'inc/vendor-overrides/ui-select'; @import 'inc/vendor-overrides/ui-select';
/** REDASH STYLING **/ /** REDASH STYLING **/
@import 'redash-newstyle'; @import 'redash-newstyle';

View File

@ -1,5 +1,5 @@
<nav class="navbar navbar-default app-header" role="navigation"> <nav class="navbar navbar-default app-header" role="navigation">
<div class="container""> <div class="container">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle" ng-click="isNavOpen = !isNavOpen"> <button type="button" class="navbar-toggle" ng-click="isNavOpen = !isNavOpen">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>

View File

@ -28,9 +28,8 @@ function Sunburst(scope, element) {
this.watches = []; this.watches = [];
// svg dimensions // svg dimensions
const width = element[0].parentElement.clientWidth; const width = element.clientWidth;
const height = scope.visualization.options.height; const height = element.offsetHeight;
const radius = Math.min(width, height) / 2;
// Breadcrumb dimensions: width, height, spacing, width of tip/tail. // Breadcrumb dimensions: width, height, spacing, width of tip/tail.
const b = { const b = {
@ -40,6 +39,11 @@ function Sunburst(scope, element) {
t: 10, t: 10,
}; };
const radius = Math.min(width - b.h, height - b.h) / 2 - 5;
if (radius <= 0) {
return;
}
// margins // margins
const margin = { const margin = {
top: radius, top: radius,
@ -77,14 +81,7 @@ function Sunburst(scope, element) {
* *
* e.g. vis, breadcrumbs, lastCrumb, summary, sunburst, legend * e.g. vis, breadcrumbs, lastCrumb, summary, sunburst, legend
*/ */
// create main vis selection const vis = d3.select(element);
const vis = d3
.select(element[0])
.append('div')
.classed('vis-container', true)
.style('position', 'relative')
.style('margin-top', '5px')
.style('height', `${height + 2 * b.h}px`);
// create and position breadcrumbs container and svg // create and position breadcrumbs container and svg
const breadcrumbs = vis const breadcrumbs = vis
@ -96,39 +93,26 @@ function Sunburst(scope, element) {
.attr('fill', 'white') .attr('fill', 'white')
.attr('font-weight', 600); .attr('font-weight', 600);
const marginLeft = (width - radius * 2) / 2;
// create and position SVG // create and position SVG
const sunburst = vis const container = vis.append('div');
// create and position summary container
const summary = container
.append('div')
.classed('summary-container', true);
const sunburst = container
.append('div') .append('div')
.classed('sunburst-container', true) .classed('sunburst-container', true)
.style('z-index', '2')
// .style("margin-left", marginLeft + "px")
.style('left', `${marginLeft}px`)
.style('position', 'absolute')
.append('svg') .append('svg')
.attr('width', width) .attr('width', radius * 2)
.attr('height', height) .attr('height', radius * 2)
.append('g') .append('g')
.attr('transform', `translate(${margin.left},${margin.top})`); .attr('transform', `translate(${margin.left},${margin.top})`);
// create last breadcrumb element // create last breadcrumb element
const lastCrumb = breadcrumbs.append('text').classed('lastCrumb', true); const lastCrumb = breadcrumbs.append('text').classed('lastCrumb', true);
// create and position summary container
const summary = vis
.append('div')
.classed('summary-container', true)
.style('position', 'absolute')
.style('top', `${b.h + radius * 0.8}px`)
.style('left', `${marginLeft + radius / 2}px`)
.style('width', `${radius}px`)
.style('height', `${radius}px`)
.style('text-align', 'center')
.style('font-size', '11px')
.style('color', '#666')
.style('z-index', '1');
// Generate a string representation for drawing a breadcrumb polygon. // Generate a string representation for drawing a breadcrumb polygon.
function breadcrumbPoints(d, i) { function breadcrumbPoints(d, i) {
const points = []; const points = [];
@ -208,8 +192,11 @@ function Sunburst(scope, element) {
.attr('opacity', 1); .attr('opacity', 1);
// update summary // update summary
summary.html(`Stage: ${d.depth}<br />` + summary.html(`
`<span class='percentage' style='font-size: 2em;'>${percentageString}</span><br />${d.value} of ${totalSize}<br />`); <span>Stage: ${d.depth}</span>
<span class='percentage' style='font-size: 2em;'>${percentageString}</span>
<span>${d.value} of ${totalSize}</span>
`);
// display summary and breadcrumbs if hidden // display summary and breadcrumbs if hidden
summary.style('visibility', ''); summary.style('visibility', '');
@ -394,7 +381,7 @@ Sunburst.prototype.remove = function remove() {
this.watches.forEach((unregister) => { this.watches.forEach((unregister) => {
unregister(); unregister();
}); });
angular.element(this.element[0]).empty('.vis-container'); angular.element(this.element).empty('.vis-container');
}; };
export default Sunburst; export default Sunburst;

View File

@ -1,12 +1,9 @@
.dashboard-wrapper { .dashboard-wrapper {
.tile { .tile {
position: absolute; display: flex;
left: 0; position: static;
top: 0; height: auto;
right: 0; margin-bottom: 15px;
bottom: 0;
margin: 0;
padding: 0;
} }
pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div { pivot-table-renderer > table, grid-renderer > div, visualization-renderer > div {
@ -31,36 +28,6 @@
} }
} }
.map-visualization-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
}
counter {
position: absolute;
left: 10px;
top: 15px;
right: 10px;
bottom: 15px;
overflow: hidden;
padding: 0;
}
.plotly-chart-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
height: auto;
overflow: hidden;
}
.gridster-preview-holder { .gridster-preview-holder {
background: #aaa; background: #aaa;
} }
@ -72,31 +39,46 @@
margin-left: 0 !important; margin-left: 0 !important;
margin-right: 0 !important; margin-right: 0 !important;
} }
.tile {
display: block;
position: static;
height: auto;
margin-bottom: 15px;
}
} }
&.gridster-mobile, .gridster-auto-height-enabled { &:not(.gridster-mobile) {
counter { .tile {
position: static; position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
overflow: hidden; overflow: hidden;
margin: 0;
padding: 0; padding: 0;
} }
.plotly-chart-container { .gridster-item:not(.gridster-auto-height-enabled) {
position: static; .sunburst-visualization-container,
height: 400px; .sankey-visualization-container,
overflow: hidden; .map-visualization-container,
} .plotly-chart-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
overflow: hidden;
}
.map-visualization-container { counter {
position: static; position: absolute;
height: 500px; left: 10px;
top: 15px;
right: 10px;
bottom: 15px;
overflow: hidden;
padding: 0;
}
} }
} }

View File

@ -1,4 +1,17 @@
<<<<<<< HEAD
<div class="container m-t-10"> <div class="container m-t-10">
=======
<!-- simple nav bar -->
<nav class="navbar navbar-inverse" role="navigation" ng-if="!$ctrl.headless">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/" target="_self"><img ng-src="{{$ctrl.logoUrl}}"/></a>
</div>
</div>
</nav>
<div class="container">
>>>>>>> master
<page-header title="{{$ctrl.dashboard.name}}"> <page-header title="{{$ctrl.dashboard.name}}">
</page-header> </page-header>
@ -16,5 +29,11 @@
</div> </div>
</div> </div>
<<<<<<< HEAD
<footer> <footer>
</footer> </footer>
=======
<style>
body { padding-bottom: 15px; }
</style>
>>>>>>> master

View File

@ -123,13 +123,6 @@
</ui-select> </ui-select>
</div> </div>
</div> </div>
<div class="form-group" ng-if="options.globalSeriesType == 'box'">
<label>
<label class="control-label">Graph Height</label>
<input name="graph-height" type="number" class="form-control" ng-model="options.height">
</label>
</div>
</div> </div>
<div class="form-group" ng-if="options.globalSeriesType == 'custom'"> <div class="form-group" ng-if="options.globalSeriesType == 'custom'">

View File

@ -65,10 +65,6 @@
</label> </label>
</div> </div>
<div class="form-group">
<label class="control-label">Map Height (px)</label>
<input class="form-control" type="number" ng-model="visualization.options.height"/>
</div>
<div class="form-group"> <div class="form-group">
<label class="control-label">Map Tiles</label> <label class="control-label">Map Tiles</label>
<select ng-options="tile.url as tile.name for tile in mapTiles" ng-model="visualization.options.mapTileUrl" <select ng-options="tile.url as tile.name for tile in mapTiles" ng-model="visualization.options.mapTileUrl"

View File

@ -1,6 +1,5 @@
import angular from 'angular'; import angular from 'angular';
import _ from 'underscore'; import _ from 'underscore';
import $ from 'jquery';
import d3 from 'd3'; import d3 from 'd3';
import d3sankey from '@/lib/visualizations/d3sankey'; import d3sankey from '@/lib/visualizations/d3sankey';
@ -95,12 +94,16 @@ function spreadNodes(height, data) {
}); });
} }
function createSankey(element, sankeyHeight, data) { function createSankey(element, data) {
const margin = { const margin = {
top: 10, right: 10, bottom: 10, left: 10, top: 10, right: 10, bottom: 10, left: 10,
}; };
const width = $(element).parent().width() - margin.left - margin.right; const width = element.offsetWidth - margin.left - margin.right;
const height = sankeyHeight - margin.top - margin.bottom; const height = element.offsetHeight - margin.top - margin.bottom;
if ((width <= 0) || (height <= 0)) {
return;
}
const format = d => d3.format(',.0f')(d); const format = d => d3.format(',.0f')(d);
const color = d3.scale.category20(); const color = d3.scale.category20();
@ -216,17 +219,20 @@ function createSankey(element, sankeyHeight, data) {
function sankeyRenderer() { function sankeyRenderer() {
return { return {
restrict: 'E', restrict: 'E',
template: '<div class="sankey-visualization-container" resize-event="handleResize()"></div>',
link(scope, element) { link(scope, element) {
const container = element[0].querySelector('.sankey-visualization-container');
function refreshData() { function refreshData() {
const queryData = scope.queryResult.getData(); const queryData = scope.queryResult.getData();
if (queryData) { if (queryData) {
// do the render logic. // do the render logic.
angular.element(element[0]).empty(); angular.element(container).empty();
createSankey(element[0], scope.visualization.options.height, queryData); createSankey(container, queryData);
} }
} }
angular.element(window).on('resize', refreshData); scope.handleResize = _.debounce(refreshData, 50);
scope.$watch('queryResult && queryResult.getData()', refreshData); scope.$watch('queryResult && queryResult.getData()', refreshData);
scope.$watch('visualization.options.height', (oldValue, newValue) => { scope.$watch('visualization.options.height', (oldValue, newValue) => {
if (oldValue !== newValue) { if (oldValue !== newValue) {
@ -250,11 +256,11 @@ export default function init(ngModule) {
ngModule.config((VisualizationProvider) => { ngModule.config((VisualizationProvider) => {
const renderTemplate = const renderTemplate =
'<sankey-renderer options="visualization.options" query-result="queryResult"></sankey-renderer>'; '<sankey-renderer options="visualization.options" query-result="queryResult"></sankey-renderer>';
const editTemplate = '<sankey-editor></sankey-editor>'; const editTemplate = '<sankey-editor></sankey-editor>';
const defaultOptions = { const defaultOptions = {
height: 300, defaultRows: 7,
}; };
VisualizationProvider.registerVisualization({ VisualizationProvider.registerVisualization({

View File

@ -1,12 +1,5 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group">
<label class="col-lg-6">Height</label>
<div class="col-lg-6">
<input type="number" ng-model="visualization.options.height" min="1" class="form-control">
</div>
</div>
<div> <div>
<hr>
This visualization expects the query result to have rows in the following format: This visualization expects the query result to have rows in the following format:
<ul> <ul>

View File

@ -1,19 +1,22 @@
import jQuery from 'jquery'; import { debounce } from 'underscore';
import Sunburst from '@/lib/visualizations/sunburst'; import Sunburst from '@/lib/visualizations/sunburst';
import editorTemplate from './sunburst-sequence-editor.html'; import editorTemplate from './sunburst-sequence-editor.html';
function sunburstSequenceRenderer() { function sunburstSequenceRenderer() {
return { return {
restrict: 'E', restrict: 'E',
template: '<div class="sunburst-visualization-container" resize-event="handleResize()"></div>',
link(scope, element) { link(scope, element) {
let sunburst = new Sunburst(scope, element); const container = element[0].querySelector('.sunburst-visualization-container');
let sunburst = new Sunburst(scope, container);
function resize() { function resize() {
sunburst.remove(); sunburst.remove();
sunburst = new Sunburst(scope, element); sunburst = new Sunburst(scope, container);
} }
jQuery(window).on('resize', resize); scope.handleResize = debounce(resize, 50);
scope.$watch('visualization.options.height', (oldValue, newValue) => { scope.$watch('visualization.options.height', (oldValue, newValue) => {
if (oldValue !== newValue) { if (oldValue !== newValue) {
resize(); resize();
@ -40,7 +43,7 @@ export default function init(ngModule) {
const editTemplate = '<sunburst-sequence-editor></sunburst-sequence-editor>'; const editTemplate = '<sunburst-sequence-editor></sunburst-sequence-editor>';
const defaultOptions = { const defaultOptions = {
height: 300, defaultRows: 7,
}; };
VisualizationProvider.registerVisualization({ VisualizationProvider.registerVisualization({

View File

@ -1,12 +1,5 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="form-group">
<label class="col-lg-6">Height</label>
<div class="col-lg-6">
<input type="number" ng-model="visualization.options.height" min="1" class="form-control">
</div>
</div>
<div> <div>
<hr>
This visualization expects the query result to have rows in one of the following formats: This visualization expects the query result to have rows in one of the following formats:
<strong>Option 1:</strong> <strong>Option 1:</strong>

View File

@ -238,5 +238,15 @@ class Redshift(PostgreSQL):
return schema.values() return schema.values()
class CockroachDB(PostgreSQL):
def __init__(self, configuration):
super(CockroachDB, self).__init__(configuration)
@classmethod
def type(cls):
return "cockroach"
register(PostgreSQL) register(PostgreSQL)
register(Redshift) register(Redshift)
register(CockroachDB)

View File

@ -43,7 +43,7 @@ def _guess_type(value):
def extract_query_ids(query): def extract_query_ids(query):
queries = re.findall(r'(?:join|from) query_(\d+)', query, re.IGNORECASE) queries = re.findall(r'(?:join|from)\s+query_(\d+)', query, re.IGNORECASE)
return [int(q) for q in queries] return [int(q) for q in queries]

View File

@ -19,6 +19,10 @@ class TestExtractQueryIds(TestCase):
query = "SELECT * FROM query_123 JOIN query_4566" query = "SELECT * FROM query_123 JOIN query_4566"
self.assertEquals([123, 4566], extract_query_ids(query)) self.assertEquals([123, 4566], extract_query_ids(query))
def test_finds_queries_with_whitespace_characters(self):
query = "SELECT * FROM query_123 a JOIN\tquery_4566 b ON a.id=b.parent_id JOIN\r\nquery_78 c ON b.id=c.parent_id"
self.assertEquals([123, 4566, 78], extract_query_ids(query))
class TestCreateTable(TestCase): class TestCreateTable(TestCase):
def test_creates_table_with_colons_in_column_name(self): def test_creates_table_with_colons_in_column_name(self):