mirror of https://github.com/apache/superset.git
[js linting] use airbnb eslint settings (#796)
* add airbnb eslint settings and lint all the code * fix linting erros
This commit is contained in:
parent
f43e5f18d5
commit
1101de5ae4
|
@ -1,3 +1,6 @@
|
||||||
node_modules/*
|
node_modules/*
|
||||||
vendor/*
|
vendor/*
|
||||||
javascripts/dist/*
|
javascripts/dist/*
|
||||||
|
visualizations/*
|
||||||
|
stylesheets/*
|
||||||
|
spec/*
|
||||||
|
|
|
@ -1,234 +1,12 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"extends": "airbnb",
|
||||||
|
|
||||||
"globals": {
|
|
||||||
"Symbol": false,
|
|
||||||
"Map": false,
|
|
||||||
"Set": false,
|
|
||||||
"Reflect": false,
|
|
||||||
},
|
|
||||||
|
|
||||||
"env": {
|
|
||||||
"es6": false,
|
|
||||||
"browser": true,
|
|
||||||
"node": true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 5,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"array-bracket-spacing": [2, "never", {
|
"prefer-template": 0,
|
||||||
"singleValue": false,
|
"new-cap": 0,
|
||||||
"objectsInArrays": false,
|
"no-restricted-syntax": 0,
|
||||||
"arraysInArrays": false
|
"guard-for-in": 0,
|
||||||
}],
|
"prefer-arrow-callback": 0,
|
||||||
"array-callback-return": [2],
|
"func-names": 0,
|
||||||
"block-spacing": [2, "always"],
|
"react/jsx-no-bind": 0,
|
||||||
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
|
}
|
||||||
"callback-return": [2, ["callback"]],
|
|
||||||
"camelcase": [0],
|
|
||||||
"comma-dangle": [2, "always-multiline"],
|
|
||||||
"comma-spacing": [2],
|
|
||||||
"comma-style": [2, "last"],
|
|
||||||
"curly": [2, "all"],
|
|
||||||
"eqeqeq": 2,
|
|
||||||
"func-names": [0],
|
|
||||||
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
|
|
||||||
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
|
|
||||||
"keyword-spacing": [2, {
|
|
||||||
"before": true,
|
|
||||||
"after": true,
|
|
||||||
"overrides": {
|
|
||||||
"return": { "after": true },
|
|
||||||
"throw": { "after": true },
|
|
||||||
"case": { "after": true }
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"linebreak-style": [2, "unix"],
|
|
||||||
"lines-around-comment": [2, {
|
|
||||||
"beforeBlockComment": false,
|
|
||||||
"afterBlockComment": false,
|
|
||||||
"beforeLineComment": false,
|
|
||||||
"allowBlockStart": true,
|
|
||||||
"allowBlockEnd": true
|
|
||||||
}],
|
|
||||||
"max-depth": [2, 5],
|
|
||||||
"max-len": [0, 80, 4],
|
|
||||||
"max-nested-callbacks": [1, 3],
|
|
||||||
"max-params": [1, 4],
|
|
||||||
"new-parens": [2],
|
|
||||||
"newline-after-var": [0],
|
|
||||||
"no-bitwise": [0],
|
|
||||||
"no-cond-assign": [2],
|
|
||||||
"no-console": [1, { allow: ["warn", "error"] }],
|
|
||||||
"no-const-assign": [2],
|
|
||||||
"no-constant-condition": [2],
|
|
||||||
"no-control-regex": [2],
|
|
||||||
"no-debugger": [2],
|
|
||||||
"no-delete-var": [2],
|
|
||||||
"no-dupe-args": [2],
|
|
||||||
"no-dupe-class-members": [2],
|
|
||||||
"no-dupe-keys": [2],
|
|
||||||
"no-duplicate-case": [2],
|
|
||||||
"no-else-return": [0],
|
|
||||||
"no-empty": [2],
|
|
||||||
"no-eq-null": [0],
|
|
||||||
"no-eval": [2],
|
|
||||||
"no-ex-assign": [2],
|
|
||||||
"no-extend-native": [2],
|
|
||||||
"no-extra-bind": [2],
|
|
||||||
"no-extra-boolean-cast": [2],
|
|
||||||
"no-extra-label": [2],
|
|
||||||
"no-extra-parens": [0], // needed for clearer #math eg (a - b) / c
|
|
||||||
"no-extra-semi": [2],
|
|
||||||
"no-fallthrough": [2],
|
|
||||||
"no-floating-decimal": [2],
|
|
||||||
"no-func-assign": [2],
|
|
||||||
"no-implied-eval": [2],
|
|
||||||
"no-implicit-coercion": [2, {
|
|
||||||
"boolean": false,
|
|
||||||
"number": true,
|
|
||||||
"string": true
|
|
||||||
}],
|
|
||||||
"no-implicit-globals": [2],
|
|
||||||
"no-inline-comments": [0],
|
|
||||||
"no-invalid-regexp": [2],
|
|
||||||
"no-irregular-whitespace": [2],
|
|
||||||
"no-iterator": [2],
|
|
||||||
"no-label-var": [2],
|
|
||||||
"no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
|
|
||||||
"no-lone-blocks": [2],
|
|
||||||
"no-lonely-if": [2],
|
|
||||||
"no-loop-func": [2],
|
|
||||||
"no-magic-numbers": [0], // doesn't work well with vis cosmetic constant
|
|
||||||
"no-mixed-requires": [1, false],
|
|
||||||
"no-mixed-spaces-and-tabs": [2, false],
|
|
||||||
"no-multi-spaces": [2, {
|
|
||||||
"exceptions": {
|
|
||||||
"ImportDeclaration": true,
|
|
||||||
"Property": true,
|
|
||||||
"VariableDeclarator": true
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"no-multi-str": [2],
|
|
||||||
"no-multiple-empty-lines": [2, { "max": 1, "maxEOF": 1 }],
|
|
||||||
"no-native-reassign": [2],
|
|
||||||
"no-negated-condition": [2],
|
|
||||||
"no-negated-in-lhs": [2],
|
|
||||||
"no-nested-ternary": [0],
|
|
||||||
"no-new": [2],
|
|
||||||
"no-new-func": [2],
|
|
||||||
"no-new-object": [2],
|
|
||||||
"no-new-require": [0],
|
|
||||||
"no-new-symbol": [2],
|
|
||||||
"no-new-wrappers": [2],
|
|
||||||
"no-obj-calls": [2],
|
|
||||||
"no-octal": [2],
|
|
||||||
"no-octal-escape": [2],
|
|
||||||
"no-path-concat": [0],
|
|
||||||
"no-process-env": [0],
|
|
||||||
"no-process-exit": [2],
|
|
||||||
"no-proto": [2],
|
|
||||||
"no-redeclare": [2],
|
|
||||||
"no-regex-spaces": [2],
|
|
||||||
"no-restricted-modules": [0],
|
|
||||||
"no-restricted-imports": [0],
|
|
||||||
"no-restricted-syntax": [2,
|
|
||||||
"DebuggerStatement",
|
|
||||||
"LabeledStatement",
|
|
||||||
"WithStatement"
|
|
||||||
],
|
|
||||||
"no-return-assign": [2, "always"],
|
|
||||||
"no-script-url": [2],
|
|
||||||
"no-self-assign": [2],
|
|
||||||
"no-self-compare": [0],
|
|
||||||
"no-sequences": [2],
|
|
||||||
"no-shadow-restricted-names": [2],
|
|
||||||
"no-spaced-func": [2],
|
|
||||||
"no-sparse-arrays": [2],
|
|
||||||
"no-sync": [0],
|
|
||||||
"no-ternary": [0],
|
|
||||||
"no-this-before-super": [2],
|
|
||||||
"no-throw-literal": [2],
|
|
||||||
"no-trailing-spaces": [2, { "skipBlankLines": false }],
|
|
||||||
"no-undef": [2, { "typeof": true }],
|
|
||||||
"no-undef-init": [2],
|
|
||||||
"no-undefined": [0],
|
|
||||||
"no-underscore-dangle": [0], // __data__ sometimes
|
|
||||||
"no-unexpected-multiline": [2],
|
|
||||||
"no-unmodified-loop-condition": [2],
|
|
||||||
"no-unneeded-ternary": [2],
|
|
||||||
"no-unreachable": [2],
|
|
||||||
"no-unused-expressions": [2],
|
|
||||||
"no-unused-labels": [2],
|
|
||||||
"no-unused-vars": [2, {
|
|
||||||
"vars": "all",
|
|
||||||
"args": "none", // (d, i) pattern d3 func makes difficult to enforce
|
|
||||||
"varsIgnorePattern": "jQuery"
|
|
||||||
}],
|
|
||||||
"no-use-before-define": [0],
|
|
||||||
"no-useless-call": [2],
|
|
||||||
"no-useless-concat": [2],
|
|
||||||
"no-useless-constructor": [2],
|
|
||||||
"no-void": [0],
|
|
||||||
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
|
|
||||||
"no-with": [2],
|
|
||||||
"no-whitespace-before-property": [2],
|
|
||||||
"object-curly-spacing": [2, "always"],
|
|
||||||
"object-shorthand": [2, "never"],
|
|
||||||
"one-var": [0],
|
|
||||||
"one-var-declaration-per-line": [2, "initializations"],
|
|
||||||
"operator-assignment": [0, "always"],
|
|
||||||
"padded-blocks": [0],
|
|
||||||
"prefer-arrow-callback": [0],
|
|
||||||
"prefer-const": [0],
|
|
||||||
"prefer-reflect": [0],
|
|
||||||
"prefer-rest-params": [0],
|
|
||||||
"prefer-spread": [0],
|
|
||||||
"prefer-template": [0],
|
|
||||||
"quote-props": [2, "as-needed", { "keywords": true }],
|
|
||||||
"radix": [2],
|
|
||||||
"require-yield": [2],
|
|
||||||
"semi": [2],
|
|
||||||
"semi-spacing": [2, { "before": false, "after": true }],
|
|
||||||
"sort-vars": [0],
|
|
||||||
"sort-imports": [0],
|
|
||||||
"space-before-function-paren": [2, { "anonymous": "always", "named": "never" }],
|
|
||||||
"space-before-blocks": [2, { "functions": "always", "keywords": "always" }],
|
|
||||||
"space-in-brackets": [0, "never", {
|
|
||||||
"singleValue": true,
|
|
||||||
"arraysInArrays": false,
|
|
||||||
"arraysInObjects": false,
|
|
||||||
"objectsInArrays": true,
|
|
||||||
"objectsInObjects": true,
|
|
||||||
"propertyName": false
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
// Temporarily not enforced
|
|
||||||
"new-cap": [2], // @TODO more tricky for the moment
|
|
||||||
"newline-per-chained-call": [2, { "ignoreChainWithDepth": 6 }],
|
|
||||||
"no-param-reassign": [0], // turn on once default args supported
|
|
||||||
"no-shadow": [2, { // @TODO more tricky for the moment with eg 'data'
|
|
||||||
"builtinGlobals": false,
|
|
||||||
"hoist": "functions",
|
|
||||||
"allow": ["i", "d"]
|
|
||||||
}],
|
|
||||||
"space-in-parens": [2, "never"],
|
|
||||||
"space-infix-ops": [2],
|
|
||||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
|
||||||
"spaced-comment": [2, "always", { "markers": ["!"] }],
|
|
||||||
"spaced-line-comment": [0, "always"],
|
|
||||||
"strict": [2, "global"],
|
|
||||||
"template-curly-spacing": [2, "never"],
|
|
||||||
"use-isnan": [2],
|
|
||||||
"valid-jsdoc": [0],
|
|
||||||
"valid-typeof": [2],
|
|
||||||
"vars-on-top": [0],
|
|
||||||
"wrap-iife": [2],
|
|
||||||
"wrap-regex": [2],
|
|
||||||
"yield-star-spacing": [2, { "before": false, "after": true }],
|
|
||||||
"yoda": [2, "never", { "exceptRange": true, "onlyEquality": false }]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
var $ = require('jquery');
|
const $ = require('jquery');
|
||||||
var utils = require('./modules/utils');
|
const utils = require('./modules/utils');
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$(':checkbox[data-checkbox-api-prefix]').change(function () {
|
$(':checkbox[data-checkbox-api-prefix]').change(function () {
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
var prefix = $this.data('checkbox-api-prefix');
|
const prefix = $this.data('checkbox-api-prefix');
|
||||||
var id = $this.attr('id');
|
const id = $this.attr('id');
|
||||||
utils.toggleCheckbox(prefix, "#" + id);
|
utils.toggleCheckbox(prefix, '#' + id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,39 +1,61 @@
|
||||||
var $ = window.$ = require('jquery');
|
const $ = window.$ = require('jquery');
|
||||||
var jQuery = window.jQuery = $;
|
const jQuery = window.jQuery = $;
|
||||||
var px = require('../modules/caravel.js');
|
const px = require('../modules/caravel.js');
|
||||||
var d3 = require('d3');
|
const d3 = require('d3');
|
||||||
var urlLib = require('url');
|
const urlLib = require('url');
|
||||||
var showModal = require('../modules/utils.js').showModal;
|
const showModal = require('../modules/utils.js').showModal;
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import SliceAdder from './components/SliceAdder.jsx';
|
import SliceAdder from './components/SliceAdder.jsx';
|
||||||
import GridLayout from './components/GridLayout.jsx';
|
import GridLayout from './components/GridLayout.jsx';
|
||||||
|
|
||||||
var ace = require('brace');
|
const ace = require('brace');
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
require('brace/mode/css');
|
require('brace/mode/css');
|
||||||
require('brace/theme/crimson_editor');
|
require('brace/theme/crimson_editor');
|
||||||
require('./main.css');
|
require('./main.css');
|
||||||
require('../caravel-select2.js');
|
require('../caravel-select2.js');
|
||||||
|
|
||||||
|
// Injects the passed css string into a style sheet with the specified className
|
||||||
|
// If a stylesheet doesn't exist with the passed className, one will be injected into <head>
|
||||||
|
function injectCss(className, css) {
|
||||||
|
const head = document.head || document.getElementsByTagName('head')[0];
|
||||||
|
let style = document.querySelector('.' + className);
|
||||||
|
|
||||||
var Dashboard = function (dashboardData) {
|
if (!style) {
|
||||||
var dashboard = $.extend(dashboardData, {
|
if (className.split(' ').length > 1) {
|
||||||
|
throw new Error('This method only supports selections with a single class name.');
|
||||||
|
}
|
||||||
|
style = document.createElement('style');
|
||||||
|
style.className = className;
|
||||||
|
style.type = 'text/css';
|
||||||
|
head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = css;
|
||||||
|
} else {
|
||||||
|
style.innerHTML = css;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dashboardContainer(dashboardData) {
|
||||||
|
let dashboard = $.extend(dashboardData, {
|
||||||
filters: {},
|
filters: {},
|
||||||
init: function () {
|
init() {
|
||||||
this.initDashboardView();
|
this.initDashboardView();
|
||||||
this.firstLoad = true;
|
this.firstLoad = true;
|
||||||
px.initFavStars();
|
px.initFavStars();
|
||||||
var sliceObjects = [],
|
const sliceObjects = [];
|
||||||
dash = this;
|
const dash = this;
|
||||||
dashboard.slices.forEach(function (data) {
|
dashboard.slices.forEach((data) => {
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
var html = '<div class="alert alert-danger">' + data.error + '</div>';
|
const html = '<div class="alert alert-danger">' + data.error + '</div>';
|
||||||
$('#slice_' + data.slice_id).find('.token').html(html);
|
$('#slice_' + data.sliceId).find('.token').html(html);
|
||||||
} else {
|
} else {
|
||||||
var slice = px.Slice(data, dash);
|
const slice = px.Slice(data, dash);
|
||||||
$('#slice_' + data.slice_id).find('a.refresh').click(function () {
|
$('#slice_' + data.sliceId).find('a.refresh').click(() => {
|
||||||
slice.render(true);
|
slice.render(true);
|
||||||
});
|
});
|
||||||
sliceObjects.push(slice);
|
sliceObjects.push(slice);
|
||||||
|
@ -45,81 +67,81 @@ var Dashboard = function (dashboardData) {
|
||||||
this.startPeriodicRender(0);
|
this.startPeriodicRender(0);
|
||||||
this.bindResizeToWindowResize();
|
this.bindResizeToWindowResize();
|
||||||
},
|
},
|
||||||
loadPreSelectFilters: function () {
|
loadPreSelectFilters() {
|
||||||
try {
|
try {
|
||||||
var filters = JSON.parse(px.getParam("preselect_filters") || "{}");
|
const filters = JSON.parse(px.getParam('preselect_filters') || '{}');
|
||||||
for (var slice_id in filters) {
|
for (const sliceId in filters) {
|
||||||
for (var col in filters[slice_id]) {
|
for (const col in filters[sliceId]) {
|
||||||
this.setFilter(slice_id, col, filters[slice_id][col], false, false);
|
this.setFilter(sliceId, col, filters[sliceId][col], false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
// console.error(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setFilter: function (slice_id, col, vals, refresh) {
|
setFilter(sliceId, col, vals, refresh) {
|
||||||
this.addFilter(slice_id, col, vals, false, refresh);
|
this.addFilter(sliceId, col, vals, false, refresh);
|
||||||
},
|
},
|
||||||
addFilter: function (slice_id, col, vals, merge = true, refresh = true) {
|
addFilter(sliceId, col, vals, merge = true, refresh = true) {
|
||||||
if (!(slice_id in this.filters)) {
|
if (!(sliceId in this.filters)) {
|
||||||
this.filters[slice_id] = {};
|
this.filters[sliceId] = {};
|
||||||
}
|
}
|
||||||
if (!(col in this.filters[slice_id]) || !merge) {
|
if (!(col in this.filters[sliceId]) || !merge) {
|
||||||
this.filters[slice_id][col] = vals;
|
this.filters[sliceId][col] = vals;
|
||||||
} else {
|
} else {
|
||||||
this.filters[slice_id][col] = d3.merge([this.filters[slice_id][col], vals]);
|
this.filters[sliceId][col] = d3.merge([this.filters[sliceId][col], vals]);
|
||||||
}
|
}
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
this.refreshExcept(slice_id);
|
this.refreshExcept(sliceId);
|
||||||
}
|
}
|
||||||
this.updateFilterParamsInUrl();
|
this.updateFilterParamsInUrl();
|
||||||
},
|
},
|
||||||
readFilters: function () {
|
readFilters() {
|
||||||
// Returns a list of human readable active filters
|
// Returns a list of human readable active filters
|
||||||
return JSON.stringify(this.filters, null, 4);
|
return JSON.stringify(this.filters, null, 4);
|
||||||
},
|
},
|
||||||
updateFilterParamsInUrl: function () {
|
updateFilterParamsInUrl() {
|
||||||
var urlObj = urlLib.parse(location.href, true);
|
const urlObj = urlLib.parse(location.href, true);
|
||||||
urlObj.query = urlObj.query || {};
|
urlObj.query = urlObj.query || {};
|
||||||
urlObj.query.preselect_filters = this.readFilters();
|
urlObj.query.preselect_filters = this.readFilters();
|
||||||
urlObj.search = null;
|
urlObj.search = null;
|
||||||
history.pushState(urlObj.query, window.title, urlLib.format(urlObj));
|
history.pushState(urlObj.query, window.title, urlLib.format(urlObj));
|
||||||
},
|
},
|
||||||
bindResizeToWindowResize: function () {
|
bindResizeToWindowResize() {
|
||||||
var resizeTimer;
|
let resizeTimer;
|
||||||
var dash = this;
|
const dash = this;
|
||||||
$(window).on('resize', function (e) {
|
$(window).on('resize', () => {
|
||||||
clearTimeout(resizeTimer);
|
clearTimeout(resizeTimer);
|
||||||
resizeTimer = setTimeout(function () {
|
resizeTimer = setTimeout(() => {
|
||||||
dash.slices.forEach(function (slice) {
|
dash.slices.forEach((slice) => {
|
||||||
slice.resize();
|
slice.resize();
|
||||||
});
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
stopPeriodicRender: function () {
|
stopPeriodicRender() {
|
||||||
if (this.refreshTimer) {
|
if (this.refreshTimer) {
|
||||||
clearTimeout(this.refreshTimer);
|
clearTimeout(this.refreshTimer);
|
||||||
this.refreshTimer = null;
|
this.refreshTimer = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startPeriodicRender: function (interval) {
|
startPeriodicRender(interval) {
|
||||||
this.stopPeriodicRender();
|
this.stopPeriodicRender();
|
||||||
var dash = this;
|
const dash = this;
|
||||||
var maxRandomDelay = Math.min(interval * 0.2, 5000);
|
const maxRandomDelay = Math.min(interval * 0.2, 5000);
|
||||||
var refreshAll = function () {
|
const refreshAll = function () {
|
||||||
dash.slices.forEach(function (slice) {
|
dash.slices.forEach(function (slice) {
|
||||||
var force = !dash.firstLoad;
|
const force = !dash.firstLoad;
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
slice.render(force);
|
slice.render(force);
|
||||||
},
|
},
|
||||||
//Randomize to prevent all widgets refreshing at the same time
|
// Randomize to prevent all widgets refreshing at the same time
|
||||||
maxRandomDelay * Math.random());
|
maxRandomDelay * Math.random());
|
||||||
});
|
});
|
||||||
dash.firstLoad = false;
|
dash.firstLoad = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var fetchAndRender = function () {
|
const fetchAndRender = function () {
|
||||||
refreshAll();
|
refreshAll();
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
dash.refreshTimer = setTimeout(function () {
|
dash.refreshTimer = setTimeout(function () {
|
||||||
|
@ -129,122 +151,130 @@ var Dashboard = function (dashboardData) {
|
||||||
};
|
};
|
||||||
fetchAndRender();
|
fetchAndRender();
|
||||||
},
|
},
|
||||||
refreshExcept: function (slice_id) {
|
refreshExcept(sliceId) {
|
||||||
var immune = this.metadata.filter_immune_slices || [];
|
const immune = this.metadata.filter_immune_slices || [];
|
||||||
this.slices.forEach(function (slice) {
|
this.slices.forEach(function (slice) {
|
||||||
if (slice.data.slice_id !== slice_id && immune.indexOf(slice.data.slice_id) === -1) {
|
if (slice.data.sliceId !== sliceId && immune.indexOf(slice.data.sliceId) === -1) {
|
||||||
slice.render();
|
slice.render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
clearFilters: function (slice_id) {
|
clearFilters(sliceId) {
|
||||||
delete this.filters[slice_id];
|
delete this.filters[sliceId];
|
||||||
this.refreshExcept(slice_id);
|
this.refreshExcept(sliceId);
|
||||||
this.updateFilterParamsInUrl();
|
this.updateFilterParamsInUrl();
|
||||||
},
|
},
|
||||||
removeFilter: function (slice_id, col, vals) {
|
removeFilter(sliceId, col, vals) {
|
||||||
if (slice_id in this.filters) {
|
if (sliceId in this.filters) {
|
||||||
if (col in this.filters[slice_id]) {
|
if (col in this.filters[sliceId]) {
|
||||||
var a = [];
|
const a = [];
|
||||||
this.filters[slice_id][col].forEach(function (v) {
|
this.filters[sliceId][col].forEach(function (v) {
|
||||||
if (vals.indexOf(v) < 0) {
|
if (vals.indexOf(v) < 0) {
|
||||||
a.push(v);
|
a.push(v);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.filters[slice_id][col] = a;
|
this.filters[sliceId][col] = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.refreshExcept(slice_id);
|
this.refreshExcept(sliceId);
|
||||||
this.updateFilterParamsInUrl();
|
this.updateFilterParamsInUrl();
|
||||||
},
|
},
|
||||||
getSlice: function (slice_id) {
|
getSlice(sliceId) {
|
||||||
slice_id = parseInt(slice_id, 10);
|
const id = parseInt(sliceId, 10);
|
||||||
for (var i=0; i < this.slices.length; i++) {
|
let i = 0;
|
||||||
if (this.slices[i].data.slice_id === slice_id) {
|
let slice = null;
|
||||||
return this.slices[i];
|
while (i < this.slices.length) {
|
||||||
|
// when the slice is found, assign to slice and break;
|
||||||
|
if (this.slices[i].data.slice_id === id) {
|
||||||
|
slice = this.slices[i];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
return slice;
|
||||||
},
|
},
|
||||||
showAddSlice: function () {
|
showAddSlice() {
|
||||||
var slicesOnDashMap = {};
|
const slicesOnDashMap = {};
|
||||||
this.reactGridLayout.serialize().forEach(function (position) {
|
const layoutPositions = this.reactGridLayout.serialize();
|
||||||
|
layoutPositions.forEach((position) => {
|
||||||
slicesOnDashMap[position.slice_id] = true;
|
slicesOnDashMap[position.slice_id] = true;
|
||||||
}, this);
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<SliceAdder dashboard={dashboard} slicesOnDashMap={slicesOnDashMap} caravel={px} />,
|
<SliceAdder dashboard={dashboard} slicesOnDashMap={slicesOnDashMap} caravel={px} />,
|
||||||
document.getElementById("add-slice-container")
|
document.getElementById('add-slice-container')
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
getAjaxErrorMsg: function (error) {
|
getAjaxErrorMsg(error) {
|
||||||
var respJSON = error.responseJSON;
|
const respJSON = error.responseJSON;
|
||||||
return (respJSON && respJSON.message) ? respJSON.message :
|
return (respJSON && respJSON.message) ? respJSON.message :
|
||||||
error.responseText;
|
error.responseText;
|
||||||
},
|
},
|
||||||
addSlicesToDashboard: function (sliceIds) {
|
addSlicesToDashboard(sliceIds) {
|
||||||
|
const getAjaxErrorMsg = this.getAjaxErrorMsg;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: 'POST',
|
||||||
url: '/caravel/add_slices/' + dashboard.id + '/',
|
url: '/caravel/add_slices/' + dashboard.id + '/',
|
||||||
data: {
|
data: {
|
||||||
data: JSON.stringify({ slice_ids: sliceIds })
|
data: JSON.stringify({ slice_ids: sliceIds }),
|
||||||
},
|
},
|
||||||
success: function () {
|
success() {
|
||||||
// Refresh page to allow for slices to re-render
|
// Refresh page to allow for slices to re-render
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error(error) {
|
||||||
var errorMsg = this.getAjaxErrorMsg(error);
|
const errorMsg = getAjaxErrorMsg(error);
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "Sorry, there was an error adding slices to this dashboard: </ br>" + errorMsg
|
body: 'Sorry, there was an error adding slices to this dashboard: </ br>' + errorMsg,
|
||||||
});
|
});
|
||||||
}.bind(this)
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
saveDashboard: function () {
|
saveDashboard() {
|
||||||
var expandedSlices = {};
|
const expandedSlices = {};
|
||||||
$.each($(".slice_info"), function (i, d) {
|
$.each($('.slice_info'), function () {
|
||||||
var widget = $(this).parents('.widget');
|
const widget = $(this).parents('.widget');
|
||||||
var sliceDescription = widget.find('.slice_description');
|
const sliceDescription = widget.find('.slice_description');
|
||||||
if (sliceDescription.is(":visible")) {
|
if (sliceDescription.is(':visible')) {
|
||||||
expandedSlices[$(widget).attr('data-slice-id')] = true;
|
expandedSlices[$(widget).attr('data-slice-id')] = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var data = {
|
const positions = this.reactGridLayout.serialize();
|
||||||
positions: this.reactGridLayout.serialize(),
|
const data = {
|
||||||
|
positions,
|
||||||
css: this.editor.getValue(),
|
css: this.editor.getValue(),
|
||||||
expanded_slices: expandedSlices
|
expanded_slices: expandedSlices,
|
||||||
};
|
};
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: 'POST',
|
||||||
url: '/caravel/save_dash/' + dashboard.id + '/',
|
url: '/caravel/save_dash/' + dashboard.id + '/',
|
||||||
data: {
|
data: {
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data),
|
||||||
},
|
},
|
||||||
success: function () {
|
success() {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Success",
|
title: 'Success',
|
||||||
body: "This dashboard was saved successfully."
|
body: 'This dashboard was saved successfully.',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error(error) {
|
||||||
var errorMsg = this.getAjaxErrorMsg(error);
|
const errorMsg = this.getAjaxErrorMsg(error);
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "Sorry, there was an error saving this dashboard: </ br>" + errorMsg
|
body: 'Sorry, there was an error saving this dashboard: </ br>' + errorMsg,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
initDashboardView: function () {
|
initDashboardView() {
|
||||||
this.posDict = {};
|
this.posDict = {};
|
||||||
this.position_json.forEach(function (position) {
|
this.position_json.forEach(function (position) {
|
||||||
this.posDict[position.slice_id] = position;
|
this.posDict[position.slice_id] = position;
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.reactGridLayout = render(
|
this.reactGridLayout = render(
|
||||||
<GridLayout slices={this.slices} posDict={this.posDict} dashboard={dashboard}/>,
|
<GridLayout slices={this.slices} posDict={this.posDict} dashboard={dashboard} />,
|
||||||
document.getElementById("grid-container")
|
document.getElementById('grid-container')
|
||||||
);
|
);
|
||||||
|
|
||||||
this.curUserId = $('.dashboard').data('user');
|
this.curUserId = $('.dashboard').data('user');
|
||||||
|
@ -260,101 +290,77 @@ var Dashboard = function (dashboardData) {
|
||||||
$(this).find('.chart-controls').fadeOut(300);
|
$(this).find('.chart-controls').fadeOut(300);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$("div.grid-container").css('visibility', 'visible');
|
$('div.grid-container').css('visibility', 'visible');
|
||||||
$("#savedash").click(this.saveDashboard.bind(this));
|
$('#savedash').click(this.saveDashboard.bind(this));
|
||||||
$("#add-slice").click(this.showAddSlice.bind(this));
|
$('#add-slice').click(this.showAddSlice.bind(this));
|
||||||
|
|
||||||
var editor = ace.edit("dash_css");
|
const editor = ace.edit('dash_css');
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
editor.$blockScrolling = Infinity;
|
editor.$blockScrolling = Infinity;
|
||||||
|
|
||||||
editor.setTheme("ace/theme/crimson_editor");
|
editor.setTheme('ace/theme/crimson_editor');
|
||||||
editor.setOptions({
|
editor.setOptions({
|
||||||
minLines: 16,
|
minLines: 16,
|
||||||
maxLines: Infinity,
|
maxLines: Infinity,
|
||||||
useWorker: false
|
useWorker: false,
|
||||||
});
|
});
|
||||||
editor.getSession().setMode("ace/mode/css");
|
editor.getSession().setMode('ace/mode/css');
|
||||||
|
|
||||||
$(".select2").select2({
|
$('.select2').select2({
|
||||||
dropdownAutoWidth: true
|
dropdownAutoWidth: true,
|
||||||
});
|
});
|
||||||
$("#css_template").on("change", function () {
|
$('#css_template').on('change', function () {
|
||||||
var css = $(this).find('option:selected').data('css');
|
const css = $(this).find('option:selected').data('css');
|
||||||
editor.setValue(css);
|
editor.setValue(css);
|
||||||
|
|
||||||
$('#dash_css').val(css);
|
$('#dash_css').val(css);
|
||||||
injectCss("dashboard-template", css);
|
injectCss('dashboard-template', css);
|
||||||
|
|
||||||
});
|
});
|
||||||
$('#filters').click(function () {
|
$('#filters').click(() => {
|
||||||
showModal({
|
showModal({
|
||||||
title: "<span class='fa fa-info-circle'></span> Current Global Filters",
|
title: '<span class="fa fa-info-circle"></span> Current Global Filters',
|
||||||
body: "The following global filters are currently applied:<br/>" + dashboard.readFilters()
|
body: 'The following global filters are currently applied:<br/>' +
|
||||||
|
dashboard.readFilters(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$("#refresh_dash_interval").on("change", function () {
|
$('#refresh_dash_interval').on('change', function () {
|
||||||
var interval = $(this).find('option:selected').val() * 1000;
|
const interval = $(this).find('option:selected').val() * 1000;
|
||||||
dashboard.startPeriodicRender(interval);
|
dashboard.startPeriodicRender(interval);
|
||||||
});
|
});
|
||||||
$('#refresh_dash').click(function () {
|
$('#refresh_dash').click(() => {
|
||||||
dashboard.slices.forEach(function (slice) {
|
dashboard.slices.forEach((slice) => {
|
||||||
slice.render(true);
|
slice.render(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("div.widget").click(function (e) {
|
$('div.widget').click(function (e) {
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
var $target = $(e.target);
|
const $target = $(e.target);
|
||||||
|
|
||||||
if ($target.hasClass("slice_info")) {
|
if ($target.hasClass('slice_info')) {
|
||||||
$this.find(".slice_description").slideToggle(0, function () {
|
$this.find('.slice_description').slideToggle(0, function () {
|
||||||
$this.find('.refresh').click();
|
$this.find('.refresh').click();
|
||||||
});
|
});
|
||||||
} else if ($target.hasClass("controls-toggle")) {
|
} else if ($target.hasClass('controls-toggle')) {
|
||||||
$this.find(".chart-controls").toggle();
|
$this.find('.chart-controls').toggle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.on("change", function () {
|
editor.on('change', function () {
|
||||||
var css = editor.getValue();
|
const css = editor.getValue();
|
||||||
$('#dash_css').val(css);
|
$('#dash_css').val(css);
|
||||||
injectCss("dashboard-template", css);
|
injectCss('dashboard-template', css);
|
||||||
});
|
});
|
||||||
|
|
||||||
var css = $('.dashboard').data('css');
|
const css = $('.dashboard').data('css');
|
||||||
injectCss("dashboard-template", css);
|
injectCss('dashboard-template', css);
|
||||||
|
},
|
||||||
// Injects the passed css string into a style sheet with the specified className
|
|
||||||
// If a stylesheet doesn't exist with the passed className, one will be injected into <head>
|
|
||||||
function injectCss(className, css) {
|
|
||||||
|
|
||||||
var head = document.head || document.getElementsByTagName('head')[0];
|
|
||||||
var style = document.querySelector('.' + className);
|
|
||||||
|
|
||||||
if (!style) {
|
|
||||||
if (className.split(' ').length > 1) {
|
|
||||||
throw new Error("This method only supports selections with a single class name.");
|
|
||||||
}
|
|
||||||
style = document.createElement('style');
|
|
||||||
style.className = className;
|
|
||||||
style.type = 'text/css';
|
|
||||||
head.appendChild(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.styleSheet) {
|
|
||||||
style.styleSheet.cssText = css;
|
|
||||||
} else {
|
|
||||||
style.innerHTML = css;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
dashboard.init();
|
dashboard.init();
|
||||||
return dashboard;
|
return dashboard;
|
||||||
};
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(() => {
|
||||||
Dashboard($('.dashboard').data('dashboard'));
|
dashboardContainer($('.dashboard').data('dashboard'));
|
||||||
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,108 +1,69 @@
|
||||||
|
import $ from 'jquery';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Responsive, WidthProvider } from 'react-grid-layout';
|
import { Responsive, WidthProvider } from 'react-grid-layout';
|
||||||
const ResponsiveReactGridLayout = WidthProvider(Responsive);
|
const ResponsiveReactGridLayout = WidthProvider(Responsive);
|
||||||
|
import SliceCell from './SliceCell';
|
||||||
|
|
||||||
require('../../../node_modules/react-grid-layout/css/styles.css');
|
require('../../../node_modules/react-grid-layout/css/styles.css');
|
||||||
require('../../../node_modules/react-resizable/css/styles.css');
|
require('../../../node_modules/react-resizable/css/styles.css');
|
||||||
|
|
||||||
const sliceCellPropTypes = {
|
const propTypes = {
|
||||||
slice: PropTypes.object.isRequired,
|
|
||||||
removeSlice: PropTypes.func.isRequired,
|
|
||||||
expandedSlices: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
const gridLayoutPropTypes = {
|
|
||||||
dashboard: PropTypes.object.isRequired,
|
dashboard: PropTypes.object.isRequired,
|
||||||
slices: PropTypes.arrayOf(PropTypes.object).isRequired,
|
slices: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
posDict: PropTypes.object.isRequired
|
posDict: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SliceCell extends React.Component {
|
|
||||||
render() {
|
|
||||||
const slice = this.props.slice,
|
|
||||||
createMarkup = function () {
|
|
||||||
return { __html: slice.description_markeddown };
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="chart-header">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-12 text-center header">
|
|
||||||
{slice.slice_name}
|
|
||||||
</div>
|
|
||||||
<div className="col-md-12 chart-controls">
|
|
||||||
<div className="pull-left">
|
|
||||||
<a title="Move chart" data-toggle="tooltip">
|
|
||||||
<i className="fa fa-arrows drag"/>
|
|
||||||
</a>
|
|
||||||
<a className="refresh" title="Force refresh data" data-toggle="tooltip">
|
|
||||||
<i className="fa fa-repeat"/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="pull-right">
|
|
||||||
{slice.description ?
|
|
||||||
<a title="Toggle chart description">
|
|
||||||
<i className="fa fa-info-circle slice_info" title={slice.description} data-toggle="tooltip"/>
|
|
||||||
</a>
|
|
||||||
: ""}
|
|
||||||
<a href={slice.edit_url} title="Edit chart" data-toggle="tooltip">
|
|
||||||
<i className="fa fa-pencil"/>
|
|
||||||
</a>
|
|
||||||
<a href={slice.slice_url} title="Explore chart" data-toggle="tooltip">
|
|
||||||
<i className="fa fa-share"/>
|
|
||||||
</a>
|
|
||||||
<a className="remove-chart" title="Remove chart from dashboard" data-toggle="tooltip">
|
|
||||||
<i className="fa fa-close" onClick={this.props.removeSlice.bind(null, slice.slice_id)}/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="slice_description bs-callout bs-callout-default"
|
|
||||||
style={this.props.expandedSlices && this.props.expandedSlices[String(slice.slice_id)] ? {} : { display: "none" }}
|
|
||||||
dangerouslySetInnerHTML={createMarkup()}>
|
|
||||||
</div>
|
|
||||||
<div className="row chart-container">
|
|
||||||
<input type="hidden" value="false"/>
|
|
||||||
<div id={slice.token} className="token col-md-12">
|
|
||||||
<img src="/static/assets/images/loading.gif" className="loading" alt="loading"/>
|
|
||||||
<div className="slice_container" id={slice.token + "_con"}></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GridLayout extends React.Component {
|
class GridLayout extends React.Component {
|
||||||
|
componentWillMount() {
|
||||||
|
const layout = [];
|
||||||
|
|
||||||
|
this.props.slices.forEach((slice, index) => {
|
||||||
|
let pos = this.props.posDict[slice.slice_id];
|
||||||
|
if (!pos) {
|
||||||
|
pos = {
|
||||||
|
col: (index * 4 + 1) % 12,
|
||||||
|
row: Math.floor((index) / 3) * 4,
|
||||||
|
size_x: 4,
|
||||||
|
size_y: 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.push({
|
||||||
|
i: String(slice.slice_id),
|
||||||
|
x: pos.col - 1,
|
||||||
|
y: pos.row,
|
||||||
|
w: pos.size_x,
|
||||||
|
minW: 2,
|
||||||
|
h: pos.size_y,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
layout,
|
||||||
|
slices: this.props.slices,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onResizeStop(layout, oldItem, newItem) {
|
||||||
|
const newSlice = this.props.dashboard.getSlice(newItem.i);
|
||||||
|
if (oldItem.w !== newItem.w || oldItem.h !== newItem.h) {
|
||||||
|
this.setState({ layout }, () => { newSlice.resize(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragStop(layout) {
|
||||||
|
this.setState({ layout });
|
||||||
|
}
|
||||||
|
|
||||||
removeSlice(sliceId) {
|
removeSlice(sliceId) {
|
||||||
$('[data-toggle="tooltip"]').tooltip("hide");
|
$('[data-toggle=tooltip]').tooltip('hide');
|
||||||
this.setState({
|
this.setState({
|
||||||
layout: this.state.layout.filter(function (reactPos) {
|
layout: this.state.layout.filter(function (reactPos) {
|
||||||
return reactPos.i !== String(sliceId);
|
return reactPos.i !== String(sliceId);
|
||||||
}),
|
}),
|
||||||
slices: this.state.slices.filter(function (slice) {
|
slices: this.state.slices.filter(function (slice) {
|
||||||
return slice.slice_id !== sliceId;
|
return slice.slice_id !== sliceId;
|
||||||
})
|
}),
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onResizeStop(layout, oldItem, newItem) {
|
|
||||||
if (oldItem.w !== newItem.w || oldItem.h !== newItem.h) {
|
|
||||||
this.setState({
|
|
||||||
layout: layout
|
|
||||||
}, function () {
|
|
||||||
this.props.dashboard.getSlice(newItem.i).resize();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragStop(layout) {
|
|
||||||
this.setState({
|
|
||||||
layout: layout
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,41 +74,11 @@ class GridLayout extends React.Component {
|
||||||
col: reactPos.x + 1,
|
col: reactPos.x + 1,
|
||||||
row: reactPos.y,
|
row: reactPos.y,
|
||||||
size_x: reactPos.w,
|
size_x: reactPos.w,
|
||||||
size_y: reactPos.h
|
size_y: reactPos.h,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
var layout = [];
|
|
||||||
|
|
||||||
this.props.slices.forEach(function (slice, index) {
|
|
||||||
var pos = this.props.posDict[slice.slice_id];
|
|
||||||
if (!pos) {
|
|
||||||
pos = {
|
|
||||||
col: (index * 4 + 1) % 12,
|
|
||||||
row: Math.floor((index) / 3) * 4,
|
|
||||||
size_x: 4,
|
|
||||||
size_y: 4
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.push({
|
|
||||||
i: String(slice.slice_id),
|
|
||||||
x: pos.col - 1,
|
|
||||||
y: pos.row,
|
|
||||||
w: pos.size_x,
|
|
||||||
minW: 2,
|
|
||||||
h: pos.size_y
|
|
||||||
});
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
layout: layout,
|
|
||||||
slices: this.props.slices
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ResponsiveReactGridLayout
|
<ResponsiveReactGridLayout
|
||||||
|
@ -157,30 +88,35 @@ class GridLayout extends React.Component {
|
||||||
onDragStop={this.onDragStop.bind(this)}
|
onDragStop={this.onDragStop.bind(this)}
|
||||||
cols={{ lg: 12, md: 12, sm: 10, xs: 8, xxs: 6 }}
|
cols={{ lg: 12, md: 12, sm: 10, xs: 8, xxs: 6 }}
|
||||||
rowHeight={100}
|
rowHeight={100}
|
||||||
autoSize={true}
|
autoSize
|
||||||
margin={[20, 20]}
|
margin={[20, 20]}
|
||||||
useCSSTransforms={false}
|
useCSSTransforms={false}
|
||||||
draggableHandle=".drag">
|
draggableHandle=".drag"
|
||||||
{this.state.slices.map((slice) => {
|
>
|
||||||
return (
|
{
|
||||||
<div
|
/* eslint arrow-body-style: 0 */
|
||||||
id={'slice_' + slice.slice_id}
|
this.state.slices.map((slice) => {
|
||||||
key={slice.slice_id}
|
return (
|
||||||
data-slice-id={slice.slice_id}
|
<div
|
||||||
className={"widget " + slice.viz_name}>
|
id={'slice_' + slice.slice_id}
|
||||||
<SliceCell
|
key={slice.slice_id}
|
||||||
slice={slice}
|
data-slice-id={slice.slice_id}
|
||||||
removeSlice={this.removeSlice.bind(this)}
|
className={`widget ${slice.viz_name}`}
|
||||||
expandedSlices={this.props.dashboard.metadata.expanded_slices}/>
|
>
|
||||||
</div>
|
<SliceCell
|
||||||
);
|
slice={slice}
|
||||||
})}
|
removeSlice={(sliceId) => this.removeSlice(sliceId)}
|
||||||
|
expandedSlices={this.props.dashboard.metadata.expanded_slices}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
</ResponsiveReactGridLayout>
|
</ResponsiveReactGridLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SliceCell.propTypes = sliceCellPropTypes;
|
GridLayout.propTypes = propTypes;
|
||||||
GridLayout.propTypes = gridLayoutPropTypes;
|
|
||||||
|
|
||||||
export default GridLayout;
|
export default GridLayout;
|
||||||
|
|
|
@ -4,37 +4,37 @@ const propTypes = {
|
||||||
modalId: PropTypes.string.isRequired,
|
modalId: PropTypes.string.isRequired,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
modalContent: PropTypes.node,
|
modalContent: PropTypes.node,
|
||||||
customButtons: PropTypes.node
|
customButton: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Modal extends React.Component {
|
function Modal({ modalId, title, modalContent, customButton }) {
|
||||||
render() {
|
return (
|
||||||
return (
|
<div className="modal fade" id={modalId} role="dialog">
|
||||||
<div className="modal fade" id={this.props.modalId} role="dialog">
|
<div className="modal-dialog" role="document">
|
||||||
<div className="modal-dialog" role="document">
|
<div className="modal-content">
|
||||||
<div className="modal-content">
|
<div className="modal-header">
|
||||||
<div className="modal-header">
|
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
|
||||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
|
<span aria-hidden="true">×</span>
|
||||||
<span aria-hidden="true">×</span>
|
</button>
|
||||||
</button>
|
<h4 className="modal-title">{title}</h4>
|
||||||
<h4 className="modal-title">{this.props.title}</h4>
|
|
||||||
</div>
|
|
||||||
<div className="modal-body">
|
|
||||||
{this.props.modalContent}
|
|
||||||
</div>
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button type="button"
|
|
||||||
className="btn btn-default"
|
|
||||||
data-dismiss="modal">
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
{this.props.customButtons}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
{modalContent}
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-default"
|
||||||
|
data-dismiss="modal"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
{customButton}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.propTypes = propTypes;
|
Modal.propTypes = propTypes;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import $ from 'jquery';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import update from 'immutability-helper';
|
import update from 'immutability-helper';
|
||||||
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
|
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
|
||||||
|
@ -6,15 +7,14 @@ require('../../../node_modules/react-bootstrap-table/css/react-bootstrap-table.c
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
dashboard: PropTypes.object.isRequired,
|
dashboard: PropTypes.object.isRequired,
|
||||||
caravel: PropTypes.object.isRequired
|
caravel: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SliceAdder extends React.Component {
|
class SliceAdder extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
slices: []
|
slices: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addSlices = this.addSlices.bind(this);
|
this.addSlices = this.addSlices.bind(this);
|
||||||
|
@ -22,46 +22,47 @@ class SliceAdder extends React.Component {
|
||||||
this.toggleAllSlices = this.toggleAllSlices.bind(this);
|
this.toggleAllSlices = this.toggleAllSlices.bind(this);
|
||||||
this.slicesLoaded = false;
|
this.slicesLoaded = false;
|
||||||
this.selectRowProp = {
|
this.selectRowProp = {
|
||||||
mode: "checkbox",
|
mode: 'checkbox',
|
||||||
clickToSelect: true,
|
clickToSelect: true,
|
||||||
onSelect: this.toggleSlice,
|
onSelect: this.toggleSlice,
|
||||||
onSelectAll: this.toggleAllSlices
|
onSelectAll: this.toggleAllSlices,
|
||||||
};
|
};
|
||||||
this.options = {
|
this.options = {
|
||||||
defaultSortOrder: "desc",
|
defaultSortOrder: 'desc',
|
||||||
defaultSortName: "modified",
|
defaultSortName: 'modified',
|
||||||
sizePerPage: 10
|
sizePerPage: 10,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
var uri = "/sliceaddview/api/read?_flt_0_created_by=" + this.props.dashboard.curUserId;
|
const uri = '/sliceaddview/api/read?_flt_0_created_by=' + this.props.dashboard.curUserId;
|
||||||
this.slicesRequest = $.ajax({
|
this.slicesRequest = $.ajax({
|
||||||
url: uri,
|
url: uri,
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
this.slicesLoaded = true;
|
this.slicesLoaded = true;
|
||||||
|
|
||||||
// Prepare slice data for table
|
// Prepare slice data for table
|
||||||
let slices = response.result;
|
const slices = response.result.map(function (slice) {
|
||||||
slices.forEach(function (slice) {
|
return {
|
||||||
slice.id = slice.data.slice_id;
|
id: slice.data.slice_id,
|
||||||
slice.sliceName = slice.data.slice_name;
|
sliceName: slice.data.slice_name,
|
||||||
slice.vizType = slice.viz_type;
|
vizType: slice.viz_type,
|
||||||
slice.modified = slice.modified;
|
modified: slice.modified,
|
||||||
|
data: slice.data,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
slices: slices,
|
slices,
|
||||||
selectionMap: {}
|
selectionMap: {},
|
||||||
});
|
});
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
error: function (error) {
|
error: function (error) {
|
||||||
this.errored = true;
|
this.errored = true;
|
||||||
this.setState({
|
this.setState({
|
||||||
errorMsg: this.props.dashboard.getAjaxErrorMsg(error)
|
errorMsg: this.props.dashboard.getAjaxErrorMsg(error),
|
||||||
});
|
});
|
||||||
}.bind(this)
|
}.bind(this),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,13 +71,12 @@ class SliceAdder extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
addSlices() {
|
addSlices() {
|
||||||
var slices = this.state.slices.filter(function (slice) {
|
const slices = this.state.slices.filter(function (slice) {
|
||||||
return this.state.selectionMap[slice.id];
|
return this.state.selectionMap[slice.id];
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
slices.forEach(function (slice) {
|
slices.forEach(function (slice) {
|
||||||
var sliceObj = this.props.caravel.Slice(slice.data, this.props.dashboard);
|
const sliceObj = this.props.caravel.Slice(slice.data, this.props.dashboard);
|
||||||
$("#slice_" + slice.data.slice_id).find('a.refresh').click(function () {
|
$('#slice_' + slice.data.slice_id).find('a.refresh').click(function () {
|
||||||
sliceObj.render(true);
|
sliceObj.render(true);
|
||||||
});
|
});
|
||||||
this.props.dashboard.slices.push(sliceObj);
|
this.props.dashboard.slices.push(sliceObj);
|
||||||
|
@ -89,23 +89,23 @@ class SliceAdder extends React.Component {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectionMap: update(this.state.selectionMap, {
|
selectionMap: update(this.state.selectionMap, {
|
||||||
[slice.id]: {
|
[slice.id]: {
|
||||||
$set: !this.state.selectionMap[slice.id]
|
$set: !this.state.selectionMap[slice.id],
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleAllSlices(value) {
|
toggleAllSlices(value) {
|
||||||
let updatePayload = {};
|
const updatePayload = {};
|
||||||
|
|
||||||
this.state.slices.forEach(function (slice) {
|
this.state.slices.forEach(function (slice) {
|
||||||
updatePayload[slice.id] = {
|
updatePayload[slice.id] = {
|
||||||
$set: value
|
$set: value,
|
||||||
};
|
};
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
selectionMap: update(this.state.selectionMap, updatePayload)
|
selectionMap: update(this.state.selectionMap, updatePayload),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,13 +134,15 @@ class SliceAdder extends React.Component {
|
||||||
}, this);
|
}, this);
|
||||||
const modalContent = (
|
const modalContent = (
|
||||||
<div>
|
<div>
|
||||||
<img src="/static/assets/images/loading.gif"
|
<img
|
||||||
className={"loading " + (hideLoad ? "hidden" : "")}
|
src="/static/assets/images/loading.gif"
|
||||||
alt={hideLoad ? "" : "loading"}/>
|
className={'loading ' + (hideLoad ? 'hidden' : '')}
|
||||||
<div className={this.errored ? "" : "hidden"}>
|
alt={hideLoad ? '' : 'loading'}
|
||||||
|
/>
|
||||||
|
<div className={this.errored ? '' : 'hidden'}>
|
||||||
{this.state.errorMsg}
|
{this.state.errorMsg}
|
||||||
</div>
|
</div>
|
||||||
<div className={this.slicesLoaded ? "" : "hidden"}>
|
<div className={this.slicesLoaded ? '' : 'hidden'}>
|
||||||
<BootstrapTable
|
<BootstrapTable
|
||||||
ref="table"
|
ref="table"
|
||||||
data={this.state.slices}
|
data={this.state.slices}
|
||||||
|
@ -149,37 +151,52 @@ class SliceAdder extends React.Component {
|
||||||
hover
|
hover
|
||||||
search
|
search
|
||||||
pagination
|
pagination
|
||||||
height="auto">
|
height="auto"
|
||||||
<TableHeaderColumn dataField="sliceName" isKey={true} dataSort={true}>Name</TableHeaderColumn>
|
>
|
||||||
<TableHeaderColumn dataField="vizType" dataSort={true}>Viz</TableHeaderColumn>
|
<TableHeaderColumn
|
||||||
|
dataField="sliceName"
|
||||||
|
isKey
|
||||||
|
dataSort
|
||||||
|
>
|
||||||
|
Name
|
||||||
|
</TableHeaderColumn>
|
||||||
|
<TableHeaderColumn
|
||||||
|
dataField="vizType"
|
||||||
|
dataSort
|
||||||
|
>
|
||||||
|
Viz
|
||||||
|
</TableHeaderColumn>
|
||||||
<TableHeaderColumn
|
<TableHeaderColumn
|
||||||
dataField="modified"
|
dataField="modified"
|
||||||
dataSort={true}
|
dataSort
|
||||||
sortFunc={this.modifiedDateComparator}
|
sortFunc={this.modifiedDateComparator}
|
||||||
// Will cause react-bootstrap-table to interpret the HTML returned
|
// Will cause react-bootstrap-table to interpret the HTML returned
|
||||||
dataFormat={modified => modified}>
|
dataFormat={modified => modified}
|
||||||
|
>
|
||||||
Modified
|
Modified
|
||||||
</TableHeaderColumn>
|
</TableHeaderColumn>
|
||||||
</BootstrapTable>
|
</BootstrapTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
const customButtons = [
|
const customButton = (
|
||||||
<button key={0}
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-default"
|
className="btn btn-default"
|
||||||
data-dismiss="modal"
|
data-dismiss="modal"
|
||||||
onClick={this.addSlices}
|
onClick={this.addSlices}
|
||||||
disabled={!enableAddSlice}>
|
disabled={!enableAddSlice}
|
||||||
Add Slices
|
>
|
||||||
|
Add Slices
|
||||||
</button>
|
</button>
|
||||||
];
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal modalId='add_slice_modal'
|
<Modal
|
||||||
modalContent={modalContent}
|
modalId="add_slice_modal"
|
||||||
title='Add New Slices'
|
modalContent={modalContent}
|
||||||
customButtons={customButtons}
|
title="Add New Slices"
|
||||||
|
customButton={customButton}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
slice: PropTypes.object.isRequired,
|
||||||
|
removeSlice: PropTypes.func.isRequired,
|
||||||
|
expandedSlices: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
function SliceCell({ expandedSlices, removeSlice, slice }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="chart-header">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 text-center header">
|
||||||
|
{slice.slice_name}
|
||||||
|
</div>
|
||||||
|
<div className="col-md-12 chart-controls">
|
||||||
|
<div className="pull-left">
|
||||||
|
<a title="Move chart" data-toggle="tooltip">
|
||||||
|
<i className="fa fa-arrows drag" />
|
||||||
|
</a>
|
||||||
|
<a className="refresh" title="Force refresh data" data-toggle="tooltip">
|
||||||
|
<i className="fa fa-repeat" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="pull-right">
|
||||||
|
{slice.description &&
|
||||||
|
<a title="Toggle chart description">
|
||||||
|
<i
|
||||||
|
className="fa fa-info-circle slice_info"
|
||||||
|
title={slice.description}
|
||||||
|
data-toggle="tooltip"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
<a
|
||||||
|
href={slice.edit_url}
|
||||||
|
title="Edit chart"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
>
|
||||||
|
<i className="fa fa-pencil" />
|
||||||
|
</a>
|
||||||
|
<a href={slice.slice_url} title="Explore chart" data-toggle="tooltip">
|
||||||
|
<i className="fa fa-share" />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="remove-chart"
|
||||||
|
title="Remove chart from dashboard"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa fa-close"
|
||||||
|
onClick={() => { removeSlice(slice.slice_id); }}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="slice_description bs-callout bs-callout-default"
|
||||||
|
style={
|
||||||
|
expandedSlices &&
|
||||||
|
expandedSlices[String(slice.slice_id)] ? {} : { display: 'none' }
|
||||||
|
}
|
||||||
|
dangerouslySetInnerHTML={{ __html: slice.description_markeddown }}
|
||||||
|
>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="row chart-container">
|
||||||
|
<input type="hidden" value="false" />
|
||||||
|
<div id={slice.token} className="token col-md-12">
|
||||||
|
<img
|
||||||
|
src="/static/assets/images/loading.gif"
|
||||||
|
className="loading"
|
||||||
|
alt="loading"
|
||||||
|
/>
|
||||||
|
<div className="slice_container" id={slice.token + '_con'}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SliceCell.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default SliceCell;
|
|
@ -16,10 +16,11 @@ export default function QueryAndSaveBtns({ canAdd, onQuery }) {
|
||||||
<button type="button" className="btn btn-primary" onClick={onQuery}>
|
<button type="button" className="btn btn-primary" onClick={onQuery}>
|
||||||
<i className="fa fa-bolt"></i>Query
|
<i className="fa fa-bolt"></i>Query
|
||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button
|
||||||
className={saveClasses}
|
type="button"
|
||||||
data-target="#save_modal"
|
className={saveClasses}
|
||||||
data-toggle="modal"
|
data-target="#save_modal"
|
||||||
|
data-toggle="modal"
|
||||||
>
|
>
|
||||||
<i className="fa fa-plus-circle"></i>Save as
|
<i className="fa fa-plus-circle"></i>Save as
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -28,31 +28,31 @@ require('../../node_modules/bootstrap-toggle/css/bootstrap-toggle.min.css');
|
||||||
var slice;
|
var slice;
|
||||||
|
|
||||||
var getPanelClass = function (fieldPrefix) {
|
var getPanelClass = function (fieldPrefix) {
|
||||||
return (fieldPrefix === "flt" ? "filter" : "having") + "_panel";
|
return (fieldPrefix === 'flt' ? 'filter' : 'having') + '_panel';
|
||||||
};
|
};
|
||||||
|
|
||||||
function prepForm() {
|
function prepForm() {
|
||||||
// Assigning the right id to form elements in filters
|
// Assigning the right id to form elements in filters
|
||||||
var fixId = function ($filter, fieldPrefix, i) {
|
var fixId = function ($filter, fieldPrefix, i) {
|
||||||
$filter.attr("id", function () {
|
$filter.attr('id', function () {
|
||||||
return fieldPrefix + "_" + i;
|
return fieldPrefix + '_' + i;
|
||||||
});
|
});
|
||||||
|
|
||||||
["col", "op", "eq"].forEach(function (fieldMiddle) {
|
['col', 'op', 'eq'].forEach(function (fieldMiddle) {
|
||||||
var fieldName = fieldPrefix + "_" + fieldMiddle;
|
var fieldName = fieldPrefix + '_' + fieldMiddle;
|
||||||
$filter.find("[id^='" + fieldName + "_']")
|
$filter.find('[id^=' + fieldName + '_]')
|
||||||
.attr("id", function () {
|
.attr('id', function () {
|
||||||
return fieldName + "_" + i;
|
return fieldName + '_' + i;
|
||||||
})
|
})
|
||||||
.attr("name", function () {
|
.attr('name', function () {
|
||||||
return fieldName + "_" + i;
|
return fieldName + '_' + i;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
["flt", "having"].forEach(function (fieldPrefix) {
|
['flt', 'having'].forEach(function (fieldPrefix) {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
$("#" + getPanelClass(fieldPrefix) + " #filters > div").each(function () {
|
$('#' + getPanelClass(fieldPrefix) + ' #filters > div').each(function () {
|
||||||
fixId($(this), fieldPrefix, i);
|
fixId($(this), fieldPrefix, i);
|
||||||
i++;
|
i++;
|
||||||
});
|
});
|
||||||
|
@ -79,11 +79,10 @@ function query(force, pushState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function initExploreView() {
|
function initExploreView() {
|
||||||
|
|
||||||
function get_collapsed_fieldsets() {
|
function get_collapsed_fieldsets() {
|
||||||
var collapsed_fieldsets = $("#collapsed_fieldsets").val();
|
var collapsed_fieldsets = $('#collapsed_fieldsets').val();
|
||||||
|
|
||||||
if (collapsed_fieldsets !== undefined && collapsed_fieldsets !== "") {
|
if (collapsed_fieldsets !== undefined && collapsed_fieldsets !== '') {
|
||||||
collapsed_fieldsets = collapsed_fieldsets.split('||');
|
collapsed_fieldsets = collapsed_fieldsets.split('||');
|
||||||
} else {
|
} else {
|
||||||
collapsed_fieldsets = [];
|
collapsed_fieldsets = [];
|
||||||
|
@ -93,18 +92,18 @@ function initExploreView() {
|
||||||
|
|
||||||
function toggle_fieldset(legend, animation) {
|
function toggle_fieldset(legend, animation) {
|
||||||
var parent = legend.parent();
|
var parent = legend.parent();
|
||||||
var fieldset = parent.find(".legend_label").text();
|
var fieldset = parent.find('.legend_label').text();
|
||||||
var collapsed_fieldsets = get_collapsed_fieldsets();
|
var collapsed_fieldsets = get_collapsed_fieldsets();
|
||||||
var index;
|
var index;
|
||||||
|
|
||||||
if (parent.hasClass("collapsed")) {
|
if (parent.hasClass('collapsed')) {
|
||||||
if (animation) {
|
if (animation) {
|
||||||
parent.find(".panel-body").slideDown();
|
parent.find('.panel-body').slideDown();
|
||||||
} else {
|
} else {
|
||||||
parent.find(".panel-body").show();
|
parent.find('.panel-body').show();
|
||||||
}
|
}
|
||||||
parent.removeClass("collapsed");
|
parent.removeClass('collapsed');
|
||||||
parent.find("span.collapser").text("[-]");
|
parent.find('span.collapser').text('[-]');
|
||||||
|
|
||||||
// removing from array, js is overcomplicated
|
// removing from array, js is overcomplicated
|
||||||
index = collapsed_fieldsets.indexOf(fieldset);
|
index = collapsed_fieldsets.indexOf(fieldset);
|
||||||
|
@ -113,20 +112,20 @@ function initExploreView() {
|
||||||
}
|
}
|
||||||
} else { // not collapsed
|
} else { // not collapsed
|
||||||
if (animation) {
|
if (animation) {
|
||||||
parent.find(".panel-body").slideUp();
|
parent.find('.panel-body').slideUp();
|
||||||
} else {
|
} else {
|
||||||
parent.find(".panel-body").hide();
|
parent.find('.panel-body').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.addClass("collapsed");
|
parent.addClass('collapsed');
|
||||||
parent.find("span.collapser").text("[+]");
|
parent.find('span.collapser').text('[+]');
|
||||||
index = collapsed_fieldsets.indexOf(fieldset);
|
index = collapsed_fieldsets.indexOf(fieldset);
|
||||||
if (index === -1 && fieldset !== "" && fieldset !== undefined) {
|
if (index === -1 && fieldset !== '' && fieldset !== undefined) {
|
||||||
collapsed_fieldsets.push(fieldset);
|
collapsed_fieldsets.push(fieldset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#collapsed_fieldsets").val(collapsed_fieldsets.join("||"));
|
$('#collapsed_fieldsets').val(collapsed_fieldsets.join('||'));
|
||||||
}
|
}
|
||||||
|
|
||||||
px.initFavStars();
|
px.initFavStars();
|
||||||
|
@ -137,7 +136,7 @@ function initExploreView() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function copyURLToClipboard(url) {
|
function copyURLToClipboard(url) {
|
||||||
var textArea = document.createElement("textarea");
|
var textArea = document.createElement('textarea');
|
||||||
textArea.style.position = 'fixed';
|
textArea.style.position = 'fixed';
|
||||||
textArea.style.left = '-1000px';
|
textArea.style.left = '-1000px';
|
||||||
textArea.value = url;
|
textArea.value = url;
|
||||||
|
@ -148,10 +147,10 @@ function initExploreView() {
|
||||||
try {
|
try {
|
||||||
var successful = document.execCommand('copy');
|
var successful = document.execCommand('copy');
|
||||||
if (!successful) {
|
if (!successful) {
|
||||||
throw new Error("Not successful");
|
throw new Error('Not successful');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.alert("Sorry, your browser does not support copying. Use Ctrl / Cmd + C!");
|
window.alert('Sorry, your browser does not support copying. Use Ctrl / Cmd + C!');
|
||||||
}
|
}
|
||||||
document.body.removeChild(textArea);
|
document.body.removeChild(textArea);
|
||||||
return successful;
|
return successful;
|
||||||
|
@ -159,12 +158,12 @@ function initExploreView() {
|
||||||
|
|
||||||
$('#shortner').click(function () {
|
$('#shortner').click(function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: 'POST',
|
||||||
url: '/r/shortner/',
|
url: '/r/shortner/',
|
||||||
data: {
|
data: {
|
||||||
data: '/' + window.location.pathname + slice.querystring()
|
data: '/' + window.location.pathname + slice.querystring(),
|
||||||
},
|
},
|
||||||
success: function (data) {
|
success(data) {
|
||||||
var close = '<a style="cursor: pointer;"><i class="fa fa-close" id="close_shortner"></i></a>';
|
var close = '<a style="cursor: pointer;"><i class="fa fa-close" id="close_shortner"></i></a>';
|
||||||
var copy = '<a style="cursor: pointer;"><i class="fa fa-clipboard" title="Copy to clipboard" id="copy_url"></i></a>';
|
var copy = '<a style="cursor: pointer;"><i class="fa fa-clipboard" title="Copy to clipboard" id="copy_url"></i></a>';
|
||||||
var spaces = ' ';
|
var spaces = ' ';
|
||||||
|
@ -175,14 +174,14 @@ function initExploreView() {
|
||||||
content: popover,
|
content: popover,
|
||||||
placement: 'left',
|
placement: 'left',
|
||||||
html: true,
|
html: true,
|
||||||
trigger: 'manual'
|
trigger: 'manual',
|
||||||
})
|
})
|
||||||
.popover('show');
|
.popover('show');
|
||||||
|
|
||||||
$('#copy_url').tooltip().click(function () {
|
$('#copy_url').tooltip().click(function () {
|
||||||
var success = copyURLToClipboard(data);
|
var success = copyURLToClipboard(data);
|
||||||
if (success) {
|
if (success) {
|
||||||
$(this).attr("data-original-title", "Copied!").tooltip('fixTitle').tooltip('show');
|
$(this).attr('data-original-title', 'Copied!').tooltip('fixTitle').tooltip('show');
|
||||||
window.setTimeout(destroyPopover, 1200);
|
window.setTimeout(destroyPopover, 1200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -192,13 +191,13 @@ function initExploreView() {
|
||||||
$shortner.popover('destroy');
|
$shortner.popover('destroy');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error(error) {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "Sorry, an error occurred during this operation:<br/>" + error
|
body: 'Sorry, an error occurred during this operation:<br/>' + error,
|
||||||
});
|
});
|
||||||
console.warn("Short URL error", error);
|
console.warn('Short URL error', error);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -219,13 +218,13 @@ function initExploreView() {
|
||||||
title: 'embed html',
|
title: 'embed html',
|
||||||
placement: 'left',
|
placement: 'left',
|
||||||
html: true,
|
html: true,
|
||||||
trigger: 'manual'
|
trigger: 'manual',
|
||||||
})
|
})
|
||||||
.popover('show');
|
.popover('show');
|
||||||
$('#copy_embed').tooltip().click(function () {
|
$('#copy_embed').tooltip().click(function () {
|
||||||
var success = copyURLToClipboard(dataToCopy);
|
var success = copyURLToClipboard(dataToCopy);
|
||||||
if (success) {
|
if (success) {
|
||||||
$(this).attr("data-original-title", "Copied!").tooltip('fixTitle').tooltip('show');
|
$(this).attr('data-original-title', 'Copied!').tooltip('fixTitle').tooltip('show');
|
||||||
window.setTimeout(destroyPopover, 1200);
|
window.setTimeout(destroyPopover, 1200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -250,17 +249,17 @@ function initExploreView() {
|
||||||
function generateEmbedHTML() {
|
function generateEmbedHTML() {
|
||||||
var width = $standalone_width.val();
|
var width = $standalone_width.val();
|
||||||
var height = $standalone_height.val();
|
var height = $standalone_height.val();
|
||||||
dataToCopy = '<iframe src="' + src_link + '" width="' + width + '" height="' + height +'"';
|
dataToCopy = '<iframe src="' + src_link + '" width="' + width + '" height="' + height + '"';
|
||||||
dataToCopy = dataToCopy + ' seamless frameBorder="0" scrolling="no"></iframe>';
|
dataToCopy = dataToCopy + ' seamless frameBorder="0" scrolling="no"></iframe>';
|
||||||
$standalone_text.val(dataToCopy);
|
$standalone_text.val(dataToCopy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#viz_type").change(function () {
|
$('#viz_type').change(function () {
|
||||||
$("#query").submit();
|
$('#query').submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#datasource_id").change(function () {
|
$('#datasource_id').change(function () {
|
||||||
var url = $(this).find('option:selected').attr('url');
|
var url = $(this).find('option:selected').attr('url');
|
||||||
window.location = url;
|
window.location = url;
|
||||||
});
|
});
|
||||||
|
@ -278,28 +277,28 @@ function initExploreView() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".select2").select2({
|
$('.select2').select2({
|
||||||
dropdownAutoWidth: true
|
|
||||||
});
|
|
||||||
$(".select2Sortable").select2({
|
|
||||||
dropdownAutoWidth: true
|
|
||||||
});
|
|
||||||
$(".select2-with-images").select2({
|
|
||||||
dropdownAutoWidth: true,
|
dropdownAutoWidth: true,
|
||||||
dropdownCssClass: "bigdrop",
|
|
||||||
formatResult: formatViz
|
|
||||||
});
|
});
|
||||||
$(".select2Sortable").select2Sortable({
|
$('.select2Sortable').select2({
|
||||||
bindOrder: 'sortableStop'
|
dropdownAutoWidth: true,
|
||||||
});
|
});
|
||||||
$("form").show();
|
$('.select2-with-images').select2({
|
||||||
|
dropdownAutoWidth: true,
|
||||||
|
dropdownCssClass: 'bigdrop',
|
||||||
|
formatResult: formatViz,
|
||||||
|
});
|
||||||
|
$('.select2Sortable').select2Sortable({
|
||||||
|
bindOrder: 'sortableStop',
|
||||||
|
});
|
||||||
|
$('form').show();
|
||||||
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
||||||
$(".ui-helper-hidden-accessible").remove(); // jQuery-ui 1.11+ creates a div for every tooltip
|
$('.ui-helper-hidden-accessible').remove(); // jQuery-ui 1.11+ creates a div for every tooltip
|
||||||
|
|
||||||
function set_filters() {
|
function set_filters() {
|
||||||
["flt", "having"].forEach(function (prefix) {
|
['flt', 'having'].forEach(function (prefix) {
|
||||||
for (var i = 1; i < 10; i++) {
|
for (var i = 1; i < 10; i++) {
|
||||||
var col = px.getParam(prefix + "_col_" + i);
|
var col = px.getParam(prefix + '_col_' + i);
|
||||||
if (col !== '') {
|
if (col !== '') {
|
||||||
add_filter(i, prefix);
|
add_filter(i, prefix);
|
||||||
}
|
}
|
||||||
|
@ -309,13 +308,13 @@ function initExploreView() {
|
||||||
set_filters();
|
set_filters();
|
||||||
|
|
||||||
function add_filter(i, fieldPrefix) {
|
function add_filter(i, fieldPrefix) {
|
||||||
var cp = $("#"+fieldPrefix+"0").clone();
|
var cp = $('#' + fieldPrefix + '0').clone();
|
||||||
$(cp).appendTo("#" + getPanelClass(fieldPrefix) + " #filters");
|
$(cp).appendTo('#' + getPanelClass(fieldPrefix) + ' #filters');
|
||||||
$(cp).show();
|
$(cp).show();
|
||||||
if (i !== undefined) {
|
if (i !== undefined) {
|
||||||
$(cp).find("#"+fieldPrefix+"_eq_0").val(px.getParam(fieldPrefix+"_eq_" + i));
|
$(cp).find('#' + fieldPrefix + '_eq_0').val(px.getParam(fieldPrefix + '_eq_' + i));
|
||||||
$(cp).find("#"+fieldPrefix+"_op_0").val(px.getParam(fieldPrefix+"_op_" + i));
|
$(cp).find('#' + fieldPrefix + '_op_0').val(px.getParam(fieldPrefix + '_op_' + i));
|
||||||
$(cp).find("#"+fieldPrefix+"_col_0").val(px.getParam(fieldPrefix+"_col_" + i));
|
$(cp).find('#' + fieldPrefix + '_col_0').val(px.getParam(fieldPrefix + '_col_' + i));
|
||||||
}
|
}
|
||||||
$(cp).find('select').select2();
|
$(cp).find('select').select2();
|
||||||
$(cp).find('.remove').click(function () {
|
$(cp).find('.remove').click(function () {
|
||||||
|
@ -323,7 +322,7 @@ function initExploreView() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(window).bind("popstate", function (event) {
|
$(window).bind('popstate', function (event) {
|
||||||
// Browser back button
|
// Browser back button
|
||||||
var returnLocation = history.location || document.location;
|
var returnLocation = history.location || document.location;
|
||||||
// Could do something more lightweight here, but we're not optimizing
|
// Could do something more lightweight here, but we're not optimizing
|
||||||
|
@ -331,11 +330,11 @@ function initExploreView() {
|
||||||
returnLocation.reload();
|
returnLocation.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#filter_panel #plus").click(function () {
|
$('#filter_panel #plus').click(function () {
|
||||||
add_filter(undefined, "flt");
|
add_filter(undefined, 'flt');
|
||||||
});
|
});
|
||||||
$("#having_panel #plus").click(function () {
|
$('#having_panel #plus').click(function () {
|
||||||
add_filter(undefined, "having");
|
add_filter(undefined, 'having');
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryAndSaveBtnsEl = document.getElementById('js-query-and-save-btns');
|
const queryAndSaveBtnsEl = document.getElementById('js-query-and-save-btns');
|
||||||
|
@ -354,7 +353,7 @@ function initExploreView() {
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
return {
|
return {
|
||||||
id: term,
|
id: term,
|
||||||
text: term
|
text: term,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,11 +361,11 @@ function initExploreView() {
|
||||||
function initSelectionToValue(element, callback) {
|
function initSelectionToValue(element, callback) {
|
||||||
callback({
|
callback({
|
||||||
id: element.val(),
|
id: element.val(),
|
||||||
text: element.val()
|
text: element.val(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".select2_freeform").each(function () {
|
$('.select2_freeform').each(function () {
|
||||||
var parent = $(this).parent();
|
var parent = $(this).parent();
|
||||||
var name = $(this).attr('name');
|
var name = $(this).attr('name');
|
||||||
var l = [];
|
var l = [];
|
||||||
|
@ -374,7 +373,7 @@ function initExploreView() {
|
||||||
for (var i = 0; i < this.options.length; i++) {
|
for (var i = 0; i < this.options.length; i++) {
|
||||||
l.push({
|
l.push({
|
||||||
id: this.options[i].value,
|
id: this.options[i].value,
|
||||||
text: this.options[i].text
|
text: this.options[i].text,
|
||||||
});
|
});
|
||||||
if (this.options[i].selected) {
|
if (this.options[i].selected) {
|
||||||
selected = this.options[i].value;
|
selected = this.options[i].value;
|
||||||
|
@ -388,14 +387,14 @@ function initExploreView() {
|
||||||
initSelection: initSelectionToValue,
|
initSelection: initSelectionToValue,
|
||||||
dropdownAutoWidth: true,
|
dropdownAutoWidth: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
data: l
|
data: l,
|
||||||
});
|
});
|
||||||
$(this).remove();
|
$(this).remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
function prepSaveDialog() {
|
function prepSaveDialog() {
|
||||||
var setButtonsState = function () {
|
var setButtonsState = function () {
|
||||||
var add_to_dash = $("input[name=add_to_dash]:checked").val();
|
var add_to_dash = $('input[name=add_to_dash]:checked').val();
|
||||||
if (add_to_dash === 'existing' || add_to_dash === 'new') {
|
if (add_to_dash === 'existing' || add_to_dash === 'new') {
|
||||||
$('.gotodash').removeAttr('disabled');
|
$('.gotodash').removeAttr('disabled');
|
||||||
} else {
|
} else {
|
||||||
|
@ -406,25 +405,25 @@ function initExploreView() {
|
||||||
url += '?_flt_0_owners=' + $('#userid').val();
|
url += '?_flt_0_owners=' + $('#userid').val();
|
||||||
$.get(url, function (data) {
|
$.get(url, function (data) {
|
||||||
var choices = [];
|
var choices = [];
|
||||||
for (var i=0; i< data.pks.length; i++) {
|
for (var i = 0; i < data.pks.length; i++) {
|
||||||
choices.push({ id: data.pks[i], text: data.result[i].dashboard_title });
|
choices.push({ id: data.pks[i], text: data.result[i].dashboard_title });
|
||||||
}
|
}
|
||||||
$('#save_to_dashboard_id').select2({
|
$('#save_to_dashboard_id').select2({
|
||||||
data: choices,
|
data: choices,
|
||||||
dropdownAutoWidth: true
|
dropdownAutoWidth: true,
|
||||||
}).on("select2-selecting", function () {
|
}).on('select2-selecting', function () {
|
||||||
$("#add_to_dash_existing").prop("checked", true);
|
$('#add_to_dash_existing').prop('checked', true);
|
||||||
setButtonsState();
|
setButtonsState();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name=add_to_dash]").change(setButtonsState);
|
$('input[name=add_to_dash]').change(setButtonsState);
|
||||||
$("input[name='new_dashboard_name']").on('focus', function () {
|
$("input[name='new_dashboard_name']").on('focus', function () {
|
||||||
$("#add_to_new_dash").prop("checked", true);
|
$('#add_to_new_dash').prop('checked', true);
|
||||||
setButtonsState();
|
setButtonsState();
|
||||||
});
|
});
|
||||||
$("input[name='new_slice_name']").on('focus', function () {
|
$("input[name='new_slice_name']").on('focus', function () {
|
||||||
$("#save_as_new").prop("checked", true);
|
$('#save_as_new').prop('checked', true);
|
||||||
setButtonsState();
|
setButtonsState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -444,30 +443,30 @@ function saveSlice() {
|
||||||
var slice_name = $('input[name=new_slice_name]').val();
|
var slice_name = $('input[name=new_slice_name]').val();
|
||||||
if (slice_name === '') {
|
if (slice_name === '') {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "You must pick a name for the new slice"
|
body: 'You must pick a name for the new slice',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.getElementById("slice_name").value = slice_name;
|
document.getElementById('slice_name').value = slice_name;
|
||||||
}
|
}
|
||||||
var add_to_dash = $('input[name=add_to_dash]:checked').val();
|
var add_to_dash = $('input[name=add_to_dash]:checked').val();
|
||||||
if (add_to_dash === 'existing' && $('#save_to_dashboard_id').val() === '') {
|
if (add_to_dash === 'existing' && $('#save_to_dashboard_id').val() === '') {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "You must pick an existing dashboard"
|
body: 'You must pick an existing dashboard',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else if (add_to_dash === 'new' && $('input[name=new_dashboard_name]').val() === '') {
|
} else if (add_to_dash === 'new' && $('input[name=new_dashboard_name]').val() === '') {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "Please enter a name for the new dashboard"
|
body: 'Please enter a name for the new dashboard',
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$('#action').val(action);
|
$('#action').val(action);
|
||||||
prepForm();
|
prepForm();
|
||||||
$("#query").submit();
|
$('#query').submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
@ -489,9 +488,9 @@ $(document).ready(function () {
|
||||||
// make checkbox inputs display as toggles
|
// make checkbox inputs display as toggles
|
||||||
$(':checkbox')
|
$(':checkbox')
|
||||||
.addClass('pull-right')
|
.addClass('pull-right')
|
||||||
.attr("data-onstyle", "default")
|
.attr('data-onstyle', 'default')
|
||||||
.bootstrapToggle({
|
.bootstrapToggle({
|
||||||
size: 'mini'
|
size: 'mini',
|
||||||
});
|
});
|
||||||
|
|
||||||
$('div.toggle').addClass('pull-right');
|
$('div.toggle').addClass('pull-right');
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
var $ = require('jquery');
|
|
||||||
var jQuery = $;
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Jumbotron } from 'react-bootstrap';
|
import { Jumbotron } from 'react-bootstrap';
|
||||||
|
|
||||||
class App extends React.Component {
|
function App() {
|
||||||
render () {
|
return (
|
||||||
return (
|
<Jumbotron>
|
||||||
<Jumbotron>
|
<h1>Caravel</h1>
|
||||||
<h1>Caravel</h1>
|
<p>Extensible visualization tool for exploring data from any database.</p>
|
||||||
<p>Extensible visualization tool for exploring data from any database.</p>
|
</Jumbotron>
|
||||||
</Jumbotron>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(<App />, document.getElementById('app'));
|
render(<App />, document.getElementById('app'));
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
var $ = require('jquery');
|
import $ from 'jquery';
|
||||||
var jQuery = $;
|
const d3 = require('d3');
|
||||||
var d3 = require('d3');
|
const Mustache = require('mustache');
|
||||||
var Mustache = require('mustache');
|
const utils = require('./utils');
|
||||||
var utils = require('./utils');
|
|
||||||
|
|
||||||
// vis sources
|
// vis sources
|
||||||
var sourceMap = {
|
/* eslint camel-case: 0 */
|
||||||
|
const sourceMap = {
|
||||||
area: 'nvd3_vis.js',
|
area: 'nvd3_vis.js',
|
||||||
bar: 'nvd3_vis.js',
|
bar: 'nvd3_vis.js',
|
||||||
bubble: 'nvd3_vis.js',
|
bubble: 'nvd3_vis.js',
|
||||||
|
@ -34,185 +33,247 @@ var sourceMap = {
|
||||||
horizon: 'horizon.js',
|
horizon: 'horizon.js',
|
||||||
mapbox: 'mapbox.jsx',
|
mapbox: 'mapbox.jsx',
|
||||||
};
|
};
|
||||||
|
const color = function () {
|
||||||
var color = function () {
|
|
||||||
// Color related utility functions go in this object
|
// Color related utility functions go in this object
|
||||||
var bnbColors = [
|
const bnbColors = [
|
||||||
//rausch hackb kazan babu lima beach barol
|
'#ff5a5f', // rausch
|
||||||
'#ff5a5f', '#7b0051', '#007A87', '#00d1c1', '#8ce071', '#ffb400', '#b4a76c',
|
'#7b0051', // hackb
|
||||||
'#ff8083', '#cc0086', '#00a1b3', '#00ffeb', '#bbedab', '#ffd266', '#cbc29a',
|
'#007A87', // kazan
|
||||||
'#ff3339', '#ff1ab1', '#005c66', '#00b3a5', '#55d12e', '#b37e00', '#988b4e',
|
'#00d1c1', // babu
|
||||||
|
'#8ce071', // lima
|
||||||
|
'#ffb400', // beach
|
||||||
|
'#b4a76c', // barol
|
||||||
|
'#ff8083',
|
||||||
|
'#cc0086',
|
||||||
|
'#00a1b3',
|
||||||
|
'#00ffeb',
|
||||||
|
'#bbedab',
|
||||||
|
'#ffd266',
|
||||||
|
'#cbc29a',
|
||||||
|
'#ff3339',
|
||||||
|
'#ff1ab1',
|
||||||
|
'#005c66',
|
||||||
|
'#00b3a5',
|
||||||
|
'#55d12e',
|
||||||
|
'#b37e00',
|
||||||
|
'#988b4e',
|
||||||
];
|
];
|
||||||
var spectrums = {
|
const spectrums = {
|
||||||
blue_white_yellow: ['#00d1c1', 'white', '#ffb400'],
|
blue_white_yellow: [
|
||||||
fire: ['white', 'yellow', 'red', 'black'],
|
'#00d1c1',
|
||||||
white_black: ['white', 'black'],
|
'white',
|
||||||
black_white: ['black', 'white'],
|
'#ffb400',
|
||||||
|
],
|
||||||
|
fire: [
|
||||||
|
'white',
|
||||||
|
'yellow',
|
||||||
|
'red',
|
||||||
|
'black',
|
||||||
|
],
|
||||||
|
white_black: [
|
||||||
|
'white',
|
||||||
|
'black',
|
||||||
|
],
|
||||||
|
black_white: [
|
||||||
|
'black',
|
||||||
|
'white',
|
||||||
|
],
|
||||||
};
|
};
|
||||||
var colorBnb = function () {
|
const colorBnb = function () {
|
||||||
// Color factory
|
// Color factory
|
||||||
var seen = {};
|
const seen = {};
|
||||||
return function (s) {
|
return function (s) {
|
||||||
if (!s) { return; }
|
if (!s) {
|
||||||
s = String(s);
|
return;
|
||||||
// next line is for caravel series that should have the same color
|
|
||||||
s = s.replace('---', '');
|
|
||||||
if (seen[s] === undefined) {
|
|
||||||
seen[s] = Object.keys(seen).length;
|
|
||||||
}
|
}
|
||||||
return this.bnbColors[seen[s] % this.bnbColors.length];
|
let stringifyS = String(s);
|
||||||
|
// next line is for caravel series that should have the same color
|
||||||
|
stringifyS = stringifyS.replace('---', '');
|
||||||
|
if (seen[stringifyS] === undefined) {
|
||||||
|
seen[stringifyS] = Object.keys(seen).length;
|
||||||
|
}
|
||||||
|
/* eslint consistent-return: 0 */
|
||||||
|
return this.bnbColors[seen[stringifyS] % this.bnbColors.length];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var colorScalerFactory = function (colors, data, accessor) {
|
const colorScalerFactory = function (colors, data, accessor) {
|
||||||
// Returns a linear scaler our of an array of color
|
// Returns a linear scaler our of an array of color
|
||||||
if (!Array.isArray(colors)) {
|
if (!Array.isArray(colors)) {
|
||||||
|
/* eslint no-param-reassign: 0 */
|
||||||
colors = spectrums[colors];
|
colors = spectrums[colors];
|
||||||
}
|
}
|
||||||
|
let ext = [
|
||||||
var ext = [0, 1];
|
0,
|
||||||
|
1,
|
||||||
|
];
|
||||||
if (data !== undefined) {
|
if (data !== undefined) {
|
||||||
ext = d3.extent(data, accessor);
|
ext = d3.extent(data, accessor);
|
||||||
}
|
}
|
||||||
|
const points = [];
|
||||||
var points = [];
|
const chunkSize = (ext[1] - ext[0]) / colors.length;
|
||||||
var chunkSize = (ext[1] - ext[0]) / colors.length;
|
$.each(colors, function (i) {
|
||||||
$.each(colors, function (i, c) {
|
|
||||||
points.push(i * chunkSize);
|
points.push(i * chunkSize);
|
||||||
});
|
});
|
||||||
return d3.scale.linear().domain(points).range(colors);
|
return d3.scale.linear().domain(points).range(colors);
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
bnbColors: bnbColors,
|
bnbColors,
|
||||||
category21: colorBnb(),
|
category21: colorBnb(),
|
||||||
colorScalerFactory: colorScalerFactory,
|
colorScalerFactory,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/* eslint wrap-iife: 0*/
|
||||||
var px = (function () {
|
const px = function () {
|
||||||
|
const visualizations = {};
|
||||||
var visualizations = {};
|
let slice;
|
||||||
var slice;
|
|
||||||
|
|
||||||
function getParam(name) {
|
function getParam(name) {
|
||||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||||
results = regex.exec(location.search);
|
const results = regex.exec(location.search);
|
||||||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
function UTC(dttm) {
|
function UTC(dttm) {
|
||||||
return new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds());
|
return new Date(
|
||||||
|
dttm.getUTCFullYear(),
|
||||||
|
dttm.getUTCMonth(),
|
||||||
|
dttm.getUTCDate(),
|
||||||
|
dttm.getUTCHours(),
|
||||||
|
dttm.getUTCMinutes(),
|
||||||
|
dttm.getUTCSeconds()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
var tickMultiFormat = d3.time.format.multi([
|
const tickMultiFormat = d3.time.format.multi([
|
||||||
[".%L", function (d) {
|
[
|
||||||
return d.getMilliseconds();
|
'.%L',
|
||||||
}], // If there are millisections, show only them
|
function (d) {
|
||||||
[":%S", function (d) {
|
return d.getMilliseconds();
|
||||||
return d.getSeconds();
|
},
|
||||||
}], // If there are seconds, show only them
|
],
|
||||||
["%a %b %d, %I:%M %p", function (d) {
|
// If there are millisections, show only them
|
||||||
return d.getMinutes() !== 0;
|
[
|
||||||
}], // If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
|
':%S',
|
||||||
["%a %b %d, %I %p", function (d) {
|
function (d) {
|
||||||
return d.getHours() !== 0;
|
return d.getSeconds();
|
||||||
}], // If there are hours that are multiples of 3, show date and AM/PM
|
},
|
||||||
["%a %b %d", function (d) {
|
],
|
||||||
return d.getDate() !== 1;
|
// If there are seconds, show only them
|
||||||
}], // If not the first of the month, do "month day, year."
|
[
|
||||||
["%B %Y", function (d) {
|
'%a %b %d, %I:%M %p',
|
||||||
return d.getMonth() !== 0 && d.getDate() === 1;
|
function (d) {
|
||||||
}], // If the first of the month, do "month day, year."
|
return d.getMinutes() !== 0;
|
||||||
["%Y", function (d) {
|
},
|
||||||
return true;
|
],
|
||||||
}], // fall back on month, year
|
// If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
|
||||||
|
[
|
||||||
|
'%a %b %d, %I %p',
|
||||||
|
function (d) {
|
||||||
|
return d.getHours() !== 0;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// If there are hours that are multiples of 3, show date and AM/PM
|
||||||
|
[
|
||||||
|
'%a %b %d',
|
||||||
|
function (d) {
|
||||||
|
return d.getDate() !== 1;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// If not the first of the month, do "month day, year."
|
||||||
|
[
|
||||||
|
'%B %Y',
|
||||||
|
function (d) {
|
||||||
|
return d.getMonth() !== 0 && d.getDate() === 1;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// If the first of the month, do "month day, year."
|
||||||
|
[
|
||||||
|
'%Y',
|
||||||
|
function () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
], // fall back on month, year
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function formatDate(dttm) {
|
function formatDate(dttm) {
|
||||||
var d = UTC(new Date(dttm));
|
const d = UTC(new Date(dttm));
|
||||||
//d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
|
// d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
|
||||||
return tickMultiFormat(d);
|
return tickMultiFormat(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeFormatFactory(d3timeFormat) {
|
function timeFormatFactory(d3timeFormat) {
|
||||||
var f = d3.time.format(d3timeFormat);
|
const f = d3.time.format(d3timeFormat);
|
||||||
return function (dttm) {
|
return function (dttm) {
|
||||||
var d = UTC(new Date(dttm));
|
const d = UTC(new Date(dttm));
|
||||||
return f(d);
|
return f(d);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function initFavStars() {
|
function initFavStars() {
|
||||||
var baseUrl = '/caravel/favstar/';
|
const baseUrl = '/caravel/favstar/';
|
||||||
// Init star behavihor for favorite
|
// Init star behavihor for favorite
|
||||||
function show() {
|
function show() {
|
||||||
if ($(this).hasClass('selected')) {
|
if ($(this).hasClass('selected')) {
|
||||||
$(this).html('<i class="fa fa-star"></i>');
|
$(this).html('<i class="fa fa-star"></i>');
|
||||||
} else {
|
} else {
|
||||||
$(this).html('<i class="fa fa-star-o"></i>');
|
$(this).html('<i class="fa fa-star-o"></i>');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$('.favstar')
|
}
|
||||||
.attr('title', 'Click to favorite/unfavorite')
|
$('.favstar')
|
||||||
.each(show)
|
.attr('title', 'Click to favorite/unfavorite')
|
||||||
.each(function () {
|
.each(show)
|
||||||
var url = baseUrl + $(this).attr("class_name");
|
.each(function () {
|
||||||
var star = this;
|
let url = baseUrl + $(this).attr('class_name');
|
||||||
url += '/' + $(this).attr("obj_id") + '/';
|
const star = this;
|
||||||
$.getJSON(url + 'count/', function (data) {
|
url += '/' + $(this).attr('obj_id') + '/';
|
||||||
if (data.count > 0) {
|
$.getJSON(url + 'count/', function (data) {
|
||||||
$(star)
|
if (data.count > 0) {
|
||||||
.addClass('selected')
|
$(star).addClass('selected').each(show);
|
||||||
.each(show);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.click(function () {
|
|
||||||
$(this).toggleClass('selected');
|
|
||||||
var url = baseUrl + $(this).attr("class_name");
|
|
||||||
url += '/' + $(this).attr("obj_id") + '/';
|
|
||||||
if ($(this).hasClass('selected')) {
|
|
||||||
url += 'select/';
|
|
||||||
} else {
|
|
||||||
url += 'unselect/';
|
|
||||||
}
|
}
|
||||||
$.get(url);
|
});
|
||||||
$(this).each(show);
|
})
|
||||||
})
|
.click(function () {
|
||||||
.tooltip();
|
$(this).toggleClass('selected');
|
||||||
|
let url = baseUrl + $(this).attr('class_name');
|
||||||
|
url += '/' + $(this).attr('obj_id') + '/';
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
url += 'select/';
|
||||||
|
} else {
|
||||||
|
url += 'unselect/';
|
||||||
|
}
|
||||||
|
$.get(url);
|
||||||
|
$(this).each(show);
|
||||||
|
})
|
||||||
|
.tooltip();
|
||||||
}
|
}
|
||||||
|
const Slice = function (data, dashboard) {
|
||||||
var Slice = function (data, dashboard) {
|
let timer;
|
||||||
var timer;
|
const token = $('#' + data.token);
|
||||||
var token = $('#' + data.token);
|
const containerId = data.token + '_con';
|
||||||
var container_id = data.token + '_con';
|
const selector = '#' + containerId;
|
||||||
var selector = '#' + container_id;
|
const container = $(selector);
|
||||||
var container = $(selector);
|
const sliceId = data.sliceId;
|
||||||
var slice_id = data.slice_id;
|
let dttm = 0;
|
||||||
var dttm = 0;
|
const stopwatch = function () {
|
||||||
var stopwatch = function () {
|
|
||||||
dttm += 10;
|
dttm += 10;
|
||||||
var num = dttm / 1000;
|
const num = dttm / 1000;
|
||||||
$('#timer').text(num.toFixed(2) + " sec");
|
$('#timer').text(num.toFixed(2) + ' sec');
|
||||||
};
|
};
|
||||||
var qrystr = '';
|
let qrystr = '';
|
||||||
var always = function (data) {
|
const always = function () {
|
||||||
//Private f, runs after done and error
|
// Private f, runs after done and error
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
$('#timer').removeClass('btn-warning');
|
$('#timer').removeClass('btn-warning');
|
||||||
};
|
};
|
||||||
slice = {
|
slice = {
|
||||||
data: data,
|
data,
|
||||||
container: container,
|
container,
|
||||||
container_id: container_id,
|
containerId,
|
||||||
selector: selector,
|
selector,
|
||||||
querystring: function (params) {
|
querystring(params) {
|
||||||
params = params || {};
|
params = params || {};
|
||||||
var parser = document.createElement('a');
|
const parser = document.createElement('a');
|
||||||
parser.href = data.json_endpoint;
|
parser.href = data.json_endpoint;
|
||||||
if (dashboard !== undefined) {
|
if (dashboard !== undefined) {
|
||||||
var flts = params.extraFilters === false ?
|
const flts =
|
||||||
'' : encodeURIComponent(JSON.stringify(dashboard.filters));
|
params.extraFilters === false ? '' :
|
||||||
qrystr = parser.search + "&extra_filters=" + flts;
|
encodeURIComponent(JSON.stringify(dashboard.filters));
|
||||||
|
qrystr = parser.search + '&extra_filters=' + flts;
|
||||||
} else if ($('#query').length === 0) {
|
} else if ($('#query').length === 0) {
|
||||||
qrystr = parser.search;
|
qrystr = parser.search;
|
||||||
} else {
|
} else {
|
||||||
|
@ -220,69 +281,66 @@ var px = (function () {
|
||||||
}
|
}
|
||||||
return qrystr;
|
return qrystr;
|
||||||
},
|
},
|
||||||
getWidgetHeader: function () {
|
getWidgetHeader() {
|
||||||
return this.container.parents("div.widget").find(".chart-header");
|
return this.container.parents('div.widget').find('.chart-header');
|
||||||
},
|
},
|
||||||
render_template: function (s) {
|
render_template(s) {
|
||||||
var context = {
|
const context = {
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
};
|
};
|
||||||
return Mustache.render(s, context);
|
return Mustache.render(s, context);
|
||||||
},
|
},
|
||||||
jsonEndpoint: function (params) {
|
jsonEndpoint(params) {
|
||||||
params = params || {};
|
params = params || {};
|
||||||
var parser = document.createElement('a');
|
const parser = document.createElement('a');
|
||||||
parser.href = data.json_endpoint;
|
parser.href = data.json_endpoint;
|
||||||
var endpoint = parser.pathname + this.querystring({
|
let endpoint = parser.pathname + this.querystring({ extraFilters: params.extraFilters });
|
||||||
extraFilters: params.extraFilters,
|
endpoint += '&json=true';
|
||||||
});
|
endpoint += '&force=' + this.force;
|
||||||
endpoint += "&json=true";
|
|
||||||
endpoint += "&force=" + this.force;
|
|
||||||
return endpoint;
|
return endpoint;
|
||||||
},
|
},
|
||||||
d3format: function (col, number) {
|
d3format(col, number) {
|
||||||
// uses the utils memoized d3format function and formats based on
|
// uses the utils memoized d3format function and formats based on
|
||||||
// column level defined preferences
|
// column level defined preferences
|
||||||
var format = this.data.column_formats[col];
|
const format = this.data.column_formats[col];
|
||||||
return utils.d3format(format, number);
|
return utils.d3format(format, number);
|
||||||
},
|
},
|
||||||
done: function (data) {
|
/* eslint no-shadow: 0 */
|
||||||
|
done(data) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
token.find("img.loading").hide();
|
token.find('img.loading').hide();
|
||||||
container.show();
|
container.show();
|
||||||
|
let cachedSelector = null;
|
||||||
var cachedSelector = null;
|
|
||||||
if (dashboard === undefined) {
|
if (dashboard === undefined) {
|
||||||
cachedSelector = $('#is_cached');
|
cachedSelector = $('#is_cached');
|
||||||
if (data !== undefined && data.is_cached) {
|
if (data !== undefined && data.is_cached) {
|
||||||
cachedSelector
|
cachedSelector
|
||||||
.attr('title', 'Served from data cached at ' + data.cached_dttm + '. Click to force-refresh')
|
.attr('title',
|
||||||
|
'Served from data cached at ' + data.cached_dttm + '. Click to force-refresh')
|
||||||
.show()
|
.show()
|
||||||
.tooltip('fixTitle');
|
.tooltip('fixTitle');
|
||||||
} else {
|
} else {
|
||||||
cachedSelector.hide();
|
cachedSelector.hide();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var refresh = this.getWidgetHeader().find('.refresh');
|
const refresh = this.getWidgetHeader().find('.refresh');
|
||||||
if (data !== undefined && data.is_cached) {
|
if (data !== undefined && data.is_cached) {
|
||||||
refresh
|
refresh
|
||||||
.addClass('danger')
|
.addClass('danger')
|
||||||
.attr(
|
.attr('title',
|
||||||
'title',
|
'Served from data cached at ' + data.cached_dttm +
|
||||||
'Served from data cached at ' + data.cached_dttm + '. Click to force-refresh')
|
'. Click to force-refresh')
|
||||||
.tooltip('fixTitle');
|
.tooltip('fixTitle');
|
||||||
} else {
|
} else {
|
||||||
refresh
|
refresh
|
||||||
.removeClass('danger')
|
.removeClass('danger')
|
||||||
.attr(
|
.attr('title', 'Click to force-refresh')
|
||||||
'title',
|
.tooltip('fixTitle');
|
||||||
'Click to force-refresh')
|
|
||||||
.tooltip('fixTitle');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data !== undefined) {
|
if (data !== undefined) {
|
||||||
$("#query_container").html(data.query);
|
$('#query_container').html(data.query);
|
||||||
}
|
}
|
||||||
$('#timer').removeClass('btn-warning');
|
$('#timer').removeClass('btn-warning');
|
||||||
$('#timer').addClass('btn-success');
|
$('#timer').addClass('btn-success');
|
||||||
|
@ -297,26 +355,26 @@ var px = (function () {
|
||||||
$('.query-and-save button').removeAttr('disabled');
|
$('.query-and-save button').removeAttr('disabled');
|
||||||
always(data);
|
always(data);
|
||||||
},
|
},
|
||||||
getErrorMsg: function (xhr) {
|
getErrorMsg(xhr) {
|
||||||
if (xhr.statusText === "timeout") {
|
if (xhr.statusText === 'timeout') {
|
||||||
return "The request timed out";
|
return 'The request timed out';
|
||||||
}
|
}
|
||||||
var msg = "";
|
let msg = '';
|
||||||
if (!xhr.responseText) {
|
if (!xhr.responseText) {
|
||||||
var status = xhr.status;
|
const status = xhr.status;
|
||||||
msg += "An unknown error occurred. (Status: " + status + ")";
|
msg += 'An unknown error occurred. (Status: ' + status + ')';
|
||||||
if (status === 0) {
|
if (status === 0) {
|
||||||
// This may happen when the worker in gunicorn times out
|
// This may happen when the worker in gunicorn times out
|
||||||
msg += " Maybe the request timed out?";
|
msg += ' Maybe the request timed out?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
},
|
},
|
||||||
error: function (msg, xhr) {
|
error(msg, xhr) {
|
||||||
token.find("img.loading").hide();
|
token.find('img.loading').hide();
|
||||||
var err = msg ? ('<div class="alert alert-danger">' + msg + '</div>') : "";
|
let err = msg ? '<div class="alert alert-danger">' + msg + '</div>' : '';
|
||||||
if (xhr) {
|
if (xhr) {
|
||||||
var extendedMsg = this.getErrorMsg(xhr);
|
const extendedMsg = this.getErrorMsg(xhr);
|
||||||
if (extendedMsg) {
|
if (extendedMsg) {
|
||||||
err += '<div class="alert alert-danger">' + extendedMsg + '</div>';
|
err += '<div class="alert alert-danger">' + extendedMsg + '</div>';
|
||||||
}
|
}
|
||||||
|
@ -329,35 +387,35 @@ var px = (function () {
|
||||||
$('.query-and-save button').removeAttr('disabled');
|
$('.query-and-save button').removeAttr('disabled');
|
||||||
always(data);
|
always(data);
|
||||||
},
|
},
|
||||||
width: function () {
|
width() {
|
||||||
return token.width();
|
return token.width();
|
||||||
},
|
},
|
||||||
height: function () {
|
height() {
|
||||||
var others = 0;
|
let others = 0;
|
||||||
var widget = container.parents('.widget');
|
const widget = container.parents('.widget');
|
||||||
var slice_description = widget.find('.slice_description');
|
const sliceDescription = widget.find('.sliceDescription');
|
||||||
if (slice_description.is(":visible")) {
|
if (sliceDescription.is(':visible')) {
|
||||||
others += widget.find('.slice_description').height() + 25;
|
others += widget.find('.sliceDescription').height() + 25;
|
||||||
}
|
}
|
||||||
others += widget.find('.chart-header').height();
|
others += widget.find('.chart-header').height();
|
||||||
return widget.height() - others - 10;
|
return widget.height() - others - 10;
|
||||||
},
|
},
|
||||||
bindResizeToWindowResize: function () {
|
bindResizeToWindowResize() {
|
||||||
var resizeTimer;
|
let resizeTimer;
|
||||||
var slice = this;
|
const slice = this;
|
||||||
$(window).on('resize', function (e) {
|
$(window).on('resize', function () {
|
||||||
clearTimeout(resizeTimer);
|
clearTimeout(resizeTimer);
|
||||||
resizeTimer = setTimeout(function () {
|
resizeTimer = setTimeout(function () {
|
||||||
slice.resize();
|
slice.resize();
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
render: function (force) {
|
render(force) {
|
||||||
if (force === undefined) {
|
if (force === undefined) {
|
||||||
force = false;
|
force = false;
|
||||||
}
|
}
|
||||||
this.force = force;
|
this.force = force;
|
||||||
token.find("img.loading").show();
|
token.find('img.loading').show();
|
||||||
container.css('height', this.height());
|
container.css('height', this.height());
|
||||||
dttm = 0;
|
dttm = 0;
|
||||||
timer = setInterval(stopwatch, 10);
|
timer = setInterval(stopwatch, 10);
|
||||||
|
@ -365,67 +423,65 @@ var px = (function () {
|
||||||
$('#timer').addClass('btn-warning');
|
$('#timer').addClass('btn-warning');
|
||||||
this.viz.render();
|
this.viz.render();
|
||||||
},
|
},
|
||||||
resize: function () {
|
resize() {
|
||||||
token.find("img.loading").show();
|
token.find('img.loading').show();
|
||||||
container.css('height', this.height());
|
container.css('height', this.height());
|
||||||
this.viz.render();
|
this.viz.render();
|
||||||
this.viz.resize();
|
this.viz.resize();
|
||||||
},
|
},
|
||||||
addFilter: function (col, vals) {
|
addFilter(col, vals) {
|
||||||
if (dashboard !== undefined) {
|
if (dashboard !== undefined) {
|
||||||
dashboard.addFilter(slice_id, col, vals);
|
dashboard.addFilter(sliceId, col, vals);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setFilter: function (col, vals) {
|
setFilter(col, vals) {
|
||||||
if (dashboard !== undefined) {
|
if (dashboard !== undefined) {
|
||||||
dashboard.setFilter(slice_id, col, vals);
|
dashboard.setFilter(sliceId, col, vals);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getFilters: function (col, vals) {
|
getFilters() {
|
||||||
if (dashboard !== undefined) {
|
if (dashboard !== undefined) {
|
||||||
return dashboard.filters[slice_id];
|
return dashboard.filters[sliceId];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
clearFilter() {
|
||||||
|
if (dashboard !== undefined) {
|
||||||
|
dashboard.clearFilter(sliceId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearFilter: function () {
|
removeFilter(col, vals) {
|
||||||
if (dashboard !== undefined) {
|
if (dashboard !== undefined) {
|
||||||
delete dashboard.clearFilter(slice_id);
|
dashboard.removeFilter(sliceId, col, vals);
|
||||||
}
|
|
||||||
},
|
|
||||||
removeFilter: function (col, vals) {
|
|
||||||
if (dashboard !== undefined) {
|
|
||||||
delete dashboard.removeFilter(slice_id, col, vals);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var visType = data.form_data.viz_type;
|
const visType = data.form_data.viz_type;
|
||||||
px.registerViz(visType);
|
px.registerViz(visType);
|
||||||
slice.viz = visualizations[data.form_data.viz_type](slice);
|
slice.viz = visualizations[data.form_data.viz_type](slice);
|
||||||
return slice;
|
return slice;
|
||||||
};
|
};
|
||||||
|
|
||||||
function registerViz(name) {
|
function registerViz(name) {
|
||||||
var visSource = sourceMap[name];
|
const visSource = sourceMap[name];
|
||||||
|
|
||||||
if (visSource) {
|
if (visSource) {
|
||||||
var visFactory = require('../../visualizations/' + visSource);
|
/* eslint global-require: 0 */
|
||||||
|
const visFactory = require('../../visualizations/' + visSource);
|
||||||
if (typeof visFactory === 'function') {
|
if (typeof visFactory === 'function') {
|
||||||
visualizations[name] = visFactory;
|
visualizations[name] = visFactory;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("require(" + name + ") failed.");
|
throw new Error('require(' + name + ') failed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export public functions
|
// Export public functions
|
||||||
return {
|
return {
|
||||||
registerViz: registerViz,
|
|
||||||
Slice: Slice,
|
|
||||||
formatDate: formatDate,
|
|
||||||
timeFormatFactory: timeFormatFactory,
|
|
||||||
color: color(),
|
color: color(),
|
||||||
getParam: getParam,
|
formatDate,
|
||||||
initFavStars: initFavStars,
|
getParam,
|
||||||
|
initFavStars,
|
||||||
|
registerViz,
|
||||||
|
Slice,
|
||||||
|
timeFormatFactory,
|
||||||
};
|
};
|
||||||
})();
|
}();
|
||||||
|
|
||||||
module.exports = px;
|
module.exports = px;
|
||||||
|
|
|
@ -1,56 +1,51 @@
|
||||||
var $ = require('jquery');
|
const $ = require('jquery');
|
||||||
var d3 = require('d3');
|
const d3 = require('d3');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utility function that takes a d3 svg:text selection and a max width, and splits the
|
Utility function that takes a d3 svg:text selection and a max width, and splits the
|
||||||
text's text across multiple tspan lines such that any given line does not exceed max width
|
text's text across multiple tspan lines such that any given line does not exceed max width
|
||||||
|
|
||||||
If text does not span multiple lines AND adjustedY is passed, will set the text to the passed val
|
If text does not span multiple lines AND adjustedY is passed,
|
||||||
|
will set the text to the passed val
|
||||||
*/
|
*/
|
||||||
function wrapSvgText(text, width, adjustedY) {
|
function wrapSvgText(text, width, adjustedY) {
|
||||||
var lineHeight = 1; // ems
|
const lineHeight = 1;
|
||||||
|
// ems
|
||||||
text.each(function () {
|
text.each(function () {
|
||||||
var text = d3.select(this),
|
const d3Text = d3.select(this);
|
||||||
words = text.text().split(/\s+/),
|
const words = d3Text.text().split(/\s+/);
|
||||||
word,
|
let word;
|
||||||
line = [],
|
let line = [];
|
||||||
lineNumber = 0,
|
let lineNumber = 0;
|
||||||
x = text.attr("x"),
|
const x = d3Text.attr('x');
|
||||||
y = text.attr("y"),
|
const y = d3Text.attr('y');
|
||||||
dy = parseFloat(text.attr("dy")),
|
const dy = parseFloat(d3Text.attr('dy'));
|
||||||
tspan = text.text(null)
|
let tspan =
|
||||||
.append("tspan")
|
d3Text.text(null).append('tspan').attr('x', x)
|
||||||
.attr("x", x)
|
.attr('y', y)
|
||||||
.attr("y", y)
|
.attr('dy', dy + 'em');
|
||||||
.attr("dy", dy + "em");
|
|
||||||
|
|
||||||
var didWrap = false;
|
let didWrap = false;
|
||||||
|
for (let i = 0; i < words.length; i++) {
|
||||||
for (var i = 0; i < words.length; i++) {
|
|
||||||
word = words[i];
|
word = words[i];
|
||||||
line.push(word);
|
line.push(word);
|
||||||
tspan.text(line.join(" "));
|
tspan.text(line.join(' '));
|
||||||
|
|
||||||
if (tspan.node().getComputedTextLength() > width) {
|
if (tspan.node().getComputedTextLength() > width) {
|
||||||
line.pop(); // remove word that pushes over the limit
|
line.pop();
|
||||||
tspan.text(line.join(" "));
|
// remove word that pushes over the limit
|
||||||
|
tspan.text(line.join(' '));
|
||||||
line = [word];
|
line = [word];
|
||||||
tspan = text.append("tspan")
|
tspan =
|
||||||
.attr("x", x)
|
d3Text.append('tspan').attr('x', x).attr('y', y)
|
||||||
.attr("y", y)
|
.attr('dy', ++lineNumber * lineHeight + dy + 'em')
|
||||||
.attr("dy", ++lineNumber * lineHeight + dy + "em")
|
.text(word);
|
||||||
.text(word);
|
|
||||||
|
|
||||||
didWrap = true;
|
didWrap = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!didWrap && typeof adjustedY !== "undefined") {
|
if (!didWrap && typeof adjustedY !== 'undefined') {
|
||||||
tspan.attr("y", adjustedY);
|
tspan.attr('y', adjustedY);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the body and title content of a modal, and shows it. Assumes HTML for modal exists and that
|
* Sets the body and title content of a modal, and shows it. Assumes HTML for modal exists and that
|
||||||
* it handles closing (i.e., works with bootstrap)
|
* it handles closing (i.e., works with bootstrap)
|
||||||
|
@ -65,47 +60,41 @@ function wrapSvgText(text, width, adjustedY) {
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
function showModal(options) {
|
function showModal(options) {
|
||||||
options.modalSelector = options.modalSelector || ".misc-modal";
|
/* eslint no-param-reassign: 0 */
|
||||||
options.titleSelector = options.titleSelector || ".misc-modal .modal-title";
|
options.modalSelector = options.modalSelector || '.misc-modal';
|
||||||
options.bodySelector = options.bodySelector || ".misc-modal .modal-body";
|
options.titleSelector = options.titleSelector || '.misc-modal .modal-title';
|
||||||
|
options.bodySelector = options.bodySelector || '.misc-modal .modal-body';
|
||||||
$(options.titleSelector).html(options.title || "");
|
$(options.titleSelector).html(options.title || '');
|
||||||
$(options.bodySelector).html(options.body || "");
|
$(options.bodySelector).html(options.body || '');
|
||||||
$(options.modalSelector).modal("show");
|
$(options.modalSelector).modal('show');
|
||||||
}
|
}
|
||||||
|
const showApiMessage = function (resp) {
|
||||||
var showApiMessage = function (resp) {
|
const template =
|
||||||
var template = '<div class="alert"> ' +
|
'<div class="alert"> ' +
|
||||||
'<button type="button" class="close" ' +
|
'<button type="button" class="close" ' +
|
||||||
'data-dismiss="alert">×</button> </div>';
|
'data-dismiss="alert">\xD7</button> </div>';
|
||||||
|
const severity = resp.severity || 'info';
|
||||||
var severity = resp.severity || 'info';
|
$(template).addClass('alert-' + severity)
|
||||||
$(template)
|
.append(resp.message)
|
||||||
.addClass('alert-' + severity)
|
.appendTo($('#alert-container'));
|
||||||
.append(resp.message)
|
|
||||||
.appendTo($('#alert-container'));
|
|
||||||
};
|
};
|
||||||
|
const toggleCheckbox = function (apiUrlPrefix, selector) {
|
||||||
var toggleCheckbox = function (apiUrlPrefix, selector) {
|
const apiUrl = apiUrlPrefix + $(selector)[0].checked;
|
||||||
var apiUrl = apiUrlPrefix + $(selector)[0].checked;
|
$.get(apiUrl).fail(function (xhr) {
|
||||||
$.get(apiUrl).fail(function (xhr, textStatus, errorThrown) {
|
const resp = xhr.responseJSON;
|
||||||
var resp = xhr.responseJSON;
|
|
||||||
if (resp && resp.message) {
|
if (resp && resp.message) {
|
||||||
showApiMessage(resp);
|
showApiMessage(resp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix the height of the table body of a DataTable with scrollY set
|
* Fix the height of the table body of a DataTable with scrollY set
|
||||||
*/
|
*/
|
||||||
var fixDataTableBodyHeight = function ($tableDom, height) {
|
const fixDataTableBodyHeight = function ($tableDom, height) {
|
||||||
var headHeight = $tableDom.find('.dataTables_scrollHead').height();
|
const headHeight = $tableDom.find('.dataTables_scrollHead').height();
|
||||||
$tableDom.find('.dataTables_scrollBody')
|
$tableDom.find('.dataTables_scrollBody').css('max-height', height - headHeight);
|
||||||
.css('max-height', height - headHeight);
|
|
||||||
};
|
};
|
||||||
|
const formatters = {};
|
||||||
var formatters = {};
|
|
||||||
function d3format(format, number) {
|
function d3format(format, number) {
|
||||||
// Formats a number and memoizes formatters to be reused
|
// Formats a number and memoizes formatters to be reused
|
||||||
format = format || '.3s';
|
format = format || '.3s';
|
||||||
|
@ -114,11 +103,10 @@ function d3format(format, number) {
|
||||||
}
|
}
|
||||||
return formatters[format](number);
|
return formatters[format](number);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
wrapSvgText: wrapSvgText,
|
d3format,
|
||||||
showModal: showModal,
|
fixDataTableBodyHeight,
|
||||||
toggleCheckbox: toggleCheckbox,
|
showModal,
|
||||||
fixDataTableBodyHeight: fixDataTableBodyHeight,
|
toggleCheckbox,
|
||||||
d3format: d3format,
|
wrapSvgText,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,93 +1,80 @@
|
||||||
var $ = window.$ = require('jquery');
|
const $ = window.$ = require('jquery');
|
||||||
var jQuery = window.jQuery = $;
|
const showModal = require('./modules/utils.js').showModal;
|
||||||
var showModal = require('./modules/utils.js').showModal;
|
|
||||||
|
|
||||||
require('./caravel-select2.js');
|
require('./caravel-select2.js');
|
||||||
|
|
||||||
require('datatables.net-bs');
|
require('datatables.net-bs');
|
||||||
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
|
const ace = require('brace');
|
||||||
var ace = require('brace');
|
|
||||||
require('brace/mode/sql');
|
require('brace/mode/sql');
|
||||||
require('brace/theme/crimson_editor');
|
require('brace/theme/crimson_editor');
|
||||||
|
|
||||||
require('../stylesheets/sql.css');
|
require('../stylesheets/sql.css');
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
function getParam(name) {
|
function getParam(name) {
|
||||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
/* eslint no-param-reassign: 0 */
|
||||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||||
results = regex.exec(location.search);
|
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
const results = regex.exec(location.search);
|
||||||
|
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSqlEditorView() {
|
function initSqlEditorView() {
|
||||||
var database_id = $('#database_id').val();
|
const databaseId = $('#databaseId').val();
|
||||||
var editor = ace.edit("sql");
|
const editor = ace.edit('sql');
|
||||||
editor.$blockScrolling = Infinity;
|
editor.$blockScrolling = Infinity;
|
||||||
editor.getSession().setUseWrapMode(true);
|
editor.getSession().setUseWrapMode(true);
|
||||||
|
|
||||||
$('#sql').hide();
|
$('#sql').hide();
|
||||||
editor.setTheme("ace/theme/crimson_editor");
|
editor.setTheme('ace/theme/crimson_editor');
|
||||||
editor.setOptions({
|
editor.setOptions({
|
||||||
minLines: 16,
|
minLines: 16,
|
||||||
maxLines: Infinity,
|
maxLines: Infinity,
|
||||||
});
|
});
|
||||||
editor.getSession().setMode("ace/mode/sql");
|
editor.getSession().setMode('ace/mode/sql');
|
||||||
editor.focus();
|
editor.focus();
|
||||||
$("select").select2({
|
|
||||||
dropdownAutoWidth: true,
|
$('select').select2({ dropdownAutoWidth: true });
|
||||||
});
|
|
||||||
|
|
||||||
function showTableMetadata() {
|
function showTableMetadata() {
|
||||||
$(".metadata").load(
|
$('.metadata').load('/caravel/table/' + databaseId + '/' + $('#dbtable').val() + '/');
|
||||||
'/caravel/table/' + database_id + '/' + $("#dbtable").val() + '/');
|
|
||||||
}
|
}
|
||||||
$("#dbtable").on("change", showTableMetadata);
|
$('#dbtable').on('change', showTableMetadata);
|
||||||
showTableMetadata();
|
showTableMetadata();
|
||||||
$("#create_view").click(function () {
|
$('#create_view').click(function () {
|
||||||
showModal({
|
showModal({
|
||||||
title: "Error",
|
title: 'Error',
|
||||||
body: "Sorry, this feature is not yet implemented",
|
body: 'Sorry, this feature is not yet implemented',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$(".sqlcontent").show();
|
$('.sqlcontent').show();
|
||||||
|
|
||||||
function selectStarOnClick() {
|
function selectStarOnClick() {
|
||||||
$.ajax('/caravel/select_star/' + database_id + '/' + $("#dbtable").val() + '/')
|
const url = '/caravel/select_star/' + databaseId + '/' + $('#dbtable').val() + '/';
|
||||||
.done(function (msg) {
|
$.ajax(url).done(function (msg) {
|
||||||
editor.setValue(msg);
|
editor.setValue(msg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
$('#select_star').click(selectStarOnClick);
|
||||||
$("#select_star").click(selectStarOnClick);
|
|
||||||
|
|
||||||
editor.setValue(getParam('sql'));
|
editor.setValue(getParam('sql'));
|
||||||
$(window).bind("popstate", function (event) {
|
$(window).bind('popstate', function () {
|
||||||
// Could do something more lightweight here, but we're not optimizing
|
// Could do something more lightweight here, but we're not optimizing
|
||||||
// for the use of the back button anyways
|
// for the use of the back button anyways
|
||||||
editor.setValue(getParam('sql'));
|
editor.setValue(getParam('sql'));
|
||||||
$("#run").click();
|
$('#run').click();
|
||||||
});
|
});
|
||||||
$("#run").click(function () {
|
$('#run').click(function () {
|
||||||
$('#results').hide(0);
|
$('#results').hide(0);
|
||||||
$('#loading').show(0);
|
$('#loading').show(0);
|
||||||
history.pushState({}, document.title, '?sql=' + encodeURIComponent(editor.getValue()));
|
history.pushState({}, document.title, '?sql=' + encodeURIComponent(editor.getValue()));
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: 'POST',
|
||||||
url: '/caravel/runsql/',
|
url: '/caravel/runsql/',
|
||||||
data: {
|
data: {
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
database_id: $('#database_id').val(),
|
databaseId: $('#databaseId').val(),
|
||||||
sql: editor.getSession().getValue(),
|
sql: editor.getSession().getValue(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
success: function (data) {
|
success(data) {
|
||||||
$('#loading').hide(0);
|
$('#loading').hide(0);
|
||||||
$('#results').show(0);
|
$('#results').show(0);
|
||||||
$('#results').html(data);
|
$('#results').html(data);
|
||||||
|
|
||||||
$('table.sql_results').DataTable({
|
$('table.sql_results').DataTable({
|
||||||
retrieve: true,
|
retrieve: true,
|
||||||
paging: false,
|
paging: false,
|
||||||
|
@ -95,7 +82,7 @@ $(document).ready(function () {
|
||||||
aaSorting: [],
|
aaSorting: [],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: function (err, err2) {
|
error(err) {
|
||||||
$('#loading').hide(0);
|
$('#loading').hide(0);
|
||||||
$('#results').show(0);
|
$('#results').show(0);
|
||||||
$('#results').html(err.responseText);
|
$('#results').html(err.responseText);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
var $ = window.$ = require('jquery');
|
const $ = window.$ = require('jquery');
|
||||||
var jQuery = window.jQuery = $;
|
/* eslint no-unused-vars: 0 */
|
||||||
var px = require('./modules/caravel.js');
|
const jQuery = window.jQuery = $;
|
||||||
|
const px = require('./modules/caravel.js');
|
||||||
|
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var slice;
|
const data = $('.slice').data('slice');
|
||||||
var data = $('.slice').data('slice');
|
const slice = px.Slice(data);
|
||||||
slice = px.Slice(data);
|
|
||||||
slice.render();
|
slice.render();
|
||||||
slice.bindResizeToWindowResize();
|
slice.bindResizeToWindowResize();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
var $ = window.$ = require('jquery');
|
const $ = window.$ = require('jquery');
|
||||||
var jQuery = window.jQuery = $;
|
/* eslint no-unused-vars: 0 */
|
||||||
|
const jQuery = window.jQuery = $;
|
||||||
require('../stylesheets/welcome.css');
|
require('../stylesheets/welcome.css');
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
require('datatables.net-bs');
|
require('datatables.net-bs');
|
||||||
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
||||||
require('../node_modules/cal-heatmap/cal-heatmap.css');
|
require('../node_modules/cal-heatmap/cal-heatmap.css');
|
||||||
var d3 = require('d3');
|
const d3 = require('d3');
|
||||||
|
const CalHeatMap = require('cal-heatmap');
|
||||||
var CalHeatMap = require('cal-heatmap');
|
|
||||||
|
|
||||||
function modelViewTable(selector, modelView, orderCol, order) {
|
function modelViewTable(selector, modelView, orderCol, order) {
|
||||||
// Builds a dataTable from a flask appbuilder api endpoint
|
// Builds a dataTable from a flask appbuilder api endpoint
|
||||||
var url = '/' + modelView.toLowerCase() + '/api/read';
|
let url = '/' + modelView.toLowerCase() + '/api/read';
|
||||||
url += '?_oc_' + modelView + '=' + orderCol;
|
url += '?_oc_' + modelView + '=' + orderCol;
|
||||||
url += '&_od_' + modelView +'=' + order;
|
url += '&_od_' + modelView + '=' + order;
|
||||||
$.getJSON(url, function (data) {
|
$.getJSON(url, function (data) {
|
||||||
var tableData = jQuery.map(data.result, function (el, i) {
|
const tableData = $.map(data.result, function (el) {
|
||||||
var row = $.map(data.list_columns, function (col, i) {
|
const row = $.map(data.list_columns, function (col) {
|
||||||
return el[col];
|
return el[col];
|
||||||
});
|
});
|
||||||
return [row];
|
return [row];
|
||||||
});
|
});
|
||||||
var cols = jQuery.map(data.list_columns, function (col, i) {
|
const cols = $.map(data.list_columns, function (col) {
|
||||||
return { sTitle: data.label_columns[col] };
|
return { sTitle: data.label_columns[col] };
|
||||||
});
|
});
|
||||||
var panel = $(selector).parents('.panel');
|
const panel = $(selector).parents('.panel');
|
||||||
panel.find("img.loading").remove();
|
panel.find('img.loading').remove();
|
||||||
$(selector).DataTable({
|
$(selector).DataTable({
|
||||||
aaData: tableData,
|
aaData: tableData,
|
||||||
aoColumns: cols,
|
aoColumns: cols,
|
||||||
|
@ -37,32 +35,28 @@ function modelViewTable(selector, modelView, orderCol, order) {
|
||||||
searching: true,
|
searching: true,
|
||||||
bInfo: false,
|
bInfo: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hack to move the searchbox in the right spot
|
// Hack to move the searchbox in the right spot
|
||||||
var search = panel.find(".dataTables_filter input");
|
const search = panel.find('.dataTables_filter input');
|
||||||
search.addClass('form-control').detach();
|
search.addClass('form-control').detach();
|
||||||
search.appendTo(panel.find(".search"));
|
search.appendTo(panel.find('.search'));
|
||||||
panel.find('.dataTables_filter').remove();
|
panel.find('.dataTables_filter').remove();
|
||||||
|
|
||||||
// Hack to display the page navigator properly
|
// Hack to display the page navigator properly
|
||||||
panel.find('.col-sm-5').remove();
|
panel.find('.col-sm-5').remove();
|
||||||
var nav = panel.find('.col-sm-7');
|
const nav = panel.find('.col-sm-7');
|
||||||
nav.removeClass('col-sm-7');
|
nav.removeClass('col-sm-7');
|
||||||
nav.addClass('col-sm-12');
|
nav.addClass('col-sm-12');
|
||||||
|
|
||||||
$(selector).slideDown();
|
$(selector).slideDown();
|
||||||
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
d3.json('/caravel/activity_per_day', function (json) {
|
d3.json('/caravel/activity_per_day', function (json) {
|
||||||
var ext = d3.extent(d3.values(json));
|
const ext = d3.extent(d3.values(json));
|
||||||
var cal = new CalHeatMap();
|
const cal = new CalHeatMap();
|
||||||
var range = 10;
|
const range = 10;
|
||||||
var legendBounds = [];
|
const legendBounds = [];
|
||||||
var step = (ext[1] - ext[0]) / (range - 1);
|
const step = (ext[1] - ext[0]) / (range - 1);
|
||||||
for (var i = 0; i< range; i++) {
|
for (let i = 0; i < range; i++) {
|
||||||
legendBounds.push(i * step + ext[0]);
|
legendBounds.push(i * step + ext[0]);
|
||||||
}
|
}
|
||||||
cal.init({
|
cal.init({
|
||||||
|
@ -70,10 +64,14 @@ $(document).ready(function () {
|
||||||
range: 13,
|
range: 13,
|
||||||
data: json,
|
data: json,
|
||||||
legend: legendBounds,
|
legend: legendBounds,
|
||||||
legendColors: ['#D6E685', '#1E6823'], // Based on github's colors
|
legendColors: [
|
||||||
domain: "month",
|
'#D6E685',
|
||||||
subDomain: "day",
|
'#1E6823',
|
||||||
itemName: "action",
|
],
|
||||||
|
// Based on github's colors
|
||||||
|
domain: 'month',
|
||||||
|
subDomain: 'day',
|
||||||
|
itemName: 'action',
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"test": "spec"
|
"test": "spec"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha --compilers js:babel-core/register --required spec/helpers/browser.js spec/**/*_spec.*",
|
"test": "npm run lint && mocha --compilers js:babel-core/register --required spec/helpers/browser.js spec/**/*_spec.*",
|
||||||
"dev": "webpack -d --watch --colors",
|
"dev": "webpack -d --watch --colors",
|
||||||
"prod": "webpack -p --colors",
|
"prod": "webpack -p --colors",
|
||||||
"lint": "npm run --silent lint:js",
|
"lint": "npm run --silent lint:js",
|
||||||
|
@ -81,7 +81,11 @@
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "^0.23.1",
|
||||||
"enzyme": "^2.0.0",
|
"enzyme": "^2.0.0",
|
||||||
"eslint": "^2.2.0",
|
"eslint": "^2.13.1",
|
||||||
|
"eslint-config-airbnb": "^9.0.1",
|
||||||
|
"eslint-plugin-import": "^1.11.1",
|
||||||
|
"eslint-plugin-jsx-a11y": "^2.0.1",
|
||||||
|
"eslint-plugin-react": "^5.2.2",
|
||||||
"exports-loader": "^0.6.3",
|
"exports-loader": "^0.6.3",
|
||||||
"file-loader": "^0.8.5",
|
"file-loader": "^0.8.5",
|
||||||
"imports-loader": "^0.6.5",
|
"imports-loader": "^0.6.5",
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
require('babel-register')();
|
require('babel-register')();
|
||||||
|
|
||||||
var jsdom = require('jsdom').jsdom;
|
const jsdom = require('jsdom').jsdom;
|
||||||
|
|
||||||
var exposedProperties = ['window', 'navigator', 'document'];
|
const exposedProperties = ['window', 'navigator', 'document'];
|
||||||
|
|
||||||
global.document = jsdom('');
|
global.document = jsdom('');
|
||||||
global.window = document.defaultView;
|
global.window = document.defaultView;
|
||||||
|
@ -16,7 +16,7 @@ Object.keys(document.defaultView).forEach((property) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
global.navigator = {
|
global.navigator = {
|
||||||
serAgent: 'node.js',
|
userAgent: 'node.js',
|
||||||
};
|
};
|
||||||
|
|
||||||
documentRef = document;
|
documentRef = document;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint global-require: 0 */
|
||||||
const d3 = window.d3 || require('d3');
|
const d3 = window.d3 || require('d3');
|
||||||
|
|
||||||
export const EARTH_CIRCUMFERENCE_KM = 40075.16;
|
export const EARTH_CIRCUMFERENCE_KM = 40075.16;
|
||||||
|
@ -23,5 +24,5 @@ export function isNumeric(num) {
|
||||||
|
|
||||||
export function rgbLuminance(r, g, b) {
|
export function rgbLuminance(r, g, b) {
|
||||||
// Formula: https://en.wikipedia.org/wiki/Relative_luminance
|
// Formula: https://en.wikipedia.org/wiki/Relative_luminance
|
||||||
return LUMINANCE_RED_WEIGHT*r + LUMINANCE_GREEN_WEIGHT*g + LUMINANCE_BLUE_WEIGHT*b;
|
return (LUMINANCE_RED_WEIGHT * r) + (LUMINANCE_GREEN_WEIGHT * g) + (LUMINANCE_BLUE_WEIGHT * b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const APP_DIR = path.resolve(__dirname, './'); // input
|
// input dir
|
||||||
const BUILD_DIR = path.resolve(__dirname, './javascripts/dist'); // output
|
const APP_DIR = path.resolve(__dirname, './');
|
||||||
|
|
||||||
|
// output dir
|
||||||
|
const BUILD_DIR = path.resolve(__dirname, './javascripts/dist');
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
entry: {
|
entry: {
|
||||||
|
@ -18,10 +21,12 @@ const config = {
|
||||||
filename: '[name].entry.js',
|
filename: '[name].entry.js',
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['', '.js', '.jsx'],
|
extensions: [
|
||||||
alias: {
|
'',
|
||||||
webworkify: 'webworkify-webpack',
|
'.js',
|
||||||
},
|
'.jsx',
|
||||||
|
],
|
||||||
|
alias: { webworkify: 'webworkify-webpack' },
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
|
@ -30,40 +35,53 @@ const config = {
|
||||||
exclude: APP_DIR + '/node_modules',
|
exclude: APP_DIR + '/node_modules',
|
||||||
loader: 'babel',
|
loader: 'babel',
|
||||||
query: {
|
query: {
|
||||||
presets: ['airbnb', 'es2015', 'react'],
|
presets: [
|
||||||
|
'airbnb',
|
||||||
|
'es2015',
|
||||||
|
'react',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/* for react-map-gl overlays */
|
/* for react-map-gl overlays */
|
||||||
{
|
{
|
||||||
test: /\.react\.js$/,
|
test: /\.react\.js$/,
|
||||||
include: APP_DIR + '/node_modules/react-map-gl/src/overlays',
|
include: APP_DIR + '/node_modules/react-map-gl/src/overlays',
|
||||||
loader: 'babel',
|
loader: 'babel',
|
||||||
},
|
},
|
||||||
|
|
||||||
/* for require('*.css') */
|
/* for require('*.css') */
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
include: APP_DIR,
|
include: APP_DIR,
|
||||||
loader: "style-loader!css-loader",
|
loader: 'style-loader!css-loader',
|
||||||
},
|
},
|
||||||
|
|
||||||
/* for css linking images */
|
/* for css linking images */
|
||||||
{ test: /\.png$/, loader: "url-loader?limit=100000" },
|
{
|
||||||
{ test: /\.jpg$/, loader: "file-loader" },
|
test: /\.png$/,
|
||||||
{ test: /\.gif$/, loader: "file-loader" },
|
loader: 'url-loader?limit=100000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.jpg$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.gif$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
},
|
||||||
/* for font-awesome */
|
/* for font-awesome */
|
||||||
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff" },
|
{
|
||||||
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" },
|
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
loader: 'url-loader?limit=10000&minetype=application/font-woff',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
},
|
||||||
/* for require('*.less') */
|
/* for require('*.less') */
|
||||||
{
|
{
|
||||||
test: /\.less$/,
|
test: /\.less$/,
|
||||||
include: APP_DIR,
|
include: APP_DIR,
|
||||||
loader: "style!css!less",
|
loader: 'style!css!less',
|
||||||
},
|
},
|
||||||
|
|
||||||
/* for mapbox */
|
/* for mapbox */
|
||||||
{
|
{
|
||||||
test: /\.json$/,
|
test: /\.json$/,
|
||||||
|
@ -88,5 +106,4 @@ const config = {
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
Loading…
Reference in New Issue