From 1101de5ae4073628fd41d49e9cc854e7610b1da4 Mon Sep 17 00:00:00 2001 From: Alanna Scott Date: Wed, 27 Jul 2016 16:57:05 -0700 Subject: [PATCH] [js linting] use airbnb eslint settings (#796) * add airbnb eslint settings and lint all the code * fix linting erros --- caravel/assets/.eslintignore | 3 + caravel/assets/.eslintrc | 240 +-------- caravel/assets/javascripts/common.js | 17 +- .../javascripts/dashboard/Dashboard.jsx | 338 ++++++------ .../dashboard/components/GridLayout.jsx | 206 +++----- .../dashboard/components/Modal.jsx | 54 +- .../dashboard/components/SliceAdder.jsx | 123 +++-- .../dashboard/components/SliceCell.js | 88 ++++ .../explore/components/QueryAndSaveBtns.jsx | 9 +- .../assets/javascripts/explore/explore.jsx | 187 ++++--- caravel/assets/javascripts/index.jsx | 18 +- caravel/assets/javascripts/modules/caravel.js | 498 ++++++++++-------- caravel/assets/javascripts/modules/utils.js | 130 +++-- caravel/assets/javascripts/sql.js | 73 ++- caravel/assets/javascripts/standalone.js | 12 +- caravel/assets/javascripts/welcome.js | 66 ++- caravel/assets/package.json | 8 +- caravel/assets/spec/helpers/browser.js | 6 +- caravel/assets/utils/common.js | 3 +- caravel/assets/webpack.config.js | 59 ++- 20 files changed, 1006 insertions(+), 1132 deletions(-) create mode 100644 caravel/assets/javascripts/dashboard/components/SliceCell.js diff --git a/caravel/assets/.eslintignore b/caravel/assets/.eslintignore index 926b5a451b..613212ecc7 100644 --- a/caravel/assets/.eslintignore +++ b/caravel/assets/.eslintignore @@ -1,3 +1,6 @@ node_modules/* vendor/* javascripts/dist/* +visualizations/* +stylesheets/* +spec/* diff --git a/caravel/assets/.eslintrc b/caravel/assets/.eslintrc index bec934dcf9..1346231fbe 100644 --- a/caravel/assets/.eslintrc +++ b/caravel/assets/.eslintrc @@ -1,234 +1,12 @@ { - "root": true, - - "globals": { - "Symbol": false, - "Map": false, - "Set": false, - "Reflect": false, - }, - - "env": { - "es6": false, - "browser": true, - "node": true, - }, - - "parserOptions": { - "ecmaVersion": 5, - "sourceType": "module" - }, - + "extends": "airbnb", "rules": { - "array-bracket-spacing": [2, "never", { - "singleValue": false, - "objectsInArrays": false, - "arraysInArrays": false - }], - "array-callback-return": [2], - "block-spacing": [2, "always"], - "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 }] + "prefer-template": 0, + "new-cap": 0, + "no-restricted-syntax": 0, + "guard-for-in": 0, + "prefer-arrow-callback": 0, + "func-names": 0, + "react/jsx-no-bind": 0, + } } diff --git a/caravel/assets/javascripts/common.js b/caravel/assets/javascripts/common.js index abe9e694ad..fd35e6a114 100644 --- a/caravel/assets/javascripts/common.js +++ b/caravel/assets/javascripts/common.js @@ -1,11 +1,10 @@ -var $ = require('jquery'); -var utils = require('./modules/utils'); - +const $ = require('jquery'); +const utils = require('./modules/utils'); $(document).ready(function () { - $(':checkbox[data-checkbox-api-prefix]').change(function () { - var $this = $(this); - var prefix = $this.data('checkbox-api-prefix'); - var id = $this.attr('id'); - utils.toggleCheckbox(prefix, "#" + id); - }); + $(':checkbox[data-checkbox-api-prefix]').change(function () { + const $this = $(this); + const prefix = $this.data('checkbox-api-prefix'); + const id = $this.attr('id'); + utils.toggleCheckbox(prefix, '#' + id); + }); }); diff --git a/caravel/assets/javascripts/dashboard/Dashboard.jsx b/caravel/assets/javascripts/dashboard/Dashboard.jsx index 1450fa1d7b..15bdfbf8f5 100644 --- a/caravel/assets/javascripts/dashboard/Dashboard.jsx +++ b/caravel/assets/javascripts/dashboard/Dashboard.jsx @@ -1,39 +1,61 @@ -var $ = window.$ = require('jquery'); -var jQuery = window.jQuery = $; -var px = require('../modules/caravel.js'); -var d3 = require('d3'); -var urlLib = require('url'); -var showModal = require('../modules/utils.js').showModal; +const $ = window.$ = require('jquery'); +const jQuery = window.jQuery = $; +const px = require('../modules/caravel.js'); +const d3 = require('d3'); +const urlLib = require('url'); +const showModal = require('../modules/utils.js').showModal; import React from 'react'; import { render } from 'react-dom'; import SliceAdder from './components/SliceAdder.jsx'; import GridLayout from './components/GridLayout.jsx'; -var ace = require('brace'); +const ace = require('brace'); require('bootstrap'); require('brace/mode/css'); require('brace/theme/crimson_editor'); require('./main.css'); 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 +function injectCss(className, css) { + const head = document.head || document.getElementsByTagName('head')[0]; + let style = document.querySelector('.' + className); -var Dashboard = function (dashboardData) { - var dashboard = $.extend(dashboardData, { + 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; + } +} + +function dashboardContainer(dashboardData) { + let dashboard = $.extend(dashboardData, { filters: {}, - init: function () { + init() { this.initDashboardView(); this.firstLoad = true; px.initFavStars(); - var sliceObjects = [], - dash = this; - dashboard.slices.forEach(function (data) { + const sliceObjects = []; + const dash = this; + dashboard.slices.forEach((data) => { if (data.error) { - var html = '
' + data.error + '
'; - $('#slice_' + data.slice_id).find('.token').html(html); + const html = '
' + data.error + '
'; + $('#slice_' + data.sliceId).find('.token').html(html); } else { - var slice = px.Slice(data, dash); - $('#slice_' + data.slice_id).find('a.refresh').click(function () { + const slice = px.Slice(data, dash); + $('#slice_' + data.sliceId).find('a.refresh').click(() => { slice.render(true); }); sliceObjects.push(slice); @@ -45,81 +67,81 @@ var Dashboard = function (dashboardData) { this.startPeriodicRender(0); this.bindResizeToWindowResize(); }, - loadPreSelectFilters: function () { + loadPreSelectFilters() { try { - var filters = JSON.parse(px.getParam("preselect_filters") || "{}"); - for (var slice_id in filters) { - for (var col in filters[slice_id]) { - this.setFilter(slice_id, col, filters[slice_id][col], false, false); + const filters = JSON.parse(px.getParam('preselect_filters') || '{}'); + for (const sliceId in filters) { + for (const col in filters[sliceId]) { + this.setFilter(sliceId, col, filters[sliceId][col], false, false); } } } catch (e) { - console.error(e); + // console.error(e); } }, - setFilter: function (slice_id, col, vals, refresh) { - this.addFilter(slice_id, col, vals, false, refresh); + setFilter(sliceId, col, vals, refresh) { + this.addFilter(sliceId, col, vals, false, refresh); }, - addFilter: function (slice_id, col, vals, merge = true, refresh = true) { - if (!(slice_id in this.filters)) { - this.filters[slice_id] = {}; + addFilter(sliceId, col, vals, merge = true, refresh = true) { + if (!(sliceId in this.filters)) { + this.filters[sliceId] = {}; } - if (!(col in this.filters[slice_id]) || !merge) { - this.filters[slice_id][col] = vals; + if (!(col in this.filters[sliceId]) || !merge) { + this.filters[sliceId][col] = vals; } 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) { - this.refreshExcept(slice_id); + this.refreshExcept(sliceId); } this.updateFilterParamsInUrl(); }, - readFilters: function () { + readFilters() { // Returns a list of human readable active filters return JSON.stringify(this.filters, null, 4); }, - updateFilterParamsInUrl: function () { - var urlObj = urlLib.parse(location.href, true); + updateFilterParamsInUrl() { + const urlObj = urlLib.parse(location.href, true); urlObj.query = urlObj.query || {}; urlObj.query.preselect_filters = this.readFilters(); urlObj.search = null; history.pushState(urlObj.query, window.title, urlLib.format(urlObj)); }, - bindResizeToWindowResize: function () { - var resizeTimer; - var dash = this; - $(window).on('resize', function (e) { + bindResizeToWindowResize() { + let resizeTimer; + const dash = this; + $(window).on('resize', () => { clearTimeout(resizeTimer); - resizeTimer = setTimeout(function () { - dash.slices.forEach(function (slice) { + resizeTimer = setTimeout(() => { + dash.slices.forEach((slice) => { slice.resize(); }); }, 500); }); }, - stopPeriodicRender: function () { + stopPeriodicRender() { if (this.refreshTimer) { clearTimeout(this.refreshTimer); this.refreshTimer = null; } }, - startPeriodicRender: function (interval) { + startPeriodicRender(interval) { this.stopPeriodicRender(); - var dash = this; - var maxRandomDelay = Math.min(interval * 0.2, 5000); - var refreshAll = function () { + const dash = this; + const maxRandomDelay = Math.min(interval * 0.2, 5000); + const refreshAll = function () { dash.slices.forEach(function (slice) { - var force = !dash.firstLoad; + const force = !dash.firstLoad; setTimeout(function () { 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()); }); dash.firstLoad = false; }; - var fetchAndRender = function () { + const fetchAndRender = function () { refreshAll(); if (interval > 0) { dash.refreshTimer = setTimeout(function () { @@ -129,122 +151,130 @@ var Dashboard = function (dashboardData) { }; fetchAndRender(); }, - refreshExcept: function (slice_id) { - var immune = this.metadata.filter_immune_slices || []; + refreshExcept(sliceId) { + const immune = this.metadata.filter_immune_slices || []; 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(); } }); }, - clearFilters: function (slice_id) { - delete this.filters[slice_id]; - this.refreshExcept(slice_id); + clearFilters(sliceId) { + delete this.filters[sliceId]; + this.refreshExcept(sliceId); this.updateFilterParamsInUrl(); }, - removeFilter: function (slice_id, col, vals) { - if (slice_id in this.filters) { - if (col in this.filters[slice_id]) { - var a = []; - this.filters[slice_id][col].forEach(function (v) { + removeFilter(sliceId, col, vals) { + if (sliceId in this.filters) { + if (col in this.filters[sliceId]) { + const a = []; + this.filters[sliceId][col].forEach(function (v) { if (vals.indexOf(v) < 0) { a.push(v); } }); - this.filters[slice_id][col] = a; + this.filters[sliceId][col] = a; } } - this.refreshExcept(slice_id); + this.refreshExcept(sliceId); this.updateFilterParamsInUrl(); }, - getSlice: function (slice_id) { - slice_id = parseInt(slice_id, 10); - for (var i=0; i < this.slices.length; i++) { - if (this.slices[i].data.slice_id === slice_id) { - return this.slices[i]; + getSlice(sliceId) { + const id = parseInt(sliceId, 10); + let i = 0; + let slice = null; + 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 () { - var slicesOnDashMap = {}; - this.reactGridLayout.serialize().forEach(function (position) { + showAddSlice() { + const slicesOnDashMap = {}; + const layoutPositions = this.reactGridLayout.serialize(); + layoutPositions.forEach((position) => { slicesOnDashMap[position.slice_id] = true; - }, this); - + }); render( , - document.getElementById("add-slice-container") + document.getElementById('add-slice-container') ); }, - getAjaxErrorMsg: function (error) { - var respJSON = error.responseJSON; + getAjaxErrorMsg(error) { + const respJSON = error.responseJSON; return (respJSON && respJSON.message) ? respJSON.message : error.responseText; }, - addSlicesToDashboard: function (sliceIds) { + addSlicesToDashboard(sliceIds) { + const getAjaxErrorMsg = this.getAjaxErrorMsg; $.ajax({ - type: "POST", + type: 'POST', url: '/caravel/add_slices/' + dashboard.id + '/', 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 window.location.reload(); }, - error: function (error) { - var errorMsg = this.getAjaxErrorMsg(error); + error(error) { + const errorMsg = getAjaxErrorMsg(error); showModal({ - title: "Error", - body: "Sorry, there was an error adding slices to this dashboard: " + errorMsg + title: 'Error', + body: 'Sorry, there was an error adding slices to this dashboard: ' + errorMsg, }); - }.bind(this) + }, }); }, - saveDashboard: function () { - var expandedSlices = {}; - $.each($(".slice_info"), function (i, d) { - var widget = $(this).parents('.widget'); - var sliceDescription = widget.find('.slice_description'); - if (sliceDescription.is(":visible")) { + saveDashboard() { + const expandedSlices = {}; + $.each($('.slice_info'), function () { + const widget = $(this).parents('.widget'); + const sliceDescription = widget.find('.slice_description'); + if (sliceDescription.is(':visible')) { expandedSlices[$(widget).attr('data-slice-id')] = true; } }); - var data = { - positions: this.reactGridLayout.serialize(), + const positions = this.reactGridLayout.serialize(); + const data = { + positions, css: this.editor.getValue(), - expanded_slices: expandedSlices + expanded_slices: expandedSlices, }; $.ajax({ - type: "POST", + type: 'POST', url: '/caravel/save_dash/' + dashboard.id + '/', data: { - data: JSON.stringify(data) + data: JSON.stringify(data), }, - success: function () { + success() { showModal({ - title: "Success", - body: "This dashboard was saved successfully." + title: 'Success', + body: 'This dashboard was saved successfully.', }); }, - error: function (error) { - var errorMsg = this.getAjaxErrorMsg(error); + error(error) { + const errorMsg = this.getAjaxErrorMsg(error); showModal({ - title: "Error", - body: "Sorry, there was an error saving this dashboard: " + errorMsg + title: 'Error', + body: 'Sorry, there was an error saving this dashboard: ' + errorMsg, }); - } + }, }); }, - initDashboardView: function () { + initDashboardView() { this.posDict = {}; this.position_json.forEach(function (position) { this.posDict[position.slice_id] = position; }, this); this.reactGridLayout = render( - , - document.getElementById("grid-container") + , + document.getElementById('grid-container') ); this.curUserId = $('.dashboard').data('user'); @@ -260,101 +290,77 @@ var Dashboard = function (dashboardData) { $(this).find('.chart-controls').fadeOut(300); } ); - $("div.grid-container").css('visibility', 'visible'); - $("#savedash").click(this.saveDashboard.bind(this)); - $("#add-slice").click(this.showAddSlice.bind(this)); + $('div.grid-container').css('visibility', 'visible'); + $('#savedash').click(this.saveDashboard.bind(this)); + $('#add-slice').click(this.showAddSlice.bind(this)); - var editor = ace.edit("dash_css"); + const editor = ace.edit('dash_css'); this.editor = editor; editor.$blockScrolling = Infinity; - editor.setTheme("ace/theme/crimson_editor"); + editor.setTheme('ace/theme/crimson_editor'); editor.setOptions({ minLines: 16, maxLines: Infinity, - useWorker: false + useWorker: false, }); - editor.getSession().setMode("ace/mode/css"); + editor.getSession().setMode('ace/mode/css'); - $(".select2").select2({ - dropdownAutoWidth: true + $('.select2').select2({ + dropdownAutoWidth: true, }); - $("#css_template").on("change", function () { - var css = $(this).find('option:selected').data('css'); + $('#css_template').on('change', function () { + const css = $(this).find('option:selected').data('css'); editor.setValue(css); $('#dash_css').val(css); - injectCss("dashboard-template", css); - + injectCss('dashboard-template', css); }); - $('#filters').click(function () { + $('#filters').click(() => { showModal({ - title: " Current Global Filters", - body: "The following global filters are currently applied:
" + dashboard.readFilters() + title: ' Current Global Filters', + body: 'The following global filters are currently applied:
' + + dashboard.readFilters(), }); }); - $("#refresh_dash_interval").on("change", function () { - var interval = $(this).find('option:selected').val() * 1000; + $('#refresh_dash_interval').on('change', function () { + const interval = $(this).find('option:selected').val() * 1000; dashboard.startPeriodicRender(interval); }); - $('#refresh_dash').click(function () { - dashboard.slices.forEach(function (slice) { + $('#refresh_dash').click(() => { + dashboard.slices.forEach((slice) => { slice.render(true); }); }); - $("div.widget").click(function (e) { - var $this = $(this); - var $target = $(e.target); + $('div.widget').click(function (e) { + const $this = $(this); + const $target = $(e.target); - if ($target.hasClass("slice_info")) { - $this.find(".slice_description").slideToggle(0, function () { + if ($target.hasClass('slice_info')) { + $this.find('.slice_description').slideToggle(0, function () { $this.find('.refresh').click(); }); - } else if ($target.hasClass("controls-toggle")) { - $this.find(".chart-controls").toggle(); + } else if ($target.hasClass('controls-toggle')) { + $this.find('.chart-controls').toggle(); } }); - editor.on("change", function () { - var css = editor.getValue(); + editor.on('change', function () { + const css = editor.getValue(); $('#dash_css').val(css); - injectCss("dashboard-template", css); + injectCss('dashboard-template', css); }); - var css = $('.dashboard').data('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 - 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; - } - } - } + const css = $('.dashboard').data('css'); + injectCss('dashboard-template', css); + }, }); dashboard.init(); return dashboard; -}; +} -$(document).ready(function () { - Dashboard($('.dashboard').data('dashboard')); +$(document).ready(() => { + dashboardContainer($('.dashboard').data('dashboard')); $('[data-toggle="tooltip"]').tooltip({ container: 'body' }); }); diff --git a/caravel/assets/javascripts/dashboard/components/GridLayout.jsx b/caravel/assets/javascripts/dashboard/components/GridLayout.jsx index 5794a1ec96..d4bb9e4a95 100644 --- a/caravel/assets/javascripts/dashboard/components/GridLayout.jsx +++ b/caravel/assets/javascripts/dashboard/components/GridLayout.jsx @@ -1,108 +1,69 @@ +import $ from 'jquery'; import React, { PropTypes } from 'react'; import { Responsive, WidthProvider } from 'react-grid-layout'; const ResponsiveReactGridLayout = WidthProvider(Responsive); +import SliceCell from './SliceCell'; require('../../../node_modules/react-grid-layout/css/styles.css'); require('../../../node_modules/react-resizable/css/styles.css'); -const sliceCellPropTypes = { - slice: PropTypes.object.isRequired, - removeSlice: PropTypes.func.isRequired, - expandedSlices: PropTypes.object -}; - -const gridLayoutPropTypes = { +const propTypes = { dashboard: 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 ( -
-
-
-
- {slice.slice_name} -
-
- -
- {slice.description ? - - - - : ""} - - - - - - - - - -
-
- -
-
-
-
-
- -
- loading -
-
-
-
- ); - } -} - 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) { - $('[data-toggle="tooltip"]').tooltip("hide"); + $('[data-toggle=tooltip]').tooltip('hide'); this.setState({ layout: this.state.layout.filter(function (reactPos) { return reactPos.i !== String(sliceId); }), slices: this.state.slices.filter(function (slice) { 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, row: reactPos.y, 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() { return ( - {this.state.slices.map((slice) => { - return ( -
- -
- ); - })} + draggableHandle=".drag" + > + { + /* eslint arrow-body-style: 0 */ + this.state.slices.map((slice) => { + return ( +
+ this.removeSlice(sliceId)} + expandedSlices={this.props.dashboard.metadata.expanded_slices} + /> +
+ ); + }) + }
); } } -SliceCell.propTypes = sliceCellPropTypes; -GridLayout.propTypes = gridLayoutPropTypes; +GridLayout.propTypes = propTypes; export default GridLayout; diff --git a/caravel/assets/javascripts/dashboard/components/Modal.jsx b/caravel/assets/javascripts/dashboard/components/Modal.jsx index daf68ca556..6245d7da4c 100644 --- a/caravel/assets/javascripts/dashboard/components/Modal.jsx +++ b/caravel/assets/javascripts/dashboard/components/Modal.jsx @@ -4,37 +4,37 @@ const propTypes = { modalId: PropTypes.string.isRequired, title: PropTypes.string, modalContent: PropTypes.node, - customButtons: PropTypes.node + customButton: PropTypes.node, }; -class Modal extends React.Component { - render() { - return ( -