diff --git a/.babelrc b/.babelrc index d4a4a37fbc546a9ef6d1541bb9451c385cd2c27f..32a31f43fddca7205a3f58af17934c02a4748589 100644 --- a/.babelrc +++ b/.babelrc @@ -4,8 +4,7 @@ "add-react-displayname", "transform-decorators-legacy", ["transform-builtin-extend", { - "globals": ["Error"], - "approximate": true + "globals": ["Error", "Array"] }] ], "presets": ["es2015", "stage-0", "react"], diff --git a/.eslintrc b/.eslintrc index a377e847d8836927aa26e85d4dbf4b82a2e3ec9a..7ff9ccf95b433cefef37199201f6471afb0d9bda 100644 --- a/.eslintrc +++ b/.eslintrc @@ -45,7 +45,8 @@ "env": { "browser": true, "es6": true, - "commonjs": true + "commonjs": true, + "jest": true }, "parser": "babel-eslint", "plugins": [ diff --git a/README.md b/README.md index 72df58721cb5638b7c138df380258a7a225df5ab..b52202286d54301d50836dc510ecc0764d0f833b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Metabase is the easy, open source way for everyone in your company to ask questi - Let anyone on your team [ask questions](http://www.metabase.com/docs/latest/users-guide/03-asking-questions) without knowing SQL - Rich beautiful [dashboards](http://www.metabase.com/docs/latest/users-guide/05-sharing-answers) with auto refresh and fullscreen - SQL Mode for analysts and data pros -- Create canonical [segments and metrics](http://www.metabase.com/docs/latest/administration-guide/06-segments-and-metrics) for your team to use +- Create canonical [segments and metrics](http://www.metabase.com/docs/latest/administration-guide/07-segments-and-metrics) for your team to use - Send data to Slack or email on a schedule with [Pulses](http://www.metabase.com/docs/latest/users-guide/09-pulses) - View data in Slack anytime with [Metabot](http://www.metabase.com/docs/latest/users-guide/10-metabot) - [Humanize data](http://www.metabase.com/docs/latest/administration-guide/03-metadata-editing) for your team by renaming, annotating and hiding fields diff --git a/bin/ci b/bin/ci index 0327a311836506b2c664d08a56db75f1c5930c69..461fdffa284967ba745f08edadf10ba88f525c38 100755 --- a/bin/ci +++ b/bin/ci @@ -23,7 +23,7 @@ node-2() { if is_engine_enabled "crate"; then run_step install-crate fi - MB_DB_TYPE=mysql MB_DB_DBNAME=circle_test MB_DB_PORT=3306 MB_DB_USER=ubuntu MB_DB_HOST=localhost \ + MB_ENCRYPTION_SECRET_KEY='Orw0AAyzkO/kPTLJRxiyKoBHXa/d6ZcO+p+gpZO/wSQ=' MB_DB_TYPE=mysql MB_DB_DBNAME=circle_test MB_DB_PORT=3306 MB_DB_USER=ubuntu MB_DB_HOST=localhost \ run_step lein-test } node-3() { @@ -45,6 +45,7 @@ node-5() { run_step lein eastwood run_step yarn run lint run_step yarn run test + run_step yarn run test-jest run_step yarn run flow } node-6() { diff --git a/docs/administration-guide/databases/bigquery.md b/docs/administration-guide/databases/bigquery.md index 8f99370e709d727b3ab43598691f79048f788d4f..58f3576f66789cee074c551a0aae9d943e44c046 100644 --- a/docs/administration-guide/databases/bigquery.md +++ b/docs/administration-guide/databases/bigquery.md @@ -7,15 +7,23 @@ Starting in v0.15.0 Metabase provides a driver for connecting to BigQuery direct 1. make sure you have a [Google Cloud Platform](https://cloud.google.com/) account with a Project you would like to use in Metabase. * Start by giving this connection a __Name__ and providing your Google Cloud Platform __Project ID__ along with your desired BigQuery __Dataset ID__. If you don't have a dataset and want to play around with something we recommend copying one of the [sample tables](https://cloud.google.com/bigquery/sample-tables) - + * Follow the `Click here` link provided below the __Client ID__ field which will open a new browser tab and guide you through the process of generating OAuth 2.0 credentials for Metabase. Make sure to choose `Other` for your application type. - + * take the resulting client ID and client secret and copy them over to Metabase. - + * Now follow the link below the __Auth Code__ field for `Click here to get an auth code` which will open a new browser window and authorize your credentials for a BigQuery access token to use the api. Simply click the `Allow` button. - + * Copy the resulting code provided into the __Auth Code__ field in Metabase. - + * Click the `Save` button! Metabase will now begin inspecting your BigQuery Dataset and finding any tables and fields to build up a sense for the schema. Give it a little bit of time to do its work and then you're all set to start querying. + + +## Using Standard SQL + +By default, Metabase tells BigQuery to interpret queries as [Legacy SQL](https://cloud.google.com/bigquery/docs/reference/legacy-sql). If you prefer using +[Standard SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/) instead, you can tell Metabase to do so by including a `#standardSQL` directive at the beginning of your query: + + diff --git a/docs/administration-guide/images/bigquery_standard_sql.png b/docs/administration-guide/images/bigquery_standard_sql.png new file mode 100644 index 0000000000000000000000000000000000000000..388b1d29c23f639f86a67a3ae951844334de9cd3 Binary files /dev/null and b/docs/administration-guide/images/bigquery_standard_sql.png differ diff --git a/docs/operations-guide/start.md b/docs/operations-guide/start.md index 901a5ec9d6c2c6c8626dd4bc76c41bb49c51062f..6440a074a198f78d7ba0826070dfe1f4b06ddf6b 100644 --- a/docs/operations-guide/start.md +++ b/docs/operations-guide/start.md @@ -8,6 +8,7 @@ * [Migrating from using the H2 database to MySQL or Postgres](#migrating-from-using-the-h2-database-to-mysql-or-postgres) * [Running database migrations manually](#running-metabase-database-migrations-manually) * [Backing up Metabase Application Data](#backing-up-metabase-application-data) +* [Encrypting your database connection details at rest](#encrypting-your-database-connection-details-at-rest) * [Customizing the Metabase Jetty Webserver](#customizing-the-metabase-jetty-webserver) * [Changing password complexity](#changing-metabase-password-complexity) * [Handling Timezones](#handling-timezones-in-metabase) @@ -221,6 +222,27 @@ Instructions can be found in the [Amazon RDS User Guide](http://docs.aws.amazon. Simply follow the same instructions you would use for making any normal database backup. It's a large topic more fit for a DBA to answer, but as long as you have a dump of the Metabase database you'll be good to go. +# Encrypting your database connection details at rest + +Metabase stores connection information for the various databases you add in the Metabase application database. To prevent bad actors from being able to access these details if they were to gain access to +the application DB, Metabase can automatically encrypt them when they are saved, and decrypt them on-the-fly whenever they are needed. The only thing you need to do is set the environment variable +`MB_ENCRYPTION_SECRET_KEY`. + +Your secret key must be at least 16 characters (longer is even better!), and we recommend using a secure random key generator to generate it. `openssl` is a good choice: + + openssl rand -base64 32 + +This gives you a cryptographically-secure, randomly-generated 32-character key that will look something like `IYqrSi5QDthvFWe4/WdAxhnra5DZC3RKx3ZSrOJDKsM=`. Set it as an environment variable and +start Metabase as usual: + + MB_ENCRYPTION_SECRET_KEY='IYqrSi5QDthvFWe4/WdAxhnra5DZC3RKx3ZSrOJDKsM=' java -jar metabase.jar + +Metabase will securely encrypt and store the connection details for any new Databases you add. (Connection details for existing databases will be encrypted as well if you save them in the admin panel). +Existing databases with unencrypted details will continue to work normally. + +Take care not to lose this key because you can't decrypt connection details without it. If you lose (or change) it, you'll have to reset all of the connection details that have been encrypted with it in the Admin Panel. + + # Customizing the Metabase Jetty webserver In most cases there will be no reason to modify any of the settings around how Metabase runs its embedded Jetty webserver to host the application, but if you wish to run HTTPS directly with your Metabase server or if you need to run on another port, that's all configurable. @@ -289,6 +311,7 @@ To ensure proper reporting it's important that timezones be set consistently in Common Pitfalls: + 1. Your database is using date/time columns without any timezone information. Typically when this happens your database will assume all the data is from whatever timezone the database is configured in or possible just default to UTC (check your database vendor to be sure). 2. Your JVM timezone is not the same as your Metabase `Report Timezone` choice. This is a very common issue and can be corrected by launching java with the `-Duser.timezone=<timezone>` option properly set to match your Metabase report timezone. diff --git a/docs/users-guide/04-visualizing-results.md b/docs/users-guide/04-visualizing-results.md index 0bce52900661543e6af9e8b237b3b3daee5266d8..d099c53e611c081814d761f587957480d8ef5f67 100644 --- a/docs/users-guide/04-visualizing-results.md +++ b/docs/users-guide/04-visualizing-results.md @@ -39,6 +39,7 @@ The Table option is good for looking at tabular data (duh), or for lists of thin Line charts are best for displaying the trend of a number over time, especially when you have lots of x-axis values. Bar charts are great for displaying a metric grouped by a category (e.g., the number of users you have by country), and they can also be useful for showing a number over time if you have a smaller number of x-axis values (like orders per month this year). Area charts are useful when comparing the the proportions between two metrics over time. Both bar and area charts can be stacked. These three charting types have very similar options, which are broken up into the following: + * **Data** — choose the fields you want to plot on your x and y axes. This is mostly useful if your table or result set contains more than two columns, like if you're trying to graph fields from an unaggregated table. You can also add additional metric fields by clicking the `Add another series` link below the y-axis dropdown, or break your current metric out by an additional dimension by clicking the `Add a series breakout` link below the x-axis dropdown (note that you can't add an additional series breakout if you have more than one metric/series). * **Display** — here's where you can make some cosmetic changes, like setting colors, and stacking bar or area charts. With line and area charts, you can also change the line style (line, curve, or step). We've also recently added the ability to create a goal line for your chart, and to configure how your chart deals with x-axis points that have missing y-axis values. * **Axes** — this is where you can hide axis markers or change their ranges, and turn split axes on or off. You can also configure the way your axes are scaled, if you're into that kind of thing. diff --git a/frontend/src/metabase/App.jsx b/frontend/src/metabase/App.jsx index 0a6c0fdec60dfa0f74c38cc313050f1566817305..73954a11290ef435c4a124c800d21a31bea3a1b0 100644 --- a/frontend/src/metabase/App.jsx +++ b/frontend/src/metabase/App.jsx @@ -23,7 +23,8 @@ export default class App extends Component { <Navbar location={location} className="flex-no-shrink" /> { errorPage && errorPage.status === 403 ? <Unauthorized /> - : errorPage && errorPage.status === 404 ? + : errorPage ? + // TODO: different error page for non-404 errors <NotFound /> : children diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js index 0ee5cd68c6795b0d976353f4287a9ec958535232..2b4dad7f1559ed0b9c281286b91262bbe4e4615c 100644 --- a/frontend/src/metabase/admin/settings/selectors.js +++ b/frontend/src/metabase/admin/settings/selectors.js @@ -21,7 +21,7 @@ const SECTIONS = [ type: "string" }, { - key: "-site-url", + key: "site-url", display_name: "Site URL", type: "string" }, diff --git a/frontend/src/metabase/components/Button.spec.js b/frontend/src/metabase/components/Button.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..b1e53dfd356e88bcb4dfa4878e045a2642ddce4e --- /dev/null +++ b/frontend/src/metabase/components/Button.spec.js @@ -0,0 +1,35 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; + +import { render } from 'enzyme'; + +import Button from './Button'; + +describe('Button', () => { + it('should render correctly', () => { + const tree = renderer.create( + <Button>Clickity click</Button> + ).toJSON(); + + expect(tree).toMatchSnapshot() + }) + it('should render correctly with an icon', () => { + const tree = renderer.create( + <Button icon='star'> + Clickity click + </Button> + ).toJSON(); + + expect(tree).toMatchSnapshot() + }) + + it('should render a primary button given the primary prop', () => { + const button = render( + <Button primary> + Clickity click + </Button> + ) + + expect(button.find('button.Button--primary').length).toEqual(1) + }) +}) diff --git a/frontend/src/metabase/components/ColumnarSelector.css b/frontend/src/metabase/components/ColumnarSelector.css index 2262b0cd526c85fd3ecd5419633acc005f11ae1e..0aa8f4763f28417c5dbe42f2a504ba125c7b1b71 100644 --- a/frontend/src/metabase/components/ColumnarSelector.css +++ b/frontend/src/metabase/components/ColumnarSelector.css @@ -67,6 +67,7 @@ .ColumnarSelector-row .Icon-check { visibility: hidden; + padding-right: 0.5rem; } .ColumnarSelector-row.ColumnarSelector-row--selected .Icon-check { diff --git a/frontend/src/metabase/components/ConstrainToScreen.jsx b/frontend/src/metabase/components/ConstrainToScreen.jsx new file mode 100644 index 0000000000000000000000000000000000000000..52b6956b27c9b6fa61041d17a42b8f0b656db450 --- /dev/null +++ b/frontend/src/metabase/components/ConstrainToScreen.jsx @@ -0,0 +1,35 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; +import ReactDOM from "react-dom"; + +import { constrainToScreen } from "metabase/lib/dom"; + +type Props = { + directions: Array<"top"|"bottom">, + padding: number, + children: React$Element<any> +}; + +export default class ConstrainToScreen extends Component<*, Props, *> { + static defaultProps = { + directions: ["top", "bottom"], + padding: 10 + } + + componentDidMount() { + this.componentDidUpdate(); + } + + componentDidUpdate() { + const { directions, padding } = this.props; + const element = ReactDOM.findDOMNode(this); + for (const direction of directions) { + constrainToScreen(element, direction, padding); + } + } + + render() { + return React.Children.only(this.props.children); + } +} diff --git a/frontend/src/metabase/components/ModalContent.jsx b/frontend/src/metabase/components/ModalContent.jsx index 4f68ae3e3d536ee85bea860b8c55cd9eafc1e457..24887a5125eb0d8a28459e7df0f0231db1393fcd 100644 --- a/frontend/src/metabase/components/ModalContent.jsx +++ b/frontend/src/metabase/components/ModalContent.jsx @@ -65,10 +65,10 @@ ModalHeader.contextTypes = MODAL_CHILD_CONTEXT_TYPES; export const ModalBody = ({ children }, { fullPageModal, formModal }) => <div - className={cx("ModalBody", { "px4": formModal, "flex flex-full": !formModal })} + className={cx("ModalBody", { "px4": formModal })} > <div - className="flex-full ml-auto mr-auto flex flex-column" + className="ml-auto mr-auto" style={{ maxWidth: (formModal && fullPageModal) ? FORM_WIDTH : undefined }} > {children} diff --git a/frontend/src/metabase/components/Popover.jsx b/frontend/src/metabase/components/Popover.jsx index 3f23203f53f480e7ea0be0d7e6506c49b0eb2c69..f4d255e88c3aea8ad4c6a7c5d362e331f5b45c7d 100644 --- a/frontend/src/metabase/components/Popover.jsx +++ b/frontend/src/metabase/components/Popover.jsx @@ -5,6 +5,8 @@ import ReactCSSTransitionGroup from "react-addons-css-transition-group"; import OnClickOutsideWrapper from "./OnClickOutsideWrapper"; import Tether from "tether"; +import { constrainToScreen } from "metabase/lib/dom"; + import cx from "classnames"; export default class Popover extends Component { @@ -239,21 +241,15 @@ export default class Popover extends Component { } if (this.props.sizeToFit) { - const verticalMargin = 5; + const verticalPadding = 5; const body = tetherOptions.element.querySelector(".PopoverBody"); if (this._tether.attachment.top === "top") { - let screenBottom = window.innerHeight + window.scrollY; - let overflowY = body.getBoundingClientRect().bottom - screenBottom; - if (overflowY + verticalMargin > 0) { - body.style.maxHeight = (body.getBoundingClientRect().height - overflowY - verticalMargin) + "px"; + if (constrainToScreen(body, "bottom", verticalPadding)) { body.classList.add("scroll-y"); body.classList.add("scroll-show"); } - } else { - let screenTop = window.scrollY; - let overflowY = screenTop - body.getBoundingClientRect().top; - if (overflowY + verticalMargin > 0) { - body.style.maxHeight = (body.getBoundingClientRect().height - overflowY - verticalMargin) + "px"; + } else if (this._tether.attachment.top === "bottom") { + if (constrainToScreen(body, "top", verticalPadding)) { body.classList.add("scroll-y"); body.classList.add("scroll-show"); } diff --git a/frontend/src/metabase/components/__snapshots__/Button.spec.js.snap b/frontend/src/metabase/components/__snapshots__/Button.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..7999ed6963013acd6e72fb39e78d59fcb86c77ca --- /dev/null +++ b/frontend/src/metabase/components/__snapshots__/Button.spec.js.snap @@ -0,0 +1,34 @@ +exports[`Button should render correctly 1`] = ` +<button + className="Button "> + <div + className="flex layout-centered"> + <div> + Clickity click + </div> + </div> +</button> +`; + +exports[`Button should render correctly with an icon 1`] = ` +<button + className="Button "> + <div + className="flex layout-centered"> + <svg + className="mr1" + fill="currentcolor" + height={14} + name="star" + size={14} + viewBox="0 0 32 32" + width={14}> + <path + d="M16 0 L21 11 L32 12 L23 19 L26 31 L16 25 L6 31 L9 19 L0 12 L11 11" /> + </svg> + <div> + Clickity click + </div> + </div> +</button> +`; diff --git a/frontend/src/metabase/css/login.css b/frontend/src/metabase/css/login.css index 833fc4f2e9d53835e7ba5c35b38cd4e71b53a214..10ab282d7f3c6fda41025543e650a13d046ef467 100644 --- a/frontend/src/metabase/css/login.css +++ b/frontend/src/metabase/css/login.css @@ -7,7 +7,6 @@ /* the login content should always sit on top of the illustration */ .Login-content { position: relative; - z-index: 1000; } .Login-header { @@ -15,7 +14,6 @@ } .brand-scene { - z-index: 4; overflow: hidden; height: 180px; } diff --git a/frontend/src/metabase/dashboard/components/DashCard.jsx b/frontend/src/metabase/dashboard/components/DashCard.jsx index a8ff165ca56f58631d56027dbfb14a4227296efc..7a368a02b283c638937b400575a5ab40c9e70193 100644 --- a/frontend/src/metabase/dashboard/components/DashCard.jsx +++ b/frontend/src/metabase/dashboard/components/DashCard.jsx @@ -113,7 +113,7 @@ export default class DashCard extends Component { return ( <div - className={"Card bordered rounded flex flex-column " + cx({ + className={"Card bordered rounded flex flex-column hover-parent hover--visibility" + cx({ "Card--recent": dashcard.isAdded, "Card--unmapped": !isMappedToAllParameters && !isEditing, "Card--slow": isSlow === "usually-slow" diff --git a/frontend/src/metabase/dashboard/components/parameters/widgets/DateRelativeWidget.jsx b/frontend/src/metabase/dashboard/components/parameters/widgets/DateRelativeWidget.jsx index 53b3f8a903f1b885942b5d0fa6dffd1e5f005c02..dfc1f98bece7aadd1c101229c11e7a373de99818 100644 --- a/frontend/src/metabase/dashboard/components/parameters/widgets/DateRelativeWidget.jsx +++ b/frontend/src/metabase/dashboard/components/parameters/widgets/DateRelativeWidget.jsx @@ -4,8 +4,8 @@ import cx from "classnames"; import _ from "underscore"; const SHORTCUTS = [ - { name: "Today", operator: ["=", "<", ">"], values: [["relative_datetime", "current"]]}, - { name: "Yesterday", operator: ["=", "<", ">"], values: [["relative_datetime", -1, "day"]]}, + { name: "Today", operator: ["=", "<", ">"], values: [["relative-datetime", "current"]]}, + { name: "Yesterday", operator: ["=", "<", ">"], values: [["relative-datetime", -1, "day"]]}, { name: "Past 7 days", operator: "time-interval", values: [-7, "day"]}, { name: "Past 30 days", operator: "time-interval", values: [-30, "day"]} ]; @@ -104,11 +104,11 @@ class PredefinedRelativeDatePicker extends Component { const FILTERS = { "today": { name: "Today", - mapping: ["=", null, ["relative_datetime", "current"]] + mapping: ["=", null, ["relative-datetime", "current"]] }, "yesterday": { name: "Yesterday", - mapping: ["=", null, ["relative_datetime", -1, "day"]] + mapping: ["=", null, ["relative-datetime", -1, "day"]] }, "past7days": { name: "Past 7 Days", diff --git a/frontend/src/metabase/dashboard/dashboard.js b/frontend/src/metabase/dashboard/dashboard.js index 6ce702c5d69be3271c6e23e3fec1bf504b31d994..0c4be999adb4871fc507f10ec61810d034b7c2ee 100644 --- a/frontend/src/metabase/dashboard/dashboard.js +++ b/frontend/src/metabase/dashboard/dashboard.js @@ -238,9 +238,6 @@ export const fetchCardDuration = createThunkAction(FETCH_CARD_DURATION, function }; }); -const SET_DASHBOARD_ID = "metabase/dashboard/SET_DASHBOARD_ID"; -export const setDashboardId = createAction(SET_DASHBOARD_ID); - export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(dashId, queryParams, enableDefaultParameters = true) { let result; return async function(dispatch, getState) { @@ -259,14 +256,13 @@ export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(dashId result = await DashboardApi.get({ dashId: dashId }); } - dispatch(setDashboardId(dashId)); - + const parameterValues = {}; if (result.parameters) { for (const parameter of result.parameters) { if (queryParams && queryParams[parameter.slug] != null) { - dispatch(setParameterValue(parameter.id, queryParams[parameter.slug])); + parameterValues[parameter.id] = queryParams[parameter.slug]; } else if (enableDefaultParameters && parameter.default != null) { - dispatch(setParameterValue(parameter.id, parameter.default)); + parameterValues[parameter.id] = parameter.default; } } } @@ -282,7 +278,11 @@ export const fetchDashboard = createThunkAction(FETCH_DASHBOARD, function(dashId .each((dbId) => dispatch(fetchDatabaseMetadata(dbId))); } - return normalize(result, dashboard); + return { + ...normalize(result, dashboard), // includes `result` and `entities` + dashboardId: dashId, + parameterValues: parameterValues + }; }; }); @@ -510,7 +510,7 @@ export const deletePublicLink = createAction(DELETE_PUBLIC_LINK, async ({ id }) const dashboardId = handleActions({ [INITIALIZE]: { next: (state) => null }, - [SET_DASHBOARD_ID]: { next: (state, { payload }) => payload } + [FETCH_DASHBOARD]: { next: (state, { payload: { dashboardId } }) => dashboardId } }, null); const isEditing = handleActions({ @@ -616,7 +616,8 @@ const cardDurations = handleActions({ const parameterValues = handleActions({ [INITIALIZE]: { next: () => ({}) }, // reset values [SET_PARAMETER_VALUE]: { next: (state, { payload: { id, value }}) => assoc(state, id, value) }, - [REMOVE_PARAMETER]: { next: (state, { payload: { id }}) => dissoc(state, id) } + [REMOVE_PARAMETER]: { next: (state, { payload: { id }}) => dissoc(state, id) }, + [FETCH_DASHBOARD]: { next: (state, { payload: { parameterValues }}) => parameterValues }, }, {}); const dashboardListing = handleActions({ diff --git a/frontend/src/metabase/icon_paths.js b/frontend/src/metabase/icon_paths.js index a0ff4b4fba07baa19010bde628f600b4bccf668c..20bbec3877f6e1fc2d6dbe8e796f40517d0bdb00 100644 --- a/frontend/src/metabase/icon_paths.js +++ b/frontend/src/metabase/icon_paths.js @@ -253,6 +253,14 @@ export var ICON_PATHS = { ICON_PATHS["illustration-line"] = ICON_PATHS['illustration-area']; ICON_PATHS["illustration-scatter"] = ICON_PATHS['illustration-area']; +// $FlowFixMe +ICON_PATHS["horizontal_bar"] = { + path: ICON_PATHS["bar"], + attrs: { + style: { transform: "rotate(90deg) scaleX(-1)" } + } +}; + export function loadIcon(name) { var def = ICON_PATHS[name]; if (!def) { diff --git a/frontend/src/metabase/lib/dom.js b/frontend/src/metabase/lib/dom.js index 94f52fcd282e07ea3d7ed8ebd5c6c0002081866b..4ed04c087ffd93e02cb47b520523929250dfb065 100644 --- a/frontend/src/metabase/lib/dom.js +++ b/frontend/src/metabase/lib/dom.js @@ -151,11 +151,6 @@ function getTextNodeAtPosition(root, index) { var STYLE_SHEET = (function() { // Create the <style> tag var style = document.createElement("style"); - style.dataset.x = "x" - - // Add a media (and/or media query) here if you'd like! - // style.setAttribute("media", "screen") - // style.setAttribute("media", "only screen and (max-width : 1024px)") // WebKit hack :( style.appendChild(document.createTextNode("/* dynamic stylesheet */")); @@ -174,3 +169,24 @@ export function addCSSRule(selector, rules, index) { STYLE_SHEET.addRule(selector, rules, index); } } + +export function constrainToScreen(element, direction, padding) { + if (direction === "bottom") { + let screenBottom = window.innerHeight + window.scrollY; + let overflowY = element.getBoundingClientRect().bottom - screenBottom; + if (overflowY + padding > 0) { + element.style.maxHeight = (element.getBoundingClientRect().height - overflowY - padding) + "px"; + return true; + } + } else if (direction === "top") { + let screenTop = window.scrollY; + let overflowY = screenTop - element.getBoundingClientRect().top; + if (overflowY + padding > 0) { + element.style.maxHeight = (element.getBoundingClientRect().height - overflowY - padding) + "px"; + return true; + } + } else { + throw new Error("Direction " + direction + " not implemented"); + } + return false; +} diff --git a/frontend/src/metabase/lib/query.js b/frontend/src/metabase/lib/query.js index 44626a40ff5bd522dc480972a8f6f10afd7e145e..9e9dfbddb224929f73d164b7488bed9c475420c7 100644 --- a/frontend/src/metabase/lib/query.js +++ b/frontend/src/metabase/lib/query.js @@ -154,7 +154,7 @@ var Query = { } let targetMatches = query.breakout.filter(b => Query.isSameField(b, field, false)); if (targetMatches.length > 0) { - // query processor expect the order_by clause to match the breakout's datetime_field unit or fk-> target, + // query processor expect the order_by clause to match the breakout's datetime-field unit or fk-> target, // so just replace it with the one that matches the target field // NOTE: if we have more than one breakout for the same target field this could match the wrong one if (targetMatches.length > 1) { @@ -352,7 +352,7 @@ var Query = { } }, - // gets the target field ID (recursively) from any type of field, including raw field ID, fk->, and datetime_field cast. + // gets the target field ID (recursively) from any type of field, including raw field ID, fk->, and datetime-field cast. getFieldTargetId: function(field) { if (Query.isRegularField(field)) { return field; @@ -366,7 +366,7 @@ var Query = { console.warn("Unknown field type: ", field); }, - // gets the table and field definitions from from a raw, fk->, or datetime_field field + // gets the table and field definitions from from a raw, fk->, or datetime-field field getFieldTarget: function(field, tableDef, path = []) { if (Query.isRegularField(field)) { return { table: tableDef, field: Table.getField(tableDef, field), path }; diff --git a/frontend/src/metabase/lib/query/field.js b/frontend/src/metabase/lib/query/field.js index 2f4a76448205f7a14fab2f108de20163d9354902..85fc1d1885ed423adfc813f0e678cfb81b83e9f6 100644 --- a/frontend/src/metabase/lib/query/field.js +++ b/frontend/src/metabase/lib/query/field.js @@ -4,7 +4,7 @@ import { mbqlEq } from "./util"; import type { Field } from "metabase/meta/types/Query"; -// gets the target field ID (recursively) from any type of field, including raw field ID, fk->, and datetime_field cast. +// gets the target field ID (recursively) from any type of field, including raw field ID, fk->, and datetime-field cast. export function getFieldTargetId(field: Field): ?FieldId { if (isRegularField(field)) { return field; diff --git a/frontend/src/metabase/lib/query_time.js b/frontend/src/metabase/lib/query_time.js index e8575acca553ab0bddb10fac699206795684c471..ac1b93f6dc403595fff1999c1345b6ed51110503 100644 --- a/frontend/src/metabase/lib/query_time.js +++ b/frontend/src/metabase/lib/query_time.js @@ -48,16 +48,16 @@ export function expandTimeIntervalFilter(filter) { n = 1; } - field = ["datetime_field", field, "as", unit]; + field = ["datetime-field", field, "as", unit]; if (n < -1) { - return ["BETWEEN", field, ["relative_datetime", n-1, unit], ["relative_datetime", -1, unit]]; + return ["BETWEEN", field, ["relative-datetime", n-1, unit], ["relative-datetime", -1, unit]]; } else if (n > 1) { - return ["BETWEEN", field, ["relative_datetime", 1, unit], ["relative_datetime", n, unit]]; + return ["BETWEEN", field, ["relative-datetime", 1, unit], ["relative-datetime", n, unit]]; } else if (n === 0) { - return ["=", field, ["relative_datetime", "current"]]; + return ["=", field, ["relative-datetime", "current"]]; } else { - return ["=", field, ["relative_datetime", n, unit]]; + return ["=", field, ["relative-datetime", n, unit]]; } } @@ -115,7 +115,7 @@ export function generateTimeValueDescription(value, bucketing) { } else { return m.format("MMMM D, YYYY"); } - } else if (Array.isArray(value) && value[0] === "relative_datetime") { + } else if (Array.isArray(value) && mbqlEq(value[0], "relative-datetime")) { let n = value[1]; let unit = value[2]; @@ -149,7 +149,7 @@ export function formatBucketing(bucketing) { export function absolute(date) { if (typeof date === "string") { return moment(date); - } else if (Array.isArray(date) && date[0] === "relative_datetime") { + } else if (Array.isArray(date) && mbqlEq(date[0], "relative-datetime")) { return moment().add(date[1], date[2]); } else { console.warn("Unknown datetime format", date); @@ -158,9 +158,9 @@ export function absolute(date) { export function parseFieldBucketing(field, defaultUnit = null) { if (Array.isArray(field)) { - if (field[0] === "datetime_field") { + if (mbqlEq(field[0], "datetime-field")) { return field[3]; - } if (field[0] === "fk->" || field[0] === "field-id") { + } if (mbqlEq(field[0], "fk->") || mbqlEq(field[0], "field-id")) { return defaultUnit; } else { console.warn("Unknown field format", field); @@ -173,9 +173,9 @@ export function parseFieldTarget(field) { if (Number.isInteger(field)) return field; if (Array.isArray(field)) { - if (field[0] === "field-id") return field[1]; - if (field[0] === "fk->") return field[1]; - if (field[0] === "datetime_field") return parseFieldTarget(field[1]); + if (mbqlEq(field[0], "field-id")) return field[1]; + if (mbqlEq(field[0], "fk->")) return field[1]; + if (mbqlEq(field[0], "datetime-field")) return parseFieldTarget(field[1]); } console.warn("Unknown field format", field); diff --git a/frontend/src/metabase/lib/schema_metadata.js b/frontend/src/metabase/lib/schema_metadata.js index 0665fd12841558ac6f46c326ebb5156c2f40a678..af86137411499c5337cd324a9885e3809ab52611 100644 --- a/frontend/src/metabase/lib/schema_metadata.js +++ b/frontend/src/metabase/lib/schema_metadata.js @@ -108,6 +108,8 @@ export const isCategory = isFieldType.bind(null, CATEGORY); export const isDimension = (col) => (col && col.source !== "aggregation"); export const isMetric = (col) => (col && col.source !== "breakout") && isSummable(col); +export const isAny = (col) => true; + export const isNumericBaseType = (field) => isa(field && field.base_type, TYPE.Number); // ZipCode, ID, etc derive from Number but should not be formatted as numbers diff --git a/frontend/src/metabase/lib/string.js b/frontend/src/metabase/lib/string.js index 2458d91a4f3bfe0e71eff15c3a5ba87dc095a196..188e46b634616b22f7bc08328fcfd2855d466454 100644 --- a/frontend/src/metabase/lib/string.js +++ b/frontend/src/metabase/lib/string.js @@ -10,3 +10,5 @@ export function createMultiwordSearchRegex(input) { "i"); } } + +export const countLines = (str) => str.split(/\n/g).length diff --git a/frontend/src/metabase/lib/visualization_settings.js b/frontend/src/metabase/lib/visualization_settings.js deleted file mode 100644 index ab59f1ef047d92154563930105420173c07bc182..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/lib/visualization_settings.js +++ /dev/null @@ -1,813 +0,0 @@ -import _ from "underscore"; - -import MetabaseSettings from "metabase/lib/settings"; - -import { - getChartTypeFromData, - DIMENSION_DIMENSION_METRIC, - DIMENSION_METRIC, - DIMENSION_METRIC_METRIC, - getColumnCardinality, - getCardColors, - getFriendlyName -} from "metabase/visualizations/lib/utils"; - -import { isNumeric, isDate, isMetric, isDimension, isLatitude, isLongitude, hasLatitudeAndLongitudeColumns } from "metabase/lib/schema_metadata"; -import Query from "metabase/lib/query"; -import { capitalize } from "metabase/lib/formatting"; - -import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries"; -import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric"; - -import ChartSettingInput from "metabase/visualizations/components/settings/ChartSettingInput.jsx"; -import ChartSettingInputNumeric from "metabase/visualizations/components/settings/ChartSettingInputNumeric.jsx"; -import ChartSettingRadio from "metabase/visualizations/components/settings/ChartSettingRadio.jsx"; -import ChartSettingSelect from "metabase/visualizations/components/settings/ChartSettingSelect.jsx"; -import ChartSettingToggle from "metabase/visualizations/components/settings/ChartSettingToggle.jsx"; -import ChartSettingFieldPicker from "metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx"; -import ChartSettingFieldsPicker from "metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx"; -import ChartSettingColorPicker from "metabase/visualizations/components/settings/ChartSettingColorPicker.jsx"; -import ChartSettingColorsPicker from "metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx"; -import ChartSettingOrderedFields from "metabase/visualizations/components/settings/ChartSettingOrderedFields.jsx"; - -function columnsAreValid(colNames, data, filter = () => true) { - if (typeof colNames === "string") { - colNames = [colNames] - } - if (!data || !Array.isArray(colNames)) { - return false; - } - const colsByName = {}; - for (const col of data.cols) { - colsByName[col.name] = col; - } - return colNames.reduce((acc, name) => - acc && (name == undefined || (colsByName[name] && filter(colsByName[name]))) - , true); -} - -function getSeriesTitles(series, vizSettings) { - return series.map(s => s.card.name); -} - -function getDefaultColumns(series) { - if (series[0].card.display === "scatter") { - return getDefaultScatterColumns(series); - } else { - return getDefaultLineAreaBarColumns(series); - } -} - -function getDefaultScatterColumns([{ data: { cols, rows } }]) { - let dimensions = cols.filter(isDimension); - let metrics = cols.filter(isMetric); - if (dimensions.length === 2 && metrics.length < 2) { - return { - dimensions: [dimensions[0].name], - metrics: [dimensions[1].name], - bubble: metrics.length === 1 ? metrics[0].name : null - } - } else { - return { - dimensions: [null], - metrics: [null], - bubble: null - }; - } -} - -function getDefaultLineAreaBarColumns([{ data: { cols, rows } }]) { - let type = getChartTypeFromData(cols, rows, false); - switch (type) { - case DIMENSION_DIMENSION_METRIC: - let dimensions = [cols[0], cols[1]]; - if (isDate(dimensions[1]) && !isDate(dimensions[0])) { - // if the series dimension is a date but the axis dimension is not then swap them - dimensions.reverse(); - } else if (getColumnCardinality(cols, rows, 1) > getColumnCardinality(cols, rows, 0)) { - // if the series dimension is higher cardinality than the axis dimension then swap them - dimensions.reverse(); - } - return { - dimensions: dimensions.map(col => col.name), - metrics: [cols[2].name] - }; - case DIMENSION_METRIC: - return { - dimensions: [cols[0].name], - metrics: [cols[1].name] - }; - case DIMENSION_METRIC_METRIC: - return { - dimensions: [cols[0].name], - metrics: cols.slice(1).map(col => col.name) - }; - default: - return { - dimensions: [null], - metrics: [null] - }; - } -} - -function getDefaultDimensionAndMetric([{ data: { cols, rows } }]) { - const type = getChartTypeFromData(cols, rows, false); - if (type === DIMENSION_METRIC) { - return { - dimension: cols[0].name, - metric: cols[1].name - }; - } else { - return { - dimension: null, - metric: null - }; - } -} - -function getOptionFromColumn(col) { - return { - name: getFriendlyName(col), - value: col.name - }; -} - -// const CURRENCIES = ["afn", "ars", "awg", "aud", "azn", "bsd", "bbd", "byr", "bzd", "bmd", "bob", "bam", "bwp", "bgn", "brl", "bnd", "khr", "cad", "kyd", "clp", "cny", "cop", "crc", "hrk", "cup", "czk", "dkk", "dop", "xcd", "egp", "svc", "eek", "eur", "fkp", "fjd", "ghc", "gip", "gtq", "ggp", "gyd", "hnl", "hkd", "huf", "isk", "inr", "idr", "irr", "imp", "ils", "jmd", "jpy", "jep", "kes", "kzt", "kpw", "krw", "kgs", "lak", "lvl", "lbp", "lrd", "ltl", "mkd", "myr", "mur", "mxn", "mnt", "mzn", "nad", "npr", "ang", "nzd", "nio", "ngn", "nok", "omr", "pkr", "pab", "pyg", "pen", "php", "pln", "qar", "ron", "rub", "shp", "sar", "rsd", "scr", "sgd", "sbd", "sos", "zar", "lkr", "sek", "chf", "srd", "syp", "tzs", "twd", "thb", "ttd", "try", "trl", "tvd", "ugx", "uah", "gbp", "usd", "uyu", "uzs", "vef", "vnd", "yer", "zwd"]; - -import { normal } from "metabase/lib/colors"; - -const isAnyField = () => true; - -const SETTINGS = { - "card.title": { - title: "Title", - widget: ChartSettingInput, - getDefault: (series) => series.length === 1 ? series[0].card.name : null, - dashboard: true, - useRawSeries: true - }, - "graph._dimension_filter": { - getDefault: ([{ card }]) => card.display === "scatter" ? isAnyField : isDimension, - useRawSeries: true - }, - "graph._metric_filter": { - getDefault: ([{ card }]) => card.display === "scatter" ? isNumeric : isMetric, - useRawSeries: true - }, - "graph.dimensions": { - section: "Data", - title: "X-axis", - widget: ChartSettingFieldsPicker, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) && - columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]), - getDefault: (series, vizSettings) => - getDefaultColumns(series).dimensions, - getProps: ([{ card, data }], vizSettings) => { - const value = vizSettings["graph.dimensions"]; - const options = data.cols.filter(vizSettings["graph._dimension_filter"]).map(getOptionFromColumn); - return { - options, - addAnother: (options.length > value.length && value.length < 2 && vizSettings["graph.metrics"].length < 2) ? - "Add a series breakout..." : null - }; - }, - readDependencies: ["graph._dimension_filter", "graph._metric_filter"], - writeDependencies: ["graph.metrics"], - dashboard: false, - useRawSeries: true - }, - "graph.metrics": { - section: "Data", - title: "Y-axis", - widget: ChartSettingFieldsPicker, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) && - columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]), - getDefault: (series, vizSettings) => - getDefaultColumns(series).metrics, - getProps: ([{ card, data }], vizSettings) => { - const value = vizSettings["graph.dimensions"]; - const options = data.cols.filter(vizSettings["graph._metric_filter"]).map(getOptionFromColumn); - return { - options, - addAnother: options.length > value.length && vizSettings["graph.dimensions"].length < 2 ? - "Add another series..." : null - }; - }, - readDependencies: ["graph._dimension_filter", "graph._metric_filter"], - writeDependencies: ["graph.dimensions"], - dashboard: false, - useRawSeries: true - }, - "scatter.bubble": { - section: "Data", - title: "Bubble size", - widget: ChartSettingFieldPicker, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid([card.visualization_settings["scatter.bubble"]], data, isNumeric), - getDefault: (series) => - getDefaultColumns(series).bubble, - getProps: ([{ card, data }], vizSettings, onChange) => { - const options = data.cols.filter(isNumeric).map(getOptionFromColumn); - return { - options, - onRemove: vizSettings["scatter.bubble"] ? () => onChange(null) : null - }; - }, - writeDependencies: ["graph.dimensions"], - dashboard: false, - useRawSeries: true - }, - "line.interpolate": { - section: "Display", - title: "Style", - widget: ChartSettingSelect, - props: { - options: [ - { name: "Line", value: "linear" }, - { name: "Curve", value: "cardinal" }, - { name: "Step", value: "step-after" }, - ] - }, - getDefault: () => "linear" - }, - "line.marker_enabled": { - section: "Display", - title: "Show point markers on lines", - widget: ChartSettingToggle - }, - "stackable.stack_type": { - section: "Display", - title: "Stacking", - widget: ChartSettingRadio, - getProps: (series, vizSettings) => ({ - options: [ - { name: "Don't stack", value: null }, - { name: "Stack", value: "stacked" }, - { name: "Stack - 100%", value: "normalized" } - ] - }), - getDefault: ([{ card, data }], vizSettings) => - // legacy setting and default for D-M-M+ charts - vizSettings["stackable.stacked"] || (card.display === "area" && vizSettings["graph.metrics"].length > 1) ? - "stacked" : null, - getHidden: (series) => - series.length < 2, - readDependencies: ["graph.metrics"] - }, - "graph.show_goal": { - section: "Display", - title: "Show goal", - widget: ChartSettingToggle, - default: false - }, - "graph.goal_value": { - section: "Display", - title: "Goal value", - widget: ChartSettingInputNumeric, - default: 0, - getHidden: (series, vizSettings) => vizSettings["graph.show_goal"] !== true, - readDependencies: ["graph.show_goal"] - }, - "line.missing": { - section: "Display", - title: "Replace missing values with", - widget: ChartSettingSelect, - default: "interpolate", - getProps: (series, vizSettings) => ({ - options: [ - { name: "Zero", value: "zero" }, - { name: "Nothing", value: "none" }, - { name: "Linear Interpolated", value: "interpolate" }, - ] - }) - }, - "graph.x_axis._is_timeseries": { - readDependencies: ["graph.dimensions"], - getDefault: ([{ data }], vizSettings) => - dimensionIsTimeseries(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0])) - }, - "graph.x_axis._is_numeric": { - readDependencies: ["graph.dimensions"], - getDefault: ([{ data }], vizSettings) => - dimensionIsNumeric(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0])) - }, - "graph.x_axis.scale": { - section: "Axes", - title: "X-axis scale", - widget: ChartSettingSelect, - default: "ordinal", - readDependencies: ["graph.x_axis._is_timeseries", "graph.x_axis._is_numeric"], - getDefault: (series, vizSettings) => - vizSettings["graph.x_axis._is_timeseries"] ? "timeseries" : - vizSettings["graph.x_axis._is_numeric"] ? "linear" : - "ordinal", - getProps: (series, vizSettings) => { - const options = []; - if (vizSettings["graph.x_axis._is_timeseries"]) { - options.push({ name: "Timeseries", value: "timeseries" }); - } - if (vizSettings["graph.x_axis._is_numeric"]) { - options.push({ name: "Linear", value: "linear" }); - options.push({ name: "Power", value: "pow" }); - options.push({ name: "Log", value: "log" }); - } - options.push({ name: "Ordinal", value: "ordinal" }); - return { options }; - } - }, - "graph.y_axis.scale": { - section: "Axes", - title: "Y-axis scale", - widget: ChartSettingSelect, - default: "linear", - getProps: (series, vizSettings) => ({ - options: [ - { name: "Linear", value: "linear" }, - { name: "Power", value: "pow" }, - { name: "Log", value: "log" } - ] - }) - }, - "graph.colors": { - section: "Display", - getTitle: ([{ card: { display } }]) => - capitalize(display === "scatter" ? "bubble" : display) + " colors", - widget: ChartSettingColorsPicker, - readDependencies: ["graph.dimensions", "graph.metrics"], - getDefault: ([{ card, data }], vizSettings) => { - return getCardColors(card); - }, - getProps: (series, vizSettings) => { - return { seriesTitles: getSeriesTitles(series, vizSettings) }; - } - }, - "graph.x_axis.axis_enabled": { - section: "Axes", - title: "Show x-axis line and marks", - widget: ChartSettingToggle, - default: true - }, - "graph.y_axis.axis_enabled": { - section: "Axes", - title: "Show y-axis line and marks", - widget: ChartSettingToggle, - default: true - }, - "graph.y_axis.auto_range": { - section: "Axes", - title: "Auto y-axis range", - widget: ChartSettingToggle, - default: true - }, - "graph.y_axis.min": { - section: "Axes", - title: "Min", - widget: ChartSettingInputNumeric, - default: 0, - getHidden: (series, vizSettings) => vizSettings["graph.y_axis.auto_range"] !== false - }, - "graph.y_axis.max": { - section: "Axes", - title: "Max", - widget: ChartSettingInputNumeric, - default: 100, - getHidden: (series, vizSettings) => vizSettings["graph.y_axis.auto_range"] !== false - }, -/* - "graph.y_axis_right.auto_range": { - section: "Axes", - title: "Auto right-hand y-axis range", - widget: ChartSettingToggle, - default: true - }, - "graph.y_axis_right.min": { - section: "Axes", - title: "Min", - widget: ChartSettingInputNumeric, - default: 0, - getHidden: (series, vizSettings) => vizSettings["graph.y_axis_right.auto_range"] !== false - }, - "graph.y_axis_right.max": { - section: "Axes", - title: "Max", - widget: ChartSettingInputNumeric, - default: 100, - getHidden: (series, vizSettings) => vizSettings["graph.y_axis_right.auto_range"] !== false - }, -*/ - "graph.y_axis.auto_split": { - section: "Axes", - title: "Use a split y-axis when necessary", - widget: ChartSettingToggle, - default: true, - getHidden: (series) => series.length < 2 - }, - "graph.x_axis.labels_enabled": { - section: "Labels", - title: "Show label on x-axis", - widget: ChartSettingToggle, - default: true - }, - "graph.x_axis.title_text": { - section: "Labels", - title: "X-axis label", - widget: ChartSettingInput, - getHidden: (series, vizSettings) => - vizSettings["graph.x_axis.labels_enabled"] === false, - getDefault: (series, vizSettings) => - series.length === 1 ? getFriendlyName(series[0].data.cols[0]) : null - }, - "graph.y_axis.labels_enabled": { - section: "Labels", - title: "Show label on y-axis", - widget: ChartSettingToggle, - default: true - }, - "graph.y_axis.title_text": { - section: "Labels", - title: "Y-axis label", - widget: ChartSettingInput, - getHidden: (series, vizSettings) => - vizSettings["graph.y_axis.labels_enabled"] === false, - getDefault: (series, vizSettings) => - series.length === 1 ? getFriendlyName(series[0].data.cols[1]) : null - }, - "pie.dimension": { - section: "Data", - title: "Dimension", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["pie.dimension"], data, isDimension), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).dimension, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isDimension).map(getOptionFromColumn) - }), - }, - "pie.metric": { - section: "Data", - title: "Measure", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["pie.metric"], data, isMetric), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).metric, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isMetric).map(getOptionFromColumn) - }), - }, - "pie.show_legend": { - section: "Display", - title: "Show legend", - widget: ChartSettingToggle - }, - "pie.show_legend_perecent": { - section: "Display", - title: "Show percentages in legend", - widget: ChartSettingToggle, - default: true - }, - "pie.slice_threshold": { - section: "Display", - title: "Minimum slice percentage", - widget: ChartSettingInputNumeric - }, - "scalar.locale": { - title: "Separator style", - widget: ChartSettingSelect, - props: { - options: [ - { name: "100000.00", value: null }, - { name: "100,000.00", value: "en" }, - { name: "100 000,00", value: "fr" }, - { name: "100.000,00", value: "de" } - ] - }, - default: "en" - }, - // "scalar.currency": { - // title: "Currency", - // widget: ChartSettingSelect, - // props: { - // options: [{ name: "None", value: null}].concat(CURRENCIES.map(currency => ({ - // name: currency.toUpperCase(), - // value: currency - // }))) - // }, - // default: null - // }, - "scalar.decimals": { - title: "Number of decimal places", - widget: ChartSettingInputNumeric - }, - "scalar.prefix": { - title: "Add a prefix", - widget: ChartSettingInput - }, - "scalar.suffix": { - title: "Add a suffix", - widget: ChartSettingInput - }, - "scalar.scale": { - title: "Multiply by a number", - widget: ChartSettingInputNumeric - }, - "progress.goal": { - section: "Display", - title: "Goal", - widget: ChartSettingInputNumeric, - default: 0 - }, - "progress.color": { - section: "Display", - title: "Color", - widget: ChartSettingColorPicker, - default: normal.green - }, - "table.pivot": { - title: "Pivot the table", - widget: ChartSettingToggle, - getHidden: ([{ card, data }]) => ( - data && data.cols.length !== 3 - ), - getDefault: ([{ card, data }]) => ( - (data && data.cols.length === 3) && - Query.isStructured(card.dataset_query) && - data.cols.filter(isMetric).length === 1 && - data.cols.filter(isDimension).length === 2 - ) - }, - "table.columns": { - title: "Fields to include", - widget: ChartSettingOrderedFields, - getHidden: (series, vizSettings) => vizSettings["table.pivot"], - isValid: ([{ card, data }]) => - card.visualization_settings["table.columns"] && - columnsAreValid(card.visualization_settings["table.columns"].map(x => x.name), data), - getDefault: ([{ data: { cols }}]) => cols.map(col => ({ - name: col.name, - enabled: col.visibility_type !== "details-only" - })), - getProps: ([{ data: { cols }}]) => ({ - columnNames: cols.reduce((o, col) => ({ ...o, [col.name]: getFriendlyName(col)}), {}) - }) - }, - "table.column_widths": { - }, - "map.type": { - title: "Map type", - widget: ChartSettingSelect, - props: { - options: [ - { name: "Pin map", value: "pin" }, - { name: "Region map", value: "region" } - ] - }, - getDefault: ([{ card, data: { cols } }]) => { - switch (card.display) { - case "state": - case "country": - return "region"; - case "pin_map": - return "pin"; - default: - if (hasLatitudeAndLongitudeColumns(cols)) { - return "pin"; - } else { - return "region"; - } - } - } - }, - "map.latitude_column": { - title: "Latitude field", - widget: ChartSettingSelect, - getDefault: ([{ card, data: { cols }}]) => - (_.find(cols, isLatitude) || {}).name, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isNumeric).map(getOptionFromColumn) - }), - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" - }, - "map.longitude_column": { - title: "Longitude field", - widget: ChartSettingSelect, - getDefault: ([{ card, data: { cols }}]) => - (_.find(cols, isLongitude) || {}).name, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isNumeric).map(getOptionFromColumn) - }), - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" - }, - "map.region": { - title: "Region map", - widget: ChartSettingSelect, - getDefault: ([{ card, data: { cols }}]) => { - switch (card.display) { - case "country": - return "world_countries"; - case "state": - default: - return "us_states"; - } - }, - getProps: () => ({ - options: Object.entries(MetabaseSettings.get("custom_geojson", {})).map(([key, value]) => ({ name: value.name, value: key })) - }), - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" - }, - "map.metric": { - title: "Metric field", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - card.visualization_settings["map.metric"] && - columnsAreValid(card.visualization_settings["map.metric"], data, isMetric), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).metric, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isMetric).map(getOptionFromColumn) - }), - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" - }, - "map.dimension": { - title: "Region field", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - card.visualization_settings["map.dimension"] && - columnsAreValid(card.visualization_settings["map.dimension"], data, isDimension), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).dimension, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isDimension).map(getOptionFromColumn) - }), - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" - }, - "map.zoom": { - }, - "map.center_latitude": { - }, - "map.center_longitude": { - }, - "map.pin_type": { - title: "Pin type", - // Don't expose this in the UI for now - // widget: ChartSettingSelect, - props: { - options: [{ name: "Tiles", value: "tiles" }, { name: "Markers", value: "markers" }] - }, - getDefault: (series) => series[0].data.rows.length >= 1000 ? "tiles" : "markers", - getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" - }, - "funnel.dimension": { - section: "Data", - title: "Step", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["funnel.dimension"], data, isDimension), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).dimension, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isDimension).map(getOptionFromColumn) - }), - dashboard: false, - useRawSeries: true, - }, - "funnel.metric": { - section: "Data", - title: "Measure", - widget: ChartSettingSelect, - isValid: ([{ card, data }], vizSettings) => - columnsAreValid(card.visualization_settings["funnel.metric"], data, isMetric), - getDefault: (series, vizSettings) => - getDefaultDimensionAndMetric(series).metric, - getProps: ([{ card, data: { cols }}]) => ({ - options: cols.filter(isMetric).map(getOptionFromColumn) - }), - dashboard: false, - useRawSeries: true, - }, - "funnel.type": { - title: "Funnel type", - section: "Display", - widget: ChartSettingSelect, - props: { - options: [{ name: "Funnel", value: "funnel"}, { name: "Bar chart", value: "bar"}] - }, - // legacy "bar" funnel was only previously available via multiseries - getDefault: (series) => series.length > 1 ? "bar" : "funnel", - useRawSeries: true - }, -}; - -const SETTINGS_PREFIXES_BY_CHART_TYPE = { - line: ["graph.", "line."], - area: ["graph.", "line.", "stackable."], - bar: ["graph.", "stackable."], - scatter: ["graph.", "scatter."], - pie: ["pie."], - scalar: ["scalar."], - table: ["table."], - map: ["map."], - funnel: ["funnel."], - progress: ["progress."], -} - -// alias legacy map types -for (const type of ["state", "country", "pin_map"]) { - SETTINGS_PREFIXES_BY_CHART_TYPE[type] = SETTINGS_PREFIXES_BY_CHART_TYPE["map"]; -} - -function getSetting(id, vizSettings, series) { - if (id in vizSettings) { - return; - } - - const settingDef = SETTINGS[id]; - const [{ card }] = series; - const visualization_settings = card.visualization_settings || {}; - - for (let dependentId of settingDef.readDependencies || []) { - getSetting(dependentId, vizSettings, series); - } - - if (settingDef.useRawSeries && series._raw) { - series = series._raw; - } - - try { - if (settingDef.getValue) { - return vizSettings[id] = settingDef.getValue(series, vizSettings); - } - - if (visualization_settings[id] !== undefined) { - if (!settingDef.isValid || settingDef.isValid(series, vizSettings)) { - return vizSettings[id] = visualization_settings[id]; - } - } - - if (settingDef.getDefault) { - return vizSettings[id] = settingDef.getDefault(series, vizSettings); - } - - if ("default" in settingDef) { - return vizSettings[id] = settingDef.default; - } - } catch (e) { - console.error("Error getting setting", id, e); - } - return vizSettings[id] = undefined; -} - -function getSettingIdsForSeries(series) { - const [{ card }] = series; - const prefixes = (SETTINGS_PREFIXES_BY_CHART_TYPE[card.display] || []).concat("card."); - return Object.keys(SETTINGS).filter(id => _.any(prefixes, (p) => id.startsWith(p))) -} - -export function getSettings(series) { - let vizSettings = {}; - for (let id of getSettingIdsForSeries(series)) { - getSetting(id, vizSettings, series); - } - return vizSettings; -} - -function getSettingWidget(id, vizSettings, series, onChangeSettings) { - const settingDef = SETTINGS[id]; - const value = vizSettings[id]; - const onChange = (value) => { - const newSettings = { [id]: value }; - for (const id of (settingDef.writeDependencies || [])) { - newSettings[id] = vizSettings[id]; - } - onChangeSettings(newSettings) - } - if (settingDef.useRawSeries && series._raw) { - series = series._raw; - } - return { - ...settingDef, - id: id, - value: value, - title: settingDef.getTitle ? settingDef.getTitle(series, vizSettings) : settingDef.title, - hidden: settingDef.getHidden ? settingDef.getHidden(series, vizSettings) : false, - disabled: settingDef.getDisabled ? settingDef.getDisabled(series, vizSettings) : false, - props: { - ...(settingDef.props ? settingDef.props : {}), - ...(settingDef.getProps ? settingDef.getProps(series, vizSettings, onChange) : {}) - }, - onChange - }; -} - -export function getSettingsWidgets(series, onChangeSettings, isDashboard = false) { - const vizSettings = getSettings(series); - return getSettingIdsForSeries(series).map(id => - getSettingWidget(id, vizSettings, series, onChangeSettings) - ).filter(widget => - widget.widget && !widget.hidden && - (widget.dashboard === undefined || widget.dashboard === isDashboard) - ); -} diff --git a/frontend/src/metabase/meta/Dashboard.js b/frontend/src/metabase/meta/Dashboard.js index 9f821f4ccd407dd0f5e8b302d0c96737d33f7acc..8d5d60f0bb5c5bd054ecbdc94f7894e926976769 100644 --- a/frontend/src/metabase/meta/Dashboard.js +++ b/frontend/src/metabase/meta/Dashboard.js @@ -13,6 +13,7 @@ import { getTemplateTags } from "./Card"; import { slugify, stripId } from "metabase/lib/formatting"; import Query from "metabase/lib/query"; import { TYPE, isa } from "metabase/lib/types"; +import { mbqlEq } from "metabase/lib/query/util"; import _ from "underscore"; @@ -140,7 +141,7 @@ export function getCardDimensions(metadata: Metadata, card: Card, filter: FieldF } else if (card.dataset_query.type === "native") { let dimensions = []; for (const tag of getTemplateTags(card)) { - if (tag.type === "dimension" && Array.isArray(tag.dimension) && tag.dimension[0] === "field-id") { + if (tag.type === "dimension" && Array.isArray(tag.dimension) && mbqlEq(tag.dimension[0], "field-id")) { const field = metadata.field(tag.dimension[1]); if (field && filter(field)) { let fieldDimension = getFieldDimension(field); @@ -154,7 +155,7 @@ export function getCardDimensions(metadata: Metadata, card: Card, filter: FieldF } function getDimensionTargetFieldId(target: DimensionTarget): ?FieldId { - if (Array.isArray(target) && target[0] === "template-tag") { + if (Array.isArray(target) && mbqlEq(target[0], "template-tag")) { return null; } else { return Query.getFieldTargetId(target); @@ -202,7 +203,7 @@ export function getCardVariables(metadata: Metadata, card: Card, filter: Templat export function getParameterMappingTargetField(metadata: Metadata, card: Card, target: ParameterMappingTarget): ?Field { if (target[0] === "dimension") { let dimension = target[1]; - if (Array.isArray(dimension) && dimension[0] === "template-tag") { + if (Array.isArray(dimension) && mbqlEq(dimension[0], "template-tag")) { if (card.dataset_query.type === "native") { let templateTag = card.dataset_query.native.template_tags[String(dimension[1])]; if (templateTag && templateTag.type === "dimension") { diff --git a/frontend/src/metabase/meta/metadata/Field.js b/frontend/src/metabase/meta/metadata/Field.js index 52279a76f1a066a07aa42aae57219d534ed12d0e..5f6955d736ad1c50cad3d5b0b12a0b3d8dd71a63 100644 --- a/frontend/src/metabase/meta/metadata/Field.js +++ b/frontend/src/metabase/meta/metadata/Field.js @@ -7,7 +7,7 @@ import type { FieldId, Field as FieldObject } from "metabase/meta/types/Field"; import type { TableId } from "metabase/meta/types/Table"; import { isDate, isNumeric, isBoolean, isString, isSummable, isCategory, isDimension, isMetric, getIconForField } from "metabase/lib/schema_metadata"; -import { isPK } from "metabase/lib/types"; +import { isPK, isFK } from "metabase/lib/types"; export default class Field extends Base { static type = "fields"; @@ -43,7 +43,9 @@ export default class Field extends Base { isCategory() { return isCategory(this._object); } isMetric() { return isMetric(this._object); } isDimension() { return isDimension(this._object); } - isID() { return isPK(this.special_type); } + isID() { return isPK(this.special_type) || isFK(this.special_type); } + isPK() { return isPK(this.special_type); } + isFK() { return isFK(this.special_type); } values(): Array<string> { let values = this._object.values; diff --git a/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx b/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx index 69567f7867f58cdaa82062f388d44c083c8e89dc..b902a25096e2c25ff4cdac9d6854c6b69643a88c 100644 --- a/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx +++ b/frontend/src/metabase/nav/containers/DashboardsDropdown.jsx @@ -7,6 +7,7 @@ import OnClickOutsideWrapper from 'metabase/components/OnClickOutsideWrapper.jsx import MetabaseAnalytics from "metabase/lib/analytics"; import CreateDashboardModal from "metabase/components/CreateDashboardModal.jsx"; import Modal from "metabase/components/Modal.jsx"; +import ConstrainToScreen from "metabase/components/ConstrainToScreen"; import _ from "underscore"; import cx from "classnames"; @@ -121,7 +122,8 @@ export default class DashboardsDropdown extends Component { { dropdownOpen ? <OnClickOutsideWrapper handleDismissal={this.closeDropdown}> - <div className="NavDropdown-content DashboardList NavDropdown-content--dashboards"> + <ConstrainToScreen> + <div className="NavDropdown-content DashboardList NavDropdown-content--dashboards scroll-y"> { dashboards.length === 0 ? <div className="NavDropdown-content-layer text-white text-centered"> <div className="p2"><div style={this.styles.dashIcon} className="ml-auto mr-auto"></div></div> @@ -153,6 +155,7 @@ export default class DashboardsDropdown extends Component { </ul> } </div> + </ConstrainToScreen> </OnClickOutsideWrapper> : null } </div> diff --git a/frontend/src/metabase/query_builder/actions.js b/frontend/src/metabase/query_builder/actions.js index 31afc48091bab24a99201e572182ee4c7591b890..5f1dbc8ad7264cca151dd5566a3472eeb691a75a 100644 --- a/frontend/src/metabase/query_builder/actions.js +++ b/frontend/src/metabase/query_builder/actions.js @@ -7,6 +7,7 @@ import moment from "moment"; import { createThunkAction } from "metabase/lib/redux"; import { push, replace } from "react-router-redux"; +import { setErrorPage } from "metabase/redux/app"; import MetabaseAnalytics from "metabase/lib/analytics"; import { loadCard, isCardDirty, startNewCard, deserializeCardFromUrl, serializeCardForUrl, cleanCopyCard, urlForCardState } from "metabase/lib/card"; @@ -110,7 +111,11 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (location, params) const { currentUser } = getState(); - let card, databases, originalCard, uiControls = { isEditing: false }; + let card, databases, originalCard; + let uiControls = { + isEditing: false, + isShowingTemplateTagsEditor: false + }; // always start the QB by loading up the databases for the application try { @@ -119,11 +124,9 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (location, params) console.log("error fetching dbs", error); // if we can't actually get the databases list then bail now - return { - uiControls: { - is500: true - } - } + dispatch(setErrorPage(error)); + + return { uiControls }; } // load up or initialize the card we'll be working on @@ -172,12 +175,7 @@ export const initializeQB = createThunkAction(INITIALIZE_QB, (location, params) } catch(error) { console.warn(error) card = null; - - if (error.status === 404) { - uiControls.is404 = true; - } else { - uiControls.is500 = true; - } + dispatch(setErrorPage(error)); } } else if (options.tutorial !== undefined && sampleDataset) { diff --git a/frontend/src/metabase/query_builder/components/FieldList.jsx b/frontend/src/metabase/query_builder/components/FieldList.jsx index 96fa67d2537c878e2fd3251ba3ffcc6f43abc566..b4ee66a8c51e9fd049554cf681afbac498377c4f 100644 --- a/frontend/src/metabase/query_builder/components/FieldList.jsx +++ b/frontend/src/metabase/query_builder/components/FieldList.jsx @@ -184,10 +184,10 @@ export default class FieldList extends Component { if (item.segment) { this.props.onFilterChange(item.value); } else if (this.itemIsSelected(item)) { - // ensure if we select the same item we don't reset datetime_field's unit + // ensure if we select the same item we don't reset datetime-field's unit this.props.onFieldChange(this.props.field); } else if (this.props.enableTimeGrouping && isDate(item.field)) { - this.props.onFieldChange(["datetime_field", item.value, "as", "day"]); + this.props.onFieldChange(["datetime-field", item.value, "as", "day"]); } else { this.props.onFieldChange(item.value); } diff --git a/frontend/src/metabase/query_builder/components/NativeQueryEditor.css b/frontend/src/metabase/query_builder/components/NativeQueryEditor.css index f4ac19a486a2438ee189c65bc377ee09e4ad342b..9370e0b0e8a2263db12255d536da50eafdb61ffc 100644 --- a/frontend/src/metabase/query_builder/components/NativeQueryEditor.css +++ b/frontend/src/metabase/query_builder/components/NativeQueryEditor.css @@ -1,6 +1,18 @@ .NativeQueryEditor .ace_editor { - height: 200px; + height: 100%; +} + +.NativeQueryEditor .react-resizable { + position: relative; +} + +.NativeQueryEditor .react-resizable-handle { + position: absolute; + width: 100%; + height: 10px; + bottom: -5px; + cursor: ns-resize; } .NativeQueryEditor .ace_editor.read-only .ace_cursor { diff --git a/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx b/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx index 57eb0636a71821d70e537322b76a1e482e1a61eb..9fd1f569756f4f5c9775d66fde611280e2f2db53 100644 --- a/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx +++ b/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx @@ -6,6 +6,9 @@ import ReactDOM from "react-dom"; import "./NativeQueryEditor.css"; +import { ResizableBox } from 'react-resizable'; +import { countLines } from "metabase/lib/string"; + import 'ace/ace'; import 'ace/ext-language_tools'; @@ -50,14 +53,26 @@ function getModeInfo(query, databases) { }; } +const SCROLL_MARGIN = 8; +const LINE_HEIGHT = 16; + +const MIN_HEIGHT_LINES = 1; +const MAX_AUTO_SIZE_LINES = 12; + +const getEditorLineHeight = (lines) => lines * LINE_HEIGHT + 2 * SCROLL_MARGIN; export default class NativeQueryEditor extends Component { constructor(props, context) { super(props, context); + const lines = props.query.native.query ? + Math.min(MAX_AUTO_SIZE_LINES, countLines(props.query.native.query)) : + MAX_AUTO_SIZE_LINES; + this.state = { - showEditor: true,//this.props.isOpen, - modeInfo: getModeInfo(props.query, props.databases) + showEditor: !(props.card && props.card.id), + modeInfo: getModeInfo(props.query, props.databases), + initialHeight: getEditorLineHeight(lines) }; this.localUpdate = false; @@ -102,32 +117,31 @@ export default class NativeQueryEditor extends Component { componentDidUpdate() { const { modeInfo } = this.state; - let editorElement = ReactDOM.findDOMNode(this.refs.editor); - let editor = ace.edit(editorElement); - if (editor.getValue() !== this.props.query.native.query) { + if (this._editor.getValue() !== this.props.query.native.query) { // This is a weird hack, but the purpose is to avoid an infinite loop caused by the fact that calling editor.setValue() // will trigger the editor 'change' event, update the query, and cause another rendering loop which we don't want, so // we need a way to update the editor without causing the onChange event to go through as well this.localUpdate = true; - editor.setValue(this.props.query.native.query); - editor.clearSelection(); + this._editor.setValue(this.props.query.native.query); + this._editor.clearSelection(); this.localUpdate = false; } if (modeInfo) { + let editorElement = ReactDOM.findDOMNode(this.refs.editor); if (!modeInfo.database || modeInfo.database.native_permissions !== "write") { - editor.setReadOnly(true); + this._editor.setReadOnly(true); editorElement.classList.add("read-only"); } else { - editor.setReadOnly(false); + this._editor.setReadOnly(false); editorElement.classList.remove("read-only"); } - if (editor.getSession().$modeId !== modeInfo.mode) { - editor.getSession().setMode(modeInfo.mode); + if (this._editor.getSession().$modeId !== modeInfo.mode) { + this._editor.getSession().setMode(modeInfo.mode); // monkey patch the mode to add our bracket/paren/braces-matching behavior if (this.state.modeInfo.mode.indexOf("sql") >= 0) { - editor.getSession().$mode.$behaviour = new SQLBehaviour(); + this._editor.getSession().$mode.$behaviour = new SQLBehaviour(); } } } @@ -135,26 +149,25 @@ export default class NativeQueryEditor extends Component { loadAceEditor() { let editorElement = ReactDOM.findDOMNode(this.refs.editor); - let editor = ace.edit(editorElement); + this._editor = ace.edit(editorElement); // listen to onChange events - editor.getSession().on('change', this.onChange); + this._editor.getSession().on('change', this.onChange); // initialize the content - editor.setValue(this.props.query.native.query); + const querySource = this.props.query.native.query; + this._editor.setValue(querySource); + + this._editor.renderer.setScrollMargin(SCROLL_MARGIN, SCROLL_MARGIN); // clear the editor selection, otherwise we start with the whole editor selected - editor.clearSelection(); + this._editor.clearSelection(); // hmmm, this could be dangerous - editor.focus(); - - this.setState({ - editor: editor - }); + this._editor.focus(); let aceLanguageTools = ace.require('ace/ext/language_tools'); - editor.setOptions({ + this._editor.setOptions({ enableBasicAutocompletion: true, enableSnippets: true, enableLiveAutocompletion: true, @@ -190,12 +203,22 @@ export default class NativeQueryEditor extends Component { }); } + _updateSize() { + const doc = this._editor.getSession().getDocument(); + const element = ReactDOM.findDOMNode(this.refs.resizeBox); + const newHeight = getEditorLineHeight(doc.getLength()); + if (newHeight > element.offsetHeight && newHeight <= getEditorLineHeight(MAX_AUTO_SIZE_LINES)) { + element.style.height = newHeight + "px"; + this._editor.resize(); + } + } + onChange(event) { - if (this.state.editor && !this.localUpdate) { + if (this._editor && !this.localUpdate) { + this._updateSize(); const { query } = this.props; - const { editor } = this.state; - if (query.native.query !== editor.getValue()) { - this.props.setQueryFn(assocIn(query, ["native", "query"], editor.getValue())); + if (query.native.query !== this._editor.getValue()) { + this.props.setQueryFn(assocIn(query, ["native", "query"], this._editor.getValue())); } } } @@ -305,9 +328,18 @@ export default class NativeQueryEditor extends Component { <Icon name={toggleEditorIcon} size={20}/> </a> </div> - <div className={"border-top " + editorClasses}> + <ResizableBox + ref="resizeBox" + className={"border-top " + editorClasses} + height={this.state.initialHeight} + minConstraints={[Infinity, getEditorLineHeight(MIN_HEIGHT_LINES)]} + axis="y" + onResizeStop={(e, data) => { + this._editor.resize(); + }} + > <div id="id_sql" ref="editor"></div> - </div> + </ResizableBox> </div> </div> ); diff --git a/frontend/src/metabase/query_builder/components/TimeGroupingPopover.jsx b/frontend/src/metabase/query_builder/components/TimeGroupingPopover.jsx index 8f228e593e9abf5c7738c44f2b2c1e49d9ea9796..3d120352d8ea388e4a438422cd24ab7ece413ace 100644 --- a/frontend/src/metabase/query_builder/components/TimeGroupingPopover.jsx +++ b/frontend/src/metabase/query_builder/components/TimeGroupingPopover.jsx @@ -58,7 +58,7 @@ export default class TimeGroupingPopover extends Component { } setField(bucketing) { - this.props.onFieldChange(["datetime_field", this.props.value, "as", bucketing]); + this.props.onFieldChange(["datetime-field", this.props.value, "as", bucketing]); } render() { diff --git a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker.jsx b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker.jsx index a3f5a5504fb26d9fd185804961d3e21202ba3fea..8b38010b96a4e643a5b3f08c31bcbb2380f1d26d 100644 --- a/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker.jsx +++ b/frontend/src/metabase/query_builder/components/filters/pickers/DatePicker.jsx @@ -9,11 +9,17 @@ import Calendar from "metabase/components/Calendar"; import moment from "moment"; +import Query from "metabase/lib/query"; import { mbqlEq } from "metabase/lib/query/util"; import _ from "underscore"; -import type { FieldFilter, TimeIntervalFilter } from "metabase/meta/types/Query"; +import type { + FieldFilter, TimeIntervalFilter, + DatetimeUnit, + ConcreteField, + LocalFieldReference, ForeignFieldReference, ExpressionReference +} from "metabase/meta/types/Query"; const SingleDatePicker = ({ filter: [op, field, value], onFilterChange }) => <SpecificDatePicker value={value} onChange={(value) => onFilterChange([op, field, value])} calendar /> @@ -83,8 +89,43 @@ class CurrentPicker extends Component<*, CurentPickerProps, CurrentPickerState> const getIntervals = ([op, field, value, unit]) => mbqlEq(op, "time-interval") && typeof value === "number" ? Math.abs(value) : 30; const getUnit = ([op, field, value, unit]) => mbqlEq(op, "time-interval") && unit ? unit : "day"; -const getDate = (value) => typeof value === "string" && moment(value).isValid() ? value : moment().format("YYYY-MM-DD"); +const getDate = (value) => { + if (typeof value !== "string" || !moment(value).isValid()) { + value = moment().format("YYYY-MM-DD"); + } + return value; +} + +const hasTime = (value) => /T\d{2}:\d{2}:\d{2}$/.test(value); + +function getDateTimeField(field: ConcreteField, bucketing: ?DatetimeUnit): ConcreteField { + let target = getDateTimeFieldTarget(field); + if (bucketing) { + // $FlowFixMe + return ["datetime-field", target, bucketing]; + } else { + return target; + } +} + +function getDateTimeFieldTarget(field: ConcreteField): LocalFieldReference|ForeignFieldReference|ExpressionReference { + if (Query.isDatetimeField(field)) { + // $FlowFixMe: + return (field[1]: LocalFieldReference|ForeignFieldReference|ExpressionReference); + } else { + // $FlowFixMe + return field; + } +} + +function getDateTimeFieldAndValues(filter: FieldFilter): [ConcreteField, any] { + const values = filter.slice(2).map(getDate); + const bucketing = _.any(values, hasTime) ? "minute" : null; + const field = getDateTimeField(filter[1], bucketing); + // $FlowFixMe + return [field, ...values]; +} export type Operator = { name: string, @@ -96,56 +137,56 @@ export type Operator = { const OPERATORS: Operator[] = [ { name: "Previous", - init: (filter) => ["time-interval", filter[1], -getIntervals(filter), getUnit(filter)], + init: (filter) => ["time-interval", getDateTimeField(filter[1]), -getIntervals(filter), getUnit(filter)], // $FlowFixMe test: ([op, field, value]) => mbqlEq(op, "time-interval") && value < 0 || Object.is(value, -0), widget: PreviousPicker, }, { name: "Next", - init: (filter) => ["time-interval", filter[1], getIntervals(filter), getUnit(filter)], + init: (filter) => ["time-interval", getDateTimeField(filter[1]), getIntervals(filter), getUnit(filter)], // $FlowFixMe test: ([op, field, value]) => mbqlEq(op, "time-interval") && value >= 0, widget: NextPicker, }, { name: "Current", - init: (filter) => ["time-interval", filter[1], "current", getUnit(filter)], + init: (filter) => ["time-interval", getDateTimeField(filter[1]), "current", getUnit(filter)], test: ([op, field, value]) => mbqlEq(op, "time-interval") && value === "current", widget: CurrentPicker, }, { name: "Before", - init: (filter) => ["<", filter[1], getDate(filter[2])], + init: (filter) => ["<", ...getDateTimeFieldAndValues(filter)], test: ([op]) => op === "<", widget: SingleDatePicker, }, { name: "After", - init: (filter) => [">", filter[1], getDate(filter[2])], + init: (filter) => [">", ...getDateTimeFieldAndValues(filter)], test: ([op]) => op === ">", widget: SingleDatePicker, }, { name: "On", - init: (filter) => ["=", filter[1], getDate(filter[2])], + init: (filter) => ["=", ...getDateTimeFieldAndValues(filter)], test: ([op]) => op === "=", widget: SingleDatePicker, }, { name: "Between", - init: (filter) => ["BETWEEN", filter[1], getDate(filter[2]), getDate(filter[3])], + init: (filter) => ["BETWEEN", ...getDateTimeFieldAndValues(filter)], test: ([op]) => op === "BETWEEN", widget: MultiDatePicker, }, { name: "Is Empty", - init: (filter) => ["IS_NULL", filter[1]], + init: (filter) => ["IS_NULL", getDateTimeField(filter[1])], test: ([op]) => op === "IS_NULL" }, { name: "Not Empty", - init: (filter) => ["NOT_NULL", filter[1]], + init: (filter) => ["NOT_NULL", getDateTimeField(filter[1])], test: ([op]) => op === "NOT_NULL" } ]; @@ -185,7 +226,17 @@ export default class DatePicker extends Component<*, Props, *> { onOperatorChange={operator => onFilterChange(operator.init(filter))} /> { Widget && - <Widget {...this.props} filter={filter} /> + <Widget + {...this.props} + filter={filter} + onFilterChange={filter => { + if (operator && operator.init) { + onFilterChange(operator.init(filter)); + } else { + onFilterChange(filter); + } + }} + /> } </div> ) diff --git a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx index b12f88295acdc494a45f47b364a7046dd1e0fb9d..a9d44d720f8d8104c5270478a425ff86c26553c7 100644 --- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx +++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx @@ -7,7 +7,6 @@ import _ from "underscore"; import { loadTableAndForeignKeys } from "metabase/lib/table"; import { isPK, isFK } from "metabase/lib/types"; -import NotFound from "metabase/components/NotFound.jsx"; import QueryBuilderTutorial from "metabase/tutorial/QueryBuilderTutorial.jsx"; import QueryHeader from "../components/QueryHeader.jsx"; @@ -182,16 +181,6 @@ export default class QueryBuilder extends Component { render() { const { card, isDirty, databases, uiControls } = this.props; - // if we can't load the card that was intended then we end up with a 404 - // TODO: we should do something more unique for is500 - if (uiControls.is404 || uiControls.is500) { - return ( - <div className="flex flex-column flex-full layout-centered"> - <NotFound /> - </div> - ); - } - // if we don't have a card at all or no databases then we are initializing, so keep it simple if (!card || !databases) { return ( diff --git a/frontend/src/metabase/query_builder/reducers.js b/frontend/src/metabase/query_builder/reducers.js index 1507f8118504a8bc061c77e873a3d7681c115578..44b31054d24d16d11bab3af941f0bdaa1b048c91 100644 --- a/frontend/src/metabase/query_builder/reducers.js +++ b/frontend/src/metabase/query_builder/reducers.js @@ -67,8 +67,6 @@ export const uiControls = handleActions({ isShowingNewbModal: false, isEditing: false, isRunning: false, - is404: false, - is500: false }); diff --git a/frontend/src/metabase/questions/containers/AddToDashboard.jsx b/frontend/src/metabase/questions/containers/AddToDashboard.jsx index 8b6c9f860b42f6f256881ad828a1ea78d636c8b8..cbd478ff5b07b62e1886d08b9a32fdfd59a4a277 100644 --- a/frontend/src/metabase/questions/containers/AddToDashboard.jsx +++ b/frontend/src/metabase/questions/containers/AddToDashboard.jsx @@ -24,7 +24,7 @@ export default class AddToDashboard extends Component { return ( <ModalContent title="Add question to dashboard?" - className="mx4 mb4" + className="px4 mb4 scroll-y" onClose={() => this.props.onClose()} > <div className="py1 flex align-center"> diff --git a/frontend/src/metabase/questions/containers/EntityList.jsx b/frontend/src/metabase/questions/containers/EntityList.jsx index 20300476f8c5fc7a0773de86f99975a68e358272..67cc28dfb991d4f02eb83880a22a790ce9453edd 100644 --- a/frontend/src/metabase/questions/containers/EntityList.jsx +++ b/frontend/src/metabase/questions/containers/EntityList.jsx @@ -179,54 +179,52 @@ export default class EntityList extends Component { const showSearchHeader = (entityIds.length > 0 && showSearchWidget); const showEntityFilterWidget = onChangeSection; return ( - <div className="full" style={style}> - <div className="full"> - { (showActionHeader || showSearchHeader || showEntityFilterWidget) && - <div className="flex align-center my1" style={{height: 40}}> - { showActionHeader ? - <ActionHeader - visibleCount={visibleCount} - selectedCount={selectedCount} - allAreSelected={allAreSelected} - sectionIsArchive={sectionIsArchive} - setAllSelected={setAllSelected} - setArchived={setArchived} - labels={labels} - /> - : showSearchHeader ? - <SearchHeader - searchText={searchText} - setSearchText={setSearchText} - /> - : - null - } - { showEntityFilterWidget && entityIds.length > 0 && - <EntityFilterWidget - section={section} - onChange={onChangeSection} - /> - } - </div> - } - <LoadingAndErrorWrapper className="full" loading={!error && loading} error={error}> - { () => - entityIds.length > 0 ? - <List - entityType={entityType} - entityIds={entityIds} - editable={editable} - setItemSelected={setItemSelected} - onEntityClick={onEntityClick} - showCollectionName={showCollectionName} + <div style={style}> + { (showActionHeader || showSearchHeader || showEntityFilterWidget) && + <div className="flex align-center my1" style={{height: 40}}> + { showActionHeader ? + <ActionHeader + visibleCount={visibleCount} + selectedCount={selectedCount} + allAreSelected={allAreSelected} + sectionIsArchive={sectionIsArchive} + setAllSelected={setAllSelected} + setArchived={setArchived} + labels={labels} + /> + : showSearchHeader ? + <SearchHeader + searchText={searchText} + setSearchText={setSearchText} /> : - <div className={S.empty}> - <EmptyState message={section.section === "all" && this.props.defaultEmptyState ? this.props.defaultEmptyState : section.empty} icon={section.icon} /> - </div> - } - </LoadingAndErrorWrapper> - </div> + null + } + { showEntityFilterWidget && entityIds.length > 0 && + <EntityFilterWidget + section={section} + onChange={onChangeSection} + /> + } + </div> + } + <LoadingAndErrorWrapper className="full" loading={!error && loading} error={error}> + { () => + entityIds.length > 0 ? + <List + entityType={entityType} + entityIds={entityIds} + editable={editable} + setItemSelected={setItemSelected} + onEntityClick={onEntityClick} + showCollectionName={showCollectionName} + /> + : + <div className={S.empty}> + <EmptyState message={section.section === "all" && this.props.defaultEmptyState ? this.props.defaultEmptyState : section.empty} icon={section.icon} /> + </div> + } + </LoadingAndErrorWrapper> </div> ); } diff --git a/frontend/src/metabase/routes.jsx b/frontend/src/metabase/routes.jsx index 3d627369684a2aedf28480405f4cc0eb17e50257..a8ecf6e6702b5ea2451a793bd76f472a2200de0e 100644 --- a/frontend/src/metabase/routes.jsx +++ b/frontend/src/metabase/routes.jsx @@ -79,7 +79,16 @@ const UserIsAuthenticated = UserAuthWrapper({ failureRedirectPath: '/auth/login', authSelector: state => state.currentUser, wrapperDisplayName: 'UserIsAuthenticated', - redirectAction: routerActions.replace, + redirectAction: (location) => + // HACK: workaround for redux-auth-wrapper not including hash + // https://github.com/mjrussell/redux-auth-wrapper/issues/121 + routerActions.replace({ + ...location, + query: { + ...location.query, + redirect: location.query.redirect + (window.location.hash || "") + } + }) }); const UserIsAdmin = UserAuthWrapper({ diff --git a/frontend/src/metabase/visualizations/AreaChart.jsx b/frontend/src/metabase/visualizations/AreaChart.jsx deleted file mode 100644 index 8b8c5bd3cf4c4ac5b10995d996f134abea41159a..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/AreaChart.jsx +++ /dev/null @@ -1,12 +0,0 @@ -/* @flow */ - -import React, { Component, PropTypes } from "react"; - -import LineAreaBarChart from "./components/LineAreaBarChart.jsx"; - -export default class AreaChart extends LineAreaBarChart { - static uiName = "Area"; - static identifier = "area"; - static iconName = "area"; - static noun = "area chart"; -} diff --git a/frontend/src/metabase/visualizations/BarChart.jsx b/frontend/src/metabase/visualizations/BarChart.jsx deleted file mode 100644 index 7efa4c50e66df2ab8f070c61e4dbdb6d47b0375e..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/BarChart.jsx +++ /dev/null @@ -1,12 +0,0 @@ -/* @flow */ - -import React, { Component, PropTypes } from "react"; - -import LineAreaBarChart from "./components/LineAreaBarChart.jsx"; - -export default class BarChart extends LineAreaBarChart { - static uiName = "Bar"; - static identifier = "bar"; - static iconName = "bar"; - static noun = "bar chart"; -} diff --git a/frontend/src/metabase/visualizations/LineChart.jsx b/frontend/src/metabase/visualizations/LineChart.jsx deleted file mode 100644 index be43536a1efe2b502b0fca9f4fb74cd850fe73f9..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/LineChart.jsx +++ /dev/null @@ -1,12 +0,0 @@ -/* @flow */ - -import React, { Component, PropTypes } from "react"; - -import LineAreaBarChart from "./components/LineAreaBarChart.jsx"; - -export default class LineChart extends LineAreaBarChart { - static uiName = "Line"; - static identifier = "line"; - static iconName = "line"; - static noun = "line chart"; -} diff --git a/frontend/src/metabase/visualizations/Map.jsx b/frontend/src/metabase/visualizations/Map.jsx deleted file mode 100644 index c209c22d095ceccedc16d93a1571e89450dab6d3..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/Map.jsx +++ /dev/null @@ -1,46 +0,0 @@ -/* @flow */ - -import React, { Component, PropTypes } from "react"; - -import ChoroplethMap from "./components/ChoroplethMap.jsx"; -import PinMap from "./PinMap.jsx"; - -import { ChartSettingsError } from "metabase/visualizations/lib/errors"; - -import type { VisualizationProps } from "metabase/visualizations"; - -export default class Map extends Component<*, VisualizationProps, *> { - static uiName = "Map"; - static identifier = "map"; - static iconName = "pinmap"; - - static aliases = ["state", "country", "pin_map"]; - - static minSize = { width: 4, height: 4 }; - - static isSensible(cols, rows) { - return true; - } - - static checkRenderable([{ data: { cols, rows} }], settings) { - if (settings["map.type"] === "pin") { - if (!settings["map.longitude_column"] || !settings["map.latitude_column"]) { - throw new ChartSettingsError("Please select longitude and latitude columns in the chart settings.", "Data"); - } - } else if (settings["map.type"] === "region"){ - if (!settings["map.dimension"] || !settings["map.metric"]) { - throw new ChartSettingsError("Please select region and metric columns in the chart settings.", "Data"); - } - } - } - - render() { - const { settings } = this.props; - const type = settings["map.type"]; - if (type === "pin") { - return <PinMap {...this.props} /> - } else if (type === "region") { - return <ChoroplethMap {...this.props} /> - } - } -} diff --git a/frontend/src/metabase/visualizations/ScatterPlot.jsx b/frontend/src/metabase/visualizations/ScatterPlot.jsx deleted file mode 100644 index 1c87375f0946d83e60a9e6f2219f551f111abad4..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/visualizations/ScatterPlot.jsx +++ /dev/null @@ -1,12 +0,0 @@ -/* @flow */ - -import React, { Component, PropTypes } from "react"; - -import LineAreaBarChart from "./components/LineAreaBarChart.jsx"; - -export default class ScatterPlot extends LineAreaBarChart { - static uiName = "Scatter"; - static identifier = "scatter"; - static iconName = "bubble"; - static noun = "scatter plot"; -} diff --git a/frontend/src/metabase/visualizations/components/ChartSettings.jsx b/frontend/src/metabase/visualizations/components/ChartSettings.jsx index 8e288b4fac99241556d4caed26d32e3b201a892e..e2d885183faf0353b78dbe69e6bc32e254ba61a4 100644 --- a/frontend/src/metabase/visualizations/components/ChartSettings.jsx +++ b/frontend/src/metabase/visualizations/components/ChartSettings.jsx @@ -6,7 +6,7 @@ import _ from "underscore"; import Warnings from "metabase/query_builder/components/Warnings.jsx"; import Visualization from "metabase/visualizations/components/Visualization.jsx" -import { getSettingsWidgets } from "metabase/lib/visualization_settings"; +import { getSettingsWidgets } from "metabase/visualizations/lib/settings"; import MetabaseAnalytics from "metabase/lib/analytics"; import { getVisualizationTransformed } from "metabase/visualizations"; diff --git a/frontend/src/metabase/visualizations/components/FunnelBar.jsx b/frontend/src/metabase/visualizations/components/FunnelBar.jsx index 58e59488884782b18bc6627961fb0d0428ea6f38..06f85d90983b55e9c39b9bd346324dfc67075756 100644 --- a/frontend/src/metabase/visualizations/components/FunnelBar.jsx +++ b/frontend/src/metabase/visualizations/components/FunnelBar.jsx @@ -3,9 +3,9 @@ import React, { Component, PropTypes } from "react"; import ReactDOM from "react-dom"; -import BarChart from "metabase/visualizations/BarChart.jsx"; +import BarChart from "metabase/visualizations/visualizations/BarChart.jsx"; -import { getSettings } from "metabase/lib/visualization_settings"; +import { getSettings } from "metabase/visualizations/lib/settings"; import { assocIn } from "icepick"; import type { VisualizationProps } from "metabase/visualizations"; diff --git a/frontend/src/metabase/visualizations/components/LegendHeader.jsx b/frontend/src/metabase/visualizations/components/LegendHeader.jsx index 98a1fc7a96e4059394eb7921717d8cc5db6ea85b..debcccb7630d521606375d3fb48f36c9262a2ed6 100644 --- a/frontend/src/metabase/visualizations/components/LegendHeader.jsx +++ b/frontend/src/metabase/visualizations/components/LegendHeader.jsx @@ -28,6 +28,7 @@ export default class LegendHeader extends Component { onRemoveSeries: PropTypes.func, actionButtons: PropTypes.node, linkToCard: PropTypes.bool, + description: PropTypes.string }; static defaultProps = { @@ -47,7 +48,7 @@ export default class LegendHeader extends Component { } render() { - const { series, hovered, onRemoveSeries, actionButtons, onHoverChange, linkToCard, settings } = this.props; + const { series, hovered, onRemoveSeries, actionButtons, onHoverChange, linkToCard, settings, description } = this.props; const showDots = series.length > 1; const isNarrow = this.state.width < 150; const showTitles = !showDots || !isNarrow; @@ -59,6 +60,7 @@ export default class LegendHeader extends Component { <LegendItem key={index} title={s.card.name} + description={description} href={linkToCard && s.card.id && Urls.card(s.card.id)} color={colors[index % colors.length]} showDot={showDots} @@ -66,19 +68,19 @@ export default class LegendHeader extends Component { isMuted={hovered && hovered.index != null && index !== hovered.index} onMouseEnter={() => onHoverChange && onHoverChange({ index })} onMouseLeave={() => onHoverChange && onHoverChange(null) } - />, + />, onRemoveSeries && index > 0 && - <Icon - name="close" - className="text-grey-2 flex-no-shrink mr1 cursor-pointer" - width={12} height={12} - onClick={() => onRemoveSeries(s.card)} - /> + <Icon + name="close" + className="text-grey-2 flex-no-shrink mr1 cursor-pointer" + width={12} height={12} + onClick={() => onRemoveSeries(s.card)} + /> ])} { actionButtons && - <span className="flex-no-shrink flex-align-right relative"> - {actionButtons} - </span> + <span className="flex-no-shrink flex-align-right relative"> + {actionButtons} + </span> } </div> ); diff --git a/frontend/src/metabase/visualizations/components/LegendItem.jsx b/frontend/src/metabase/visualizations/components/LegendItem.jsx index 5498193e830b9c4c68d17aa10e91116c06a0f684..d62be8776af3340b953571d18170a183e9ea82e1 100644 --- a/frontend/src/metabase/visualizations/components/LegendItem.jsx +++ b/frontend/src/metabase/visualizations/components/LegendItem.jsx @@ -1,6 +1,7 @@ import React, { Component, PropTypes } from "react"; import ReactDOM from "react-dom"; +import Icon from "metabase/components/Icon.jsx"; import Tooltip from "metabase/components/Tooltip.jsx"; import Ellipsified from "metabase/components/Ellipsified.jsx"; @@ -26,7 +27,7 @@ export default class LegendItem extends Component { }; render() { - const { title, href, color, showDot, showTitle, isMuted, showTooltip, showDotTooltip, onMouseEnter, onMouseLeave, className } = this.props; + const { title, href, color, showDot, showTitle, isMuted, showTooltip, showDotTooltip, onMouseEnter, onMouseLeave, className, description } = this.props; return ( <LegendLink href={href} @@ -44,8 +45,18 @@ export default class LegendItem extends Component { </Tooltip> } { showTitle && - <Ellipsified showTooltip={showTooltip}>{title}</Ellipsified> + <div className="flex align-center"> + <span className="mr1"><Ellipsified showTooltip={showTooltip}>{title}</Ellipsified></span> + { description && + <div className="hover-child"> + <Tooltip tooltip={description} maxWidth={'22em'}> + <Icon name='info' /> + </Tooltip> + </div> + } + </div> } + </LegendLink> ); } diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.css b/frontend/src/metabase/visualizations/components/LineAreaBarChart.css index eec6ccb6f741a217b7637afc5a658656496b5c41..a584964fd3a27bd14cd2c69b5d84e79f464fdf7e 100644 --- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.css +++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.css @@ -3,6 +3,7 @@ margin-left: -0.5em; margin-right: -0.5em; margin-bottom: -0.5em; + overflow: hidden; } /* TODO (@kdoh) remove this if dc-js/dc.js#1260 is merged */ @@ -27,6 +28,13 @@ fill: #C5C6C8; } +.LineAreaBarChart .dc-chart g.row text.outside { + fill: #C5C6C8; +} +.LineAreaBarChart .dc-chart g.row text.inside { + fill: white; +} + /* turn off ticks and domain lines */ .LineAreaBarChart .dc-chart .axis.y .domain, .LineAreaBarChart .dc-chart .axis.yr .domain, @@ -54,8 +62,14 @@ .LineAreaBarChart .dc-chart rect.bar:hover { fill-opacity: 1; } -/* highlight single series bar */ -.LineAreaBarChart.mute-0 .dc-chart rect.bar:hover { + +.LineAreaBarChart .dc-chart g.row rect { + fill-opacity: 1; +} + +/* highlight single series bar and row charts */ +.LineAreaBarChart.mute-0 .dc-chart rect.bar:hover, +.LineAreaBarChart.mute-0 .dc-chart g.row:hover { opacity: 1 !important; } @@ -92,8 +106,10 @@ .LineAreaBarChart .dc-chart .area, .LineAreaBarChart .dc-chart .bar, .LineAreaBarChart .dc-chart .line, -.LineAreaBarChart .dc-chart .dot { - transition: opacity 0.1s linear; +.LineAreaBarChart .dc-chart .dot, +.LineAreaBarChart .dc-chart .row, +.LineAreaBarChart .dc-chart .bubble { + transition: opacity 0.15s linear; } .LineAreaBarChart .dc-chart .axis.y, diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx index 641e2af7b18b2bde535a09220d6f6a91fe4be58c..28f1f3099ca1d8122f0cdceac58e9884fbe37123 100644 --- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx +++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx @@ -7,7 +7,6 @@ import LegendHeader from "./LegendHeader.jsx"; import ChartTooltip from "./ChartTooltip.jsx"; import "./LineAreaBarChart.css"; -import lineAreaBarRenderer from "metabase/visualizations/lib/LineAreaBarRenderer"; import { isNumeric, isDate } from "metabase/lib/schema_metadata"; import { @@ -15,12 +14,12 @@ import { getFriendlyName } from "metabase/visualizations/lib/utils"; import { addCSSRule } from "metabase/lib/dom"; +import { formatValue } from "metabase/lib/formatting"; -import { getSettings } from "metabase/lib/visualization_settings"; +import { getSettings } from "metabase/visualizations/lib/settings"; import { MinRowsError, ChartSettingsError } from "metabase/visualizations/lib/errors"; -import crossfilter from "crossfilter"; import _ from "underscore"; import cx from "classnames"; @@ -32,16 +31,21 @@ for (let i = 0; i < MAX_SERIES; i++) { addCSSRule(`.LineAreaBarChart.mute-${i} svg.stacked .stack._${i} .line`, MUTE_STYLE); addCSSRule(`.LineAreaBarChart.mute-${i} svg.stacked .stack._${i} .bar`, MUTE_STYLE); addCSSRule(`.LineAreaBarChart.mute-${i} svg.stacked .dc-tooltip._${i} .dot`, MUTE_STYLE); + addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .sub._${i} .bar`, MUTE_STYLE); addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .sub._${i} .line`, MUTE_STYLE); addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .sub._${i} .dot`, MUTE_STYLE); addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .sub._${i} .bubble`, MUTE_STYLE); + + // row charts don't support multiseries + addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .row`, MUTE_STYLE); } import type { VisualizationProps } from "metabase/visualizations"; export default class LineAreaBarChart extends Component<*, VisualizationProps, *> { - static identifier; + static identifier: string; + static renderer: (element: Element, props: VisualizationProps) => any; static noHeader = true; static supportsSeries = true; @@ -93,7 +97,7 @@ export default class LineAreaBarChart extends Component<*, VisualizationProps, * } static transformSeries(series) { - let newSeries = [].concat(...series.map((s) => transformSingleSeries(s, series))); + let newSeries = [].concat(...series.map((s, seriesIndex) => transformSingleSeries(s, series, seriesIndex))); if (_.isEqual(series, newSeries) || newSeries.length === 0) { return series; } else { @@ -124,10 +128,6 @@ export default class LineAreaBarChart extends Component<*, VisualizationProps, * } } - getChartType() { - return this.constructor.identifier; - } - getFidelity() { let fidelity = { x: 0, y: 0 }; let size = this.props.gridSize || { width: Infinity, height: Infinity }; @@ -201,6 +201,7 @@ export default class LineAreaBarChart extends Component<*, VisualizationProps, * <LegendHeader className="flex-no-shrink" series={titleHeaderSeries} + description={settings["card.description"]} actionButtons={actionButtons} linkToCard={linkToCard} /> @@ -218,12 +219,11 @@ export default class LineAreaBarChart extends Component<*, VisualizationProps, * : null } <CardRenderer {...this.props} - chartType={this.getChartType()} series={series} settings={settings} className="renderer flex-full" maxSeries={MAX_SERIES} - renderer={lineAreaBarRenderer} + renderer={this.constructor.renderer} /> <ChartTooltip series={series} hovered={hovered} /> </div> @@ -238,7 +238,7 @@ function getColumnsFromNames(cols, names) { return names.map(name => _.findWhere(cols, { name })); } -function transformSingleSeries(s, series) { +function transformSingleSeries(s, series, seriesIndex) { const { card, data } = s; // HACK: prevents cards from being transformed too many times @@ -251,25 +251,39 @@ function transformSingleSeries(s, series) { const dimensions = settings["graph.dimensions"].filter(d => d != null); const metrics = settings["graph.metrics"].filter(d => d != null); - const dimensionIndexes = dimensions.map(dimensionName => + const dimensionColumnIndexes = dimensions.map(dimensionName => _.findIndex(cols, (col) => col.name === dimensionName) ); - const metricIndexes = metrics.map(metricName => + const metricColumnIndexes = metrics.map(metricName => _.findIndex(cols, (col) => col.name === metricName) ); - - const bubbleIndex = settings["scatter.bubble"] && _.findIndex(cols, (col) => col.name === settings["scatter.bubble"]); - const extraIndexes = bubbleIndex && bubbleIndex >= 0 ? [bubbleIndex] : []; + const bubbleColumnIndex = settings["scatter.bubble"] && _.findIndex(cols, (col) => col.name === settings["scatter.bubble"]); + const extraColumnIndexes = bubbleColumnIndex && bubbleColumnIndex >= 0 ? [bubbleColumnIndex] : []; if (dimensions.length > 1) { - const dataset = crossfilter(rows); - const [dimensionIndex, seriesIndex] = dimensionIndexes; - const rowIndexes = [dimensionIndex].concat(metricIndexes, extraIndexes); - const seriesGroup = dataset.dimension(d => d[seriesIndex]).group() - return seriesGroup.reduce( - (p, v) => p.concat([rowIndexes.map(i => v[i])]), - (p, v) => null, () => [] - ).all().map(o => ({ + const [dimensionColumnIndex, seriesColumnIndex] = dimensionColumnIndexes; + const rowColumnIndexes = [dimensionColumnIndex].concat(metricColumnIndexes, extraColumnIndexes); + + const breakoutValues = []; + const breakoutRowsByValue = new Map; + + for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) { + const row = rows[rowIndex]; + const seriesValue = row[seriesColumnIndex]; + + let seriesRows = breakoutRowsByValue.get(seriesValue); + if (!seriesRows) { + breakoutRowsByValue.set(seriesValue, seriesRows = []); + breakoutValues.push(seriesValue); + } + + let newRow = rowColumnIndexes.map(columnIndex => row[columnIndex]); + // $FlowFixMe: _origin not typed + newRow._origin = { seriesIndex, rowIndex, row, cols }; + seriesRows.push(newRow); + } + + return breakoutValues.map((breakoutValue) => ({ card: { ...card, // if multiseries include the card title as well as the breakout value @@ -277,22 +291,23 @@ function transformSingleSeries(s, series) { // show series title if it's multiseries series.length > 1 && card.name, // always show grouping value - o.key + formatValue(breakoutValue, cols[seriesColumnIndex]) ].filter(n => n).join(": "), _transformed: true, - _breakoutValue: o.key, - _breakoutColumn: cols[seriesIndex] + _breakoutValue: breakoutValue, + _breakoutColumn: cols[seriesColumnIndex] }, data: { - rows: o.value, - cols: rowIndexes.map(i => cols[i]) + rows: breakoutRowsByValue.get(breakoutValue), + cols: rowColumnIndexes.map(i => cols[i]), + _rawCols: cols } })); } else { - const dimensionIndex = dimensionIndexes[0]; - return metricIndexes.map(metricIndex => { - const col = cols[metricIndex]; - const rowIndexes = [dimensionIndex].concat(metricIndex, extraIndexes); + const dimensionColumnIndex = dimensionColumnIndexes[0]; + return metricColumnIndexes.map(metricColumnIndex => { + const col = cols[metricColumnIndex]; + const rowColumnIndexes = [dimensionColumnIndex].concat(metricColumnIndex, extraColumnIndexes); return { card: { ...card, @@ -300,15 +315,19 @@ function transformSingleSeries(s, series) { // show series title if it's multiseries series.length > 1 && card.name, // show column name if there are multiple metrics - metricIndexes.length > 1 && getFriendlyName(col) + metricColumnIndexes.length > 1 && getFriendlyName(col) ].filter(n => n).join(": "), _transformed: true, }, data: { - rows: rows.map(row => - rowIndexes.map(i => row[i]) - ), - cols: rowIndexes.map(i => cols[i]) + rows: rows.map((row, rowIndex) => { + const newRow = rowColumnIndexes.map(i => row[i]); + // $FlowFixMe: _origin not typed + newRow._origin = { seriesIndex, rowIndex, row, cols }; + return newRow; + }), + cols: rowColumnIndexes.map(i => cols[i]), + _rawCols: cols } }; }); diff --git a/frontend/src/metabase/visualizations/PinMap.jsx b/frontend/src/metabase/visualizations/components/PinMap.jsx similarity index 96% rename from frontend/src/metabase/visualizations/PinMap.jsx rename to frontend/src/metabase/visualizations/components/PinMap.jsx index df30ad4e47b8d411ea9ff7555c6679dc791e7323..ff434eefc77991d348e5bb278e58b8357e11a03d 100644 --- a/frontend/src/metabase/visualizations/PinMap.jsx +++ b/frontend/src/metabase/visualizations/components/PinMap.jsx @@ -5,8 +5,8 @@ import React, { Component, PropTypes } from "react"; import { hasLatitudeAndLongitudeColumns } from "metabase/lib/schema_metadata"; import { LatitudeLongitudeError } from "metabase/visualizations/lib/errors"; -import LeafletMarkerPinMap from "./components/LeafletMarkerPinMap.jsx"; -import LeafletTilePinMap from "./components/LeafletTilePinMap.jsx"; +import LeafletMarkerPinMap from "./LeafletMarkerPinMap.jsx"; +import LeafletTilePinMap from "./LeafletTilePinMap.jsx"; import _ from "underscore"; import cx from "classnames"; diff --git a/frontend/src/metabase/visualizations/Table.css b/frontend/src/metabase/visualizations/components/Table.css similarity index 100% rename from frontend/src/metabase/visualizations/Table.css rename to frontend/src/metabase/visualizations/components/Table.css diff --git a/frontend/src/metabase/visualizations/TableInteractive.css b/frontend/src/metabase/visualizations/components/TableInteractive.css similarity index 100% rename from frontend/src/metabase/visualizations/TableInteractive.css rename to frontend/src/metabase/visualizations/components/TableInteractive.css diff --git a/frontend/src/metabase/visualizations/TableInteractive.jsx b/frontend/src/metabase/visualizations/components/TableInteractive.jsx similarity index 100% rename from frontend/src/metabase/visualizations/TableInteractive.jsx rename to frontend/src/metabase/visualizations/components/TableInteractive.jsx diff --git a/frontend/src/metabase/visualizations/TableSimple.jsx b/frontend/src/metabase/visualizations/components/TableSimple.jsx similarity index 100% rename from frontend/src/metabase/visualizations/TableSimple.jsx rename to frontend/src/metabase/visualizations/components/TableSimple.jsx diff --git a/frontend/src/metabase/visualizations/components/Visualization.jsx b/frontend/src/metabase/visualizations/components/Visualization.jsx index 72a6fc7e211fff3430ad451e80856af5990ddb16..1d7ed4f5cd18a2c683e09d78eff15f7a30913db5 100644 --- a/frontend/src/metabase/visualizations/components/Visualization.jsx +++ b/frontend/src/metabase/visualizations/components/Visualization.jsx @@ -11,7 +11,7 @@ import Tooltip from "metabase/components/Tooltip.jsx"; import { duration, formatNumber } from "metabase/lib/formatting"; import { getVisualizationTransformed } from "metabase/visualizations"; -import { getSettings } from "metabase/lib/visualization_settings"; +import { getSettings } from "metabase/visualizations/lib/settings"; import { isSameSeries } from "metabase/visualizations/lib/utils"; import Utils from "metabase/lib/utils"; @@ -150,8 +150,10 @@ export default class Visualization extends Component<*, Props, State> { transform(newProps) { this.setState({ - yAxisSplit: null, + hovered: null, + error: null, warnings: [], + yAxisSplit: null, ...getVisualizationTransformed(newProps.series) }); } @@ -257,6 +259,7 @@ export default class Visualization extends Component<*, Props, State> { series } actionButtons={extra} + description={settings["card.description"]} settings={settings} linkToCard={linkToCard} /> diff --git a/frontend/src/metabase/visualizations/index.js b/frontend/src/metabase/visualizations/index.js index d2241b44c2e6fd88152d80ba7591802466225492..e5547e0078a860d8fb88f5e23513b520cfa5b2e6 100644 --- a/frontend/src/metabase/visualizations/index.js +++ b/frontend/src/metabase/visualizations/index.js @@ -2,16 +2,17 @@ import { Component } from "react"; -import Scalar from "./Scalar.jsx"; -import Progress from "./Progress.jsx"; -import Table from "./Table.jsx"; -import LineChart from "./LineChart.jsx"; -import BarChart from "./BarChart.jsx"; -import PieChart from "./PieChart.jsx"; -import AreaChart from "./AreaChart.jsx"; -import MapViz from "./Map.jsx"; -import Funnel from "./Funnel.jsx"; -import ScatterPlot from "./ScatterPlot.jsx"; +import Scalar from "./visualizations/Scalar.jsx"; +import Progress from "./visualizations/Progress.jsx"; +import Table from "./visualizations/Table.jsx"; +import LineChart from "./visualizations/LineChart.jsx"; +import BarChart from "./visualizations/BarChart.jsx"; +import RowChart from "./visualizations/RowChart.jsx"; +import PieChart from "./visualizations/PieChart.jsx"; +import AreaChart from "./visualizations/AreaChart.jsx"; +import MapViz from "./visualizations/Map.jsx"; +import ScatterPlot from "./visualizations/ScatterPlot.jsx"; +import Funnel from "./visualizations/Funnel.jsx"; import _ from "underscore"; @@ -113,8 +114,9 @@ registerVisualization(Scalar); registerVisualization(Progress); registerVisualization(Table); registerVisualization(LineChart); -registerVisualization(BarChart); registerVisualization(AreaChart); +registerVisualization(BarChart); +registerVisualization(RowChart); registerVisualization(ScatterPlot); registerVisualization(PieChart); registerVisualization(MapViz); diff --git a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js index d4730443d6d87e1094f8a19015bc3e0f6ed1c106..2b267d0267447afe7576aad7a00e661b646b6c01 100644 --- a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js +++ b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js @@ -60,6 +60,11 @@ const Y_LABEL_PADDING = 22; const UNAGGREGATED_DATA_WARNING = (col) => `"${getFriendlyName(col)}" is an unaggregated field: if it has more than one value at a point on the x-axis, the values will be summed.` const NULL_DIMENSION_WARNING = "Data includes missing dimension values."; +type CrossfilterGroup = { + top: (n: number) => { key: any, value: any }, + all: () => { key: any, value: any }, +} + function adjustTicksIfNeeded(axis, axisSize: number, minPixelsPerTick: number) { const ticks = axis.ticks(); // d3.js is dumb and sometimes numTicks is a number like 10 and other times it is an Array like [10] @@ -81,10 +86,16 @@ function getDcjsChartType(cardType) { } } -function applyChartBoundary(chart, element) { - return chart - .width(getAvailableCanvasWidth(element)) - .height(getAvailableCanvasHeight(element)); +function initChart(chart, element) { + // set the bounds + chart.width(getAvailableCanvasWidth(element)); + chart.height(getAvailableCanvasHeight(element)); + // disable animations + chart.transitionDuration(0); + // if the chart supports 'brushing' (brush-based range filter), disable this since it intercepts mouse hovers which means we can't see tooltips + if (chart.brushOn) { + chart.brushOn(false); + } } function applyChartTimeseriesXAxis(chart, settings, series, xValues, xDomain, xInterval) { @@ -290,9 +301,16 @@ function applyChartTooltips(chart, series, isStacked, onHoverChange) { let data = []; if (Array.isArray(d.key)) { // scatter - data = d.key.map((value, index) => ( - { key: getFriendlyName(cols[index]), value: value, col: cols[index] } - )); + if (d.key._origin) { + data = d.key._origin.row.map((value, index) => { + const col = d.key._origin.cols[index]; + return { key: getFriendlyName(col), value: value, col }; + }); + } else { + data = d.key.map((value, index) => ( + { key: getFriendlyName(cols[index]), value: value, col: cols[index] } + )); + } } else if (d.data) { // line, area, bar if (!isSingleSeriesBar) { cols = series[seriesIndex].data.cols; @@ -695,6 +713,35 @@ function moment_fast_toString() { return this._i; } +function makeIndexMap(values: Array<Value>): Map<Value, number> { + let indexMap = new Map() + for (const [index, key] of values.entries()) { + indexMap.set(key, index); + } + return indexMap; +} + +// HACK: This ensures each group is sorted by the same order as xValues, +// otherwise we can end up with line charts with x-axis labels in the correct order +// but the points in the wrong order. There may be a more efficient way to do this. +function forceSortedGroup(group: CrossfilterGroup, indexMap: Map<Value, number>): void { + // $FlowFixMe + const sorted = group.top(Infinity).sort((a, b) => indexMap.get(a.key) - indexMap.get(b.key)); + for (let i = 0; i < sorted.length; i++) { + sorted[i].index = i; + } + group.all = () => sorted; +} + +function forceSortedGroupsOfGroups(groupsOfGroups: CrossfilterGroup[][], indexMap: Map<Value, number>): void { + for (const groups of groupsOfGroups) { + for (const group of groups) { + forceSortedGroup(group, indexMap) + } + } +} + + export default function lineAreaBar(element, { series, onHoverChange, onRender, chartType, isScalarSeries, settings, maxSeries }) { const colors = settings["graph.colors"]; @@ -719,16 +766,21 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, } let datas = series.map((s, index) => - s.data.rows.map(row => [ - // don't parse as timestamp if we're going to display as a quantitative scale, e.x. years and Unix timestamps - (isDimensionTimeseries && !isQuantitative) ? - HACK_parseTimestamp(row[0], s.data.cols[0].unit, warn) - : isDimensionNumeric ? - row[0] - : - String(row[0]) - , ...row.slice(1) - ]) + s.data.rows.map(row => { + let newRow = [ + // don't parse as timestamp if we're going to display as a quantitative scale, e.x. years and Unix timestamps + (isDimensionTimeseries && !isQuantitative) ? + HACK_parseTimestamp(row[0], s.data.cols[0].unit, warn) + : isDimensionNumeric ? + row[0] + : + String(row[0]) + , ...row.slice(1) + ] + // $FlowFixMe: _origin not typed + newRow._origin = row._origin; + return newRow; + }) ); // compute the x-values @@ -790,9 +842,9 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, let dataset = crossfilter(); datas.map(data => dataset.add(data)); - dimension = dataset.dimension(d => [d[0], d[1]]); + dimension = dataset.dimension(row => row); groups = datas.map(data => { - let dim = crossfilter(data).dimension(d => d); + let dim = crossfilter(data).dimension(row => row); return [ dim.group().reduceSum((d) => d[2] || 1) ] @@ -852,26 +904,13 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, yAxisSplit = [series.map((s,i) => i)]; } - // HACK: This ensures each group is sorted by the same order as xValues, - // otherwise we can end up with line charts with x-axis labels in the correct order - // but the points in the wrong order. There may be a more efficient way to do this. // Don't apply to linear or timeseries X-axis since the points are always plotted in order if (!isTimeseries && !isQuantitative) { - let sortMap = new Map() - for (const [index, key] of xValues.entries()) { - sortMap.set(key, index); - } - for (const group of groups) { - group.forEach(g => { - const sorted = g.top(Infinity).sort((a, b) => sortMap.get(a.key) - sortMap.get(b.key)); - g.all = () => sorted; - }); - } + forceSortedGroupsOfGroups(groups, makeIndexMap(xValues)); } let parent = dc.compositeChart(element); - applyChartBoundary(parent, element); - parent.transitionDuration(0); + initChart(parent, element); let charts = groups.map((group, index) => { let chart = dc[getDcjsChartType(chartType)](parent); @@ -963,10 +1002,10 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, } } - let chart = parent.compose(charts); + parent.compose(charts); if (groups.length > 1 && !isScalarSeries) { - chart.on("renderlet.grouped-bar", function (chart) { + parent.on("renderlet.grouped-bar", function (chart) { // HACK: dc.js doesn't support grouped bar charts so we need to manually resize/reposition them // https://github.com/dc-js/dc.js/issues/558 let barCharts = chart.selectAll(".sub rect:first-child")[0].map(node => node.parentNode.parentNode.parentNode); @@ -989,18 +1028,18 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, // HACK: compositeChart + ordinal X axis shenanigans if (chartType === "bar") { - chart._rangeBandPadding(BAR_PADDING_RATIO) // https://github.com/dc-js/dc.js/issues/678 + parent._rangeBandPadding(BAR_PADDING_RATIO) // https://github.com/dc-js/dc.js/issues/678 } else { - chart._rangeBandPadding(1) // https://github.com/dc-js/dc.js/issues/662 + parent._rangeBandPadding(1) // https://github.com/dc-js/dc.js/issues/662 } // x-axis settings if (isTimeseries) { - applyChartTimeseriesXAxis(chart, settings, series, xValues, xDomain, xInterval); + applyChartTimeseriesXAxis(parent, settings, series, xValues, xDomain, xInterval); } else if (isQuantitative) { - applyChartQuantitativeXAxis(chart, settings, series, xValues, xDomain, xInterval); + applyChartQuantitativeXAxis(parent, settings, series, xValues, xDomain, xInterval); } else { - applyChartOrdinalXAxis(chart, settings, series, xValues); + applyChartOrdinalXAxis(parent, settings, series, xValues); } // y-axis settings @@ -1009,14 +1048,14 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, extent: d3.extent([].concat(...indexes.map(index => yExtents[index]))) })); if (left && left.series.length > 0) { - applyChartYAxis(chart, settings, left.series, left.extent, "left"); + applyChartYAxis(parent, settings, left.series, left.extent, "left"); } if (right && right.series.length > 0) { - applyChartYAxis(chart, settings, right.series, right.extent, "right"); + applyChartYAxis(parent, settings, right.series, right.extent, "right"); } const isSplitAxis = (right && right.series.length) && (left && left.series.length > 0); - applyChartTooltips(chart, series, isStacked, (hovered) => { + applyChartTooltips(parent, series, isStacked, (hovered) => { if (onHoverChange) { // disable tooltips on lines if (hovered && hovered.element && hovered.element.classList.contains("line")) { @@ -1026,16 +1065,11 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, } }); - // if the chart supports 'brushing' (brush-based range filter), disable this since it intercepts mouse hovers which means we can't see tooltips - if (chart.brushOn) { - chart.brushOn(false); - } - // render - chart.render(); + parent.render(); // apply any on-rendering functions - lineAndBarOnRender(chart, settings, onGoalHover, isSplitAxis, isStacked); + lineAndBarOnRender(parent, settings, onGoalHover, isSplitAxis, isStacked); // only ordinal axis can display "null" values if (isOrdinal) { @@ -1047,5 +1081,123 @@ export default function lineAreaBar(element, { series, onHoverChange, onRender, warnings: Object.keys(warnings) }); - return chart; + return parent; +} + +export const lineRenderer = (element, props) => lineAreaBar(element, { ...props, chartType: "line" }); +export const areaRenderer = (element, props) => lineAreaBar(element, { ...props, chartType: "area" }); +export const barRenderer = (element, props) => lineAreaBar(element, { ...props, chartType: "bar" }); +export const scatterRenderer = (element, props) => lineAreaBar(element, { ...props, chartType: "scatter" }); + +export function rowRenderer( + element, + { settings, series, onHoverChange, height } +) { + const chart = dc.rowChart(element); + + const colors = settings["graph.colors"]; + + const dataset = crossfilter(series[0].data.rows); + const dimension = dataset.dimension(d => d[0]); + const group = dimension.group().reduceSum(d => d[1]); + const xDomain = d3.extent(series[0].data.rows, d => d[1]); + const yValues = series[0].data.rows.map(d => d[0]); + + forceSortedGroup(group, makeIndexMap(yValues)); + + initChart(chart, element); + + chart.on("renderlet.tooltips", chart => { + chart.selectAll(".row rect").on("mousemove", (d, i) => { + const { cols } = series[0].data; + onHoverChange && onHoverChange({ + // for single series bar charts, fade the series and highlght the hovered element with CSS + index: -1, + event: d3.event, + data: [ + { key: getFriendlyName(cols[0]), value: d.key, col: cols[0] }, + { key: getFriendlyName(cols[1]), value: d.value, col: cols[1] } + ] + }); + }).on("mouseleave", () => { + onHoverChange && onHoverChange(null); + }); + }); + + chart + .ordinalColors([ colors[0] ]) + .x(d3.scale.linear().domain(xDomain)) + .elasticX(true) + .dimension(dimension) + .group(group) + .ordering(d => d.index); + + let labelPadHorizontal = 5; + let labelPadVertical = 1; + let labelsOutside = false; + + chart.on("renderlet.bar-labels", chart => { + chart + .selectAll("g.row text") + .attr("text-anchor", labelsOutside ? "end" : "start") + .attr("x", labelsOutside ? -labelPadHorizontal : labelPadHorizontal) + .classed(labelsOutside ? "outside" : "inside", true); + }); + + if (settings["graph.y_axis.labels_enabled"]) { + chart.on("renderlet.axis-labels", chart => { + chart + .svg() + .append("text") + .attr("class", "x-axis-label") + .attr("text-anchor", "middle") + .attr("x", chart.width() / 2) + .attr("y", chart.height() - 10) + .text(settings["graph.y_axis.title_text"]); + }); + } + + // inital render + chart.render(); + + // bottom label height + let axisLabelHeight = 0; + if (settings["graph.y_axis.labels_enabled"]) { + axisLabelHeight = chart + .select(".x-axis-label") + .node() + .getBoundingClientRect().height; + chart.margins().bottom += axisLabelHeight; + } + + // cap number of rows to fit + let rects = chart.selectAll(".row rect")[0]; + let containerHeight = rects[rects.length - 1].getBoundingClientRect().bottom - + rects[0].getBoundingClientRect().top; + let maxTextHeight = Math.max( + ...chart.selectAll("g.row text")[0].map( + e => e.getBoundingClientRect().height + ) + ); + let rowHeight = maxTextHeight + chart.gap() + labelPadVertical * 2; + let cap = Math.max(1, Math.floor(containerHeight / rowHeight)); + chart.cap(cap); + + chart.render(); + + // check if labels overflow after rendering correct number of rows + let maxTextWidth = 0; + for (const elem of chart.selectAll("g.row")[0]) { + let rect = elem.querySelector("rect").getBoundingClientRect(); + let text = elem.querySelector("text").getBoundingClientRect(); + maxTextWidth = Math.max(maxTextWidth, text.width); + if (rect.width < text.width + labelPadHorizontal * 2) { + labelsOutside = true; + } + } + + if (labelsOutside) { + chart.margins().left += maxTextWidth; + chart.render(); + } } diff --git a/frontend/src/metabase/visualizations/lib/settings.js b/frontend/src/metabase/visualizations/lib/settings.js new file mode 100644 index 0000000000000000000000000000000000000000..8f6b54e33f0d4f484d375f255b05977acddcb63f --- /dev/null +++ b/frontend/src/metabase/visualizations/lib/settings.js @@ -0,0 +1,273 @@ +import { getVisualizationRaw } from "metabase/visualizations"; + +import { + getChartTypeFromData, + DIMENSION_DIMENSION_METRIC, + DIMENSION_METRIC, + DIMENSION_METRIC_METRIC, + getColumnCardinality, + getFriendlyName +} from "./utils"; + +import { isDate, isMetric, isDimension } from "metabase/lib/schema_metadata"; + +import ChartSettingInput from "metabase/visualizations/components/settings/ChartSettingInput.jsx"; +import ChartSettingInputNumeric from "metabase/visualizations/components/settings/ChartSettingInputNumeric.jsx"; +import ChartSettingRadio from "metabase/visualizations/components/settings/ChartSettingRadio.jsx"; +import ChartSettingSelect from "metabase/visualizations/components/settings/ChartSettingSelect.jsx"; +import ChartSettingToggle from "metabase/visualizations/components/settings/ChartSettingToggle.jsx"; +import ChartSettingFieldPicker from "metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx"; +import ChartSettingFieldsPicker from "metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx"; +import ChartSettingColorPicker from "metabase/visualizations/components/settings/ChartSettingColorPicker.jsx"; +import ChartSettingColorsPicker from "metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx"; + +const WIDGETS = { + input: ChartSettingInput, + number: ChartSettingInputNumeric, + radio: ChartSettingRadio, + select: ChartSettingSelect, + toggle: ChartSettingToggle, + field: ChartSettingFieldPicker, + fields: ChartSettingFieldsPicker, + color: ChartSettingColorPicker, + colors: ChartSettingColorsPicker, +} + +export function columnsAreValid(colNames, data, filter = () => true) { + if (typeof colNames === "string") { + colNames = [colNames] + } + if (!data || !Array.isArray(colNames)) { + return false; + } + const colsByName = {}; + for (const col of data.cols) { + colsByName[col.name] = col; + } + return colNames.reduce((acc, name) => + acc && (name == undefined || (colsByName[name] && filter(colsByName[name]))) + , true); +} + +export function getDefaultColumns(series) { + if (series[0].card.display === "scatter") { + return getDefaultScatterColumns(series); + } else { + return getDefaultLineAreaBarColumns(series); + } +} + +function getDefaultScatterColumns([{ data: { cols, rows } }]) { + let dimensions = cols.filter(isDimension); + let metrics = cols.filter(isMetric); + if (dimensions.length === 2 && metrics.length < 2) { + return { + dimensions: [dimensions[0].name], + metrics: [dimensions[1].name], + bubble: metrics.length === 1 ? metrics[0].name : null + } + } else { + return { + dimensions: [null], + metrics: [null], + bubble: null + }; + } +} + +function getDefaultLineAreaBarColumns([{ data: { cols, rows } }]) { + let type = getChartTypeFromData(cols, rows, false); + switch (type) { + case DIMENSION_DIMENSION_METRIC: + let dimensions = [cols[0], cols[1]]; + if (isDate(dimensions[1]) && !isDate(dimensions[0])) { + // if the series dimension is a date but the axis dimension is not then swap them + dimensions.reverse(); + } else if (getColumnCardinality(cols, rows, 1) > getColumnCardinality(cols, rows, 0)) { + // if the series dimension is higher cardinality than the axis dimension then swap them + dimensions.reverse(); + } + return { + dimensions: dimensions.map(col => col.name), + metrics: [cols[2].name] + }; + case DIMENSION_METRIC: + return { + dimensions: [cols[0].name], + metrics: [cols[1].name] + }; + case DIMENSION_METRIC_METRIC: + return { + dimensions: [cols[0].name], + metrics: cols.slice(1).map(col => col.name) + }; + default: + return { + dimensions: [null], + metrics: [null] + }; + } +} + +export function getDefaultDimensionAndMetric([{ data: { cols, rows } }]) { + const type = getChartTypeFromData(cols, rows, false); + if (type === DIMENSION_METRIC) { + return { + dimension: cols[0].name, + metric: cols[1].name + }; + } else { + return { + dimension: null, + metric: null + }; + } +} + +export function getOptionFromColumn(col) { + return { + name: getFriendlyName(col), + value: col.name + }; +} + +export function metricSetting(id) { + return fieldSetting(id, isMetric, (series) => getDefaultDimensionAndMetric(series).metric) +} + +export function dimensionSetting(id) { + return fieldSetting(id, isDimension, (series) => getDefaultDimensionAndMetric(series).dimension) +} + +export function fieldSetting(id, filter, getDefault) { + return { + widget: "select", + isValid: ([{ card, data }], vizSettings) => + columnsAreValid(card.visualization_settings[id], data, filter), + getDefault: getDefault, + getProps: ([{ card, data: { cols }}]) => ({ + options: cols.filter(filter).map(getOptionFromColumn) + }), + }; +} + +const COMMON_SETTINGS = { + "card.title": { + title: "Title", + widget: "input", + getDefault: (series) => series.length === 1 ? series[0].card.name : null, + dashboard: true, + useRawSeries: true + }, + "card.description": { + title: "Description", + widget: "input", + getDefault: (series) => series.length === 1 ? series[0].card.description : null, + dashboard: true, + useRawSeries: true + }, +}; + +function getSetting(settingDefs, id, vizSettings, series) { + if (id in vizSettings) { + return; + } + + const settingDef = settingDefs[id]; + const [{ card }] = series; + const visualization_settings = card.visualization_settings || {}; + + for (let dependentId of settingDef.readDependencies || []) { + getSetting(settingDefs, dependentId, vizSettings, series); + } + + if (settingDef.useRawSeries && series._raw) { + series = series._raw; + } + + try { + if (settingDef.getValue) { + return vizSettings[id] = settingDef.getValue(series, vizSettings); + } + + if (visualization_settings[id] !== undefined) { + if (!settingDef.isValid || settingDef.isValid(series, vizSettings)) { + return vizSettings[id] = visualization_settings[id]; + } + } + + if (settingDef.getDefault) { + return vizSettings[id] = settingDef.getDefault(series, vizSettings); + } + + if ("default" in settingDef) { + return vizSettings[id] = settingDef.default; + } + } catch (e) { + console.error("Error getting setting", id, e); + } + return vizSettings[id] = undefined; +} + + +function getSettingDefintionsForSeries(series) { + const { CardVisualization } = getVisualizationRaw(series); + const definitions = { + ...COMMON_SETTINGS, + ...(CardVisualization.settings || {}) + } + for (const id in definitions) { + definitions[id].id = id + } + return definitions; +} + +export function getSettings(series) { + let vizSettings = {}; + let settingsDefs = getSettingDefintionsForSeries(series); + for (let id in settingsDefs) { + getSetting(settingsDefs, id, vizSettings, series); + } + return vizSettings; +} + +function getSettingWidget(settingDef, vizSettings, series, onChangeSettings) { + const id = settingDef.id; + const value = vizSettings[id]; + const onChange = (value) => { + const newSettings = { [id]: value }; + for (const id of (settingDef.writeDependencies || [])) { + newSettings[id] = vizSettings[id]; + } + onChangeSettings(newSettings) + } + if (settingDef.useRawSeries && series._raw) { + series = series._raw; + } + return { + ...settingDef, + id: id, + value: value, + title: settingDef.getTitle ? settingDef.getTitle(series, vizSettings) : settingDef.title, + hidden: settingDef.getHidden ? settingDef.getHidden(series, vizSettings) : false, + disabled: settingDef.getDisabled ? settingDef.getDisabled(series, vizSettings) : false, + props: { + ...(settingDef.props ? settingDef.props : {}), + ...(settingDef.getProps ? settingDef.getProps(series, vizSettings, onChange) : {}) + }, + widget: typeof settingDef.widget === "string" ? + WIDGETS[settingDef.widget] : + settingDef.widget, + onChange + }; +} + +export function getSettingsWidgets(series, onChangeSettings, isDashboard = false) { + const vizSettings = getSettings(series); + return Object.values(getSettingDefintionsForSeries(series)).map(settingDef => + getSettingWidget(settingDef, vizSettings, series, onChangeSettings) + ).filter(widget => + widget.widget && !widget.hidden && + (widget.dashboard === undefined || widget.dashboard === isDashboard) + ); +} diff --git a/frontend/src/metabase/visualizations/lib/settings/graph.js b/frontend/src/metabase/visualizations/lib/settings/graph.js new file mode 100644 index 0000000000000000000000000000000000000000..46dc61c60f59666a63d4bfea914afc8b7d395f74 --- /dev/null +++ b/frontend/src/metabase/visualizations/lib/settings/graph.js @@ -0,0 +1,325 @@ +import { capitalize } from "metabase/lib/formatting"; +import { isDimension, isMetric, isNumeric, isAny } from "metabase/lib/schema_metadata"; + +import { columnsAreValid, getDefaultColumns, getOptionFromColumn } from "metabase/visualizations/lib/settings"; +import { getCardColors, getFriendlyName } from "metabase/visualizations/lib/utils"; +import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric"; +import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries"; + +import _ from "underscore"; + +function getSeriesTitles(series, vizSettings) { + return series.map(s => s.card.name); +} + +export const GRAPH_DATA_SETTINGS = { + "graph._dimension_filter": { + getDefault: ([{ card }]) => card.display === "scatter" ? isAny : isDimension, + useRawSeries: true + }, + "graph._metric_filter": { + getDefault: ([{ card }]) => card.display === "scatter" ? isNumeric : isMetric, + useRawSeries: true + }, + "graph.dimensions": { + section: "Data", + title: "X-axis", + widget: "fields", + isValid: ([{ card, data }], vizSettings) => + columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) && + columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]), + getDefault: (series, vizSettings) => + getDefaultColumns(series).dimensions, + getProps: ([{ card, data }], vizSettings) => { + const value = vizSettings["graph.dimensions"]; + const options = data.cols.filter(vizSettings["graph._dimension_filter"]).map(getOptionFromColumn); + return { + options, + addAnother: (options.length > value.length && value.length < 2 && vizSettings["graph.metrics"].length < 2) ? + "Add a series breakout..." : null + }; + }, + readDependencies: ["graph._dimension_filter", "graph._metric_filter"], + writeDependencies: ["graph.metrics"], + dashboard: false, + useRawSeries: true + }, + "graph.metrics": { + section: "Data", + title: "Y-axis", + widget: "fields", + isValid: ([{ card, data }], vizSettings) => + columnsAreValid(card.visualization_settings["graph.dimensions"], data, vizSettings["graph._dimension_filter"]) && + columnsAreValid(card.visualization_settings["graph.metrics"], data, vizSettings["graph._metric_filter"]), + getDefault: (series, vizSettings) => + getDefaultColumns(series).metrics, + getProps: ([{ card, data }], vizSettings) => { + const value = vizSettings["graph.dimensions"]; + const options = data.cols.filter(vizSettings["graph._metric_filter"]).map(getOptionFromColumn); + return { + options, + addAnother: options.length > value.length && vizSettings["graph.dimensions"].length < 2 ? + "Add another series..." : null + }; + }, + readDependencies: ["graph._dimension_filter", "graph._metric_filter"], + writeDependencies: ["graph.dimensions"], + dashboard: false, + useRawSeries: true + }, +}; + +export const GRAPH_BUBBLE_SETTINGS = { + "scatter.bubble": { + section: "Data", + title: "Bubble size", + widget: "field", + isValid: ([{ card, data }], vizSettings) => + columnsAreValid([card.visualization_settings["scatter.bubble"]], data, isNumeric), + getDefault: (series) => + getDefaultColumns(series).bubble, + getProps: ([{ card, data }], vizSettings, onChange) => { + const options = data.cols.filter(isNumeric).map(getOptionFromColumn); + return { + options, + onRemove: vizSettings["scatter.bubble"] ? () => onChange(null) : null + }; + }, + writeDependencies: ["graph.dimensions"], + dashboard: false, + useRawSeries: true + }, +} + +export const LINE_SETTINGS = { + "line.interpolate": { + section: "Display", + title: "Style", + widget: "select", + props: { + options: [ + { name: "Line", value: "linear" }, + { name: "Curve", value: "cardinal" }, + { name: "Step", value: "step-after" }, + ] + }, + getDefault: () => "linear" + }, + "line.marker_enabled": { + section: "Display", + title: "Show point markers on lines", + widget: "toggle" + }, +} + +export const STACKABLE_SETTINGS = { + "stackable.stack_type": { + section: "Display", + title: "Stacking", + widget: "radio", + getProps: (series, vizSettings) => ({ + options: [ + { name: "Don't stack", value: null }, + { name: "Stack", value: "stacked" }, + { name: "Stack - 100%", value: "normalized" } + ] + }), + getDefault: ([{ card, data }], vizSettings) => + // legacy setting and default for D-M-M+ charts + vizSettings["stackable.stacked"] || (card.display === "area" && vizSettings["graph.metrics"].length > 1) ? + "stacked" : null, + getHidden: (series) => + series.length < 2, + readDependencies: ["graph.metrics"] + } +} + +export const GRAPH_GOAL_SETTINGS = { + "graph.show_goal": { + section: "Display", + title: "Show goal", + widget: "toggle", + default: false + }, + "graph.goal_value": { + section: "Display", + title: "Goal value", + widget: "number", + default: 0, + getHidden: (series, vizSettings) => vizSettings["graph.show_goal"] !== true, + readDependencies: ["graph.show_goal"] + }, +} + +export const LINE_SETTINGS_2 = { + "line.missing": { + section: "Display", + title: "Replace missing values with", + widget: "select", + default: "interpolate", + getProps: (series, vizSettings) => ({ + options: [ + { name: "Zero", value: "zero" }, + { name: "Nothing", value: "none" }, + { name: "Linear Interpolated", value: "interpolate" }, + ] + }) + }, +} + +export const GRAPH_COLORS_SETTINGS = { + "graph.colors": { + section: "Display", + getTitle: ([{ card: { display } }]) => + capitalize(display === "scatter" ? "bubble" : display) + " colors", + widget: "colors", + readDependencies: ["graph.dimensions", "graph.metrics"], + getDefault: ([{ card, data }], vizSettings) => { + return getCardColors(card); + }, + getProps: (series, vizSettings) => { + return { seriesTitles: getSeriesTitles(series, vizSettings) }; + } + } +} + +export const GRAPH_AXIS_SETTINGS = { + "graph.x_axis._is_timeseries": { + readDependencies: ["graph.dimensions"], + getDefault: ([{ data }], vizSettings) => + dimensionIsTimeseries(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0])) + }, + "graph.x_axis._is_numeric": { + readDependencies: ["graph.dimensions"], + getDefault: ([{ data }], vizSettings) => + dimensionIsNumeric(data, _.findIndex(data.cols, (c) => c.name === vizSettings["graph.dimensions"].filter(d => d)[0])) + }, + "graph.x_axis.scale": { + section: "Axes", + title: "X-axis scale", + widget: "select", + default: "ordinal", + readDependencies: ["graph.x_axis._is_timeseries", "graph.x_axis._is_numeric"], + getDefault: (series, vizSettings) => + vizSettings["graph.x_axis._is_timeseries"] ? "timeseries" : + vizSettings["graph.x_axis._is_numeric"] ? "linear" : + "ordinal", + getProps: (series, vizSettings) => { + const options = []; + if (vizSettings["graph.x_axis._is_timeseries"]) { + options.push({ name: "Timeseries", value: "timeseries" }); + } + if (vizSettings["graph.x_axis._is_numeric"]) { + options.push({ name: "Linear", value: "linear" }); + options.push({ name: "Power", value: "pow" }); + options.push({ name: "Log", value: "log" }); + } + options.push({ name: "Ordinal", value: "ordinal" }); + return { options }; + } + }, + "graph.y_axis.scale": { + section: "Axes", + title: "Y-axis scale", + widget: "select", + default: "linear", + getProps: (series, vizSettings) => ({ + options: [ + { name: "Linear", value: "linear" }, + { name: "Power", value: "pow" }, + { name: "Log", value: "log" } + ] + }) + }, + "graph.x_axis.axis_enabled": { + section: "Axes", + title: "Show x-axis line and marks", + widget: "toggle", + default: true + }, + "graph.y_axis.axis_enabled": { + section: "Axes", + title: "Show y-axis line and marks", + widget: "toggle", + default: true + }, + "graph.y_axis.auto_range": { + section: "Axes", + title: "Auto y-axis range", + widget: "toggle", + default: true + }, + "graph.y_axis.min": { + section: "Axes", + title: "Min", + widget: "number", + default: 0, + getHidden: (series, vizSettings) => vizSettings["graph.y_axis.auto_range"] !== false + }, + "graph.y_axis.max": { + section: "Axes", + title: "Max", + widget: "number", + default: 100, + getHidden: (series, vizSettings) => vizSettings["graph.y_axis.auto_range"] !== false + }, +/* + "graph.y_axis_right.auto_range": { + section: "Axes", + title: "Auto right-hand y-axis range", + widget: "toggle", + default: true + }, + "graph.y_axis_right.min": { + section: "Axes", + title: "Min", + widget: "number", + default: 0, + getHidden: (series, vizSettings) => vizSettings["graph.y_axis_right.auto_range"] !== false + }, + "graph.y_axis_right.max": { + section: "Axes", + title: "Max", + widget: "number", + default: 100, + getHidden: (series, vizSettings) => vizSettings["graph.y_axis_right.auto_range"] !== false + }, +*/ + "graph.y_axis.auto_split": { + section: "Axes", + title: "Use a split y-axis when necessary", + widget: "toggle", + default: true, + getHidden: (series) => series.length < 2 + }, + "graph.x_axis.labels_enabled": { + section: "Labels", + title: "Show label on x-axis", + widget: "toggle", + default: true + }, + "graph.x_axis.title_text": { + section: "Labels", + title: "X-axis label", + widget: "input", + getHidden: (series, vizSettings) => + vizSettings["graph.x_axis.labels_enabled"] === false, + getDefault: (series, vizSettings) => + series.length === 1 ? getFriendlyName(series[0].data.cols[0]) : null + }, + "graph.y_axis.labels_enabled": { + section: "Labels", + title: "Show label on y-axis", + widget: "toggle", + default: true + }, + "graph.y_axis.title_text": { + section: "Labels", + title: "Y-axis label", + widget: "input", + getHidden: (series, vizSettings) => + vizSettings["graph.y_axis.labels_enabled"] === false, + getDefault: (series, vizSettings) => + series.length === 1 ? getFriendlyName(series[0].data.cols[1]) : null + }, +} diff --git a/frontend/src/metabase/visualizations/visualizations/AreaChart.jsx b/frontend/src/metabase/visualizations/visualizations/AreaChart.jsx new file mode 100644 index 0000000000000000000000000000000000000000..4732041c65bd3c9ba989cca1b9192bce244fe030 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/AreaChart.jsx @@ -0,0 +1,35 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import LineAreaBarChart from "../components/LineAreaBarChart.jsx"; +import { areaRenderer } from "../lib/LineAreaBarRenderer"; + +import { + GRAPH_DATA_SETTINGS, + LINE_SETTINGS, + STACKABLE_SETTINGS, + GRAPH_GOAL_SETTINGS, + LINE_SETTINGS_2, + GRAPH_COLORS_SETTINGS, + GRAPH_AXIS_SETTINGS +} from "../lib/settings/graph"; + +export default class AreaChart extends LineAreaBarChart { + static uiName = "Area"; + static identifier = "area"; + static iconName = "area"; + static noun = "area chart"; + + static settings = { + ...GRAPH_DATA_SETTINGS, + ...LINE_SETTINGS, + ...STACKABLE_SETTINGS, + ...GRAPH_GOAL_SETTINGS, + ...LINE_SETTINGS_2, + ...GRAPH_COLORS_SETTINGS, + ...GRAPH_AXIS_SETTINGS + }; + + static renderer = areaRenderer; +} diff --git a/frontend/src/metabase/visualizations/visualizations/BarChart.jsx b/frontend/src/metabase/visualizations/visualizations/BarChart.jsx new file mode 100644 index 0000000000000000000000000000000000000000..3df88ea438cfc3d5a3e159916e1dfa8347a08637 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/BarChart.jsx @@ -0,0 +1,31 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import LineAreaBarChart from "../components/LineAreaBarChart.jsx"; +import { barRenderer } from "../lib/LineAreaBarRenderer"; + +import { + GRAPH_DATA_SETTINGS, + STACKABLE_SETTINGS, + GRAPH_GOAL_SETTINGS, + GRAPH_COLORS_SETTINGS, + GRAPH_AXIS_SETTINGS +} from "../lib/settings/graph"; + +export default class BarChart extends LineAreaBarChart { + static uiName = "Bar"; + static identifier = "bar"; + static iconName = "bar"; + static noun = "bar chart"; + + static settings = { + ...GRAPH_DATA_SETTINGS, + ...STACKABLE_SETTINGS, + ...GRAPH_GOAL_SETTINGS, + ...GRAPH_COLORS_SETTINGS, + ...GRAPH_AXIS_SETTINGS + }; + + static renderer = barRenderer; +} diff --git a/frontend/src/metabase/visualizations/Funnel.jsx b/frontend/src/metabase/visualizations/visualizations/Funnel.jsx similarity index 69% rename from frontend/src/metabase/visualizations/Funnel.jsx rename to frontend/src/metabase/visualizations/visualizations/Funnel.jsx index b638f2a9c572e626e5bcc7ba894148ada3169fbe..8ed850eb82a488cb8c0362944fb6ea037f8b63a8 100644 --- a/frontend/src/metabase/visualizations/Funnel.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Funnel.jsx @@ -5,16 +5,17 @@ import React, { Component, PropTypes } from "react"; import { MinRowsError, ChartSettingsError } from "metabase/visualizations/lib/errors"; import { formatValue } from "metabase/lib/formatting"; -import { getSettings } from "metabase/lib/visualization_settings"; -import FunnelNormal from "./components/FunnelNormal"; -import FunnelBar from "./components/FunnelBar"; -import LegendHeader from "./components/LegendHeader"; +import { getSettings, metricSetting, dimensionSetting } from "metabase/visualizations/lib/settings"; + +import FunnelNormal from "../components/FunnelNormal"; +import FunnelBar from "../components/FunnelBar"; +import LegendHeader from "../components/LegendHeader"; import _ from "underscore"; import cx from "classnames"; -import type { VisualizationProps } from "."; +import type { VisualizationProps } from ".."; export default class Funnel extends Component<*, VisualizationProps, *> { static uiName = "Funnel"; @@ -41,6 +42,34 @@ export default class Funnel extends Component<*, VisualizationProps, *> { } } + static settings = { + "funnel.dimension": { + section: "Data", + title: "Step", + ...dimensionSetting("pie.dimension"), + dashboard: false, + useRawSeries: true, + }, + "funnel.metric": { + section: "Data", + title: "Measure", + ...metricSetting("pie.metric"), + dashboard: false, + useRawSeries: true, + }, + "funnel.type": { + title: "Funnel type", + section: "Display", + widget: "select", + props: { + options: [{ name: "Funnel", value: "funnel"}, { name: "Bar chart", value: "bar"}] + }, + // legacy "bar" funnel was only previously available via multiseries + getDefault: (series) => series.length > 1 ? "bar" : "funnel", + useRawSeries: true + }, + } + static transformSeries(series) { let [{ card, data: { rows, cols }}] = series; diff --git a/frontend/src/metabase/visualizations/visualizations/LineChart.jsx b/frontend/src/metabase/visualizations/visualizations/LineChart.jsx new file mode 100644 index 0000000000000000000000000000000000000000..922dcb00dd9ef48b723075b5b614436250f5c8c9 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/LineChart.jsx @@ -0,0 +1,33 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import LineAreaBarChart from "../components/LineAreaBarChart.jsx"; +import { lineRenderer } from "../lib/LineAreaBarRenderer"; + +import { + GRAPH_DATA_SETTINGS, + LINE_SETTINGS, + GRAPH_GOAL_SETTINGS, + LINE_SETTINGS_2, + GRAPH_COLORS_SETTINGS, + GRAPH_AXIS_SETTINGS +} from "../lib/settings/graph"; + +export default class LineChart extends LineAreaBarChart { + static uiName = "Line"; + static identifier = "line"; + static iconName = "line"; + static noun = "line chart"; + + static settings = { + ...GRAPH_DATA_SETTINGS, + ...LINE_SETTINGS, + ...GRAPH_GOAL_SETTINGS, + ...LINE_SETTINGS_2, + ...GRAPH_COLORS_SETTINGS, + ...GRAPH_AXIS_SETTINGS + }; + + static renderer = lineRenderer; +} diff --git a/frontend/src/metabase/visualizations/visualizations/Map.jsx b/frontend/src/metabase/visualizations/visualizations/Map.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a1a32dee10936b6354b7c1d2ee908f4a2d143210 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Map.jsx @@ -0,0 +1,136 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import ChoroplethMap from "../components/ChoroplethMap.jsx"; +import PinMap from "../components/PinMap.jsx"; + +import { ChartSettingsError } from "metabase/visualizations/lib/errors"; +import { isNumeric, isLatitude, isLongitude, hasLatitudeAndLongitudeColumns } from "metabase/lib/schema_metadata"; +import { metricSetting, dimensionSetting, fieldSetting } from "metabase/visualizations/lib/settings"; +import MetabaseSettings from "metabase/lib/settings"; + +import type { VisualizationProps } from "metabase/visualizations"; + +import _ from "underscore"; + +export default class Map extends Component<*, VisualizationProps, *> { + static uiName = "Map"; + static identifier = "map"; + static iconName = "pinmap"; + + static aliases = ["state", "country", "pin_map"]; + + static minSize = { width: 4, height: 4 }; + + static isSensible(cols, rows) { + return true; + } + + static settings = { + "map.type": { + title: "Map type", + widget: "select", + props: { + options: [ + { name: "Pin map", value: "pin" }, + { name: "Region map", value: "region" } + ] + }, + getDefault: ([{ card, data: { cols } }]) => { + switch (card.display) { + case "state": + case "country": + return "region"; + case "pin_map": + return "pin"; + default: + if (hasLatitudeAndLongitudeColumns(cols)) { + return "pin"; + } else { + return "region"; + } + } + } + }, + "map.latitude_column": { + title: "Latitude field", + ...fieldSetting("map.latitude_column", isNumeric, + ([{ data: { cols }}]) => (_.find(cols, isLatitude) || {}).name), + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" + }, + "map.longitude_column": { + title: "Longitude field", + ...fieldSetting("map.longitude_column", isNumeric, + ([{ data: { cols }}]) => (_.find(cols, isLongitude) || {}).name), + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" + }, + "map.region": { + title: "Region map", + widget: "select", + getDefault: ([{ card, data: { cols }}]) => { + switch (card.display) { + case "country": + return "world_countries"; + case "state": + default: + return "us_states"; + } + }, + getProps: () => ({ + // $FlowFixMe: + options: Object.entries(MetabaseSettings.get("custom_geojson", {})).map(([key, value]) => ({ name: value.name, value: key })) + }), + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" + }, + "map.metric": { + title: "Metric field", + ...metricSetting("map.metric"), + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" + }, + "map.dimension": { + title: "Region field", + widget: "select", + ...dimensionSetting("map.dimension"), + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "region" + }, + "map.zoom": { + }, + "map.center_latitude": { + }, + "map.center_longitude": { + }, + "map.pin_type": { + title: "Pin type", + // Don't expose this in the UI for now + // widget: ChartSettingSelect, + props: { + options: [{ name: "Tiles", value: "tiles" }, { name: "Markers", value: "markers" }] + }, + getDefault: (series) => series[0].data.rows.length >= 1000 ? "tiles" : "markers", + getHidden: (series, vizSettings) => vizSettings["map.type"] !== "pin" + } + } + + static checkRenderable([{ data: { cols, rows} }], settings) { + if (settings["map.type"] === "pin") { + if (!settings["map.longitude_column"] || !settings["map.latitude_column"]) { + throw new ChartSettingsError("Please select longitude and latitude columns in the chart settings.", "Data"); + } + } else if (settings["map.type"] === "region"){ + if (!settings["map.dimension"] || !settings["map.metric"]) { + throw new ChartSettingsError("Please select region and metric columns in the chart settings.", "Data"); + } + } + } + + render() { + const { settings } = this.props; + const type = settings["map.type"]; + if (type === "pin") { + return <PinMap {...this.props} /> + } else if (type === "region") { + return <ChoroplethMap {...this.props} /> + } + } +} diff --git a/frontend/src/metabase/visualizations/PieChart.css b/frontend/src/metabase/visualizations/visualizations/PieChart.css similarity index 100% rename from frontend/src/metabase/visualizations/PieChart.css rename to frontend/src/metabase/visualizations/visualizations/PieChart.css diff --git a/frontend/src/metabase/visualizations/PieChart.jsx b/frontend/src/metabase/visualizations/visualizations/PieChart.jsx similarity index 82% rename from frontend/src/metabase/visualizations/PieChart.jsx rename to frontend/src/metabase/visualizations/visualizations/PieChart.jsx index 88b3ec6ba34561bc5fbfee585b9d3849cf7deffc..0efb2e80edf190ac1513a3a5e70d0b567aff3141 100644 --- a/frontend/src/metabase/visualizations/PieChart.jsx +++ b/frontend/src/metabase/visualizations/visualizations/PieChart.jsx @@ -4,11 +4,12 @@ import React, { Component, PropTypes } from "react"; import ReactDOM from "react-dom"; import styles from "./PieChart.css"; -import ChartTooltip from "./components/ChartTooltip.jsx"; -import ChartWithLegend from "./components/ChartWithLegend.jsx"; +import ChartTooltip from "../components/ChartTooltip.jsx"; +import ChartWithLegend from "../components/ChartWithLegend.jsx"; import { ChartSettingsError } from "metabase/visualizations/lib/errors"; import { getFriendlyName } from "metabase/visualizations/lib/utils"; +import { metricSetting, dimensionSetting } from "metabase/visualizations/lib/settings"; import { formatValue } from "metabase/lib/formatting"; @@ -49,6 +50,35 @@ export default class PieChart extends Component<*, Props, *> { } } + static settings = { + "pie.dimension": { + section: "Data", + title: "Dimension", + ...dimensionSetting("pie.dimension") + }, + "pie.metric": { + section: "Data", + title: "Measure", + ...metricSetting("pie.metric") + }, + "pie.show_legend": { + section: "Display", + title: "Show legend", + widget: "toggle" + }, + "pie.show_legend_perecent": { + section: "Display", + title: "Show percentages in legend", + widget: "toggle", + default: true + }, + "pie.slice_threshold": { + section: "Display", + title: "Minimum slice percentage", + widget: "number" + }, + } + componentDidUpdate() { let groupElement = ReactDOM.findDOMNode(this.refs.group); let detailElement = ReactDOM.findDOMNode(this.refs.detail); @@ -89,16 +119,20 @@ export default class PieChart extends Component<*, Props, *> { .partition((d) => d.percentage > sliceThreshold) .value(); - let otherTotal = others.reduce((acc, o) => acc + o.value, 0); let otherSlice; - if (otherTotal > 0) { - otherSlice = { - key: "Other", - value: otherTotal, - percentage: otherTotal / total, - color: "gray" - }; - slices.push(otherSlice); + if (others.length > 1) { + let otherTotal = others.reduce((acc, o) => acc + o.value, 0); + if (otherTotal > 0) { + otherSlice = { + key: "Other", + value: otherTotal, + percentage: otherTotal / total, + color: "gray" + }; + slices.push(otherSlice); + } + } else { + slices.push(...others); } // increase "other" slice so it's barely visible diff --git a/frontend/src/metabase/visualizations/Progress.jsx b/frontend/src/metabase/visualizations/visualizations/Progress.jsx similarity index 94% rename from frontend/src/metabase/visualizations/Progress.jsx rename to frontend/src/metabase/visualizations/visualizations/Progress.jsx index 186421ee7e1f4d7e0d40d8869c3822124cb753ab..15ae1c1c09029503b613ec9ebec85fa16c3930fc 100644 --- a/frontend/src/metabase/visualizations/Progress.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Progress.jsx @@ -7,6 +7,7 @@ import { formatValue } from "metabase/lib/formatting"; import { isNumeric } from "metabase/lib/schema_metadata"; import Icon from "metabase/components/Icon.jsx"; import IconBorder from "metabase/components/IconBorder.jsx"; +import { normal } from "metabase/lib/colors"; import Color from "color"; import cx from "classnames"; @@ -33,6 +34,21 @@ export default class Progress extends Component<*, VisualizationProps, *> { } } + static settings = { + "progress.goal": { + section: "Display", + title: "Goal", + widget: "number", + default: 0 + }, + "progress.color": { + section: "Display", + title: "Color", + widget: "color", + default: normal.green + }, + } + componentDidMount() { this.componentDidUpdate(); } diff --git a/frontend/src/metabase/visualizations/visualizations/RowChart.jsx b/frontend/src/metabase/visualizations/visualizations/RowChart.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c35274410df90e46718d856692f82e903fabd0e0 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/RowChart.jsx @@ -0,0 +1,37 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import LineAreaBarChart from "../components/LineAreaBarChart.jsx"; +import { rowRenderer } from "../lib/LineAreaBarRenderer"; + +import { + GRAPH_DATA_SETTINGS, + GRAPH_COLORS_SETTINGS +} from "metabase/visualizations/lib/settings/graph"; + +export default class RowChart extends LineAreaBarChart { + static uiName = "Row Chart"; + static identifier = "row"; + static iconName = "horizontal_bar"; + static noun = "row chart"; + + static supportsSeries = false; + + static renderer = rowRenderer; + + static settings = { + ...GRAPH_DATA_SETTINGS, + ...GRAPH_COLORS_SETTINGS + } +} + +// rename these settings +RowChart.settings["graph.metrics"] = { + ...RowChart.settings["graph.metrics"], + title: "X-axis" +} +RowChart.settings["graph.dimensions"] = { + ...RowChart.settings["graph.dimensions"], + title: "Y-axis" +} diff --git a/frontend/src/metabase/visualizations/Scalar.css b/frontend/src/metabase/visualizations/visualizations/Scalar.css similarity index 100% rename from frontend/src/metabase/visualizations/Scalar.css rename to frontend/src/metabase/visualizations/visualizations/Scalar.css diff --git a/frontend/src/metabase/visualizations/Scalar.jsx b/frontend/src/metabase/visualizations/visualizations/Scalar.jsx similarity index 73% rename from frontend/src/metabase/visualizations/Scalar.jsx rename to frontend/src/metabase/visualizations/visualizations/Scalar.jsx index 4e353aa692593fc558da4f238a67abccbb7f59d3..fb37b7cb882cf279fb6f45845fbf6159be3f30bd 100644 --- a/frontend/src/metabase/visualizations/Scalar.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Scalar.jsx @@ -4,6 +4,8 @@ import React, { Component, PropTypes } from "react"; import { Link } from "react-router"; import styles from "./Scalar.css"; +import Icon from "metabase/components/Icon.jsx"; +import Tooltip from "metabase/components/Tooltip.jsx"; import Ellipsified from "metabase/components/Ellipsified.jsx"; import Urls from "metabase/lib/urls"; @@ -67,8 +69,41 @@ export default class Scalar extends Component<*, VisualizationProps, *> { } } + static settings = { + "scalar.locale": { + title: "Separator style", + widget: "select", + props: { + options: [ + { name: "100000.00", value: null }, + { name: "100,000.00", value: "en" }, + { name: "100 000,00", value: "fr" }, + { name: "100.000,00", value: "de" } + ] + }, + default: "en" + }, + "scalar.decimals": { + title: "Number of decimal places", + widget: "number" + }, + "scalar.prefix": { + title: "Add a prefix", + widget: "input" + }, + "scalar.suffix": { + title: "Add a suffix", + widget: "input" + }, + "scalar.scale": { + title: "Multiply by a number", + widget: "number" + }, + }; + render() { let { card, data, className, actionButtons, gridSize, settings, linkToCard } = this.props; + let description = settings["card.description"]; let isSmall = gridSize && gridSize.width < 4; const column = getIn(data, ["cols", 0]); @@ -143,13 +178,22 @@ export default class Scalar extends Component<*, VisualizationProps, *> { > {compactScalarValue} </Ellipsified> - <Ellipsified className={styles.Title} tooltip={card.name}> - { linkToCard ? - <Link to={Urls.card(card.id)} className="no-decoration fullscreen-normal-text fullscreen-night-text">{settings["card.title"]}</Link> - : - <span className="fullscreen-normal-text fullscreen-night-text">{settings["card.title"]}</span> + <div className={styles.Title + " flex align-center"}> + <Ellipsified tooltip={card.name}> + { linkToCard ? + <Link to={Urls.card(card.id)} className="no-decoration fullscreen-normal-text fullscreen-night-text">{settings["card.title"]}</Link> + : + <span className="fullscreen-normal-text fullscreen-night-text">{settings["card.title"]}</span> + } + </Ellipsified> + { description && + <div className="hover-child"> + <Tooltip tooltip={description} maxWidth={'22em'}> + <Icon name='info' /> + </Tooltip> + </div> } - </Ellipsified> + </div> </div> ); } diff --git a/frontend/src/metabase/visualizations/visualizations/ScatterPlot.jsx b/frontend/src/metabase/visualizations/visualizations/ScatterPlot.jsx new file mode 100644 index 0000000000000000000000000000000000000000..8a5c9ac2dc1eb713966092f6a3319c9a6f5daaea --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/ScatterPlot.jsx @@ -0,0 +1,31 @@ +/* @flow */ + +import React, { Component, PropTypes } from "react"; + +import LineAreaBarChart from "../components/LineAreaBarChart.jsx"; +import { scatterRenderer } from "../lib/LineAreaBarRenderer"; + +import { + GRAPH_DATA_SETTINGS, + GRAPH_BUBBLE_SETTINGS, + GRAPH_GOAL_SETTINGS, + GRAPH_COLORS_SETTINGS, + GRAPH_AXIS_SETTINGS +} from "../lib/settings/graph"; + +export default class ScatterPlot extends LineAreaBarChart { + static uiName = "Scatter"; + static identifier = "scatter"; + static iconName = "bubble"; + static noun = "scatter plot"; + + static renderer = scatterRenderer; + + static settings = { + ...GRAPH_DATA_SETTINGS, + ...GRAPH_BUBBLE_SETTINGS, + ...GRAPH_GOAL_SETTINGS, + ...GRAPH_COLORS_SETTINGS, + ...GRAPH_AXIS_SETTINGS + } +} diff --git a/frontend/src/metabase/visualizations/Table.jsx b/frontend/src/metabase/visualizations/visualizations/Table.jsx similarity index 66% rename from frontend/src/metabase/visualizations/Table.jsx rename to frontend/src/metabase/visualizations/visualizations/Table.jsx index 7bec7cd8bf6f7d44b7450d8cb7b71ff350bdd1b5..1b186d023a2bfeffece08921a98e00e94834f31a 100644 --- a/frontend/src/metabase/visualizations/Table.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Table.jsx @@ -2,10 +2,17 @@ import React, { Component, PropTypes } from "react"; -import TableInteractive from "./TableInteractive.jsx"; -import TableSimple from "./TableSimple.jsx"; +import TableInteractive from "../components/TableInteractive.jsx"; +import TableSimple from "../components/TableSimple.jsx"; import * as DataGrid from "metabase/lib/data_grid"; + +import Query from "metabase/lib/query"; +import { isMetric, isDimension } from "metabase/lib/schema_metadata"; +import { columnsAreValid } from "metabase/visualizations/lib/settings"; +import { getFriendlyName } from "metabase/visualizations/lib/utils"; +import ChartSettingOrderedFields from "metabase/visualizations/components/settings/ChartSettingOrderedFields.jsx"; + import _ from "underscore"; import { getIn } from "icepick"; @@ -43,6 +50,39 @@ export default class Table extends Component<*, Props, State> { // scalar can always be rendered, nothing needed here } + static settings = { + "table.pivot": { + title: "Pivot the table", + widget: "toggle", + getHidden: ([{ card, data }]) => ( + data && data.cols.length !== 3 + ), + getDefault: ([{ card, data }]) => ( + (data && data.cols.length === 3) && + Query.isStructured(card.dataset_query) && + data.cols.filter(isMetric).length === 1 && + data.cols.filter(isDimension).length === 2 + ) + }, + "table.columns": { + title: "Fields to include", + widget: ChartSettingOrderedFields, + getHidden: (series, vizSettings) => vizSettings["table.pivot"], + isValid: ([{ card, data }]) => + card.visualization_settings["table.columns"] && + columnsAreValid(card.visualization_settings["table.columns"].map(x => x.name), data), + getDefault: ([{ data: { cols }}]) => cols.map(col => ({ + name: col.name, + enabled: col.visibility_type !== "details-only" + })), + getProps: ([{ data: { cols }}]) => ({ + columnNames: cols.reduce((o, col) => ({ ...o, [col.name]: getFriendlyName(col)}), {}) + }) + }, + "table.column_widths": { + }, + } + constructor(props: Props) { super(props); diff --git a/frontend/test/unit/lib/query.spec.js b/frontend/test/unit/lib/query.spec.js index acf8e487094eff46947127caaf2ea6d68f4e4973..ffe759d48c828dc39b41dff806f7aea2ef16c259 100644 --- a/frontend/test/unit/lib/query.spec.js +++ b/frontend/test/unit/lib/query.spec.js @@ -142,32 +142,32 @@ describe('Query', () => { expect(query.order_by).toEqual([[["fk->", 1, 2], "ascending"]]); }); - it('should not remove sort clauses with datetime_fields on fields appearing in breakout', () => { + it('should not remove sort clauses with datetime-fields on fields appearing in breakout', () => { let query = { source_table: 0, aggregation: ["count"], - breakout: [["datetime_field", 1, "as", "week"]], + breakout: [["datetime-field", 1, "as", "week"]], filter: [], order_by: [ - [["datetime_field", 1, "as", "week"], "ascending"] + [["datetime-field", 1, "as", "week"], "ascending"] ] }; Query.cleanQuery(query); - expect(query.order_by).toEqual([[["datetime_field", 1, "as", "week"], "ascending"]]); + expect(query.order_by).toEqual([[["datetime-field", 1, "as", "week"], "ascending"]]); }); - it('should replace order_by clauses with the exact matching datetime_fields version in the breakout', () => { + it('should replace order_by clauses with the exact matching datetime-fields version in the breakout', () => { let query = { source_table: 0, aggregation: ["count"], - breakout: [["datetime_field", 1, "as", "week"]], + breakout: [["datetime-field", 1, "as", "week"]], filter: [], order_by: [ [1, "ascending"] ] }; Query.cleanQuery(query); - expect(query.order_by).toEqual([[["datetime_field", 1, "as", "week"], "ascending"]]); + expect(query.order_by).toEqual([[["datetime-field", 1, "as", "week"], "ascending"]]); }); it('should replace order_by clauses with the exact matching fk-> version in the breakout', () => { @@ -248,14 +248,14 @@ describe('Query', () => { expect(target.path).toEqual([]); expect(target.unit).toEqual(undefined); }); - it('should return unit object for old-style datetime_field', () => { + it('should return unit object for old-style datetime-field', () => { let target = Query.getFieldTarget(["datetime-field", 1, "as", "day"], table1); expect(target.table).toEqual(table1); expect(target.field).toEqual(field1); expect(target.path).toEqual([]); expect(target.unit).toEqual("day"); }); - it('should return unit object for new-style datetime_field', () => { + it('should return unit object for new-style datetime-field', () => { let target = Query.getFieldTarget(["datetime-field", 1, "as", "day"], table1); expect(target.table).toEqual(table1); expect(target.field).toEqual(field1); diff --git a/frontend/test/unit/lib/query_time.spec.js b/frontend/test/unit/lib/query_time.spec.js index c9f3a20852c9df0e26f0217328a331b7322313dc..aca42b3c2439b486d7b106f8831b6d1f88ee80b8 100644 --- a/frontend/test/unit/lib/query_time.spec.js +++ b/frontend/test/unit/lib/query_time.spec.js @@ -8,14 +8,14 @@ describe('query_time', () => { expect( expandTimeIntervalFilter(["time-interval", 100, "current", "month"]) ).toEqual( - ["=", ["datetime_field", 100, "as", "month"], ["relative_datetime", "current"]] + ["=", ["datetime-field", 100, "as", "month"], ["relative-datetime", "current"]] ); }); it('translate [-30, "day"] correctly', () => { expect( expandTimeIntervalFilter(["time-interval", 100, -30, "day"]) ).toEqual( - ["BETWEEN", ["datetime_field", 100, "as", "day"], ["relative_datetime", -31, "day"], ["relative_datetime", -1, "day"]] + ["BETWEEN", ["datetime-field", 100, "as", "day"], ["relative-datetime", -31, "day"], ["relative-datetime", -1, "day"]] ); }); }); @@ -29,17 +29,17 @@ describe('query_time', () => { ); }); - it ('should convert relative_datetime "current"', () => { + it ('should convert relative-datetime "current"', () => { expect( - absolute(["relative_datetime", "current"]).format("YYYY-MM-DD HH") + absolute(["relative-datetime", "current"]).format("YYYY-MM-DD HH") ).toBe( moment().format("YYYY-MM-DD HH") ); }); - it ('should convert relative_datetime -1 "month"', () => { + it ('should convert relative-datetime -1 "month"', () => { expect( - absolute(["relative_datetime", -1, "month"]).format("YYYY-MM-DD HH") + absolute(["relative-datetime", -1, "month"]).format("YYYY-MM-DD HH") ).toBe( moment().subtract(1, "month").format("YYYY-MM-DD HH") ); @@ -95,22 +95,22 @@ describe('query_time', () => { describe('relative dates', () => { it ('should handle "="', () => { - let [start, end] = computeFilterTimeRange(["=", 1, ["relative_datetime", "current"]]); + let [start, end] = computeFilterTimeRange(["=", 1, ["relative-datetime", "current"]]); expect(start.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().format("YYYY-MM-DD 00:00:00")); expect(end.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().format("YYYY-MM-DD 23:59:59")); }); it ('should handle "<"', () => { - let [start, end] = computeFilterTimeRange(["<", 1, ["relative_datetime", "current"]]); + let [start, end] = computeFilterTimeRange(["<", 1, ["relative-datetime", "current"]]); expect(start.year()).toBeLessThan(-10000); expect(end.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().format("YYYY-MM-DD 00:00:00")); }); it ('should handle ">"', () => { - let [start, end] = computeFilterTimeRange([">", 1, ["relative_datetime", "current"]]); + let [start, end] = computeFilterTimeRange([">", 1, ["relative-datetime", "current"]]); expect(start.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().format("YYYY-MM-DD 23:59:59")); expect(end.year()).toBeGreaterThan(10000); }); it ('should handle "BETWEEN"', () => { - let [start, end] = computeFilterTimeRange(["BETWEEN", 1, ["relative_datetime", -1, "day"], ["relative_datetime", 1, "day"]]); + let [start, end] = computeFilterTimeRange(["BETWEEN", 1, ["relative-datetime", -1, "day"], ["relative-datetime", 1, "day"]]); expect(start.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().subtract(1, "day").format("YYYY-MM-DD 00:00:00")); expect(end.format("YYYY-MM-DD HH:mm:ss")).toEqual(moment().add(1, "day").format("YYYY-MM-DD 23:59:59")); }); diff --git a/frontend/test/unit/visualizations/lib/errors.spec.js b/frontend/test/unit/visualizations/lib/errors.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..62199125b519e56ba20c07564f99050a4488bb54 --- /dev/null +++ b/frontend/test/unit/visualizations/lib/errors.spec.js @@ -0,0 +1,10 @@ +import { MinRowsError } from 'metabase/visualizations/lib/errors'; + +describe('MinRowsError', () => { + it("should be an instanceof Error", () => { + expect(new MinRowsError(1, 0) instanceof Error).toBe(true); + }); + it("should be an instanceof MinRowsError", () => { + expect(new MinRowsError(1, 0) instanceof MinRowsError).toBe(true); + }); +}); diff --git a/frontend/test/unit/lib/visualization_settings.spec.js b/frontend/test/unit/visualizations/lib/settings.spec.js similarity index 80% rename from frontend/test/unit/lib/visualization_settings.spec.js rename to frontend/test/unit/visualizations/lib/settings.spec.js index a135b10e54599f14110e2837e8dada8f2b202618..31bc43b3fb47a54ba5a25937861dd6fa566e7b9a 100644 --- a/frontend/test/unit/lib/visualization_settings.spec.js +++ b/frontend/test/unit/visualizations/lib/settings.spec.js @@ -1,6 +1,10 @@ -import { getSettings } from 'metabase/lib/visualization_settings'; -import { DateTimeColumn, NumberColumn } from "../support/visualizations"; +// NOTE: need to load visualizations first for getSettings to work +import "metabase/visualizations"; + +import { getSettings } from 'metabase/visualizations/lib/settings'; + +import { DateTimeColumn, NumberColumn } from "../../support/visualizations"; describe('visualization_settings', () => { describe('getSettings', () => { diff --git a/package.json b/package.json index 1c0b8e04c8f0b9967483a7efd6fbb84280f964d8..ce7a4c9b7e42611104144e2fdec3426492234ac7 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "babel-eslint": "^7.1.1", "babel-loader": "^6.2.4", "babel-plugin-add-react-displayname": "^0.0.4", - "babel-plugin-transform-builtin-extend": "^1.1.0", + "babel-plugin-transform-builtin-extend": "^1.1.2", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-flow-strip-types": "^6.8.0", "babel-preset-es2015": "^6.6.0", @@ -83,6 +83,7 @@ "babel-register": "^6.11.6", "concurrently": "^3.1.0", "css-loader": "^0.26.1", + "enzyme": "^2.7.0", "eslint": "^3.5.0", "eslint-import-resolver-webpack": "^0.8.0", "eslint-loader": "^1.6.0", @@ -104,6 +105,7 @@ "jasmine-promises": "^0.4.1", "jasmine-reporters": "^2.2.0", "jasmine-spec-reporter": "^3.0.0", + "jest": "^18.1.0", "json-loader": "^0.5.4", "karma": "^1.3.0", "karma-chrome-launcher": "^2.0.0", @@ -117,8 +119,9 @@ "postcss-loader": "^1.2.1", "postcss-url": "^5.1.1", "promise-loader": "^1.0.0", - "react-addons-test-utils": "^15.3.1", + "react-addons-test-utils": "^15.4.2", "react-hot-loader": "^1.3.0", + "react-test-renderer": "^15.4.2", "sauce-connect-launcher": "^1.1.1", "selenium-webdriver": "^2.53.3", "style-loader": "^0.13.0", @@ -139,9 +142,18 @@ "test-e2e-sauce": "USE_SAUCE=true yarn run test-e2e", "build": "webpack --bail", "build-watch": "webpack --watch", - "build-hot": "NODE_ENV=hot webpack --bail && NODE_ENV=hot webpack-dev-server", + "build-hot": "NODE_ENV=hot webpack --bail && NODE_ENV=hot webpack-dev-server --progress", "start": "yarn run build && lein ring server", "storybook": "start-storybook -p 9001", - "preinstall": "ps -fp $PPID | grep -q yarn || echo '\\033[0;33mSorry, npm is not supported. Please use Yarn (https://yarnpkg.com/).\\033[0m'" + "preinstall": "ps -fp $PPID | grep -q yarn || echo '\\033[0;33mSorry, npm is not supported. Please use Yarn (https://yarnpkg.com/).\\033[0m'", + "test-jest": "jest" + }, + "jest": { + "testPathIgnorePatterns": [ + "<rootDir>/frontend/test/" + ], + "modulePaths": [ + "<rootDir>/frontend/src" + ] } } diff --git a/project.clj b/project.clj index 7c27b5388976db5add13619851df80be5ad4c160..825ac3799b2dbcec459e36b132bc54e424142cec 100644 --- a/project.clj +++ b/project.clj @@ -26,6 +26,7 @@ org.clojure/clojurescript]] ; fixed length queue implementation, used in log buffering [amalloy/ring-gzip-middleware "0.1.3"] ; Ring middleware to GZIP responses if client can handle it [aleph "0.4.1"] ; Async HTTP library; WebSockets + [buddy/buddy-core "1.2.0"] ; various cryptograhpic functions [cheshire "5.7.0"] ; fast JSON encoding (used by Ring JSON middleware) [clj-http "3.4.1" ; HTTP client :exclusions [commons-codec diff --git a/src/metabase/api/database.clj b/src/metabase/api/database.clj index 403ebf0021ec06812382cb4a6d5af1c4c77fdf4e..975dbd0f82bdf08765592bf1f7f2e2034859fe1f 100644 --- a/src/metabase/api/database.clj +++ b/src/metabase/api/database.clj @@ -89,10 +89,12 @@ (defn- autocomplete-tables [db-id prefix] (db/select [Table :id :db_id :schema :name] - :db_id db-id - :active true - :%lower.name [:like (str (str/lower-case prefix) "%")] - {:order-by [[:%lower.name :asc]]})) + {:where [:and [:= :db_id db-id] + [:= :active true] + [:like :%lower.name (str (str/lower-case prefix) "%")] + [:or [:= :visibility_type nil] + [:not= :visibility_type "hidden"]]] + :order-by [[:%lower.name :asc]]})) (defn- autocomplete-fields [db-id prefix] (db/select [Field :name :base_type :special_type :id :table_id [:table.name :table_name]] diff --git a/src/metabase/api/session.clj b/src/metabase/api/session.clj index c53ec31dbb7df25299bca1ca59672bf5664aeadb..f5aed8c1ad94ee228349ed300446f489a5b62211 100644 --- a/src/metabase/api/session.clj +++ b/src/metabase/api/session.clj @@ -75,14 +75,14 @@ (defendpoint POST "/forgot_password" "Send a reset email when user has forgotten their password." - [:as {:keys [server-name] {:keys [email]} :body, remote-address :remote-addr, :as request}] + [:as {:keys [server-name] {:keys [email]} :body, remote-address :remote-addr}] {email su/Email} (throttle/check (forgot-password-throttlers :ip-address) remote-address) (throttle/check (forgot-password-throttlers :email) email) ;; Don't leak whether the account doesn't exist, just pretend everything is ok (when-let [{user-id :id, google-auth? :google_auth} (db/select-one ['User :id :google_auth] :email email, :is_active true)] (let [reset-token (set-user-password-reset-token! user-id) - password-reset-url (str (public-settings/site-url request) "/auth/reset_password/" reset-token)] + password-reset-url (str (public-settings/site-url) "/auth/reset_password/" reset-token)] (email/send-password-reset-email! email google-auth? server-name password-reset-url) (log/info password-reset-url)))) diff --git a/src/metabase/api/setup.clj b/src/metabase/api/setup.clj index 1eb164404d6c95394e21230227b0899a34444f44..45c91302ea434e04dcd3b5ee496b36b0be9f8e43 100644 --- a/src/metabase/api/setup.clj +++ b/src/metabase/api/setup.clj @@ -27,15 +27,13 @@ (defendpoint POST "/" "Special endpoint for creating the first user during setup. This endpoint both creates the user AND logs them in and returns a session ID." - [:as {{:keys [token] {:keys [name engine details is_full_sync]} :database, {:keys [first_name last_name email password]} :user, {:keys [allow_tracking site_name]} :prefs} :body, :as request}] + [:as {{:keys [token] {:keys [name engine details is_full_sync]} :database, {:keys [first_name last_name email password]} :user, {:keys [allow_tracking site_name]} :prefs} :body}] {token SetupToken site_name su/NonBlankString first_name su/NonBlankString last_name su/NonBlankString email su/Email password su/ComplexPassword} - ;; Call (public-settings/site-url request) to set the Site URL setting if it's not already set - (public-settings/site-url request) ;; Now create the user (let [session-id (str (java.util.UUID/randomUUID)) new-user (db/insert! User diff --git a/src/metabase/api/table.clj b/src/metabase/api/table.clj index 2a8b8ca6cd12c4b1312af26372297eb2101a2db3..ea06b1ef9aa25b5bd25049977c9cd229ed760366 100644 --- a/src/metabase/api/table.clj +++ b/src/metabase/api/table.clj @@ -12,7 +12,8 @@ [metabase.sync-database :as sync-database] [metabase.util.schema :as su])) -(def ^:private TableEntityType +;; TODO - I don't think this is used for anything any more +(def ^:private ^:deprecated TableEntityType "Schema for a valid table entity type." (apply s/enum (map name table/entity-types))) diff --git a/src/metabase/api/user.clj b/src/metabase/api/user.clj index fa2ba67c267c184759e0e5f5024826c75ada1bd0..a3bdab8c8890221e2e72aa95b152b556842a4624 100644 --- a/src/metabase/api/user.clj +++ b/src/metabase/api/user.clj @@ -87,10 +87,12 @@ {password su/ComplexPassword} (check-self-or-superuser id) (let-404 [user (db/select-one [User :password_salt :password], :id id, :is_active true)] - (when (and (not (:is_superuser @*current-user*)) - (= id *current-user-id*)) + ;; admins are allowed to reset anyone's password (in the admin people list) so no need to check the value of `old_password` for them + ;; regular users have to know their password, however + (when-not (:is_superuser @*current-user*) (checkp (creds/bcrypt-verify (str (:password_salt user) old_password) (:password user)) "old_password" "Invalid password"))) (user/set-user-password! id password) + ;; return the updated User (User id)) diff --git a/src/metabase/core.clj b/src/metabase/core.clj index b5d2af14b4414eac6216590f1322e7c51bab39c3..2b8a82c194b8bba0bb7c4735b10aa9851b1b67cb 100644 --- a/src/metabase/core.clj +++ b/src/metabase/core.clj @@ -46,6 +46,7 @@ mb-middleware/wrap-current-user-id ; looks for :metabase-session-id and sets :metabase-user-id if Session ID is valid mb-middleware/wrap-api-key ; looks for a Metabase API Key on the request and assocs as :metabase-api-key mb-middleware/wrap-session-id ; looks for a Metabase Session ID and assoc as :metabase-session-id + mb-middleware/maybe-set-site-url ; set the value of `site-url` if it hasn't been set yet wrap-cookies ; Parses cookies in the request map and assocs as :cookies wrap-session ; reads in current HTTP session and sets :session/key wrap-gzip)) ; GZIP response if client can handle it diff --git a/src/metabase/db/migrations.clj b/src/metabase/db/migrations.clj index b0de741d714df5aae1a78ee77a533b08f265849c..2fe1a23508cd2272f807e5c85ab8682dc3fd0f84 100644 --- a/src/metabase/db/migrations.clj +++ b/src/metabase/db/migrations.clj @@ -29,7 +29,7 @@ [raw-column :refer [RawColumn]] [raw-table :refer [RawTable]] [table :refer [Table] :as table] - [setting :as setting] + [setting :refer [Setting], :as setting] [user :refer [User]]) [metabase.public-settings :as public-settings] [metabase.util :as u])) @@ -321,9 +321,9 @@ (db/update-where! 'Field {:special_type [:not-like "type/%"]} :special_type nil)) -;; make sure there are no trailing slashes on the `-site-url` setting. This could be the case in some situtations if the setting was set -;; by some other method besides the `site-url` helper function before the magic setter was in place -(defmigration ^{:atuhor "camsaul", :added "0.23.0"} remove-trailing-slashes-from-site-url-setting - ;; just fetching the setting and setting it again via the magic setter will remove the trailing slash - (when-let [site-url (public-settings/-site-url)] - (public-settings/-site-url site-url))) +;; Copy the value of the old setting `-site-url` to the new `site-url` if applicable. +;; (`site-url` used to be stored internally as `-site-url`; this was confusing, see #4188 for details) +;; This has the side effect of making sure the `site-url` has no trailing slashes (as part of the magic setter fn; this was fixed as part of #4123) +(defmigration ^{:author "camsaul", :added "0.23.0"} copy-site-url-setting-and-remove-trailing-slashes + (when-let [site-url (db/select-one-field :value Setting :key "-site-url")] + (public-settings/site-url site-url))) diff --git a/src/metabase/driver/bigquery.clj b/src/metabase/driver/bigquery.clj index afba894b1c1eaeeca3327b5b626d0be4598fb86a..0ed07847ec1ab77a0cb66320b3fea1b5620b1123 100644 --- a/src/metabase/driver/bigquery.clj +++ b/src/metabase/driver/bigquery.clj @@ -121,6 +121,8 @@ {:pre [client (seq project-id) (seq query-string)]} (let [request (doto (QueryRequest.) (.setTimeoutMs (* query-timeout-seconds 1000)) + ;; if the query contains a `#standardSQL` directive then use Standard SQL instead of legacy SQL + (.setUseLegacySql (not (s/includes? query-string "#standardSQL"))) (.setQuery query-string))] (google/execute (.query (.jobs client) project-id request))))) diff --git a/src/metabase/email/messages.clj b/src/metabase/email/messages.clj index e372ea6d90a08a14c61998cae0336fe8b0a30d65..f1e67fd9accc185f993c662d47c91766cfc5b220 100644 --- a/src/metabase/email/messages.clj +++ b/src/metabase/email/messages.clj @@ -9,7 +9,7 @@ [toucan.db :as db] (metabase [config :as config] [email :as email]) - [metabase.models.setting :as setting] + [metabase.public-settings :as public-settings] [metabase.pulse.render :as render] [metabase.util :as u] (metabase.util [quotation :as quotation] @@ -49,7 +49,7 @@ (defn send-new-user-email! "Send an email to INVITIED letting them know INVITOR has invited them to join Metabase." [invited invitor join-url] - (let [company (or (setting/get :site-name) "Unknown") + (let [company (or (public-settings/site-name) "Unknown") message-body (stencil/render-file "metabase/email/new_user_invite" (merge {:emailType "new_user_invite" :invitedName (:first_name invited) @@ -70,7 +70,7 @@ "Return a `:recipients` vector for all Admin users." [] (concat (db/select-field :email 'User, :is_superuser true, :is_active true) - (when-let [admin-email (setting/get :admin-email)] + (when-let [admin-email (public-settings/admin-email)] [admin-email]))) (defn send-user-joined-admin-notification-email! @@ -96,7 +96,7 @@ :joinedUserEmail (:email new-user) :joinedDate (u/format-date "EEEE, MMMM d") ; e.g. "Wednesday, July 13". TODO - is this what we want? :invitorEmail invitor-email - :joinedUserEditUrl (str (setting/get :-site-url) "/admin/people")} + :joinedUserEditUrl (str (public-settings/site-url) "/admin/people")} (random-quote-context))))) diff --git a/src/metabase/logger.clj b/src/metabase/logger.clj index 7547902a479e1116c27688ea2b4689424612aed4..bf759429d9fbdfcb88d64cf2a13d27da8386ea56 100644 --- a/src/metabase/logger.clj +++ b/src/metabase/logger.clj @@ -10,15 +10,16 @@ (def ^:private ^:const max-log-entries 2500) -(def ^:private messages (atom (ring-buffer max-log-entries))) +(defonce ^:private messages (atom (ring-buffer max-log-entries))) +;; TODO - rename to `messages` (defn get-messages - "Get the list of currently buffered log entries" + "Get the list of currently buffered log entries, from most-recent to oldest." [] (reverse (seq @messages))) -(def ^:private formatter (time/formatter "MMM dd HH:mm:ss" (t/default-time-zone))) +(defonce ^:private formatter (time/formatter "MMM dd HH:mm:ss" (t/default-time-zone))) (defn -append "Append a new EVENT to the `messages` atom. diff --git a/src/metabase/middleware.clj b/src/metabase/middleware.clj index 2b1c85000573b901b39590d07c0dfcc1bf4c9520..511503b4393027c6bca6e28518d6a4f4e06181d4 100644 --- a/src/metabase/middleware.clj +++ b/src/metabase/middleware.clj @@ -12,6 +12,7 @@ (metabase.models [session :refer [Session]] [setting :refer [defsetting]] [user :refer [User], :as user]) + [metabase.public-settings :as public-settings] [metabase.util :as u]) (:import com.fasterxml.jackson.core.JsonGenerator)) @@ -238,6 +239,23 @@ (index? request) (html-page-security-headers)))))) +;;; # ------------------------------------------------------------ SETTING SITE-URL ------------------------------------------------------------ + +;; It's important for us to know what the site URL is for things like returning links, etc. +;; this is stored in the `site-url` Setting; we can set it automatically by looking at the `Origin` or `Host` headers sent with a request. +;; Effectively the very first API request that gets sent to us (usually some sort of setup request) ends up setting the (initial) value of `site-url` + +(defn maybe-set-site-url + "Middleware to set the `site-url` Setting if it's unset the first time a request is made." + [handler] + (fn [{{:strs [origin host] :as headers} :headers, :as request}] + (when-not (public-settings/site-url) + (when-let [site-url (or origin host)] + (log/info "Setting Metabase site URL to" site-url) + (public-settings/site-url site-url))) + (handler request))) + + ;;; # ------------------------------------------------------------ JSON SERIALIZATION CONFIG ------------------------------------------------------------ ;; Tell the JSON middleware to use a date format that includes milliseconds (why?) diff --git a/src/metabase/models/database.clj b/src/metabase/models/database.clj index f648112288151ce005fee88180f1cf0bda42fdaa..5a45eacedb2ec1385ef7c35637da00835c10b238 100644 --- a/src/metabase/models/database.clj +++ b/src/metabase/models/database.clj @@ -42,7 +42,7 @@ models/IModel (merge models/IModelDefaults {:hydration-keys (constantly [:database :db]) - :types (constantly {:details :json, :engine :keyword}) + :types (constantly {:details :encrypted-json, :engine :keyword}) :properties (constantly {:timestamped? true}) :post-insert post-insert :post-select post-select diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj index 0f84ec9a8461717f378e8ee01f7fa033afb7b343..804877b9dd93f5c4cba623b15d2d48aa53bb7016 100644 --- a/src/metabase/models/interface.clj +++ b/src/metabase/models/interface.clj @@ -1,10 +1,10 @@ (ns metabase.models.interface - (:require [cheshire.core :as json] + (:require [clojure.core.memoize :as memoize] + [cheshire.core :as json] [toucan.models :as models] - (metabase [config :as config] - [util :as u]) - [metabase.models.common :as common])) - + [metabase.config :as config] + [metabase.util :as u] + [metabase.util.encryption :as encryption])) ;;; ------------------------------------------------------------ Toucan Extensions ------------------------------------------------------------ @@ -29,6 +29,16 @@ :in identity :out u/jdbc-clob->str) +(def ^:private encrypted-json-in (comp encryption/maybe-encrypt json-in)) +(def ^:private encrypted-json-out (comp json-out encryption/maybe-decrypt)) + +;; cache the decryption/JSON parsing because it's somewhat slow (~500µs vs ~100µs on a *fast* computer) +(def ^:private cached-encrypted-json-out (memoize/ttl encrypted-json-out :ttl/threshold (* 60 60 1000))) ; cache decrypted JSON for one hour + +(models/add-type! :encrypted-json + :in encrypted-json-in + :out (comp cached-encrypted-json-out u/jdbc-clob->str)) + (defn- add-created-at-timestamp [obj & _] (assoc obj :created_at (u/new-sql-timestamp))) diff --git a/src/metabase/models/table.clj b/src/metabase/models/table.clj index 234127d75ff3122f41928b32b45f2ba10b2647e5..27e565ee22d7ec3928117440714d549a9f75c881 100644 --- a/src/metabase/models/table.clj +++ b/src/metabase/models/table.clj @@ -16,7 +16,8 @@ ;;; ------------------------------------------------------------ Constants + Entity ------------------------------------------------------------ -(def ^:const entity-types +;; TODO - I don't think this is used for anything anymore +(def ^:const ^:deprecated entity-types "Valid values for `Table.entity_type` (field may also be `nil`)." #{:person :event :photo :place}) diff --git a/src/metabase/models/user.clj b/src/metabase/models/user.clj index 11c2e5b64392ef83e0c14bf4f7200fd4325f726e..ded039af793ad5fb00feb8edd29d1e8b2e29f73b 100644 --- a/src/metabase/models/user.clj +++ b/src/metabase/models/user.clj @@ -6,11 +6,10 @@ [models :as models]) [metabase.email.messages :as email] (metabase.models [permissions :as perms] - [permissions-group :as perm-group] - [permissions-group-membership :refer [PermissionsGroupMembership], :as perm-membership] - [setting :as setting]) - [metabase.util :as u] - [metabase.models.permissions-group :as group]) + [permissions-group :as group] + [permissions-group-membership :refer [PermissionsGroupMembership], :as perm-membership]) + [metabase.public-settings :as public-settings] + [metabase.util :as u]) (:import java.util.UUID)) ;;; ------------------------------------------------------------ Entity & Lifecycle ------------------------------------------------------------ @@ -44,12 +43,12 @@ #_(log/info (format "Adding user %d to All Users permissions group..." user-id)) (db/insert! PermissionsGroupMembership :user_id user-id - :group_id (:id (perm-group/all-users)))) + :group_id (:id (group/all-users)))) (when superuser? #_(log/info (format "Adding user %d to Admin permissions group..." user-id)) (db/insert! PermissionsGroupMembership :user_id user-id - :group_id (:id (perm-group/admin)))))) + :group_id (:id (group/admin)))))) (defn- pre-update [{:keys [email reset_token is_superuser id] :as user}] ;; when `:is_superuser` is toggled add or remove the user from the 'Admin' group as appropriate @@ -163,7 +162,7 @@ "Generate a properly formed password reset url given a password reset token." [reset-token] {:pre [(string? reset-token)]} - (str (setting/get :-site-url) "/auth/reset_password/" reset-token)) + (str (public-settings/site-url) "/auth/reset_password/" reset-token)) ;;; ------------------------------------------------------------ Permissions ------------------------------------------------------------ diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj index a671c04dd8b308a0bf1bdf988ef3d04629f6220c..f5db40aa810336b624909f88698db8240964af93 100644 --- a/src/metabase/public_settings.clj +++ b/src/metabase/public_settings.clj @@ -22,12 +22,12 @@ "The name used for this instance of Metabase." :default "Metabase") -(defsetting -site-url +(defsetting site-url "The base URL of this Metabase instance, e.g. \"http://metabase.my-company.com\". This is *guaranteed* never to have a tailing slash." :setter (fn [new-value] - (setting/set-string! :-site-url (when new-value - (s/replace new-value #"/$" ""))))) + (setting/set-string! :site-url (when new-value + (s/replace new-value #"/$" ""))))) (defsetting admin-email "The email address users should be referred to if they encounter a problem.") @@ -41,20 +41,6 @@ "The map tile server URL template used in map visualizations, for example from OpenStreetMaps or MapBox." :default "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png") -(defn site-url - "Fetch the site base URL that should be used for password reset emails, etc. - This strips off any trailing slashes that may have been added. - - The first time this function is called, we'll set the value of the setting `-site-url` with the value of - the ORIGIN header (falling back to HOST if needed, i.e. for unit tests) of some API request. - Subsequently, the site URL can only be changed via the admin page." - {:arglists '([request])} - [{{:strs [origin host]} :headers}] - {:pre [(or origin host)] - :post [(string? %)]} - (or (-site-url) - (-site-url (or origin host)))) - (defsetting enable-public-sharing "Enable admins to create publically viewable links for Cards and Dashboards?" :type :boolean diff --git a/src/metabase/query_processor.clj b/src/metabase/query_processor.clj index da0153a62d8c9dd6bd99fdbbd58856a929a0a76f..c3597bd0ada7aef5b616814e8d1fc1dbb5372a7f 100644 --- a/src/metabase/query_processor.clj +++ b/src/metabase/query_processor.clj @@ -164,7 +164,8 @@ (u/prog1 (params/expand-parameters query) (when (and (not *disable-qp-logging*) (not= <> query)) - (log/debug (u/format-color 'cyan "\n\nPARAMS/SUBSTITUTED: %s\n%s" (u/emoji "😻") (u/pprint-to-str (second (data/diff query <>)))))))) + (when-let [diff (second (data/diff query <>))] + (log/debug (u/format-color 'cyan "\n\nPARAMS/SUBSTITUTED: %s\n%s" (u/emoji "😻") (u/pprint-to-str diff))))))) (defn- pre-substitute-parameters [qp] (comp qp substitute-parameters)) diff --git a/src/metabase/util.clj b/src/metabase/util.clj index 9c21a88c6395ef6ac2b2f4fcbd5ede97a1b1e059..b5f9820bb47858db5e95a7a1933330d0666f72fa 100644 --- a/src/metabase/util.clj +++ b/src/metabase/util.clj @@ -305,7 +305,7 @@ (defprotocol ^:private IClobToStr (jdbc-clob->str ^String [this] - "Convert a Postgres/H2/SQLServer JDBC Clob to a string.")) + "Convert a Postgres/H2/SQLServer JDBC Clob to a string. (If object isn't a Clob, this function returns it as-is.)")) (extend-protocol IClobToStr nil (jdbc-clob->str [_] nil) @@ -811,3 +811,9 @@ {k (if-not (seq nested-keys) v (select-nested-keys v nested-keys))}))) + +(defn base-64-string? + "Is S a Base-64 encoded string?" + ^Boolean [s] + (boolean (when (string? s) + (re-find #"^[0-9A-Za-z/+]+=*$" s)))) diff --git a/src/metabase/util/embed.clj b/src/metabase/util/embed.clj index 4c6c451365472215fcace14af3e72d715ea0c0dc..0e9bf99d148f2743638eed0c7107e841845e2fef 100644 --- a/src/metabase/util/embed.clj +++ b/src/metabase/util/embed.clj @@ -9,10 +9,10 @@ (oembed-url \"/x\") -> \"http://localhost:3000/api/public/oembed?url=x&format=json\"" ^String [^String relative-url] - (str (public-settings/-site-url) + (str (public-settings/site-url) "/api/public/oembed" ;; NOTE: some oEmbed consumers require `url` be the first param??? - "?url=" (codec/url-encode (str (public-settings/-site-url) relative-url)) + "?url=" (codec/url-encode (str (public-settings/site-url) relative-url)) "&format=json")) (defn- oembed-link diff --git a/src/metabase/util/encryption.clj b/src/metabase/util/encryption.clj new file mode 100644 index 0000000000000000000000000000000000000000..1778fe0604aa6f77bc5b1ee0031ab35e6f9df180 --- /dev/null +++ b/src/metabase/util/encryption.clj @@ -0,0 +1,75 @@ +(ns metabase.util.encryption + "Utility functions for encrypting and decrypting strings using AES256 CBC + HMAC SHA512 and the `MB_ENCRYPTION_SECRET_KEY` env var." + (:require (buddy.core [codecs :as codecs] + [crypto :as crypto] + [kdf :as kdf] + [nonce :as nonce]) + [clojure.tools.logging :as log] + [environ.core :as env] + [ring.util.codec :as codec] + [metabase.util :as u])) + +(defn secret-key->hash + "Generate a 64-byte byte array hash of SECRET-KEY using 100,000 iterations of PBKDF2+SHA512." + [^String secret-key] + (kdf/get-bytes (kdf/engine {:alg :pbkdf2+sha512 + :key secret-key + :iterations 100000}) ; 100,000 iterations takes about ~160ms on my laptop + 64)) + +(defonce ^:private default-secret-key + (when-let [secret-key (env/env :mb-encryption-secret-key)] + (when (seq secret-key) + (assert (>= (count secret-key) 16) + "MB_ENCRYPTION_SECRET_KEY must be at least 16 characters.") + (secret-key->hash secret-key)))) + +;; log a nice message letting people know whether DB details encryption is enabled +(log/info (format "DB details encryption is %s for this Metabase instance. %s" + (if default-secret-key "ENABLED" "DISABLED") + (u/emoji (if default-secret-key "ðŸ”" "🔓")))) + +(defn encrypt + "Encrypt string S as hex bytes using a SECRET-KEY (a 64-byte byte array), by default the hashed value of `MB_ENCRYPTION_SECRET_KEY`." + (^String [^String s] + (encrypt default-secret-key s)) + (^String [^String secret-key, ^String s] + (let [iv (nonce/random-bytes 16)] + (codec/base64-encode (byte-array (concat iv + (crypto/encrypt (codecs/to-bytes s) secret-key iv {:algorithm :aes256-cbc-hmac-sha512}))))))) + +(defn decrypt + "Decrypt string S using a SECRET-KEY (a 64-byte byte array), by default the hashed value of `MB_ENCRYPTION_SECRET_KEY`." + (^String [^String s] + (decrypt default-secret-key s)) + (^String [secret-key, ^String s] + (let [bytes (codec/base64-decode s) + [iv message] (split-at 16 bytes)] + (codecs/bytes->str (crypto/decrypt (byte-array message) secret-key (byte-array iv) {:algorithm :aes256-cbc-hmac-sha512}))))) + + +(defn maybe-encrypt + "If `MB_ENCRYPTION_SECRET_KEY` is set, return an encrypted version of S; otherwise return S as-is." + (^String [^String s] + (maybe-encrypt default-secret-key s)) + (^String [secret-key, ^String s] + (if secret-key + (when (seq s) + (encrypt secret-key s)) + s))) + +(defn maybe-decrypt + "If `MB_ENCRYPTION_SECRET_KEY` is set and S is encrypted, decrypt S; otherwise return S as-is." + (^String [^String s] + (maybe-decrypt default-secret-key s)) + (^String [secret-key, ^String s] + (if (and secret-key (seq s)) + (try + (decrypt secret-key s) + (catch Throwable e + (if (u/base-64-string? s) + ;; if we can't decrypt `s`, but it *is* encrypted, log an error message and return `nil` + (log/error "Cannot decrypt encrypted details. Have you changed or forgot to set MB_ENCRYPTION_SECRET_KEY?" (.getMessage e)) + ;; otherwise return S without decrypting. It's probably not decrypted in the first place + s))) + s))) diff --git a/src/metabase/util/urls.clj b/src/metabase/util/urls.clj index 8c895e679b01c0185d35357cc1c49c7898e78b0d..db1c2948f50289fd71a4222729b61d59259f920c 100644 --- a/src/metabase/util/urls.clj +++ b/src/metabase/util/urls.clj @@ -13,25 +13,25 @@ (pulse-url 10) -> \"http://localhost:3000/pulse#10\"" [^Integer id] - (format "%s/pulse#%d" (public-settings/-site-url) id)) + (format "%s/pulse#%d" (public-settings/site-url) id)) (defn dashboard-url "Return an appropriate URL for a `Dashboard` with ID. (dashboard-url 10) -> \"http://localhost:3000/dash/10\"" [^Integer id] - (format "%s/dash/%d" (public-settings/-site-url) id)) + (format "%s/dash/%d" (public-settings/site-url) id)) (defn card-url "Return an appropriate URL for a `Card` with ID. (card-url 10) -> \"http://localhost:3000/card/10\"" [^Integer id] - (format "%s/card/%d" (public-settings/-site-url) id)) + (format "%s/card/%d" (public-settings/site-url) id)) (defn segment-url "Return an appropriate URL for a `Segment` with ID. (segment-url 10) -> \"http://localhost:3000/admin/datamodel/segment/10\"" [^Integer id] - (format "%s/admin/datamodel/segment/%d" (public-settings/-site-url) id)) + (format "%s/admin/datamodel/segment/%d" (public-settings/site-url) id)) diff --git a/test/metabase/api/geojson_test.clj b/test/metabase/api/geojson_test.clj index f71cbdc215f1f5290ddcc8b7d06627cc07fd61f3..227facbf2dfc722a09b84c99e2cee16b21b1d1f7 100644 --- a/test/metabase/api/geojson_test.clj +++ b/test/metabase/api/geojson_test.clj @@ -3,7 +3,8 @@ [schema.core :as s] [metabase.api.geojson :refer [custom-geojson]] [metabase.test.data.users :refer [user->client]] - [metabase.test.util :as tu])) + [metabase.test.util :as tu] + [metabase.util :as u])) (tu/resolve-private-vars metabase.api.geojson valid-json-url? @@ -56,10 +57,12 @@ ;;; test that we can set the value of custom-geojson via the normal routes (expect (merge @builtin-geojson test-custom-geojson) - ;; bind a temporary value so it will get set back to its old value here after the API calls are done stomping all over it - (tu/with-temporary-setting-values [custom-geojson nil] - ((user->client :crowberto) :put 200 "setting/custom-geojson" {:value test-custom-geojson}) - ((user->client :crowberto) :get 200 "setting/custom-geojson"))) + ;; try this up to 3 times since Circle's outbound connections likes to randomly stop working + (u/auto-retry 3 + ;; bind a temporary value so it will get set back to its old value here after the API calls are done stomping all over it + (tu/with-temporary-setting-values [custom-geojson nil] + ((user->client :crowberto) :put 200 "setting/custom-geojson" {:value test-custom-geojson}) + ((user->client :crowberto) :get 200 "setting/custom-geojson")))) ;;; test the endpoint that acts as a proxy for JSON files diff --git a/test/metabase/publc_settings_test.clj b/test/metabase/publc_settings_test.clj index 2dc9b797499d697b6c51caeb53837e5da0a367d2..dd97384d940c35d566b0d19c13f3efa1ff9b80c8 100644 --- a/test/metabase/publc_settings_test.clj +++ b/test/metabase/publc_settings_test.clj @@ -3,9 +3,9 @@ [metabase.public-settings :as public-settings] [metabase.test.util :as tu])) -;; double-check that setting the `-site-url` setting will automatically strip off trailing slashes +;; double-check that setting the `site-url` setting will automatically strip off trailing slashes (expect "http://localhost:3000" - (tu/with-temporary-setting-values [-site-url nil] - (public-settings/-site-url "http://localhost:3000/") - (public-settings/-site-url))) + (tu/with-temporary-setting-values [site-url nil] + (public-settings/site-url "http://localhost:3000/") + (public-settings/site-url))) diff --git a/test/metabase/test/util.clj b/test/metabase/test/util.clj index 2df520beb5a358eed034c9527b8479b1d2cb9ebc..839cead1244956bda609fdfad58a1c5723180841 100644 --- a/test/metabase/test/util.clj +++ b/test/metabase/test/util.clj @@ -1,6 +1,7 @@ (ns metabase.test.util "Helper functions and macros for writing unit tests." - (:require [clojure.walk :as walk] + (:require [clojure.tools.logging :as log] + [clojure.walk :as walk] [cheshire.core :as json] [expectations :refer :all] (toucan [db :as db] @@ -282,3 +283,20 @@ ^Boolean [^String s] (boolean (when (string? s) (re-matches #"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$" s)))) + +(defn do-with-log-messages [f] + (let [messages (atom [])] + (with-redefs [log/log* (fn [_ & message] + (swap! messages conj (vec message)))] + (f)) + @messages)) + +(defmacro with-log-messages + "Execute BODY, and return a vector of all messages logged using the `log/` family of functions. + Messages are of the format `[:level throwable message]`, and are returned in chronological order + from oldest to newest. + + (with-log-messages (log/warn \"WOW\")) ; -> [[:warn nil \"WOW\"]]" + {:style/indent 0} + [& body] + `(do-with-log-messages (fn [] ~@body))) diff --git a/test/metabase/util/encryption_test.clj b/test/metabase/util/encryption_test.clj new file mode 100644 index 0000000000000000000000000000000000000000..cc2471cef79cf689f605a41fca01f6ac995db16a --- /dev/null +++ b/test/metabase/util/encryption_test.clj @@ -0,0 +1,53 @@ +(ns metabase.util.encryption-test + (:require [clojure.string :as str] + [expectations :refer :all] + [metabase.test.util :as tu] + [metabase.util.encryption :as encryption])) + +(def ^:private secret (encryption/secret-key->hash "Orw0AAyzkO/kPTLJRxiyKoBHXa/d6ZcO+p+gpZO/wSQ=")) +(def ^:private secret-2 (encryption/secret-key->hash "0B9cD6++AME+A7/oR7Y2xvPRHX3cHA2z7w+LbObd/9Y=")) + +;; test that hashing a secret key twice gives you the same results +(expect + (= (vec (encryption/secret-key->hash "Toucans")) + (vec (encryption/secret-key->hash "Toucans")))) + +;; two different secret keys should have different results +(expect (not= (vec secret) + (vec secret-2))) + +;; test that we can encrypt a message. Should be base-64 +(expect + #"^[0-9A-Za-z/+]+=*$" + (encryption/encrypt secret "Hello!")) + +;; test that encrypting something twice gives you two different ciphertexts +(expect + (not= (encryption/encrypt secret "Hello!") + (encryption/encrypt secret "Hello!"))) + +;; test that we can decrypt something +(expect + "Hello!" + (encryption/decrypt secret (encryption/encrypt secret "Hello!"))) + +;; trying to decrypt something with the wrong key with `decrypt` should throw an Exception +(expect + Exception + (encryption/decrypt secret-2 (encryption/encrypt secret "WOW"))) + +;; trying to `maybe-decrypt` something that's not encrypted should return it as-is +(expect + "{\"a\":100}" + (encryption/maybe-decrypt secret "{\"a\":100}")) + +;; trying to decrypt something that is encrypted with the wrong key with `maybe-decrypt` should return `nil`... +(expect + nil + (encryption/maybe-decrypt secret-2 (encryption/encrypt secret "WOW"))) + +(expect + (some (fn [[_ _ message]] + (str/includes? message "Cannot decrypt encrypted details. Have you changed or forgot to set MB_ENCRYPTION_SECRET_KEY? Message seems corrupt or manipulated.")) + (tu/with-log-messages + (encryption/maybe-decrypt secret-2 (encryption/encrypt secret "WOW"))))) diff --git a/test/metabase/util_test.clj b/test/metabase/util_test.clj index ee1c5b3d6edc420af6c3fdcb9a066f3a8543b37f..a17d043795dad96442589aaabc2451c7c9f6fe03 100644 --- a/test/metabase/util_test.clj +++ b/test/metabase/util_test.clj @@ -202,3 +202,11 @@ (expect {} (select-nested-keys {} [:c])) + + +;; tests for base-64-string? +(expect (base-64-string? "ABc")) +(expect (base-64-string? "ABc/+asdasd==")) +(expect false (base-64-string? 100)) +(expect false (base-64-string? "<<>>")) +(expect false (base-64-string? "{\"a\": 10}")) diff --git a/test_resources/log4j.properties b/test_resources/log4j.properties index 3880ae2e38901487f610c722af28494d7b8565f8..993488ed722d55bcad76dbc98f3f8c197a2989a4 100644 --- a/test_resources/log4j.properties +++ b/test_resources/log4j.properties @@ -17,5 +17,7 @@ log4j.appender.file.layout.ConversionPattern=%d [%t] %-5p%c - %m%n # customizations to logging by package log4j.logger.com.mchange=ERROR log4j.logger.metabase=ERROR -log4j.logger.metabase.test.data.datasets=INFO +log4j.logger.metabase.middleware=INFO log4j.logger.metabase.test-setup=INFO +log4j.logger.metabase.test.data.datasets=INFO +log4j.logger.metabase.util.encryption=INFO diff --git a/webpack.config.js b/webpack.config.js index 236b50c4fd056005afb97dd8f05f0e3bb849c208..ab995c92a99e9d6445bcc2cde0a523431c970603 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -213,6 +213,8 @@ if (NODE_ENV === "hot") { hot: true, inline: true, contentBase: "frontend" + // if you want to reduce stats noise + // stats: 'minimal' // values: none, errors-only, minimal, normal, verbose }; config.plugins.unshift( diff --git a/yarn.lock b/yarn.lock index 2828a1c1a4a5bfad2ebad89f7d69bc0438191c7c..56499011af5f7dc5621c4fa9eabf2abfb28d86f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,8 +34,8 @@ resolved "https://registry.yarnpkg.com/@kadira/storybook-channel/-/storybook-channel-1.1.0.tgz#806d1cdf2498d11cce09871a6fd27bbb41ed3564" "@kadira/storybook-ui@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@kadira/storybook-ui/-/storybook-ui-3.10.1.tgz#d0ab3b00fce419fff11c45d386104e74765f953c" + version "3.11.0" + resolved "https://registry.yarnpkg.com/@kadira/storybook-ui/-/storybook-ui-3.11.0.tgz#a5ccdcc479aa5e08465c58e7df493e37e4b2a14a" dependencies: "@kadira/react-split-pane" "^1.4.0" babel-runtime "^6.5.0" @@ -45,6 +45,7 @@ json-stringify-safe "^5.0.1" keycode "^2.1.1" lodash.pick "^4.2.1" + lodash.sortby "^4.7.0" mantra-core "^1.7.0" podda "^1.2.1" qs "^6.2.0" @@ -55,8 +56,8 @@ redux "^3.5.2" "@kadira/storybook@^2.35.2": - version "2.35.2" - resolved "https://registry.yarnpkg.com/@kadira/storybook/-/storybook-2.35.2.tgz#2314481e66effdf1ff129d41e3fda986b6375b38" + version "2.35.3" + resolved "https://registry.yarnpkg.com/@kadira/storybook/-/storybook-2.35.3.tgz#8106195e1733623baf60db6adaa678dc29285d12" dependencies: "@kadira/react-split-pane" "^1.4.0" "@kadira/storybook-addon-actions" "^1.0.2" @@ -115,22 +116,15 @@ winston "^2.1.1" ws "^1.0.1" -abab@^1.0.0: +abab@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" abbrev@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - -accepts@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.1.4.tgz#d71c96f7d41d0feda2c38cd14e8a27c04158df4a" - dependencies: - mime-types "~2.0.4" - negotiator "0.4.9" + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" -accepts@~1.3.3: +accepts@1.3.3, accepts@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: @@ -138,40 +132,36 @@ accepts@~1.3.3: negotiator "0.6.1" ace-builds@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.2.5.tgz#41c5360cdee6c43e73735d3e3558121f9fea37a9" + version "1.2.6" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.2.6.tgz#a9233c27c37b8494f20af84917ee1619489af429" -acorn-globals@^1.0.4: - version "1.0.9" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-1.0.9.tgz#55bb5e98691507b74579d0513413217c380c54cf" +acorn-globals@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" dependencies: - acorn "^2.1.0" + acorn "^4.0.4" -acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: +acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" -acorn@^2.1.0, acorn@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" +acorn@4.0.4, acorn@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" acorn@^3.0.0, acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - adm-zip@0.4.4, adm-zip@~0.4.3: version "0.4.4" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" -after@0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" agent-base@2: version "2.0.1" @@ -181,8 +171,8 @@ agent-base@2: semver "~5.0.1" airbnb-js-shims@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.0.1.tgz#7d5a7d772c8c6fdeb624ea3cef62506091b180b5" + version "1.1.1" + resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.1.1.tgz#27224f0030f244e6570442ed1020772c1434aec2" dependencies: array-includes "^3.0.2" es5-shim "^4.5.9" @@ -194,12 +184,12 @@ airbnb-js-shims@^1.0.1: string.prototype.padstart "^3.0.0" ajv-keywords@^1.0.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.7.0: - version "4.10.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.3.tgz#3e4fea9675b157de7888b80dd0ed735b83f28e11" + version "4.11.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -224,7 +214,7 @@ annotate-react-dom@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/annotate-react-dom/-/annotate-react-dom-1.1.0.tgz#607c14d2565198d4bf365f6f05c60a61ba939a16" -ansi-escapes@^1.1.0: +ansi-escapes@^1.1.0, ansi-escapes@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -237,8 +227,8 @@ ansi-regex@^0.2.0, ansi-regex@^0.2.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-style-parser@^1.0.1: version "1.0.1" @@ -254,6 +244,10 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +ansicolors@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + any-promise@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-0.1.0.tgz#830b680aa7e56f33451d4b049f3bd8044498ee27" @@ -269,9 +263,15 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + aproba@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" are-we-there-yet@~1.1.2: version "1.1.2" @@ -341,11 +341,18 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +array.prototype.find@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.3.tgz#08c3ec33e32ec4bab362a2958e686ae92f59271d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + arraybuffer.slice@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" -arrify@^1.0.0: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -379,9 +386,9 @@ assert@^1.1.1: dependencies: util "0.10.3" -ast-types@0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.2.tgz#2cc19979d15c655108bf565323b8e7ee38751f6b" +ast-types@0.9.5: + version "0.9.5" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.5.tgz#1a660a09945dbceb1f9c9cbb715002617424e04a" async-each@^1.0.0: version "1.0.1" @@ -391,13 +398,13 @@ async@^0.9.0, async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -async@^1.3.0, async@^1.4.2, async@^1.5.0: +async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2: - version "2.1.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" +async@^2.1.2, async@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" dependencies: lodash "^4.14.0" @@ -414,14 +421,14 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" autoprefixer@^6.0.2, autoprefixer@^6.3.1, autoprefixer@^6.3.7: - version "6.6.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.6.1.tgz#11a4077abb4b313253ec2f6e1adb91ad84253519" + version "6.7.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.4.tgz#b4405a263325c04a7c2b1c86fc603ad7bbfe01c6" dependencies: - browserslist "~1.5.1" - caniuse-db "^1.0.30000604" + browserslist "^1.7.4" + caniuse-db "^1.0.30000624" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^5.2.8" + postcss "^5.2.14" postcss-value-parser "^3.2.3" aws-sign2@~0.6.0: @@ -429,21 +436,21 @@ aws-sign2@~0.6.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" babel-cli@^6.11.4: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186" + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.23.0.tgz#52ff946a2b0f64645c35e7bd5eea267aa0948c0f" dependencies: - babel-core "^6.18.0" - babel-polyfill "^6.16.0" - babel-register "^6.18.0" - babel-runtime "^6.9.0" + babel-core "^6.23.0" + babel-polyfill "^6.23.0" + babel-register "^6.23.0" + babel-runtime "^6.22.0" commander "^2.8.1" convert-source-map "^1.1.0" fs-readdir-recursive "^1.0.0" - glob "^5.0.5" + glob "^7.0.0" lodash "^4.2.0" output-file-sync "^1.1.0" path-is-absolute "^1.0.0" @@ -451,29 +458,29 @@ babel-cli@^6.11.4: source-map "^0.5.0" v8flags "^2.0.10" optionalDependencies: - chokidar "^1.0.0" + chokidar "^1.6.1" -babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26" +babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: chalk "^1.1.0" esutils "^2.0.2" - js-tokens "^2.0.0" - -babel-core@^6.11.4, babel-core@^6.18.0, babel-core@^6.20.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.21.0.tgz#75525480c21c803f826ef3867d22c19f080a3724" - dependencies: - babel-code-frame "^6.20.0" - babel-generator "^6.21.0" - babel-helpers "^6.16.0" - babel-messages "^6.8.0" - babel-register "^6.18.0" - babel-runtime "^6.20.0" - babel-template "^6.16.0" - babel-traverse "^6.21.0" - babel-types "^6.21.0" + js-tokens "^3.0.0" + +babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.20.0, babel-core@^6.23.0: + version "6.23.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.23.0" + babel-helpers "^6.23.0" + babel-messages "^6.23.0" + babel-register "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" babylon "^6.11.0" convert-source-map "^1.1.0" debug "^2.1.1" @@ -495,169 +502,191 @@ babel-eslint@^7.1.1: babylon "^6.13.0" lodash.pickby "^4.6.0" -babel-generator@^6.21.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.21.0.tgz#605f1269c489a1c75deeca7ea16d43d4656c8494" +babel-generator@^6.18.0, babel-generator@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5" dependencies: - babel-messages "^6.8.0" - babel-runtime "^6.20.0" - babel-types "^6.21.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.2.0" source-map "^0.5.0" + trim-right "^1.0.1" -babel-helper-bindify-decorators@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.18.0.tgz#fc00c573676a6e702fffa00019580892ec8780a5" +babel-helper-bindify-decorators@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.22.0.tgz#d7f5bc261275941ac62acfc4e20dacfb8a3fe952" dependencies: - babel-runtime "^6.0.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" -babel-helper-builder-binary-assignment-operator-visitor@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.18.0.tgz#8ae814989f7a53682152e3401a04fabd0bb333a6" +babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" dependencies: - babel-helper-explode-assignable-expression "^6.18.0" - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-helper-explode-assignable-expression "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-helper-builder-react-jsx@^6.8.0: - version "6.21.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.21.1.tgz#c4a24208655be9dc1cccf14d366da176f20645e4" +babel-helper-builder-react-jsx@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.23.0.tgz#d53fc8c996e0bc56d0de0fc4cc55a7138395ea4b" dependencies: - babel-runtime "^6.9.0" - babel-types "^6.21.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" esutils "^2.0.0" lodash "^4.2.0" -babel-helper-call-delegate@^6.18.0, babel-helper-call-delegate@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" +babel-helper-call-delegate@^6.22.0, babel-helper-call-delegate@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" dependencies: - babel-helper-hoist-variables "^6.18.0" - babel-runtime "^6.0.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" -babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" +babel-helper-define-map@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7" dependencies: - babel-helper-function-name "^6.18.0" - babel-runtime "^6.9.0" - babel-types "^6.18.0" + babel-helper-function-name "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" lodash "^4.2.0" -babel-helper-explode-assignable-expression@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.18.0.tgz#14b8e8c2d03ad735d4b20f1840b24cd1f65239fe" +babel-helper-explode-assignable-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" dependencies: - babel-runtime "^6.0.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" -babel-helper-explode-class@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.18.0.tgz#c44f76f4fa23b9c5d607cbac5d4115e7a76f62cb" +babel-helper-explode-class@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.22.0.tgz#646304924aa6388a516843ba7f1855ef8dfeb69b" dependencies: - babel-helper-bindify-decorators "^6.18.0" - babel-runtime "^6.0.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-helper-bindify-decorators "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" -babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" +babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0, babel-helper-function-name@^6.8.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" dependencies: - babel-helper-get-function-arity "^6.18.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" -babel-helper-get-function-arity@^6.18.0, babel-helper-get-function-arity@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" +babel-helper-get-function-arity@^6.22.0, babel-helper-get-function-arity@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-helper-hoist-variables@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" +babel-helper-hoist-variables@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-helper-optimise-call-expression@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" +babel-helper-optimise-call-expression@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" -babel-helper-regex@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" +babel-helper-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" dependencies: - babel-runtime "^6.9.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" lodash "^4.2.0" -babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.16.2: - version "6.20.3" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.20.3.tgz#9dd3b396f13e35ef63e538098500adc24c63c4e7" +babel-helper-remap-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" dependencies: - babel-helper-function-name "^6.18.0" - babel-runtime "^6.20.0" - babel-template "^6.16.0" - babel-traverse "^6.20.0" - babel-types "^6.20.0" + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" -babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" +babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd" dependencies: - babel-helper-optimise-call-expression "^6.18.0" - babel-messages "^6.8.0" - babel-runtime "^6.0.0" - babel-template "^6.16.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-helper-optimise-call-expression "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" -babel-helpers@^6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" +babel-helpers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" dependencies: - babel-runtime "^6.0.0" - babel-template "^6.16.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-jest@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-18.0.0.tgz#17ebba8cb3285c906d859e8707e4e79795fb65e3" + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^3.0.0" + babel-preset-jest "^18.0.0" babel-loader@^6.2.4: - version "6.2.10" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0" + version "6.3.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.3.2.tgz#18de4566385578c1b4f8ffe6cbc668f5e2a5ef03" dependencies: find-cache-dir "^0.1.1" - loader-utils "^0.2.11" + loader-utils "^0.2.16" mkdirp "^0.5.1" object-assign "^4.0.1" -babel-messages@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" babel-plugin-add-react-displayname@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.4.tgz#bc2a74bcbee6e505025b3352fea85ee7bc4c6f7c" -babel-plugin-check-es2015-constants@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" +babel-plugin-check-es2015-constants@^6.22.0, babel-plugin-check-es2015-constants@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" + +babel-plugin-istanbul@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-3.1.2.tgz#11d5abde18425ec24b5d648c7e0b5d25cd354a22" + dependencies: + find-up "^1.1.2" + istanbul-lib-instrument "^1.4.2" + object-assign "^4.1.0" + test-exclude "^3.3.0" + +babel-plugin-jest-hoist@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz#4150e70ecab560e6e7344adc849498072d34e12a" babel-plugin-react-docgen@^1.4.2: version "1.4.2" @@ -719,40 +748,40 @@ babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" -babel-plugin-syntax-trailing-function-commas@^6.13.0, babel-plugin-syntax-trailing-function-commas@^6.3.13, babel-plugin-syntax-trailing-function-commas@^6.8.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.20.0.tgz#442835e19179f45b87e92d477d70b9f1f18b5c4f" +babel-plugin-syntax-trailing-function-commas@^6.13.0, babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-generator-functions@^6.17.0: - version "6.17.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.17.0.tgz#d0b5a2b2f0940f2b245fa20a00519ed7bc6cae54" +babel-plugin-transform-async-generator-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.22.0.tgz#a720a98153a7596f204099cd5409f4b3c05bab46" dependencies: - babel-helper-remap-async-to-generator "^6.16.2" + babel-helper-remap-async-to-generator "^6.22.0" babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-async-to-generator@^6.16.0, babel-plugin-transform-async-to-generator@^6.8.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" dependencies: - babel-helper-remap-async-to-generator "^6.16.0" + babel-helper-remap-async-to-generator "^6.22.0" babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-builtin-extend@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-builtin-extend/-/babel-plugin-transform-builtin-extend-1.1.0.tgz#460c9f3801467ea373366987c9638f939867dfa4" +babel-plugin-transform-builtin-extend@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-builtin-extend/-/babel-plugin-transform-builtin-extend-1.1.2.tgz#5e96fecf58b8fa1ed74efcad88475b2af3c9116e" dependencies: babel-runtime "^6.2.0" babel-template "^6.3.0" -babel-plugin-transform-class-constructor-call@^6.3.13: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.18.0.tgz#80855e38a1ab47b8c6c647f8ea1bcd2c00ca3aae" +babel-plugin-transform-class-constructor-call@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.22.0.tgz#11a4d2216abb5b0eef298b493748f4f2f4869120" dependencies: babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" babel-plugin-transform-class-properties@6.16.0: version "6.16.0" @@ -762,14 +791,14 @@ babel-plugin-transform-class-properties@6.16.0: babel-plugin-syntax-class-properties "^6.8.0" babel-runtime "^6.9.1" -babel-plugin-transform-class-properties@^6.18.0: - version "6.19.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f" +babel-plugin-transform-class-properties@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b" dependencies: - babel-helper-function-name "^6.18.0" + babel-helper-function-name "^6.23.0" babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.9.1" - babel-template "^6.15.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.4" @@ -779,67 +808,65 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-runtime "^6.2.0" babel-template "^6.3.0" -babel-plugin-transform-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.13.0.tgz#82d65c1470ae83e2d13eebecb0a1c2476d62da9d" +babel-plugin-transform-decorators@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.22.0.tgz#c03635b27a23b23b7224f49232c237a73988d27c" dependencies: - babel-helper-define-map "^6.8.0" - babel-helper-explode-class "^6.8.0" + babel-helper-explode-class "^6.22.0" babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" - babel-types "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-types "^6.22.0" -babel-plugin-transform-do-expressions@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.8.0.tgz#fda692af339835cc255bb7544efb8f7c1306c273" +babel-plugin-transform-do-expressions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" dependencies: babel-plugin-syntax-do-expressions "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-arrow-functions@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" +babel-plugin-transform-es2015-arrow-functions@^6.22.0, babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0, babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.18.0, babel-plugin-transform-es2015-block-scoping@^6.6.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.21.0.tgz#e840687f922e70fb2c42bb13501838c174a115ed" +babel-plugin-transform-es2015-block-scoping@^6.22.0, babel-plugin-transform-es2015-block-scoping@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51" dependencies: - babel-runtime "^6.20.0" - babel-template "^6.15.0" - babel-traverse "^6.21.0" - babel-types "^6.21.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" lodash "^4.2.0" -babel-plugin-transform-es2015-classes@^6.18.0, babel-plugin-transform-es2015-classes@^6.6.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" +babel-plugin-transform-es2015-classes@^6.22.0, babel-plugin-transform-es2015-classes@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1" dependencies: - babel-helper-define-map "^6.18.0" - babel-helper-function-name "^6.18.0" - babel-helper-optimise-call-expression "^6.18.0" - babel-helper-replace-supers "^6.18.0" - babel-messages "^6.8.0" - babel-runtime "^6.9.0" - babel-template "^6.14.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" + babel-helper-define-map "^6.23.0" + babel-helper-function-name "^6.23.0" + babel-helper-optimise-call-expression "^6.23.0" + babel-helper-replace-supers "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" -babel-plugin-transform-es2015-computed-properties@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" dependencies: - babel-helper-define-map "^6.8.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" babel-plugin-transform-es2015-destructuring@6.16.0: version "6.16.0" @@ -847,78 +874,78 @@ babel-plugin-transform-es2015-destructuring@6.16.0: dependencies: babel-runtime "^6.9.0" -babel-plugin-transform-es2015-destructuring@^6.18.0, babel-plugin-transform-es2015-destructuring@^6.6.0: - version "6.19.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: - babel-runtime "^6.9.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.6.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.8.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-plugin-transform-es2015-for-of@^6.18.0, babel-plugin-transform-es2015-for-of@^6.6.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.3.13, babel-plugin-transform-es2015-function-name@^6.9.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" dependencies: - babel-helper-function-name "^6.8.0" - babel-runtime "^6.9.0" - babel-types "^6.9.0" + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-plugin-transform-es2015-literals@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" +babel-plugin-transform-es2015-literals@^6.22.0, babel-plugin-transform-es2015-literals@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-modules-amd@^6.18.0, babel-plugin-transform-es2015-modules-amd@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.18.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" -babel-plugin-transform-es2015-modules-commonjs@^6.18.0, babel-plugin-transform-es2015-modules-commonjs@^6.6.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" +babel-plugin-transform-es2015-modules-commonjs@^6.22.0, babel-plugin-transform-es2015-modules-commonjs@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.23.0.tgz#cba7aa6379fb7ec99250e6d46de2973aaffa7b92" dependencies: - babel-plugin-transform-strict-mode "^6.18.0" - babel-runtime "^6.0.0" - babel-template "^6.16.0" - babel-types "^6.18.0" + babel-plugin-transform-strict-mode "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-types "^6.23.0" -babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-es2015-modules-systemjs@^6.18.0: - version "6.19.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" +babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-es2015-modules-systemjs@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0" dependencies: - babel-helper-hoist-variables "^6.18.0" - babel-runtime "^6.11.6" - babel-template "^6.14.0" + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" -babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015-modules-umd@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" +babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015-modules-umd@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.23.0.tgz#8d284ae2e19ed8fe21d2b1b26d6e7e0fcd94f0f1" dependencies: - babel-plugin-transform-es2015-modules-amd "^6.18.0" - babel-runtime "^6.0.0" - babel-template "^6.8.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" -babel-plugin-transform-es2015-object-super@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" dependencies: - babel-helper-replace-supers "^6.8.0" - babel-runtime "^6.0.0" + babel-helper-replace-supers "^6.22.0" + babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@6.17.0: version "6.17.0" @@ -931,127 +958,148 @@ babel-plugin-transform-es2015-parameters@6.17.0: babel-traverse "^6.16.0" babel-types "^6.16.0" -babel-plugin-transform-es2015-parameters@^6.18.0, babel-plugin-transform-es2015-parameters@^6.6.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.21.0.tgz#46a655e6864ef984091448cdf024d87b60b2a7d8" +babel-plugin-transform-es2015-parameters@^6.22.0, babel-plugin-transform-es2015-parameters@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b" dependencies: - babel-helper-call-delegate "^6.18.0" - babel-helper-get-function-arity "^6.18.0" - babel-runtime "^6.9.0" - babel-template "^6.16.0" - babel-traverse "^6.21.0" - babel-types "^6.21.0" + babel-helper-call-delegate "^6.22.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" -babel-plugin-transform-es2015-shorthand-properties@^6.18.0, babel-plugin-transform-es2015-shorthand-properties@^6.3.13: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-plugin-transform-es2015-spread@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" +babel-plugin-transform-es2015-spread@^6.22.0, babel-plugin-transform-es2015-spread@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" dependencies: - babel-helper-regex "^6.8.0" - babel-runtime "^6.0.0" - babel-types "^6.8.0" + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-plugin-transform-es2015-template-literals@^6.6.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" +babel-plugin-transform-es2015-template-literals@^6.22.0, babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.18.0, babel-plugin-transform-es2015-typeof-symbol@^6.6.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.6.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.3.13: - version "6.11.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" dependencies: - babel-helper-regex "^6.8.0" - babel-runtime "^6.0.0" + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.3.13, babel-plugin-transform-exponentiation-operator@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.8.0.tgz#db25742e9339eade676ca9acec46f955599a68a4" +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.8.0" + babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-export-extensions@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.8.0.tgz#fa80ff655b636549431bfd38f6b817bd82e47f5b" +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" dependencies: babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-flow-strip-types@^6.3.13, babel-plugin-transform-flow-strip-types@^6.8.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.21.0.tgz#2eea3f8b5bb234339b47283feac155cfb237b948" +babel-plugin-transform-flow-strip-types@^6.22.0, babel-plugin-transform-flow-strip-types@^6.3.13, babel-plugin-transform-flow-strip-types@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" dependencies: babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-function-bind@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.8.0.tgz#e7f334ce69f50d28fe850a822eaaab9fa4f4d821" +babel-plugin-transform-function-bind@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97" dependencies: babel-plugin-syntax-function-bind "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-object-rest-spread@6.16.0, babel-plugin-transform-object-rest-spread@^6.16.0: +babel-plugin-transform-object-rest-spread@6.16.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9" dependencies: babel-plugin-syntax-object-rest-spread "^6.8.0" babel-runtime "^6.0.0" +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.22.0" + babel-plugin-transform-react-constant-elements@6.9.1: version "6.9.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.9.1.tgz#125b86d96cb322e2139b607fd749ad5fbb17f005" dependencies: babel-runtime "^6.9.1" -babel-plugin-transform-react-display-name@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.8.0.tgz#f7a084977383d728bdbdc2835bba0159577f660e" +babel-plugin-transform-react-display-name@^6.23.0, babel-plugin-transform-react-display-name@^6.3.13: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" -babel-plugin-transform-react-jsx-self@6.11.0, babel-plugin-transform-react-jsx-self@^6.11.0: +babel-plugin-transform-react-jsx-self@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4" dependencies: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.9.0" -babel-plugin-transform-react-jsx-source@6.9.0, babel-plugin-transform-react-jsx-source@^6.3.13: +babel-plugin-transform-react-jsx-self@^6.11.0, babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@6.9.0: version "6.9.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00" dependencies: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.9.0" -babel-plugin-transform-react-jsx@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.8.0.tgz#94759942f70af18c617189aa7f3593f1644a71ab" +babel-plugin-transform-react-jsx-source@^6.22.0, babel-plugin-transform-react-jsx-source@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" dependencies: - babel-helper-builder-react-jsx "^6.8.0" babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.23.0, babel-plugin-transform-react-jsx@^6.3.13: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.23.0.tgz#23e892f7f2e759678eb5e4446a8f8e94e81b3470" + dependencies: + babel-helper-builder-react-jsx "^6.23.0" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" babel-plugin-transform-regenerator@6.16.1: version "6.16.1" @@ -1061,9 +1109,9 @@ babel-plugin-transform-regenerator@6.16.1: babel-types "^6.16.0" private "~0.1.5" -babel-plugin-transform-regenerator@^6.16.0, babel-plugin-transform-regenerator@^6.6.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.21.0.tgz#75d0c7e7f84f379358f508451c68a2c5fa5a9703" +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.6.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" dependencies: regenerator-transform "0.9.8" @@ -1073,18 +1121,18 @@ babel-plugin-transform-runtime@6.15.0: dependencies: babel-runtime "^6.9.0" -babel-plugin-transform-strict-mode@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" +babel-plugin-transform-strict-mode@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" dependencies: - babel-runtime "^6.0.0" - babel-types "^6.18.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" -babel-polyfill@^6.16.0, babel-polyfill@^6.6.1: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.20.0.tgz#de4a371006139e20990aac0be367d398331204e7" +babel-polyfill@^6.23.0, babel-polyfill@^6.6.1: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" dependencies: - babel-runtime "^6.20.0" + babel-runtime "^6.22.0" core-js "^2.4.0" regenerator-runtime "^0.10.0" @@ -1122,46 +1170,58 @@ babel-preset-env@0.0.6: browserslist "^1.4.0" babel-preset-es2015@^6.16.0, babel-preset-es2015@^6.6.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" - dependencies: - babel-plugin-check-es2015-constants "^6.3.13" - babel-plugin-transform-es2015-arrow-functions "^6.3.13" - babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" - babel-plugin-transform-es2015-block-scoping "^6.18.0" - babel-plugin-transform-es2015-classes "^6.18.0" - babel-plugin-transform-es2015-computed-properties "^6.3.13" - babel-plugin-transform-es2015-destructuring "^6.18.0" - babel-plugin-transform-es2015-duplicate-keys "^6.6.0" - babel-plugin-transform-es2015-for-of "^6.18.0" - babel-plugin-transform-es2015-function-name "^6.9.0" - babel-plugin-transform-es2015-literals "^6.3.13" - babel-plugin-transform-es2015-modules-amd "^6.18.0" - babel-plugin-transform-es2015-modules-commonjs "^6.18.0" - babel-plugin-transform-es2015-modules-systemjs "^6.18.0" - babel-plugin-transform-es2015-modules-umd "^6.18.0" - babel-plugin-transform-es2015-object-super "^6.3.13" - babel-plugin-transform-es2015-parameters "^6.18.0" - babel-plugin-transform-es2015-shorthand-properties "^6.18.0" - babel-plugin-transform-es2015-spread "^6.3.13" - babel-plugin-transform-es2015-sticky-regex "^6.3.13" - babel-plugin-transform-es2015-template-literals "^6.6.0" - babel-plugin-transform-es2015-typeof-symbol "^6.18.0" - babel-plugin-transform-es2015-unicode-regex "^6.3.13" - babel-plugin-transform-regenerator "^6.16.0" + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.22.0" + babel-plugin-transform-es2015-classes "^6.22.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-plugin-transform-es2015-modules-systemjs "^6.22.0" + babel-plugin-transform-es2015-modules-umd "^6.22.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.22.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" babel-preset-es2016@^6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.16.0.tgz#c7daf5feedeee99c867813bdf0d573d94ca12812" + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz#b061aaa3983d40c9fbacfa3743b5df37f336156c" dependencies: - babel-plugin-transform-exponentiation-operator "^6.3.13" + babel-plugin-transform-exponentiation-operator "^6.22.0" babel-preset-es2017@^6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.16.0.tgz#536c6287778a758948ddd092b466b6ef50b786fa" + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz#de2f9da5a30c50d293fb54a0ba15d6ddc573f0f2" dependencies: - babel-plugin-syntax-trailing-function-commas "^6.8.0" - babel-plugin-transform-async-to-generator "^6.16.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + +babel-preset-jest@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-18.0.0.tgz#84faf8ca3ec65aba7d5e3f59bbaed935ab24049e" + dependencies: + babel-plugin-jest-hoist "^18.0.0" babel-preset-latest@6.16.0: version "6.16.0" @@ -1189,7 +1249,7 @@ babel-preset-react-app@^1.0.0: babel-preset-react "6.16.0" babel-runtime "6.11.6" -babel-preset-react@6.16.0, babel-preset-react@^6.5.0: +babel-preset-react@6.16.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.16.0.tgz#aa117d60de0928607e343c4828906e4661824316" dependencies: @@ -1201,47 +1261,58 @@ babel-preset-react@6.16.0, babel-preset-react@^6.5.0: babel-plugin-transform-react-jsx-self "^6.11.0" babel-plugin-transform-react-jsx-source "^6.3.13" -babel-preset-stage-0@^6.5.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.16.0.tgz#f5a263c420532fd57491f1a7315b3036e428f823" +babel-preset-react@^6.5.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.23.0.tgz#eb7cee4de98a3f94502c28565332da9819455195" dependencies: - babel-plugin-transform-do-expressions "^6.3.13" - babel-plugin-transform-function-bind "^6.3.13" - babel-preset-stage-1 "^6.16.0" - -babel-preset-stage-1@^6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.16.0.tgz#9d31fbbdae7b17c549fd3ac93e3cf6902695e479" - dependencies: - babel-plugin-transform-class-constructor-call "^6.3.13" - babel-plugin-transform-export-extensions "^6.3.13" - babel-preset-stage-2 "^6.16.0" + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.23.0" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" -babel-preset-stage-2@^6.16.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.18.0.tgz#9eb7bf9a8e91c68260d5ba7500493caaada4b5b5" +babel-preset-stage-0@^6.5.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz#707eeb5b415da769eff9c42f4547f644f9296ef9" dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.18.0" - babel-plugin-transform-decorators "^6.13.0" - babel-preset-stage-3 "^6.17.0" + babel-plugin-transform-do-expressions "^6.22.0" + babel-plugin-transform-function-bind "^6.22.0" + babel-preset-stage-1 "^6.22.0" -babel-preset-stage-3@^6.17.0: - version "6.17.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.17.0.tgz#b6638e46db6e91e3f889013d8ce143917c685e39" +babel-preset-stage-1@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.22.0.tgz#7da05bffea6ad5a10aef93e320cfc6dd465dbc1a" dependencies: - babel-plugin-syntax-trailing-function-commas "^6.3.13" - babel-plugin-transform-async-generator-functions "^6.17.0" - babel-plugin-transform-async-to-generator "^6.16.0" - babel-plugin-transform-exponentiation-operator "^6.3.13" - babel-plugin-transform-object-rest-spread "^6.16.0" + babel-plugin-transform-class-constructor-call "^6.22.0" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.22.0" -babel-register@^6.11.6, babel-register@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" +babel-preset-stage-2@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07" dependencies: - babel-core "^6.18.0" - babel-runtime "^6.11.6" + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.22.0" + babel-plugin-transform-decorators "^6.22.0" + babel-preset-stage-3 "^6.22.0" + +babel-preset-stage-3@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.22.0.tgz#a4e92bbace7456fafdf651d7a7657ee0bbca9c2e" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.11.6, babel-register@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3" + dependencies: + babel-core "^6.23.0" + babel-runtime "^6.22.0" core-js "^2.4.0" home-or-tmp "^2.0.0" lodash "^4.2.0" @@ -1255,49 +1326,49 @@ babel-runtime@6.11.6: core-js "^2.4.0" regenerator-runtime "^0.9.5" -babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.20.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f" +babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.3.0, babel-template@^6.8.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" +babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0, babel-template@^6.3.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" dependencies: - babel-runtime "^6.9.0" - babel-traverse "^6.16.0" - babel-types "^6.16.0" + babel-runtime "^6.22.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" babylon "^6.11.0" lodash "^4.2.0" -babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.20.0, babel-traverse@^6.21.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad" +babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: + version "6.23.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" dependencies: - babel-code-frame "^6.20.0" - babel-messages "^6.8.0" - babel-runtime "^6.20.0" - babel-types "^6.21.0" - babylon "^6.11.0" + babel-code-frame "^6.22.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + babylon "^6.15.0" debug "^2.2.0" globals "^9.0.0" invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.13.0, babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.20.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2" +babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" dependencies: - babel-runtime "^6.20.0" + babel-runtime "^6.22.0" esutils "^2.0.2" lodash "^4.2.0" to-fast-properties "^1.0.1" -babylon@^6.11.0, babylon@^6.13.0: - version "6.14.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" +babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" babylon@~5.8.3: version "5.8.38" @@ -1307,7 +1378,7 @@ backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" -balanced-match@0.1.0, balanced-match@~0.1.0: +balanced-match@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" @@ -1319,32 +1390,28 @@ balanced-match@^0.4.1, balanced-match@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" -base64-arraybuffer@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz#474df4a9f2da24e05df3158c3b1db3c3cd46a154" +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" -base64id@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" batch@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" bcrypt-pbkdf@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" -benchmark@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-1.0.0.tgz#2f1e2fa4c359f11122aa183082218e957e390c73" - better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -1369,10 +1436,6 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@2.9.6: - version "2.9.6" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.9.6.tgz#1fc3a6b1685267dc121b5ec89b32ce069d81ab7d" - bluebird@^3.3.0, bluebird@^3.3.3, bluebird@^3.4.7: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" @@ -1385,20 +1448,20 @@ bo-selector@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/bo-selector/-/bo-selector-0.0.10.tgz#9816dcb00adf374ea87941a863b2acfc026afa3e" -body-parser@^1.12.4: - version "1.15.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" +body-parser@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.16.1.tgz#51540d045adfa7a0c6995a014bb6b1ed9b802329" dependencies: bytes "2.4.0" content-type "~1.0.2" - debug "~2.2.0" + debug "2.6.1" depd "~1.1.0" - http-errors "~1.5.0" - iconv-lite "0.4.13" + http-errors "~1.5.1" + iconv-lite "0.4.15" on-finished "~2.3.0" - qs "6.2.0" - raw-body "~2.1.7" - type-is "~1.6.13" + qs "6.2.1" + raw-body "~2.2.0" + type-is "~1.6.14" boolbase@~1.0.0: version "1.0.0" @@ -1432,8 +1495,14 @@ braces@^1.8.2: repeat-element "^1.1.2" brorand@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" + version "1.0.7" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.7.tgz#6677fa5e4901bdbf9c9ec2a748e28dca407a9bfc" + +browser-resolve@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" browserify-aes@0.4.0: version "0.4.0" @@ -1492,11 +1561,18 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^1.0.0, browserslist@^1.0.1, browserslist@^1.4.0, browserslist@~1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.1.tgz#67c3f2a1a6ad174cd01d25d2362e6e6083b26986" +browserslist@^1.0.0, browserslist@^1.0.1, browserslist@^1.4.0, browserslist@^1.5.2, browserslist@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.4.tgz#56a12da876f787223743a866224ccd8f97014628" + dependencies: + caniuse-db "^1.0.30000624" + electron-to-chromium "^1.2.2" + +bser@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" dependencies: - caniuse-db "^1.0.30000601" + node-int64 "^0.4.0" buffer-shims@^1.0.0: version "1.0.0" @@ -1522,13 +1598,13 @@ buffered-spawn@~1.1.1: err-code "^0.1.0" q "^1.0.1" -builtin-modules@^1.1.1: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -builtin-status-codes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-2.0.0.tgz#6f22003baacf003ccd287afe6872151fddc58579" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" bytes@2.3.0: version "2.3.0" @@ -1552,6 +1628,10 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + camel-case@3.0.x: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -1563,19 +1643,29 @@ camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" -caniuse-api@^1.3.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.2.tgz#8f393c682f661c0a997b77bba6e826483fb3600e" +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +caniuse-api@^1.3.2, caniuse-api@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.3.tgz#5018e674b51c393e4d50614275dc017e27c4a2a2" dependencies: browserslist "^1.0.1" caniuse-db "^1.0.30000346" lodash.memoize "^4.1.0" lodash.uniq "^4.3.0" - shelljs "^0.7.0" -caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000601, caniuse-db@^1.0.30000604: - version "1.0.30000604" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000604.tgz#bc139270a777564d19c0aadcd832b491d093bda5" +caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000624: + version "1.0.30000624" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000624.tgz#554b87547895e36f5fe128f4b7448a2ea5bf2213" + +cardinal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + dependencies: + ansicolors "~0.2.1" + redeyed "~1.0.0" case-sensitive-paths-webpack-plugin@^1.1.2: version "1.1.4" @@ -1616,11 +1706,32 @@ change-emitter@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.2.tgz#6b88ca4d5d864e516f913421b11899a860aee8db" +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + chevrotain@^0.21.0: - version "0.21.0" - resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-0.21.0.tgz#7e54eee5abb049caf2421c32b56c848e2cb64f71" + version "0.21.1" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-0.21.1.tgz#93103242bcfaed2f36d472aa8abaaf6aa39169c5" -chokidar@^1.0.0, chokidar@^1.4.1: +chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" dependencies: @@ -1635,6 +1746,10 @@ chokidar@^1.0.0, chokidar@^1.4.1: optionalDependencies: fsevents "^1.0.0" +ci-info@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534" + cipher-base@^1.0.0, cipher-base@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" @@ -1655,12 +1770,11 @@ classnames@^2.1.3, classnames@^2.2.3, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" -clean-css@3.4.x: - version "3.4.23" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.23.tgz#604fbbca24c12feb59b02f00b84f1fb7ded6d001" +clean-css@4.0.x: + version "4.0.7" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.7.tgz#d8fa8b4d87a125f38fa3d64afc59abfc68ba7790" dependencies: - commander "2.8.x" - source-map "0.4.x" + source-map "0.5.x" cli-color@^0.3.2: version "0.3.3" @@ -1677,6 +1791,19 @@ cli-cursor@^1.0.1: dependencies: restore-cursor "^1.0.1" +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + +cli-usage@^0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/cli-usage/-/cli-usage-0.1.4.tgz#7c01e0dc706c234b39c933838c8e20b2175776e2" + dependencies: + marked "^0.3.6" + marked-terminal "^1.6.2" + cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" @@ -1689,6 +1816,14 @@ cliui@^2.1.0: right-align "^0.1.1" wordwrap "0.0.2" +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + clone@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" @@ -1712,8 +1847,8 @@ color-convert@^0.5.3: resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" color-convert@^1.3.0, color-convert@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.8.2.tgz#be868184d7c8631766d54e7078e2672d7c7e3339" + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: color-name "^1.1.1" @@ -1764,7 +1899,7 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" -colors@1.0.x: +colors@1.0.3, colors@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" @@ -1788,12 +1923,6 @@ commander@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" -commander@2.8.x: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" - commander@2.9.x, commander@^2.8.1, commander@^2.9.0, commander@~2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" @@ -1818,9 +1947,9 @@ component-emitter@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" -component-emitter@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe" +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" @@ -1856,16 +1985,16 @@ concat-stream@^1.4.6: typedarray "^0.0.6" concurrently@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.1.0.tgz#dc5ef0459090012604756668894c04b434ef90d1" + version "3.3.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.3.0.tgz#d8eb7a9765fdf0b28d12220dc058e14d03c7dd4f" dependencies: - bluebird "2.9.6" chalk "0.5.1" commander "2.6.0" + date-fns "^1.23.0" lodash "^4.5.1" - moment "^2.11.2" rx "2.3.24" - spawn-default-shell "^1.1.0" + spawn-command "^0.0.2-1" + supports-color "^3.2.3" tree-kill "^1.1.0" configstore@^2.0.0: @@ -1886,12 +2015,12 @@ connect-history-api-fallback@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" -connect@^3.3.5: - version "3.5.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198" +connect@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.0.tgz#f09a4f7dcd17324b663b725c815bdb1c4158a46e" dependencies: - debug "~2.2.0" - finalhandler "0.5.0" + debug "2.6.1" + finalhandler "1.0.0" parseurl "~1.3.1" utils-merge "1.0.0" @@ -1913,9 +2042,9 @@ contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -content-disposition@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type-parser@^1.0.1: version "1.0.1" @@ -1926,8 +2055,8 @@ content-type@~1.0.2: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" convert-source-map@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + version "1.4.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" cookie-signature@1.0.6: version "1.0.6" @@ -2064,7 +2193,7 @@ css-loader@^0.26.1: postcss-modules-values "^1.1.0" source-list-map "^0.1.4" -css-select@^1.1.0: +css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" dependencies: @@ -2141,18 +2270,18 @@ cssesc@^0.1.0: postcss-value-parser "^3.2.3" postcss-zindex "^2.0.1" -csso@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" +csso@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.1.tgz#4f8d91a156f2f1c2aebb40b8fb1b5eb83d94d3b9" dependencies: clap "^1.0.9" source-map "^0.5.3" -cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.1.tgz#c9e37ef2490e64f6d1baa10fda852257082c25d3" +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" -"cssstyle@>= 0.2.36 < 0.3.0": +"cssstyle@>= 0.2.37 < 0.3.0": version "0.2.37" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" dependencies: @@ -2182,24 +2311,24 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +date-fns@^1.23.0: + version "1.27.2" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.27.2.tgz#ce82f420bc028356cc661fc55c0494a56a990c9c" + date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" dc@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dc/-/dc-2.0.0.tgz#ec7b30afe0617085ed956789908b1ea1fcd0cf22" + version "2.1.3" + resolved "https://registry.yarnpkg.com/dc/-/dc-2.1.3.tgz#472d6930b8b5a98850a066b9cb705127834980f5" dependencies: crossfilter2 "~1.3" d3 "^3" -debug@0.7.4, debug@~0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - -debug@2, debug@^2.1.1, debug@^2.2.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" +debug@2, debug@2.6.1, debug@^2.1.1, debug@^2.2.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" dependencies: ms "0.7.2" @@ -2209,7 +2338,17 @@ debug@2.2.0, debug@~2.2.0: dependencies: ms "0.7.1" -decamelize@^1.0.0, decamelize@^1.1.2: +debug@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +debug@~0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2229,6 +2368,12 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -2285,7 +2430,7 @@ di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" -diff@^3.2.0: +diff@^3.0.0, diff@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" @@ -2325,9 +2470,9 @@ dom-converter@~0.1: dependencies: utila "~0.3" -dom-helpers@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367" +"dom-helpers@^2.4.0 || ^3.0.0": + version "3.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" dom-serialize@^2.2.0: version "2.2.1" @@ -2338,7 +2483,7 @@ dom-serialize@^2.2.0: extend "^3.0.0" void-elements "^2.0.0" -dom-serializer@0: +dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" dependencies: @@ -2349,7 +2494,7 @@ domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" -domelementtype@1: +domelementtype@1, domelementtype@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" @@ -2363,13 +2508,19 @@ domhandler@2.1: dependencies: domelementtype "1" +domhandler@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + dependencies: + domelementtype "1" + domutils@1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" dependencies: domelementtype "1" -domutils@1.5.1: +domutils@1.5.1, domutils@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" dependencies: @@ -2392,13 +2543,17 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +electron-to-chromium@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.2.tgz#e41bc9488c88e3cfa1e94bde28e8420d7d47c47c" + element-class@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/element-class/-/element-class-0.2.2.tgz#9d3bbd0767f9013ef8e1c8ebe722c1402a60050e" elliptic@^6.0.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" + version "6.3.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2419,43 +2574,44 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" -engine.io-client@1.6.9: - version "1.6.9" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.6.9.tgz#1d6ad48048a5083c95096943b29d36efdb212401" +engine.io-client@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab" dependencies: - component-emitter "1.1.2" + component-emitter "1.2.1" component-inherit "0.0.3" - debug "2.2.0" - engine.io-parser "1.2.4" + debug "2.3.3" + engine.io-parser "1.3.2" has-cors "1.1.0" indexof "0.0.1" - parsejson "0.0.1" - parseqs "0.0.2" - parseuri "0.0.4" - ws "1.0.1" - xmlhttprequest-ssl "1.5.1" + parsejson "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + ws "1.1.2" + xmlhttprequest-ssl "1.5.3" yeast "0.1.2" -engine.io-parser@1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.2.4.tgz#e0897b0bf14e792d4cd2a5950553919c56948c42" +engine.io-parser@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a" dependencies: - after "0.8.1" + after "0.8.2" arraybuffer.slice "0.0.6" - base64-arraybuffer "0.1.2" + base64-arraybuffer "0.1.5" blob "0.0.4" - has-binary "0.1.6" - utf8 "2.1.0" + has-binary "0.1.7" + wtf-8 "1.0.0" -engine.io@1.6.10: - version "1.6.10" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.6.10.tgz#f87d84e1bd21d1a2ec7f8deef0c62054acdfb27a" +engine.io@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.3.tgz#8de7f97895d20d39b85f88eeee777b2bd42b13d4" dependencies: - accepts "1.1.4" - base64id "0.1.0" - debug "2.2.0" - engine.io-parser "1.2.4" - ws "1.0.1" + accepts "1.3.3" + base64id "1.0.0" + cookie "0.3.1" + debug "2.3.3" + engine.io-parser "1.3.2" + ws "1.1.2" enhanced-resolve@~0.9.0: version "0.9.1" @@ -2469,15 +2625,29 @@ ent@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" -entities@~1.1.1: +entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +enzyme@^2.7.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.7.1.tgz#76370e1d99e91f73091bb8c4314b7c128cc2d621" + dependencies: + cheerio "^0.22.0" + function.prototype.name "^1.0.0" + is-subset "^0.1.1" + lodash "^4.17.2" + object-is "^1.0.1" + object.assign "^4.0.4" + object.entries "^1.0.3" + object.values "^1.0.3" + uuid "^2.0.3" + err-code@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-0.1.2.tgz#122a92b3342b9899da02b5ac994d30f95d4763ee" -errno@^0.1.3: +"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" dependencies: @@ -2489,9 +2659,9 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.4.3, es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" +es-abstract@^1.4.3, es-abstract@^1.5.0, es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.0" @@ -2559,8 +2729,8 @@ es6-set@~0.1.3: event-emitter "~0.3.4" es6-shim@^0.35.1: - version "0.35.2" - resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.2.tgz#45c5b3eb2f792ed28f130d826239be50affb897f" + version "0.35.3" + resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26" es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: version "3.1.0" @@ -2631,8 +2801,8 @@ eslint-import-resolver-node@^0.2.0: resolve "^1.1.6" eslint-import-resolver-webpack@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.8.0.tgz#025b5887bd26f27489d1a33b7d7b40c2c14d9b83" + version "0.8.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.8.1.tgz#c7f8b4d5bd3c5b489457e5728c5db1c4ffbac9aa" dependencies: array-find "^1.0.0" debug "^2.2.0" @@ -2663,8 +2833,8 @@ eslint-module-utils@^2.0.0: pkg-dir "^1.0.0" eslint-plugin-flowtype@^2.22.0: - version "2.29.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.29.2.tgz#91b4fde0400c4c37ca4440b43bdbc95fc405bea9" + version "2.30.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.30.0.tgz#3054a265f9c8afe3046c3d41b72d32a736f9b4ae" dependencies: lodash "^4.15.0" @@ -2688,15 +2858,18 @@ eslint-plugin-jasmine@^2.2.0: resolved "https://registry.yarnpkg.com/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.2.0.tgz#7135879383c39a667c721d302b9f20f0389543de" eslint-plugin-react@^6.3.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.8.0.tgz#741ab5438a094532e5ce1bbb935d6832356f492d" + version "6.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.0.tgz#9c48b48d101554b5355413e7c64238abde6ef1ef" dependencies: + array.prototype.find "^2.0.1" doctrine "^1.2.2" + has "^1.0.1" jsx-ast-utils "^1.3.4" + object.assign "^4.0.4" eslint@^3.5.0: - version "3.12.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.12.2.tgz#6be5a9aa29658252abd7f91e9132bab1f26f3c34" + version "3.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.16.0.tgz#4a468ab93618a9eb6e3f1499038b38851f828630" dependencies: babel-code-frame "^6.16.0" chalk "^1.1.3" @@ -2704,7 +2877,7 @@ eslint@^3.5.0: debug "^2.1.1" doctrine "^1.2.2" escope "^3.6.0" - espree "^3.3.1" + espree "^3.4.0" estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" @@ -2728,26 +2901,30 @@ eslint@^3.5.0: require-uncached "^1.0.2" shelljs "^0.7.5" strip-bom "^3.0.0" - strip-json-comments "~1.0.1" + strip-json-comments "~2.0.1" table "^3.7.8" text-table "~0.2.0" user-home "^2.0.0" -espree@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" +espree@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" dependencies: - acorn "^4.0.1" + acorn "4.0.4" acorn-jsx "^3.0.0" esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@~3.1.0: +esprima@^3.1.1, esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" +esprima@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + esrecurse@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" @@ -2775,6 +2952,10 @@ etag@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" +etag@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + event-emitter@~0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" @@ -2790,7 +2971,7 @@ events@^1.0.0, events@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" -eventsource@~0.1.6: +eventsource@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" dependencies: @@ -2802,6 +2983,12 @@ evp_bytestokey@^1.0.0: dependencies: create-hash "^1.1.1" +exec-sh@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + dependencies: + merge "^1.1.3" + exenv@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.0.tgz#3835f127abf075bfe082d0aed4484057c78e3c89" @@ -2849,12 +3036,12 @@ exports-loader@^0.6.3: source-map "0.1.x" express@^4.13.3: - version "4.14.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + version "4.14.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" dependencies: accepts "~1.3.3" array-flatten "1.1.1" - content-disposition "0.5.1" + content-disposition "0.5.2" content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" @@ -2863,19 +3050,19 @@ express@^4.13.3: encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.7.0" - finalhandler "0.5.0" + finalhandler "0.5.1" fresh "0.3.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.2" + proxy-addr "~1.1.3" qs "6.2.0" range-parser "~1.2.0" - send "0.14.1" - serve-static "~1.11.1" - type-is "~1.6.13" + send "0.14.2" + serve-static "~1.11.2" + type-is "~1.6.14" utils-merge "1.0.0" vary "~1.1.0" @@ -2920,14 +3107,20 @@ faye-websocket@^0.10.0: websocket-driver ">=0.5.1" faye-websocket@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.0.tgz#d9ccf0e789e7db725d74bc4877d23aa42972ac50" + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" dependencies: websocket-driver ">=0.5.1" +fb-watchman@^1.8.0, fb-watchman@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" + dependencies: + bser "1.0.2" + fbjs@^0.8.1, fbjs@^0.8.4: - version "0.8.8" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.8.tgz#02f1b6e0ea0d46c24e0b51a2d24df069563a5ad6" + version "0.8.9" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14" dependencies: core-js "^1.0.0" isomorphic-fetch "^2.1.1" @@ -2961,6 +3154,13 @@ filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" @@ -2971,14 +3171,26 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" +finalhandler@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" dependencies: debug "~2.2.0" escape-html "~1.0.3" on-finished "~2.3.0" - statuses "~1.3.0" + statuses "~1.3.1" + unpipe "~1.0.0" + +finalhandler@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" + dependencies: + debug "2.6.1" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" unpipe "~1.0.0" find-cache-dir@^0.1.1: @@ -2993,7 +3205,7 @@ find-root@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/find-root/-/find-root-0.1.2.tgz#98d2267cff1916ccaf2743b3a0eea81d79d7dcd1" -find-up@^1.0.0: +find-up@^1.0.0, find-up@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: @@ -3057,6 +3269,10 @@ fresh@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" +fresh@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.4.0.tgz#475626a934a8d3480b2101a1d6ecef7dafd7c553" + fs-access@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" @@ -3098,8 +3314,8 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0: - version "1.0.17" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + version "1.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" dependencies: nan "^2.3.0" node-pre-gyp "^0.6.29" @@ -3125,6 +3341,14 @@ function-bind@^1.0.2, function-bind@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" +function.prototype.name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.0.tgz#5f523ca64e491a5f95aba80cc1e391080a14482e" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + is-callable "^1.1.2" + fuse.js@^2.2.0: version "2.6.1" resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.6.1.tgz#d118e00f9a859f7b354ed4f7740214249e32a57a" @@ -3134,8 +3358,8 @@ fuzzysearch@^1.0.3: resolved "https://registry.yarnpkg.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008" gauge@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + version "2.7.3" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -3144,7 +3368,6 @@ gauge@~2.7.1: signal-exit "^3.0.0" string-width "^1.0.1" strip-ansi "^3.0.1" - supports-color "^0.2.0" wide-align "^1.1.0" gen-css-identifier@^1.0.0: @@ -3161,6 +3384,10 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + getpass@^0.1.1: version "0.1.6" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" @@ -3180,16 +3407,6 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^5.0.5: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" @@ -3202,8 +3419,8 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: path-is-absolute "^1.0.0" globals@^9.0.0, globals@^9.14.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + version "9.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" globby@^5.0.0: version "5.0.0" @@ -3224,7 +3441,7 @@ gm@~1.21.1: array-series "~0.1.5" debug "~2.2.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3232,6 +3449,10 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" +growly@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + handlebars@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-1.3.0.tgz#9e9b130a93e389491322d975cf3ec1818c37ce34" @@ -3240,6 +3461,16 @@ handlebars@^1.3.0: optionalDependencies: uglify-js "~2.3" +handlebars@^4.0.3: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -3261,12 +3492,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-binary@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" - dependencies: - isarray "0.0.1" - has-binary@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" @@ -3307,8 +3532,8 @@ hawk@~3.1.3: sntp "1.x.x" he@1.1.x: - version "1.1.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.0.tgz#29319d49beec13a9b1f3c4f9b2a6dde4859bb2a7" + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" history@^3.0.0: version "3.2.1" @@ -3320,8 +3545,8 @@ history@^3.0.0: warning "^3.0.0" history@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/history/-/history-4.5.0.tgz#7313388109333bf5796fff7407cee1850e8c5061" + version "4.5.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.5.1.tgz#44935a51021e3b8e67ebac267a35675732aba569" dependencies: invariant "^2.2.1" loose-envify "^1.2.0" @@ -3344,6 +3569,10 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +hosted-git-info@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" + html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" @@ -3359,11 +3588,11 @@ html-entities@^1.2.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" html-minifier@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.2.3.tgz#d2ff536e24d95726c332493d8f77d84dbed85372" + version "3.3.3" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.3.3.tgz#5e85516b2aff3c3fb9bda351879375868386d6f6" dependencies: camel-case "3.0.x" - clean-css "3.4.x" + clean-css "4.0.x" commander "2.9.x" he "1.1.x" ncname "1.0.x" @@ -3372,8 +3601,8 @@ html-minifier@^3.2.3: uglify-js "2.7.x" html-webpack-plugin@^2.14.0: - version "2.26.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.26.0.tgz#ba97c8a66f912b85df80d2aeea65966c8bd9249e" + version "2.28.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.28.0.tgz#2e7863b57e5fd48fe263303e2ffc934c3064d009" dependencies: bluebird "^3.4.7" html-minifier "^3.2.3" @@ -3382,6 +3611,17 @@ html-webpack-plugin@^2.14.0: pretty-error "^2.0.2" toposort "^1.0.0" +htmlparser2@^3.9.1: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + htmlparser2@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" @@ -3391,7 +3631,7 @@ htmlparser2@~3.3.0: domutils "1.1" readable-stream "1.0" -http-errors@~1.5.0: +http-errors@~1.5.0, http-errors@~1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" dependencies: @@ -3443,10 +3683,14 @@ icepick@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/icepick/-/icepick-1.3.0.tgz#e4942842ed8f9ee778d7dd78f7e36627f49fdaef" -iconv-lite@0.4.13, iconv-lite@^0.4.13, iconv-lite@~0.4.13: +iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" +iconv-lite@0.4.15, iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + icss-replace-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" @@ -3456,8 +3700,8 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + version "3.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" image-diff@^1.6.3: version "1.6.3" @@ -3504,8 +3748,8 @@ indexof@0.0.1: resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflection@^1.7.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4: version "1.0.6" @@ -3562,9 +3806,13 @@ invariant@2.x.x, invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1: dependencies: loose-envify "^1.0.0" -ipaddr.js@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" is-absolute-url@^2.0.0: version "2.1.0" @@ -3595,19 +3843,29 @@ is-buffer@^1.0.2: version "1.1.4" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" -is-callable@^1.1.1, is-callable@^1.1.3: +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.2, is-callable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" +is-ci@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" + dependencies: + ci-info "^1.0.0" + is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" is-dom@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.7.tgz#d5ffac0b73f90d07d9d1061436f60c409a071caf" - dependencies: - jsdom "^9.9.1" + version "1.0.9" + resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d" is-dotfile@^1.0.0: version "1.0.2" @@ -3719,8 +3977,10 @@ is-property@^1.0.0: resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" is-regex@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.3.tgz#0d55182bddf9f2fde278220aec3a75642c908637" + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" is-relative@^0.2.1: version "0.2.1" @@ -3742,6 +4002,10 @@ is-stream@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + is-svg@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" @@ -3762,6 +4026,10 @@ is-unc-path@^0.1.1: dependencies: unc-path-regex "^0.1.0" +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" @@ -3803,6 +4071,70 @@ isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +istanbul-api@^1.1.0-alpha.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.1.tgz#d36e2f1560d1a43ce304c4ff7338182de61c8f73" + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.0.0" + istanbul-lib-hook "^1.0.0" + istanbul-lib-instrument "^1.3.0" + istanbul-lib-report "^1.0.0-alpha.3" + istanbul-lib-source-maps "^1.1.0" + istanbul-reports "^1.0.0" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.0-alpha, istanbul-lib-coverage@^1.0.0-alpha.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz#f263efb519c051c5f1f3343034fc40e7b43ff212" + +istanbul-lib-hook@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.0.tgz#fc5367ee27f59268e8f060b0c7aaf051d9c425c5" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.3.0, istanbul-lib-instrument@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.4.2.tgz#0e2fdfac93c1dabf2e31578637dc78a19089f43e" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.13.0" + istanbul-lib-coverage "^1.0.0" + semver "^5.3.0" + +istanbul-lib-report@^1.0.0-alpha.3: + version "1.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0-alpha.3.tgz#32d5f6ec7f33ca3a602209e278b2e6ff143498af" + dependencies: + async "^1.4.2" + istanbul-lib-coverage "^1.0.0-alpha" + mkdirp "^0.5.1" + path-parse "^1.0.5" + rimraf "^2.4.3" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.0.tgz#9d429218f35b823560ea300a96ff0c3bbdab785f" + dependencies: + istanbul-lib-coverage "^1.0.0-alpha.0" + mkdirp "^0.5.1" + rimraf "^2.4.4" + source-map "^0.5.3" + +istanbul-reports@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.1.tgz#9a17176bc4a6cbebdae52b2f15961d52fa623fbc" + dependencies: + handlebars "^4.0.3" + jasmine-core@^2.4.1, jasmine-core@~2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.5.2.tgz#6f61bd79061e27f43e6f9355e44b3c6cab6ff297" @@ -3820,19 +4152,201 @@ jasmine-reporters@^2.2.0: xmldom "^0.1.22" jasmine-spec-reporter@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-3.0.0.tgz#a9d11d55fabf75226d7e5ebbc1a850762e627563" + version "3.2.0" + resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-3.2.0.tgz#fdbe85a80ccdd3b276746bc77fde83c1ce773eff" dependencies: colors "1.1.2" jasmine@^2.4.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.5.2.tgz#6283cef7085c095cc25d651e954df004f7e3e421" + version "2.5.3" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.5.3.tgz#5441f254e1fc2269deb1dfd93e0e57d565ff4d22" dependencies: exit "^0.1.2" glob "^7.0.6" jasmine-core "~2.5.2" +jest-changed-files@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-17.0.2.tgz#f5657758736996f590a51b87e5c9369d904ba7b7" + +jest-cli@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-18.1.0.tgz#5ead36ecad420817c2c9baa2aa7574f63257b3d6" + dependencies: + ansi-escapes "^1.4.0" + callsites "^2.0.0" + chalk "^1.1.1" + graceful-fs "^4.1.6" + is-ci "^1.0.9" + istanbul-api "^1.1.0-alpha.1" + istanbul-lib-coverage "^1.0.0" + istanbul-lib-instrument "^1.1.1" + jest-changed-files "^17.0.2" + jest-config "^18.1.0" + jest-environment-jsdom "^18.1.0" + jest-file-exists "^17.0.0" + jest-haste-map "^18.1.0" + jest-jasmine2 "^18.1.0" + jest-mock "^18.0.0" + jest-resolve "^18.1.0" + jest-resolve-dependencies "^18.1.0" + jest-runtime "^18.1.0" + jest-snapshot "^18.1.0" + jest-util "^18.1.0" + json-stable-stringify "^1.0.0" + node-notifier "^4.6.1" + sane "~1.4.1" + strip-ansi "^3.0.1" + throat "^3.0.0" + which "^1.1.1" + worker-farm "^1.3.1" + yargs "^6.3.0" + +jest-config@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-18.1.0.tgz#6111740a6d48aab86ff5a9e6ab0b98bd993b6ff4" + dependencies: + chalk "^1.1.1" + jest-environment-jsdom "^18.1.0" + jest-environment-node "^18.1.0" + jest-jasmine2 "^18.1.0" + jest-mock "^18.0.0" + jest-resolve "^18.1.0" + jest-util "^18.1.0" + json-stable-stringify "^1.0.0" + +jest-diff@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-18.1.0.tgz#4ff79e74dd988c139195b365dc65d87f606f4803" + dependencies: + chalk "^1.1.3" + diff "^3.0.0" + jest-matcher-utils "^18.1.0" + pretty-format "^18.1.0" + +jest-environment-jsdom@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-18.1.0.tgz#18b42f0c4ea2bae9f36cab3639b1e8f8c384e24e" + dependencies: + jest-mock "^18.0.0" + jest-util "^18.1.0" + jsdom "^9.9.1" + +jest-environment-node@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-18.1.0.tgz#4d6797572c8dda99acf5fae696eb62945547c779" + dependencies: + jest-mock "^18.0.0" + jest-util "^18.1.0" + +jest-file-exists@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-17.0.0.tgz#7f63eb73a1c43a13f461be261768b45af2cdd169" + +jest-haste-map@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-18.1.0.tgz#06839c74b770a40c1a106968851df8d281c08375" + dependencies: + fb-watchman "^1.9.0" + graceful-fs "^4.1.6" + micromatch "^2.3.11" + sane "~1.4.1" + worker-farm "^1.3.1" + +jest-jasmine2@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-18.1.0.tgz#094e104c2c189708766c77263bb2aecb5860a80b" + dependencies: + graceful-fs "^4.1.6" + jest-matcher-utils "^18.1.0" + jest-matchers "^18.1.0" + jest-snapshot "^18.1.0" + jest-util "^18.1.0" + +jest-matcher-utils@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-18.1.0.tgz#1ac4651955ee2a60cef1e7fcc98cdfd773c0f932" + dependencies: + chalk "^1.1.3" + pretty-format "^18.1.0" + +jest-matchers@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-18.1.0.tgz#0341484bf87a1fd0bac0a4d2c899e2b77a3f1ead" + dependencies: + jest-diff "^18.1.0" + jest-matcher-utils "^18.1.0" + jest-util "^18.1.0" + pretty-format "^18.1.0" + +jest-mock@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-18.0.0.tgz#5c248846ea33fa558b526f5312ab4a6765e489b3" + +jest-resolve-dependencies@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-18.1.0.tgz#8134fb5caf59c9ed842fe0152ab01c52711f1bbb" + dependencies: + jest-file-exists "^17.0.0" + jest-resolve "^18.1.0" + +jest-resolve@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-18.1.0.tgz#6800accb536658c906cd5e29de412b1ab9ac249b" + dependencies: + browser-resolve "^1.11.2" + jest-file-exists "^17.0.0" + jest-haste-map "^18.1.0" + resolve "^1.2.0" + +jest-runtime@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-18.1.0.tgz#3abfd687175b21fc3b85a2b8064399e997859922" + dependencies: + babel-core "^6.0.0" + babel-jest "^18.0.0" + babel-plugin-istanbul "^3.0.0" + chalk "^1.1.3" + graceful-fs "^4.1.6" + jest-config "^18.1.0" + jest-file-exists "^17.0.0" + jest-haste-map "^18.1.0" + jest-mock "^18.0.0" + jest-resolve "^18.1.0" + jest-snapshot "^18.1.0" + jest-util "^18.1.0" + json-stable-stringify "^1.0.0" + micromatch "^2.3.11" + yargs "^6.3.0" + +jest-snapshot@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-18.1.0.tgz#55b96d2ee639c9bce76f87f2a3fd40b71c7a5916" + dependencies: + jest-diff "^18.1.0" + jest-file-exists "^17.0.0" + jest-matcher-utils "^18.1.0" + jest-util "^18.1.0" + natural-compare "^1.4.0" + pretty-format "^18.1.0" + +jest-util@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-18.1.0.tgz#3a99c32114ab17f84be094382527006e6d4bfc6a" + dependencies: + chalk "^1.1.1" + diff "^3.0.0" + graceful-fs "^4.1.6" + jest-file-exists "^17.0.0" + jest-mock "^18.0.0" + mkdirp "^0.5.1" + +jest@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-18.1.0.tgz#bcebf1e203dee5c2ad2091c805300a343d9e6c7d" + dependencies: + jest-cli "^18.1.0" + jodid25519@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" @@ -3854,52 +4368,51 @@ js-managed-css@^1.4.1: gen-css-identifier "^1.0.0" insert-css "^0.2.0" -js-tokens@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" -js-yaml@^3.4.3, js-yaml@^3.5.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" +js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.7.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" dependencies: argparse "^1.0.7" - esprima "^2.6.0" + esprima "^3.1.1" -js-yaml@~3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: argparse "^1.0.7" esprima "^2.6.0" jsbn@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsdom@^9.9.1: - version "9.9.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.9.1.tgz#84f3972ad394ab963233af8725211bce4d01bfd5" + version "9.11.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.11.0.tgz#a95b0304e521a2ca5a63c6ea47bf7708a7a84591" dependencies: - abab "^1.0.0" - acorn "^2.4.0" - acorn-globals "^1.0.4" + abab "^1.0.3" + acorn "^4.0.4" + acorn-globals "^3.1.0" array-equal "^1.0.0" content-type-parser "^1.0.1" - cssom ">= 0.3.0 < 0.4.0" - cssstyle ">= 0.2.36 < 0.3.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.2.37 < 0.3.0" escodegen "^1.6.1" html-encoding-sniffer "^1.0.1" - iconv-lite "^0.4.13" nwmatcher ">= 1.3.9 < 2.0.0" parse5 "^1.5.1" - request "^2.55.0" - sax "^1.1.4" - symbol-tree ">= 3.1.0 < 4.0.0" - tough-cookie "^2.3.1" - webidl-conversions "^3.0.1" + request "^2.79.0" + sax "^1.2.1" + symbol-tree "^3.2.1" + tough-cookie "^2.3.2" + webidl-conversions "^4.0.0" whatwg-encoding "^1.0.1" - whatwg-url "^4.1.0" - xml-name-validator ">= 2.0.1 < 3.0.0" + whatwg-url "^4.3.0" + xml-name-validator "^2.0.1" jsesc@^1.3.0: version "1.3.0" @@ -3927,10 +4440,6 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json3@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.2.6.tgz#f6efc93c06a04de9aec53053df2559bb19e2038b" - json3@3.3.2, json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" @@ -3962,10 +4471,9 @@ jsprim@^1.2.2: verror "1.3.6" jsx-ast-utils@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.3.5.tgz#9ba6297198d9f754594d62e59496ffb923778dd4" + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz#5afe38868f56bc8cc7aeaef0100ba8c75bd12591" dependencies: - acorn-jsx "^3.0.1" object-assign "^4.1.0" karma-chrome-launcher@^2.0.0: @@ -3987,8 +4495,8 @@ karma-junit-reporter@^1.1.0: xmlbuilder "8.2.2" karma-nyan-reporter@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/karma-nyan-reporter/-/karma-nyan-reporter-0.2.4.tgz#361bc4135002cbe504a36e38f3506e866d6a852c" + version "0.2.5" + resolved "https://registry.yarnpkg.com/karma-nyan-reporter/-/karma-nyan-reporter-0.2.5.tgz#aab7925f34166ebcef9308bbee11679f58ddaa31" dependencies: cli-color "^0.3.2" @@ -4003,20 +4511,20 @@ karma-webpack@^1.7.0: webpack-dev-middleware "^1.0.11" karma@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/karma/-/karma-1.3.0.tgz#b2b94e8f499fadd0069d54f9aef4a4d48ec5cc1f" + version "1.5.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-1.5.0.tgz#9c4c14f0400bef2c04c8e8e6bff59371025cc009" dependencies: bluebird "^3.3.0" - body-parser "^1.12.4" + body-parser "^1.16.1" chokidar "^1.4.1" colors "^1.1.0" combine-lists "^1.0.0" - connect "^3.3.5" + connect "^3.6.0" core-js "^2.2.0" di "^0.0.1" dom-serialize "^2.2.0" expand-braces "^0.1.1" - glob "^7.0.3" + glob "^7.1.1" graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" @@ -4027,11 +4535,12 @@ karma@^1.3.0: optimist "^0.6.1" qjobs "^1.1.4" range-parser "^1.2.0" - rimraf "^2.3.3" - socket.io "1.4.7" + rimraf "^2.6.0" + safe-buffer "^5.0.1" + socket.io "1.7.3" source-map "^0.5.3" - tmp "0.0.28" - useragent "^2.1.9" + tmp "0.0.31" + useragent "^2.1.12" keycode@^2.1.1: version "2.1.8" @@ -4053,9 +4562,15 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + leaflet@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.0.2.tgz#fa4fbcb7844944fc2bfb0bcf9ca0dea13463ca21" + version "1.0.3" + resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.0.3.tgz#1f401b98b45c8192134c6c8d69686253805007c8" levn@^0.3.0, levn@~0.3.0: version "0.3.0" @@ -4064,9 +4579,19 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.12, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: - version "0.2.16" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" dependencies: big.js "^3.1.3" emojis-list "^2.0.0" @@ -4077,6 +4602,36 @@ lodash-es@^4.2.0, lodash-es@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" +lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + +lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._baseclone@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._baseassign "^3.0.0" + lodash._basefor "^3.0.0" + lodash.isarray "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" @@ -4085,6 +4640,10 @@ lodash._baseget@^3.0.0: version "3.7.2" resolved "https://registry.yarnpkg.com/lodash._baseget/-/lodash._baseget-3.7.2.tgz#1b6ae1d5facf3c25532350a13c1197cb8bb674f4" +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -4103,14 +4662,45 @@ lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" +lodash.clonedeep@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" + dependencies: + lodash._baseclone "^3.0.0" + lodash._bindcallback "^3.0.0" + lodash.cond@^4.3.0: version "4.5.2" resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + lodash.get@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-3.7.0.tgz#3ce68ae2c91683b281cc5394128303cbf75e691f" @@ -4118,10 +4708,6 @@ lodash.get@^3.7.0: lodash._baseget "^3.0.0" lodash._topath "^3.0.0" -lodash.indexof@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/lodash.indexof/-/lodash.indexof-4.0.5.tgz#53714adc2cddd6ed87638f893aa9b6c24e31ef3c" - lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -4142,7 +4728,7 @@ lodash.isplainobject@^3.2.0: lodash.isarguments "^3.0.0" lodash.keysin "^3.0.0" -lodash.keys@^3.1.2: +lodash.keys@^3.0.0, lodash.keys@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: @@ -4157,10 +4743,18 @@ lodash.keysin@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + lodash.memoize@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" +lodash.merge@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + lodash.pick@^4.2.0, lodash.pick@^4.2.1, lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -4169,6 +4763,22 @@ lodash.pickby@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + lodash.template@^4.2.4: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" @@ -4205,11 +4815,11 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: - js-tokens "^2.0.0" + js-tokens "^3.0.0" lower-case@^1.1.1: version "1.1.3" @@ -4233,6 +4843,12 @@ macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + mantra-core@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/mantra-core/-/mantra-core-1.7.0.tgz#a8c83e8cee83ef6a7383131519fe8031ad546386" @@ -4241,11 +4857,23 @@ mantra-core@^1.7.0: react-komposer "^1.9.0" react-simple-di "^1.2.0" -math-expression-evaluator@^1.2.14: - version "1.2.14" - resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab" +marked-terminal@^1.6.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904" dependencies: - lodash.indexof "^4.0.5" + cardinal "^1.0.0" + chalk "^1.1.3" + cli-table "^0.3.1" + lodash.assign "^4.2.0" + node-emoji "^1.4.1" + +marked@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" + +math-expression-evaluator@^1.2.14: + version "1.2.16" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9" media-typer@0.3.0: version "0.3.0" @@ -4285,6 +4913,10 @@ merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -4314,25 +4946,15 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" - -mime-db@~1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7" +"mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: - version "2.1.13" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" - dependencies: - mime-db "~1.25.0" - -mime-types@~2.0.4: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.0.14.tgz#310e159db23e077f8bb22b748dabfa4957140aa6" + version "2.1.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: - mime-db "~1.12.0" + mime-db "~1.26.0" mime@1.2.x: version "1.2.11" @@ -4346,20 +4968,24 @@ minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" -minimist@0.0.8, minimist@~0.0.1: +minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -4374,7 +5000,7 @@ mobx@^2.3.4: version "2.7.0" resolved "https://registry.yarnpkg.com/mobx/-/mobx-2.7.0.tgz#cf3d82d18c0ca7f458d8f2a240817b3dc7e54a01" -moment@2.14.1, moment@^2.11.2: +moment@2.14.1: version "2.14.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.14.1.tgz#b35b27c47e57ed2ddc70053d6b07becdb291741c" @@ -4399,8 +5025,8 @@ mz@^2.3.1, mz@^2.6.0: thenify-all "^1.0.0" nan@^2.3.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8" + version "2.5.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" natural-compare@^1.4.0: version "1.4.0" @@ -4412,10 +5038,6 @@ ncname@1.0.x: dependencies: xml-char-classes "^1.0.0" -negotiator@0.4.9: - version "0.4.9" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.4.9.tgz#92e46b6db53c7e421ed64a2bc94f08be7630df3f" - negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -4425,8 +5047,8 @@ next-tick@~0.2.2: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-0.2.2.tgz#75da4a927ee5887e39065880065b7336413b310d" no-case@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.0.tgz#ca2825ccb76b18e6f79d573dcfbf1eace33dd164" + version "2.3.1" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.1.tgz#7aeba1c73a52184265554b7dc03baf720df80081" dependencies: lower-case "^1.1.1" @@ -4436,6 +5058,12 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" +node-emoji@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.5.1.tgz#fd918e412769bf8c448051238233840b2aff16a1" + dependencies: + string.prototype.codepointat "^0.2.0" + node-fetch@^1.0.1: version "1.6.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" @@ -4443,6 +5071,10 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + node-libs-browser@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b" @@ -4527,9 +5159,21 @@ node-libs-browser@^2.0.0: util "^0.10.3" vm-browserify "0.0.4" +node-notifier@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-4.6.1.tgz#056d14244f3dcc1ceadfe68af9cff0c5473a33f3" + dependencies: + cli-usage "^0.1.1" + growly "^1.2.0" + lodash.clonedeep "^3.0.0" + minimist "^1.1.1" + semver "^5.1.0" + shellwords "^0.1.0" + which "^1.0.5" + node-pre-gyp@^0.6.29: - version "0.6.32" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + version "0.6.33" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.33.tgz#640ac55198f6a925972e0c16c4ac26a034d5ecc9" dependencies: mkdirp "~0.5.1" nopt "~3.0.6" @@ -4547,6 +5191,15 @@ nopt@~3.0.6: dependencies: abbrev "1" +normalize-package-data@^2.3.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -4556,8 +5209,8 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" normalize-url@^1.4.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.8.0.tgz#a9550b079aa3523c85d78df24eef1959fce359ab" + version "1.9.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.0.tgz#c2bb50035edee62cd81edb2d45da68dc25e3423e" dependencies: object-assign "^4.0.1" prepend-http "^1.0.0" @@ -4565,8 +5218,8 @@ normalize-url@^1.4.0: sort-keys "^1.0.0" normalizr@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalizr/-/normalizr-3.0.2.tgz#ac51ab65af807e9022b9f16a767fb1449c0dae6a" + version "3.2.1" + resolved "https://registry.yarnpkg.com/normalizr/-/normalizr-3.2.1.tgz#85a2d3d0ffb9c3b08f4131cb8d8fbfb7e9211b35" npmlog@^4.0.1: version "4.0.2" @@ -4607,10 +5260,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -4619,10 +5276,22 @@ object-hash@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.5.tgz#bdd844e030d0861b692ca175c6cab6868ec233d7" -object-keys@^1.0.8: +object-is@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" + +object-keys@^1.0.10, object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" +object.assign@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + object-keys "^1.0.10" + object.entries@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" @@ -4665,7 +5334,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0: +once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -4731,6 +5400,12 @@ os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -4789,21 +5464,21 @@ parse5@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" -parsejson@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.1.tgz#9b10c6c0d825ab589e685153826de0a3ba278bcc" +parsejson@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" -parseqs@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.2.tgz#9dfe70b2cddac388bde4f35b1f240fa58adbe6c7" +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" -parseuri@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.4.tgz#806582a39887e1ea18dd5e2fe0e01902268e9350" +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" @@ -4835,10 +5510,22 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + pbkdf2-compat@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" @@ -4892,8 +5579,8 @@ pkginfo@^0.4.0: resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.0.tgz#349dbb7ffd38081fcadc0853df687f0c7744cd65" pleeease-filters@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-3.0.0.tgz#35a4d4c2086413eabc2ce17aaa2ec29054e3075c" + version "3.0.1" + resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-3.0.1.tgz#4dfe0e8f1046613517c64b728bc80608a7ebf22f" dependencies: onecolor "~2.4.0" postcss "^5.0.4" @@ -4997,16 +5684,16 @@ postcss-color-rgba-fallback@^2.0.0: rgb-hex "^1.0.0" postcss-colormin@^2.1.8: - version "2.2.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" dependencies: colormin "^1.0.5" postcss "^5.0.13" postcss-value-parser "^3.2.3" postcss-convert-values@^2.3.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.0.tgz#08c6d06130fe58a91a21ff50829e1aad6a3a1acc" + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" dependencies: postcss "^5.0.11" postcss-value-parser "^3.1.2" @@ -5052,10 +5739,10 @@ postcss-custom-media@^5.0.0: postcss "^5.0.0" postcss-custom-properties@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-5.0.1.tgz#e07d4f6c78e547cf04274f120f490d236e33ea19" + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-5.0.2.tgz#9719d78f2da9cf9f53810aebc23d4656130aceb1" dependencies: - balanced-match "~0.1.0" + balanced-match "^0.4.2" postcss "^5.0.0" postcss-custom-selectors@^3.0.0: @@ -5111,8 +5798,8 @@ postcss-font-variant@^2.0.0: postcss "^5.0.4" postcss-import@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-9.0.0.tgz#751fcd21c53eec6eb468890384ce3c114968b391" + version "9.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-9.1.0.tgz#95fe9876a1e79af49fbdc3589f01fe5aa7cc1e80" dependencies: object-assign "^4.0.1" postcss "^5.0.14" @@ -5128,25 +5815,25 @@ postcss-initial@^1.3.1: lodash.template "^4.2.4" postcss "^5.0.19" -postcss-load-config@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.0.0.tgz#1399f60dcd6bd9c3124b2eb22960f77f9dc08b3d" +postcss-load-config@^1.0.0, postcss-load-config@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a" dependencies: cosmiconfig "^2.1.0" object-assign "^4.1.0" - postcss-load-options "^1.0.2" - postcss-load-plugins "^2.0.0" + postcss-load-options "^1.2.0" + postcss-load-plugins "^2.3.0" -postcss-load-options@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.0.2.tgz#b99eb5759a588f4b2dd8b6471c6985f72060e7b0" +postcss-load-options@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c" dependencies: cosmiconfig "^2.1.0" object-assign "^4.1.0" -postcss-load-plugins@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.1.0.tgz#dbb6f46271df8d16e19b5d691ebda5175ce424a0" +postcss-load-plugins@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92" dependencies: cosmiconfig "^2.1.1" object-assign "^4.1.0" @@ -5161,17 +5848,17 @@ postcss-loader@1.1.0: postcss-load-config "^1.0.0" postcss-loader@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-1.2.1.tgz#8809ab184a9f903a01f660385f2e296ff563d22c" + version "1.3.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-1.3.1.tgz#7907bdfe5e953cf4b6d97cbd8edcd17956369030" dependencies: loader-utils "^0.2.16" - object-assign "^4.1.0" - postcss "^5.2.6" - postcss-load-config "^1.0.0" + object-assign "^4.1.1" + postcss "^5.2.14" + postcss-load-config "^1.2.0" postcss-media-minmax@^2.1.0: version "2.1.2" - resolved "http://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-2.1.2.tgz#444c5cf8926ab5e4fd8a2509e9297e751649cdf8" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-2.1.2.tgz#444c5cf8926ab5e4fd8a2509e9297e751649cdf8" dependencies: postcss "^5.0.4" @@ -5184,16 +5871,19 @@ postcss-merge-idents@^2.1.5: postcss-value-parser "^3.1.1" postcss-merge-longhand@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz#ff59b5dec6d586ce2cea183138f55c5876fa9cdc" + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" dependencies: postcss "^5.0.4" postcss-merge-rules@^2.0.3: - version "2.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.11.tgz#c5d7c8de5056a7377aea0dff2fd83f92cafb9b8a" + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" postcss "^5.0.4" + postcss-selector-parser "^2.2.2" vendors "^1.0.0" postcss-message-helpers@^2.0.0: @@ -5282,8 +5972,8 @@ postcss-normalize-url@^3.0.7: postcss-value-parser "^3.2.3" postcss-ordered-values@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" dependencies: postcss "^5.0.4" postcss-value-parser "^3.0.1" @@ -5350,7 +6040,7 @@ postcss-selector-parser@^1.1.4: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.0: +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.0, postcss-selector-parser@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz#3d70f5adda130da51c7c0c2fc023f56b1374fe08" dependencies: @@ -5407,14 +6097,14 @@ postcss@^4.1.7: js-base64 "~2.1.8" source-map "~0.4.2" -postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.21, postcss@^5.0.3, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.1.1, postcss@^5.2.0, postcss@^5.2.5, postcss@^5.2.6, postcss@^5.2.8: - version "5.2.8" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.8.tgz#05720c49df23c79bda51fd01daeb1e9222e94390" +postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.21, postcss@^5.0.3, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.1.1, postcss@^5.2.0, postcss@^5.2.14, postcss@^5.2.5: + version "5.2.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.14.tgz#47b4fbde363fd4f81e547f7e0e43d6d300267330" dependencies: chalk "^1.1.3" js-base64 "^2.1.9" source-map "^0.5.6" - supports-color "^3.1.2" + supports-color "^3.2.3" prelude-ls@~1.1.2: version "1.1.2" @@ -5435,9 +6125,15 @@ pretty-error@^2.0.2: renderkid "~2.0.0" utila "~0.4" +pretty-format@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-18.1.0.tgz#fb65a86f7a7f9194963eee91865c1bcf1039e284" + dependencies: + ansi-styles "^2.2.1" + private@^0.1.6, private@~0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" @@ -5471,12 +6167,12 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -proxy-addr@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" +proxy-addr@~1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" dependencies: forwarded "~0.1.0" - ipaddr.js "1.1.1" + ipaddr.js "1.2.0" prr@~0.0.0: version "0.0.0" @@ -5512,13 +6208,17 @@ qs@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" +qs@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" + qs@^6.1.0, qs@^6.2.0, qs@~6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + version "6.3.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d" query-string@^4.1.0, query-string@^4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822" + version "4.3.2" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.2.tgz#ec0fd765f58a50031a3968c2431386f8947a5cdd" dependencies: object-assign "^4.1.0" strict-uri-encode "^1.0.0" @@ -5556,38 +6256,50 @@ range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" -raw-body@~2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" +raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" dependencies: bytes "2.4.0" - iconv-lite "0.4.13" + iconv-lite "0.4.15" unpipe "1.0.0" rc@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + version "1.1.7" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.7.tgz#c5ea564bb07aff9fd3a5b32e906c1d3a65940fea" dependencies: deep-extend "~0.4.0" ini "~1.3.0" minimist "^1.2.0" - strip-json-comments "~1.0.4" + strip-json-comments "~2.0.1" react-addons-css-transition-group@^15.2.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.4.1.tgz#60b133fac5116e4009e56ab0674dc2ddcc1a18f6" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.4.2.tgz#b7828834dfa14229fe07750e331e8a8cb6fb7745" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" react-addons-perf@^15.2.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-addons-perf/-/react-addons-perf-15.4.1.tgz#c6dd5a7011f43cd3222f47b7cb1aebe9d4174cb0" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-perf/-/react-addons-perf-15.4.2.tgz#110bdcf5c459c4f77cb85ed634bcd3397536383b" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" react-addons-shallow-compare@^15.2.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.4.1.tgz#b68103dd4d13144cb221065f6021de1822bd435a" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.4.2.tgz#027ffd9720e3a1e0b328dcd8fc62e214a0d174a5" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" -react-addons-test-utils@^15.3.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1" +react-addons-test-utils@^15.4.2: + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz#93bcaa718fcae7360d42e8fb1c09756cc36302a2" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" react-ansi-style@^1.0.0: version "1.0.0" @@ -5619,8 +6331,8 @@ react-docgen@^2.12.1: recast "^0.11.5" react-dom@^15.2.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f" dependencies: fbjs "^0.8.1" loose-envify "^1.1.0" @@ -5641,8 +6353,8 @@ react-fuzzy@^0.3.3: fuse.js "^2.2.0" react-height@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-height/-/react-height-2.1.1.tgz#14c27a8e3a7e43a17dd128c8f3ee00f03b0001c2" + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-height/-/react-height-2.2.0.tgz#c65de6a7f7245c848f5ec9d3087f0758b90d7a0b" react-hot-api@^0.4.5: version "0.4.7" @@ -5704,8 +6416,8 @@ react-motion@^0.4.5: raf "^3.1.0" react-redux@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.1.tgz#84a41bd4cdd180452bb6922bc79ad25bd5abb7c4" + version "5.0.2" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.2.tgz#3d9878f5f71c6fafcd45de1fbb162ea31f389814" dependencies: hoist-non-react-statics "^1.0.3" invariant "^2.0.0" @@ -5714,8 +6426,8 @@ react-redux@^5.0.1: loose-envify "^1.1.0" react-resizable@^1.0.1: - version "1.4.6" - resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.4.6.tgz#2cdc2186606f3a564444ecd4cfea7f400301a3ea" + version "1.6.0" + resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.6.0.tgz#7968c456538a349db1742680f9a05dc9780e6188" dependencies: react-draggable "^2.1.0" @@ -5729,12 +6441,12 @@ react-retina-image@^2.0.0: object-assign "^4.1.0" react-router-redux@^4.0.5: - version "4.0.7" - resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.7.tgz#9b1fde4e70106c50f47214e12bdd888cfb96e2a6" + version "4.0.8" + resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" react-router@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.0.tgz#3f313e4dbaf57048c48dd0a8c3cac24d93667dff" + version "3.0.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.2.tgz#5a19156678810e01d81901f9c0fef63284b8a514" dependencies: history "^3.0.0" hoist-non-react-statics "^1.2.0" @@ -5759,17 +6471,25 @@ react-stubber@^1.0.0: dependencies: babel-runtime "^6.5.0" +react-test-renderer@^15.4.2: + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.4.2.tgz#27e1dff5d26d0e830f99614c487622bc831416f3" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" + react-virtualized@^8.6.0: - version "8.8.1" - resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-8.8.1.tgz#d12aad7f759ddc158f98ab60981290501b9ce95e" + version "8.11.4" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-8.11.4.tgz#0bb94f1ecbd286d07145ce63983d0a11724522c0" dependencies: babel-runtime "^6.11.6" classnames "^2.2.3" - dom-helpers "^2.4.0" + dom-helpers "^2.4.0 || ^3.0.0" + loose-envify "^1.3.0" react@^15.2.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react/-/react-15.4.1.tgz#498e918602677a3983cd0fd206dfe700389a0dd6" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef" dependencies: fbjs "^0.8.4" loose-envify "^1.1.0" @@ -5781,6 +6501,21 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + readable-stream@1.0, readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -5791,8 +6526,8 @@ readable-stream@1.0, readable-stream@~1.0.2: string_decoder "~0.10.x" "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + version "2.2.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729" dependencies: buffer-shims "^1.0.0" core-util-is "~1.0.0" @@ -5832,10 +6567,10 @@ readline2@^1.0.1: mute-stream "0.0.5" recast@^0.11.5: - version "0.11.18" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.18.tgz#07af6257ca769868815209401d4d60eef1b5b947" + version "0.11.22" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.22.tgz#dedeb18fb001a2bbc6ac34475fda53dfe3d47dfa" dependencies: - ast-types "0.9.2" + ast-types "0.9.5" esprima "~3.1.0" private "~0.1.5" source-map "~0.5.0" @@ -5855,6 +6590,12 @@ recompose@^0.21.2: hoist-non-react-statics "^1.0.0" symbol-observable "^1.0.4" +redeyed@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + dependencies: + esprima "~3.0.0" + reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" @@ -5874,8 +6615,8 @@ reduce-reducers@^0.1.0: resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.1.2.tgz#fa1b4718bc5292a71ddd1e5d839c9bea9770f14b" redux-actions@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-1.2.0.tgz#4f421f1aa74c827d5e8abce6c009d5872c4af3e6" + version "1.2.1" + resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-1.2.1.tgz#649711d88f49f1dde5bc5a1cea8ceec5b54d9181" dependencies: invariant "^2.2.1" lodash "^4.13.1" @@ -5889,17 +6630,18 @@ redux-auth-wrapper@^0.9.0: lodash.isempty "4.4.0" redux-form@5: - version "5.3.3" - resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-5.3.3.tgz#e65e995095c739f068a7c2adfd8229d966a43af8" + version "5.3.4" + resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-5.3.4.tgz#0536ec71daf919fc6ec93c9b39a9581213715980" dependencies: deep-equal "^1.0.1" hoist-non-react-statics "^1.0.5" + invariant "^2.0.0" is-promise "^2.1.0" react-lazy-cache "^3.0.1" redux-logger@^2.6.1: - version "2.7.4" - resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-2.7.4.tgz#891e5d29e7f111d08b5781a237b9965b5858c7f8" + version "2.8.1" + resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-2.8.1.tgz#c00e689ba00342f44858701d76b1d73fbade72bd" dependencies: deep-diff "0.3.4" @@ -5916,8 +6658,8 @@ redux-router@^2.1.2: deep-equal "^1.0.1" redux-thunk@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98" + version "2.2.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" redux@^3.5.2: version "3.6.0" @@ -5933,8 +6675,8 @@ regenerate@^1.2.1: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + version "0.10.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" regenerator-runtime@^0.9.5: version "0.9.6" @@ -5950,7 +6692,7 @@ regenerator-transform@0.9.8: regex-cache@^0.4.2: version "0.4.3" - resolved "http://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" dependencies: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" @@ -6013,7 +6755,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@^2.55.0, request@^2.64.0, request@^2.74.0, request@^2.79.0: +request@^2.64.0, request@^2.74.0, request@^2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: @@ -6038,10 +6780,18 @@ request@^2.55.0, request@^2.64.0, request@^2.74.0, request@^2.79.0: tunnel-agent "~0.4.1" uuid "^3.0.0" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + require-from-string@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6058,8 +6808,8 @@ reselect@^2.0.1: resolved "https://registry.yarnpkg.com/reselect/-/reselect-2.5.4.tgz#b7d23fdf00b83fa7ad0279546f8dbbbd765c7047" resize-observer-polyfill@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.3.2.tgz#f467efc15a86d9ee5096fd6d7f628c8a54bb805a" + version "1.4.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.4.1.tgz#db97349f0f5b29764ce3e03bf8982ddbfa076613" resolve-from@^1.0.0: version "1.0.1" @@ -6069,6 +6819,10 @@ resolve-pathname@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.0.2.tgz#e55c016eb2e9df1de98e85002282bfb38c630436" +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" @@ -6098,7 +6852,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.5.4, rimraf@~2.5.1, rimraf@~2.5.4: +rimraf@2, rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.0.tgz#89b8a0fe432b9ff9ec9a925a00b6cdb3a91bbada" + dependencies: + glob "^7.0.5" + +rimraf@~2.5.1, rimraf@~2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: @@ -6126,9 +6886,24 @@ rx@2.3.24: version "2.3.24" resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7" +safe-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +sane@~1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.4.1.tgz#88f763d74040f5f0c256b6163db399bf110ac715" + dependencies: + exec-sh "^0.2.0" + fb-watchman "^1.8.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.10.0" + sauce-connect-launcher@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.1.1.tgz#c648067efc579be694acb03c575b43f6fabfd521" + version "1.2.0" + resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.0.tgz#6dc26611ef23428abe8b8f49e0044d7c752b8a6c" dependencies: adm-zip "~0.4.3" async "^2.1.2" @@ -6140,9 +6915,9 @@ sax@0.6.x: version "0.6.1" resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" -sax@^1.1.4, sax@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" +sax@^1.2.1, sax@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" screenfull@^3.0.0: version "3.0.2" @@ -6158,7 +6933,7 @@ selenium-webdriver@^2.53.3: ws "^1.0.1" xml2js "0.4.4" -semver@^5.3.0, semver@~5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -6170,9 +6945,9 @@ semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" +send@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" dependencies: debug "~2.2.0" depd "~1.1.0" @@ -6181,19 +6956,19 @@ send@0.14.1: escape-html "~1.0.3" etag "~1.7.0" fresh "0.3.0" - http-errors "~1.5.0" + http-errors "~1.5.1" mime "1.3.4" - ms "0.7.1" + ms "0.7.2" on-finished "~2.3.0" range-parser "~1.2.0" - statuses "~1.3.0" + statuses "~1.3.1" serve-favicon@^2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.3.2.tgz#dd419e268de012ab72b319d337f2105013f9381f" + version "2.4.0" + resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.0.tgz#064dcdfdb0f250ae3b148eb18c8bbf3d185e3dd0" dependencies: - etag "~1.7.0" - fresh "0.3.0" + etag "~1.8.0" + fresh "0.4.0" ms "0.7.2" parseurl "~1.3.1" @@ -6209,16 +6984,16 @@ serve-index@^1.7.2: mime-types "~2.1.11" parseurl "~1.3.1" -serve-static@~1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" +serve-static@~1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.14.1" + send "0.14.2" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -6250,14 +7025,18 @@ shallowequal@0.2.x, shallowequal@^0.2.2: dependencies: lodash.keys "^3.1.2" -shelljs@^0.7.0, shelljs@^0.7.4, shelljs@^0.7.5: - version "0.7.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" +shelljs@^0.7.4, shelljs@^0.7.5: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" +shellwords@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -6286,66 +7065,56 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -socket.io-adapter@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.4.0.tgz#fb9f82ab1aa65290bf72c3657955b930a991a24f" +socket.io-adapter@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: - debug "2.2.0" - socket.io-parser "2.2.2" + debug "2.3.3" + socket.io-parser "2.3.1" -socket.io-client@1.4.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.4.6.tgz#49b0ba537efd15b8297c84016e642e1c7c752c3d" +socket.io-client@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.3.tgz#b30e86aa10d5ef3546601c09cde4765e381da377" dependencies: backo2 "1.0.2" component-bind "1.0.0" - component-emitter "1.2.0" - debug "2.2.0" - engine.io-client "1.6.9" + component-emitter "1.2.1" + debug "2.3.3" + engine.io-client "1.8.3" has-binary "0.1.7" indexof "0.0.1" object-component "0.0.3" - parseuri "0.0.4" - socket.io-parser "2.2.6" + parseuri "0.0.5" + socket.io-parser "2.3.1" to-array "0.1.4" -socket.io-parser@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.2.2.tgz#3d7af6b64497e956b7d9fe775f999716027f9417" - dependencies: - benchmark "1.0.0" - component-emitter "1.1.2" - debug "0.7.4" - isarray "0.0.1" - json3 "3.2.6" - -socket.io-parser@2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.2.6.tgz#38dfd61df50dcf8ab1d9e2091322bf902ba28b99" +socket.io-parser@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: - benchmark "1.0.0" component-emitter "1.1.2" debug "2.2.0" isarray "0.0.1" json3 "3.3.2" -socket.io@1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.4.7.tgz#92b7f7cb88c5797d4daee279fe8075dbe6d3fa1c" +socket.io@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b" dependencies: - debug "2.2.0" - engine.io "1.6.10" + debug "2.3.3" + engine.io "1.8.3" has-binary "0.1.7" - socket.io-adapter "0.4.0" - socket.io-client "1.4.6" - socket.io-parser "2.2.6" + object-assign "4.1.0" + socket.io-adapter "0.5.0" + socket.io-client "1.7.3" + socket.io-parser "2.3.1" sockjs-client@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.1.tgz#284843e9a9784d7c474b1571b3240fca9dda4bb0" + version "1.1.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.2.tgz#f0212a8550e4c9468c8cceaeefd2e3493c033ad5" dependencies: debug "^2.2.0" - eventsource "~0.1.6" + eventsource "0.1.6" faye-websocket "~0.11.0" inherits "^2.0.1" json3 "^3.3.2" @@ -6364,13 +7133,13 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -source-list-map@^0.1.4, source-list-map@~0.1.0, source-list-map@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.7.tgz#d4b5ce2a46535c72c7e8527c71a77d250618172e" +source-list-map@^0.1.4, source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" source-map-support@^0.4.2: - version "0.4.8" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.8.tgz#4871918d8a3af07289182e974e32844327b2e98b" + version "0.4.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" dependencies: source-map "^0.5.3" @@ -6380,33 +7149,47 @@ source-map@0.1.x, source-map@^0.1.41, source-map@~0.1.7: dependencies: amdefine ">=0.0.4" -source-map@0.4.x, source-map@^0.4.4, source-map@~0.4.1, source-map@~0.4.2: +source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@^0.4.4, source-map@~0.4.1, source-map@~0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" dependencies: amdefine ">=0.0.4" -spawn-default-shell@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/spawn-default-shell/-/spawn-default-shell-1.1.0.tgz#095439d44c4b7c0aff56a53929fbaab87878e7c6" +spawn-command@^0.0.2-1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -6430,7 +7213,7 @@ stack-trace@0.0.x: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" -"statuses@>= 1.3.1 < 2", statuses@~1.3.0: +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -6446,10 +7229,10 @@ stream-cache@~0.0.1: resolved "https://registry.yarnpkg.com/stream-cache/-/stream-cache-0.0.2.tgz#1ac5ad6832428ca55667dbdee395dad4e6db118f" stream-http@^2.3.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.5.0.tgz#585eee513217ed98fe199817e7313b6f772a6802" + version "2.6.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.3.tgz#4c3ddbf9635968ea2cfd4e48d43de5def2625ac3" dependencies: - builtin-status-codes "^2.0.0" + builtin-status-codes "^3.0.0" inherits "^2.0.1" readable-stream "^2.1.0" to-arraybuffer "^1.0.0" @@ -6459,7 +7242,7 @@ strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -6474,6 +7257,10 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string.prototype.codepointat@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78" + string.prototype.padend@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" @@ -6510,13 +7297,19 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" -strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" style-loader@0.13.1, style-loader@^0.13.0: version "0.13.1" @@ -6532,20 +7325,20 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" +supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2, supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: has-flag "^1.0.0" svgo@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" dependencies: coa "~1.0.1" colors "~1.1.2" - csso "~2.2.1" - js-yaml "~3.6.1" + csso "~2.3.1" + js-yaml "~3.7.0" mkdirp "~0.5.1" sax "~1.2.1" whet.extend "~0.9.9" @@ -6554,9 +7347,9 @@ symbol-observable@^1.0.2, symbol-observable@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" -"symbol-tree@>= 3.1.0 < 4.0.0": - version "3.2.1" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.1.tgz#8549dd1d01fa9f893c18cc9ab0b106b4d9b168cb" +symbol-tree@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" table@^3.7.8: version "3.8.3" @@ -6594,6 +7387,16 @@ tar@~2.2.1: fstream "^1.0.2" inherits "2" +test-exclude@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-3.3.0.tgz#7a17ca1239988c98367b0621456dbb7d4bc38977" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + tether@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/tether/-/tether-1.4.0.tgz#0f9fa171f75bf58485d8149e94799d7ae74d1c1a" @@ -6614,6 +7417,10 @@ thenify-all@^1.0.0, thenify-all@^1.6.0: dependencies: any-promise "^1.0.0" +throat@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6" + through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -6645,12 +7452,16 @@ tmp@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" -tmp@0.0.28: - version "0.0.28" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" +tmp@0.0.31, tmp@0.0.x: + version "0.0.31" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: os-tmpdir "~1.0.1" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" @@ -6668,10 +7479,10 @@ toggle-selection@^1.0.3: resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.5.tgz#726c703de607193a73c32c7df49cd24950fc574f" toposort@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.0.tgz#b66cf385a1a8a8e68e45b8259e7f55875e8b06ef" + version "1.0.3" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.3.tgz#f02cd8a74bd8be2fc0e98611c3bacb95a171869c" -tough-cookie@^2.3.1, tough-cookie@~2.3.0: +tough-cookie@^2.3.2, tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: @@ -6685,6 +7496,10 @@ tree-kill@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.1.0.tgz#c963dcf03722892ec59cba569e940b71954d1729" +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -6707,7 +7522,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@~1.6.13: +type-is@~1.6.14: version "1.6.14" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" dependencies: @@ -6722,7 +7537,7 @@ ua-parser-js@^0.7.9: version "0.7.12" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" -uglify-js@2.7.x, uglify-js@~2.7.3: +uglify-js@2.7.x, uglify-js@^2.6, uglify-js@~2.7.3: version "2.7.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" dependencies: @@ -6764,8 +7579,8 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" uniqid@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" dependencies: macaddress "^0.2.8" @@ -6785,8 +7600,8 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" unused-files-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unused-files-webpack-plugin/-/unused-files-webpack-plugin-3.0.0.tgz#6403248ac2948c004d541976a58be2df656ac324" + version "3.0.1" + resolved "https://registry.yarnpkg.com/unused-files-webpack-plugin/-/unused-files-webpack-plugin-3.0.1.tgz#7c0739c4c02f707d094612d1bb4d8118044d29df" dependencies: glob "^7.0.3" @@ -6813,8 +7628,8 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.1: - version "1.1.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.7.tgz#025cff999653a459ab34232147d89514cc87d74a" + version "1.1.8" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.8.tgz#7a65b3a8d57a1e86af6b4e2276e34774167c0156" dependencies: querystringify "0.0.x" requires-port "1.0.x" @@ -6836,15 +7651,12 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -useragent@^2.1.9: - version "2.1.10" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.10.tgz#2456c5c2b722b47f3d8321ed257b490a3d9bb2af" +useragent@^2.1.12: + version "2.1.12" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.12.tgz#aa7da6cdc48bdc37ba86790871a7321d64edbaa2" dependencies: lru-cache "2.2.x" - -utf8@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.0.tgz#0cfec5c8052d44a23e3aaa908104e8075f95dfd5" + tmp "0.0.x" util-deprecate@~1.0.1: version "1.0.2" @@ -6882,6 +7694,13 @@ v8flags@^2.0.10: dependencies: user-home "^1.1.1" +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + value-equal@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.2.0.tgz#4f41c60a3fc011139a2ec3d3340a8998ae8b69c0" @@ -6914,12 +7733,22 @@ void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" dependencies: loose-envify "^1.0.0" +watch@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + watchpack@^0.2.1: version "0.2.9" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" @@ -6937,10 +7766,14 @@ webchauffeur@^1.2.0: mz "^2.6.0" promise-chain-decorator "^1.2.0" -webidl-conversions@^3.0.0, webidl-conversions@^3.0.1: +webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" +webidl-conversions@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0" + webpack-core@~0.6.9: version "0.6.9" resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" @@ -6949,8 +7782,8 @@ webpack-core@~0.6.9: source-map "~0.4.1" webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.4.0, webpack-dev-middleware@^1.6.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.9.0.tgz#a1c67a3dfd8a5c5d62740aa0babe61758b4c84aa" + version "1.10.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893" dependencies: memory-fs "~0.4.1" mime "^1.3.4" @@ -6958,8 +7791,8 @@ webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.4.0, webpack-dev-middl range-parser "^1.0.3" webpack-dev-server@^1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-1.16.2.tgz#8bebc2c4ce1c45a15c72dd769d9ba08db306a793" + version "1.16.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-1.16.3.tgz#cbb6a0d3e7c8eb5453b3e9befcbe843219f62661" dependencies: compression "^1.5.2" connect-history-api-fallback "^1.3.0" @@ -6976,8 +7809,8 @@ webpack-dev-server@^1.16.2: webpack-dev-middleware "^1.4.0" webpack-hot-middleware@^2.13.2, webpack-hot-middleware@^2.14.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.15.0.tgz#71995af7c0025f109df482f86f1e10379526d026" + version "2.17.0" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.17.0.tgz#5af55fd2bc2f9a4392edd553f2a0fbebd4d75e78" dependencies: ansi-html "0.0.6" html-entities "^1.2.0" @@ -6993,10 +7826,10 @@ webpack-postcss-tools@^1.1.2: resolve "^1.1.6" webpack-sources@^0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.3.tgz#15ce2fb79d0a1da727444ba7c757bf164294f310" + version "0.1.4" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.4.tgz#ccc2c817e08e5fa393239412690bb481821393cd" dependencies: - source-list-map "~0.1.0" + source-list-map "~0.1.7" source-map "~0.5.3" webpack@^1.13.1, webpack@^1.14.0: @@ -7036,12 +7869,12 @@ whatwg-encoding@^1.0.1: iconv-lite "0.4.13" whatwg-fetch@>=0.10.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" + version "2.0.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.2.tgz#fe294d1d89e36c5be8b3195057f2e4bc74fc980e" -whatwg-url@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.2.0.tgz#abf1a3f5ff4bc2005b3f0c2119382631789d8e44" +whatwg-url@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.4.0.tgz#594f95781545c13934a62db40897c818cafa2e04" dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -7050,7 +7883,11 @@ whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" -which@^1.1.1, which@^1.2.1: +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@^1.0.5, which@^1.1.1, which@^1.2.1: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: @@ -7067,8 +7904,8 @@ window-size@0.1.0: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" winston@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.0.tgz#207faaab6fccf3fe493743dd2b03dbafc7ceb78c" + version "2.3.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.1.tgz#0b48420d978c01804cf0230b648861598225a119" dependencies: async "~1.0.0" colors "1.0.x" @@ -7089,15 +7926,29 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +worker-farm@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff" + dependencies: + errno ">=0.1.1 <0.2.0-0" + xtend ">=4.0.0 <4.1.0-0" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" dependencies: - graceful-fs "^4.1.2" + graceful-fs "^4.1.11" imurmurhash "^0.1.4" slide "^1.1.5" @@ -7107,19 +7958,16 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.0.1.tgz#7d0b2a2e58cddd819039c29c9de65045e1b310e9" +ws@1.1.2, ws@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" dependencies: options ">=0.0.5" ultron "1.0.x" -ws@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" - dependencies: - options ">=0.0.5" - ultron "1.0.x" +wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" @@ -7131,7 +7979,7 @@ xml-char-classes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" -"xml-name-validator@>= 2.0.1 < 3.0.0": +xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" @@ -7150,18 +7998,46 @@ xmldom@^0.1.19, xmldom@^0.1.22: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -xmlhttprequest-ssl@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz#3b7741fea4a86675976e908d296d4445961faa67" +xmlhttprequest-ssl@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xpath-builder@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/xpath-builder/-/xpath-builder-0.0.7.tgz#67d6bbc3f6a320ec317e3e6368c5706b6111deec" -xtend@^4.0.0: +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs@^6.3.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"