refactor: migrate table chart to new API (#10270)

* refactor: migrate table chart to new API

* chore: bump superset-ui to 0.17.0

* Fix Cypress tests

* Apply soft-conversion to numeric metrics

Fix time column formatting test

* Add translation to chart does not exist error

* Bump to 0.17.1
This commit is contained in:
Jesse Yang 2021-01-29 03:12:09 -08:00 committed by GitHub
parent bab86abd92
commit e3db935c62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 680 additions and 390 deletions

View File

@ -362,7 +362,7 @@ ignored-argument-names=_.*
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
max-returns=10
# Maximum number of branch for function / method body
max-branches=12

View File

@ -20,19 +20,20 @@ import {
getChartAliases,
isLegacyResponse,
getSliceIdFromRequestUrl,
JsonObject,
} from '../../utils/vizPlugins';
import { WORLD_HEALTH_DASHBOARD } from './dashboard.helper';
describe('Dashboard load', () => {
let dashboard;
let aliases;
let aliases: string[];
beforeEach(() => {
cy.login();
cy.visit(WORLD_HEALTH_DASHBOARD);
cy.get('#app').then(data => {
const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
cy.get('#app').then(nodes => {
const bootstrapData = JSON.parse(nodes[0].dataset.bootstrap || '');
dashboard = bootstrapData.dashboard_data;
const { slices } = dashboard;
// then define routes and create alias for each requests
@ -53,7 +54,7 @@ describe('Dashboard load', () => {
sliceId = responseBody.form_data.slice_id;
} else {
sliceId = getSliceIdFromRequestUrl(request.url);
responseBody.result.forEach(element => {
responseBody.result.forEach((element: JsonObject) => {
expect(element).to.have.property('error', null);
expect(element).to.have.property('status', 'success');
});

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { interceptChart, parsePostForm } from 'cypress/utils';
import { interceptChart, parsePostForm, Slice } from 'cypress/utils';
import { TABBED_DASHBOARD } from './dashboard.helper';
describe('Dashboard tabs', () => {
@ -40,24 +40,28 @@ describe('Dashboard tabs', () => {
cy.visit(TABBED_DASHBOARD);
cy.get('#app').then(data => {
const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
const dashboard = bootstrapData.dashboard_data;
const bootstrapData = JSON.parse(data[0].dataset.bootstrap || '');
const dashboard = bootstrapData.dashboard_data as { slices: Slice[] };
filterId = dashboard.slices.find(
slice => slice.form_data.viz_type === 'filter_box',
).slice_id;
)?.slice_id;
boxplotId = dashboard.slices.find(
slice => slice.form_data.viz_type === 'box_plot',
).slice_id;
)?.slice_id;
treemapId = dashboard.slices.find(
slice => slice.form_data.viz_type === 'treemap',
).slice_id;
)?.slice_id;
linechartId = dashboard.slices.find(
slice => slice.form_data.viz_type === 'line',
).slice_id;
interceptChart(filterId).as('filterRequest');
interceptChart(treemapId).as('treemapRequest');
interceptChart(linechartId).as('linechartRequest');
interceptChart(boxplotId, false).as('boxplotRequest');
)?.slice_id;
interceptChart({ sliceId: filterId, legacy: true }).as('filterRequest');
interceptChart({ sliceId: treemapId, legacy: true }).as('treemapRequest');
interceptChart({ sliceId: linechartId, legacy: true }).as(
'linechartRequest',
);
interceptChart({ sliceId: boxplotId, legacy: false }).as(
'boxplotRequest',
);
});
});
@ -140,7 +144,7 @@ describe('Dashboard tabs', () => {
// send new query from same tab
cy.wait('@treemapRequest').then(({ request }) => {
const requestBody = parsePostForm(request.body);
const requestParams = JSON.parse(requestBody.form_data);
const requestParams = JSON.parse(requestBody.form_data as string);
expect(requestParams.extra_filters[0]).deep.eq({
col: 'region',
op: '==',
@ -153,7 +157,7 @@ describe('Dashboard tabs', () => {
cy.wait('@linechartRequest').then(({ request }) => {
const requestBody = parsePostForm(request.body);
const requestParams = JSON.parse(requestBody.form_data);
const requestParams = JSON.parse(requestBody.form_data as string);
expect(requestParams.extra_filters[0]).deep.eq({
col: 'region',
op: '==',

View File

@ -20,12 +20,14 @@ import {
isLegacyResponse,
getChartAliases,
parsePostForm,
Dashboard,
JsonObject,
} from 'cypress/utils';
import { WORLD_HEALTH_DASHBOARD } from './dashboard.helper';
describe('Dashboard form data', () => {
const urlParams = { param1: '123', param2: 'abc' };
let dashboard;
let dashboard: Dashboard;
beforeEach(() => {
cy.login();
@ -33,7 +35,7 @@ describe('Dashboard form data', () => {
cy.visit(WORLD_HEALTH_DASHBOARD, { qs: urlParams });
cy.get('#app').then(data => {
const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
const bootstrapData = JSON.parse(data[0].dataset.bootstrap || '');
dashboard = bootstrapData.dashboard_data;
});
});
@ -47,13 +49,16 @@ describe('Dashboard form data', () => {
const responseBody = response?.body;
if (isLegacyResponse(responseBody)) {
const requestParams = JSON.parse(
parsePostForm(request.body).form_data,
parsePostForm(request.body).form_data as string,
);
expect(requestParams.url_params).deep.eq(urlParams);
} else {
request.body.queries.forEach(query => {
expect(query.url_params).deep.eq(urlParams);
});
// TODO: export url params to chart data API
request.body.queries.forEach(
(query: { url_params: JsonObject }) => {
expect(query.url_params).deep.eq(urlParams);
},
);
}
}),
),

View File

@ -19,6 +19,7 @@
// ***********************************************
// Tests for setting controls in the UI
// ***********************************************
import { interceptChart } from 'cypress/utils';
import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper';
describe('Datasource control', () => {
@ -29,10 +30,10 @@ describe('Datasource control', () => {
let numScripts = 0;
cy.login();
cy.intercept('GET', '/superset/explore_json/**').as('getJson');
cy.intercept('POST', '/superset/explore_json/**').as('postJson');
interceptChart({ legacy: false }).as('chartData');
cy.visitChartByName('Num Births Trend');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test="open-datasource-tab').click({ force: true });
cy.get('[data-test="datasource-menu-trigger"]').click();
@ -90,13 +91,13 @@ describe('Datasource control', () => {
describe('VizType control', () => {
beforeEach(() => {
cy.login();
cy.intercept('GET', '/superset/explore_json/**').as('getJson');
cy.intercept('POST', '/superset/explore_json/**').as('postJson');
interceptChart({ legacy: false }).as('tableChartData');
interceptChart({ legacy: true }).as('lineChartData');
});
it('Can change vizType', () => {
cy.visitChartByName('Daily Totals');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@tableChartData' });
let numScripts = 0;
cy.get('script').then(nodes => {
@ -114,27 +115,29 @@ describe('VizType control', () => {
});
cy.get('button[data-test="run-query-button"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg' });
cy.verifySliceSuccess({
waitAlias: '@lineChartData',
chartSelector: 'svg',
});
});
});
describe('Time range filter', () => {
beforeEach(() => {
cy.login();
cy.intercept('GET', '/superset/explore_json/**').as('getJson');
cy.intercept('POST', '/superset/explore_json/**').as('postJson');
interceptChart({ legacy: true }).as('chartData');
});
it('Advanced time_range params', () => {
const formData = {
...FORM_DATA_DEFAULTS,
metrics: [NUM_METRIC],
viz_type: 'line',
time_range: '100 years ago : now',
metrics: [NUM_METRIC],
};
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=time-range-trigger]')
.click()
@ -152,13 +155,13 @@ describe('Time range filter', () => {
it('Common time_range params', () => {
const formData = {
...FORM_DATA_DEFAULTS,
metrics: [NUM_METRIC],
viz_type: 'line',
metrics: [NUM_METRIC],
time_range: 'Last year',
};
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=time-range-trigger]')
.click()
@ -172,13 +175,13 @@ describe('Time range filter', () => {
it('Previous time_range params', () => {
const formData = {
...FORM_DATA_DEFAULTS,
metrics: [NUM_METRIC],
viz_type: 'line',
metrics: [NUM_METRIC],
time_range: 'previous calendar month',
};
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=time-range-trigger]')
.click()
@ -192,13 +195,13 @@ describe('Time range filter', () => {
it('Custom time_range params', () => {
const formData = {
...FORM_DATA_DEFAULTS,
metrics: [NUM_METRIC],
viz_type: 'line',
metrics: [NUM_METRIC],
time_range: 'DATEADD(DATETIME("today"), -7, day) : today',
};
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=time-range-trigger]')
.click()
@ -215,13 +218,13 @@ describe('Time range filter', () => {
it('No filter time_range params', () => {
const formData = {
...FORM_DATA_DEFAULTS,
metrics: [NUM_METRIC],
viz_type: 'line',
metrics: [NUM_METRIC],
time_range: 'No filter',
};
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=time-range-trigger]')
.click()
@ -235,16 +238,16 @@ describe('Time range filter', () => {
describe('Groupby control', () => {
it('Set groupby', () => {
cy.login();
cy.intercept('GET', '/superset/explore_json/**').as('getJson');
cy.intercept('POST', '/superset/explore_json/**').as('postJson');
interceptChart({ legacy: true }).as('chartData');
cy.visitChartByName('Num Births Trend');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=groupby]').within(() => {
cy.get('.Select__control').click();
cy.get('input[type=text]').type('state{enter}');
});
cy.get('button[data-test="run-query-button"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg' });
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'svg' });
});
});

View File

@ -22,25 +22,25 @@
import rison from 'rison';
import shortid from 'shortid';
import { interceptChart } from 'cypress/utils';
import { HEALTH_POP_FORM_DATA_DEFAULTS } from './visualizations/shared.helper';
const apiURL = (endpoint, queryObject) =>
const apiURL = (endpoint: string, queryObject: Record<string, unknown>) =>
`${endpoint}?q=${rison.encode(queryObject)}`;
describe('Test explore links', () => {
beforeEach(() => {
cy.login();
cy.intercept('GET', '/superset/explore_json/**').as('getJson');
cy.intercept('POST', '/superset/explore_json/**').as('postJson');
interceptChart({ legacy: true }).as('chartData');
});
it('Open and close view query modal', () => {
cy.visitChartByName('Growth Rate');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('button#query').click();
cy.get('span').contains('View query').parent().click();
cy.wait('@postJson').then(() => {
cy.wait('@chartData').then(() => {
cy.get('code');
});
cy.get('.ant-modal-content').within(() => {
@ -52,7 +52,7 @@ describe('Test explore links', () => {
cy.intercept('POST', 'r/shortner/').as('getShortUrl');
cy.visitChartByName('Growth Rate');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=short-link-button]').click();
@ -64,12 +64,12 @@ describe('Test explore links', () => {
.then(text => {
cy.visit(text);
});
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
});
it('Test iframe link', () => {
cy.visitChartByName('Growth Rate');
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test=embed-code-button]').click();
cy.get('#embed-code-popover').within(() => {
@ -78,6 +78,8 @@ describe('Test explore links', () => {
});
it('Test chart save as AND overwrite', () => {
interceptChart({ legacy: false }).as('tableChartData');
const formData = {
...HEALTH_POP_FORM_DATA_DEFAULTS,
viz_type: 'table',
@ -87,20 +89,20 @@ describe('Test explore links', () => {
const newChartName = `Test chart [${shortid.generate()}]`;
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@tableChartData' });
cy.url().then(() => {
cy.get('[data-test="query-save-button"]').click();
cy.get('[data-test="saveas-radio"]').check();
cy.get('[data-test="new-chart-name"]').type(newChartName);
cy.get('[data-test="btn-modal-save"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@tableChartData' });
cy.visitChartByName(newChartName);
// Overwriting!
cy.get('[data-test="query-save-button"]').click();
cy.get('[data-test="save-overwrite-radio"]').check();
cy.get('[data-test="btn-modal-save"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@tableChartData' });
const query = {
filters: [
{
@ -110,6 +112,7 @@ describe('Test explore links', () => {
},
],
};
cy.request(apiURL('/api/v1/chart/', query)).then(response => {
expect(response.body.count).equals(1);
cy.request('DELETE', `/api/v1/chart/${response.body.ids[0]}`);
@ -123,7 +126,7 @@ describe('Test explore links', () => {
const dashboardTitle = `Test dashboard [${shortid.generate()}]`;
cy.visitChartByName(chartName);
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test="query-save-button"]').click();
cy.get('[data-test="saveas-radio"]').check();
@ -134,7 +137,7 @@ describe('Test explore links', () => {
.type(`${dashboardTitle}{enter}{enter}`);
cy.get('[data-test="btn-modal-save"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
let query = {
filters: [
{
@ -149,7 +152,7 @@ describe('Test explore links', () => {
});
cy.visitChartByName(newChartName);
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
cy.get('[data-test="query-save-button"]').click();
cy.get('[data-test="save-overwrite-radio"]').check();
@ -161,7 +164,7 @@ describe('Test explore links', () => {
.type(`${dashboardTitle}{enter}{enter}`);
cy.get('[data-test="btn-modal-save"]').click();
cy.verifySliceSuccess({ waitAlias: '@postJson' });
cy.verifySliceSuccess({ waitAlias: '@chartData' });
query = {
filters: [
{

View File

@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { interceptChart } from 'cypress/utils';
import {
FORM_DATA_DEFAULTS,
NUM_METRIC,
@ -34,7 +35,7 @@ describe('Visualization > Table', () => {
const PERCENT_METRIC = {
expressionType: 'SQL',
sqlExpression: 'CAST(SUM(num_girls)+AS+FLOAT)/SUM(num)',
sqlExpression: 'CAST(SUM(num_girls) AS FLOAT)/SUM(num)',
column: null,
aggregate: null,
hasCustomLabel: true,
@ -44,7 +45,7 @@ describe('Visualization > Table', () => {
beforeEach(() => {
cy.login();
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
interceptChart({ legacy: false }).as('chartData');
});
it('Use default time column', () => {
@ -66,8 +67,8 @@ describe('Visualization > Table', () => {
});
// when format with smart_date, time column use format by granularity
cy.get('.chart-container td:nth-child(1)').contains('2008 Q1');
// other column with timestamp use raw timestamp
cy.get('.chart-container td:nth-child(3)').contains('2008-01-01T00:00:00');
// other column with timestamp use adaptive formatting
cy.get('.chart-container td:nth-child(3)').contains('2008');
cy.get('.chart-container td:nth-child(4)').contains('TX');
});
@ -99,7 +100,7 @@ describe('Visualization > Table', () => {
groupby: ['name'],
});
cy.verifySliceSuccess({
waitAlias: '@getJson',
waitAlias: '@chartData',
querySubstring: /group by.*name/i,
chartSelector: 'table',
});
@ -115,14 +116,14 @@ describe('Visualization > Table', () => {
groupby: ['name'],
});
cy.verifySliceSuccess({
waitAlias: '@getJson',
waitAlias: '@chartData',
querySubstring: /group by.*name/i,
chartSelector: 'table',
});
// should handle sorting correctly
cy.get('.chart-container th').contains('name').click();
cy.get('.chart-container td:nth-child(2):eq(0)').contains('Abigail');
cy.get('.chart-container td:nth-child(2):eq(0)').contains('Aaron');
cy.get('.chart-container th').contains('Time').click().click();
cy.get('.chart-container td:nth-child(1):eq(0)').contains('2008');
});
@ -134,7 +135,7 @@ describe('Visualization > Table', () => {
metrics: [],
groupby: ['name'],
});
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' });
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Test table with groupby order desc', () => {
@ -144,7 +145,7 @@ describe('Visualization > Table', () => {
groupby: ['name'],
order_desc: true,
});
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' });
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Test table with groupby and limit', () => {
@ -156,9 +157,9 @@ describe('Visualization > Table', () => {
row_limit: limit,
};
cy.visitChartByParams(JSON.stringify(formData));
cy.wait('@getJson').then(({ response }) => {
cy.wait('@chartData').then(({ response }) => {
cy.verifySliceContainer('table');
expect(response?.body.data.records.length).to.eq(limit);
expect(response?.body.result[0].data.length).to.eq(limit);
});
cy.get('span.label-danger').contains('10 rows');
});
@ -178,7 +179,7 @@ describe('Visualization > Table', () => {
cy.get('div[data-test="all_columns"]').should('be.visible');
cy.get('div[data-test="groupby"]').should('not.exist');
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' });
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
// should allow switch to aggregate mode
cy.get('div[data-test="query_mode"] .btn').contains('Aggregate').click();
@ -196,14 +197,13 @@ describe('Visualization > Table', () => {
all_columns: ['name', 'state', 'ds', 'num'],
metrics: [],
row_limit: limit,
order_by_cols: ['["num",+false]'],
order_by_cols: ['["num", false]'],
};
cy.visitChartByParams(JSON.stringify(formData));
cy.wait('@getJson').then(({ response }) => {
cy.wait('@chartData').then(({ response }) => {
cy.verifySliceContainer('table');
const responseBody = response?.body;
const { records } = responseBody.data;
const records = response?.body.result[0].data;
expect(records[0].num).greaterThan(records[records.length - 1].num);
});
});
@ -215,7 +215,7 @@ describe('Visualization > Table', () => {
const formData = { ...VIZ_DEFAULTS, metrics, adhoc_filters: filters };
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' });
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Tests table number formatting with % in metric name', () => {
@ -227,7 +227,7 @@ describe('Visualization > Table', () => {
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({
waitAlias: '@getJson',
waitAlias: '@chartData',
querySubstring: /group by.*state/i,
chartSelector: 'table',
});

View File

@ -90,9 +90,8 @@ Cypress.Commands.add(
cy.verifySliceContainer(chartSelector);
const responseBody = response?.body;
if (querySubstring) {
const query = responseBody
? (responseBody as { query: string }).query
: '';
const query: string =
responseBody.query || responseBody.result[0].query || '';
if (querySubstring instanceof RegExp) {
expect(query).to.match(querySubstring);
} else {

View File

@ -17,7 +17,30 @@
* under the License.
*/
const V1_PLUGINS = ['box_plot', 'echarts_timeseries', 'word_cloud', 'pie'];
export type JsonPrimitive = string | number | boolean | null;
export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
export type JsonArray = JsonValue[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type JsonObject = { [member: string]: any };
export interface Slice {
slice_id: number;
form_data: {
viz_type: string;
};
}
export interface Dashboard {
slices: Slice[];
}
const V1_PLUGINS = [
'box_plot',
'echarts_timeseries',
'word_cloud',
'pie',
'table',
];
export const DASHBOARD_CHART_ALIAS_PREFIX = 'getJson_';
export function isLegacyChart(vizType: string): boolean {
@ -34,7 +57,7 @@ export function getSliceIdFromRequestUrl(url: string) {
return query?.match(/\d+/)?.[0];
}
export function getChartAliases(slices: any[]): string[] {
export function getChartAliases(slices: Slice[]): string[] {
const aliases: string[] = [];
Array.from(slices).forEach(slice => {
const vizType = slice.form_data.viz_type;
@ -54,11 +77,24 @@ export function getChartAliases(slices: any[]): string[] {
return aliases;
}
export function interceptChart(sliceId: number, isLegacy = true) {
const formData = { slice_id: sliceId };
const encodedFormData = encodeURIComponent(JSON.stringify(formData));
const url = isLegacy
? `**/superset/explore_json/?form_data=${encodedFormData}*`
: `**/api/v1/chart/data?form_data=${encodedFormData}*`;
return cy.intercept('POST', url);
export function interceptChart({
sliceId,
legacy = false,
method = 'POST',
}: {
sliceId?: number;
legacy?: boolean;
method?: 'POST' | 'GET';
}) {
const urlBase = legacy ? '**/superset/explore_json/' : '**/api/v1/chart/data';
let url;
if (sliceId) {
const encodedFormData = encodeURIComponent(
JSON.stringify({ slice_id: sliceId }),
);
url = `${urlBase}?form_data=${encodedFormData}*`;
} else {
url = `${urlBase}**`;
}
return cy.intercept(method, url);
}

View File

@ -6072,9 +6072,12 @@
}
},
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-interpolate": {
"version": "2.0.1",
@ -18549,19 +18552,19 @@
}
},
"@superset-ui/chart-controls": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.16.9.tgz",
"integrity": "sha512-GTwnJx5AhiYqwed3F3FCz+8Yuc56jlLM/g872zoHYQUejnAXGs/Iomeznga6+281DKfsbCO6ptH6qiOZYDH8PA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.17.1.tgz",
"integrity": "sha512-dfJRoVH0WbG5FQ8smszVtiYLI3NvvLAQxW6HRgOqTLegiKocIIB8hjpMpGrOPxx2G0mBigAubeQowC1VOlpAZQ==",
"requires": {
"@superset-ui/core": "0.16.7",
"@superset-ui/core": "0.17.1",
"lodash": "^4.17.15",
"prop-types": "^15.7.2"
}
},
"@superset-ui/core": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.16.7.tgz",
"integrity": "sha512-9i/o9ZC+dJibhoWZnoKGvxMMFcz65LjHuYk+hRspuRWA4qwobcdu64piQpfwuFVhw1yh3cbdxq+OSsNmNX9A9g==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.17.1.tgz",
"integrity": "sha512-VnWhb5FjMOrAF2+PJG4WkvscmgtRnnFZBEqG+2g8TSSby2RfIrGB390Dq6abqc9SmBmjNPLj6zkzsvJZv8DsOA==",
"requires": {
"@babel/runtime": "^7.1.2",
"@emotion/core": "^10.0.28",
@ -18574,7 +18577,7 @@
"@types/lodash": "^4.14.149",
"@types/rison": "0.0.6",
"@types/seedrandom": "^2.4.28",
"@vx/responsive": "^0.0.197",
"@vx/responsive": "^0.0.199",
"csstype": "^2.6.4",
"d3-format": "^1.3.2",
"d3-interpolate": "^1.4.0",
@ -18594,9 +18597,9 @@
},
"dependencies": {
"@vx/responsive": {
"version": "0.0.197",
"resolved": "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.197.tgz",
"integrity": "sha512-Qv15PJ/Hy79LjyfJ/9E8z+zacKAnD43O2Jg9wvB6PFSNs73xPEDy/mHTYxH+FZv94ruAE3scBO0330W29sQpyg==",
"version": "0.0.199",
"resolved": "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.199.tgz",
"integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==",
"requires": {
"@types/lodash": "^4.14.146",
"@types/react": "*",
@ -18606,9 +18609,12 @@
}
},
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-interpolate": {
"version": "1.4.0",
@ -18641,12 +18647,12 @@
}
},
"@superset-ui/legacy-plugin-chart-calendar": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.16.9.tgz",
"integrity": "sha512-8SbUVhuyXYB4Jh4ucFEonhWwF9/rEVOmR/E28bfS3dVJ3lChRx2T8ijv0pRxXNuPSl619Qm61/ec4637V7I//g==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.17.1.tgz",
"integrity": "sha512-v9Hh2hNdxsu3vSRtx1KjqsDhDYlCStbEQekp2+BKRH55RKitbJzbw+6GgXxA09s/6VgIxji8oEaZVYAWylzJtQ==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3-array": "^2.0.3",
"d3-selection": "^1.4.0",
"d3-tip": "^0.9.1",
@ -18654,72 +18660,78 @@
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
}
}
},
"@superset-ui/legacy-plugin-chart-chord": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.16.9.tgz",
"integrity": "sha512-QK3yJLDzkrIDYAfvAXmZI/nms0fl54WPSQlEN42e17IRe8Z/UNMd7Un4IyAEPjNJqt53uBJq5CEKIBAIB2eTng==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.17.1.tgz",
"integrity": "sha512-xJbr9oyHBOBRp1IWQn1HuLsrArJtADVk2FE6r4QZTVYCKzJoKrQTqQEfkA2roHOHfOZtlcHcD1rlOMt8KpdmDw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"prop-types": "^15.6.2",
"react": "^16.13.1"
}
},
"@superset-ui/legacy-plugin-chart-country-map": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.16.9.tgz",
"integrity": "sha512-h58JI45Gg/Y7FQEY3v6Wsh07XvYSrH88d+6MJN0Iv72nv9X2iC5h9QVyN0M0jYDpqnfMkoPzsP90Ana8pYqjCw==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.17.1.tgz",
"integrity": "sha512-CCJPFGp0P1lEX4W0JqcSC0Lq43gx8BSUNeE//xz+ZKc9JoERttVCKjwEyFCov6Y++iFM/EfDpg1bRS0XpJxD4A==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"d3-array": "^2.0.3",
"prop-types": "^15.6.2"
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
}
}
},
"@superset-ui/legacy-plugin-chart-event-flow": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.16.9.tgz",
"integrity": "sha512-FWaaXmZXaslb0XlJS3xRcZlFpvGcWtNlGc4x01jrW8vSUzZ16wnQqqPO7b46K6LDJYfgaglXEzNK4gwPWLHKoA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.17.1.tgz",
"integrity": "sha512-pGuo5cVjLRJILKbE2oc7mFoWUTrOIf2ChNLHpULZZeNtpG8H3gXGA97qK+5KgXtslfv2BVi1sbR97VV9IH3gTw==",
"requires": {
"@data-ui/event-flow": "^0.0.84",
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-force-directed": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.16.9.tgz",
"integrity": "sha512-2kryYHT1HqzpYLXkMW5ocCVEJ57K1zGII6mP+piIhqkEgzfSUL1+mUjfzUypuvc+zpKOuWiDxaGwVJqE8gGSbA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.17.1.tgz",
"integrity": "sha512-F8aV/iGBeHOh+9ewE8rfpWN2J/avAvlWl1zIM/PZTMlwimVwBXj8voTWk32LVL+Cb+9DwntB5KA093r8yWHK5Q==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"prop-types": "^15.7.2"
}
},
"@superset-ui/legacy-plugin-chart-heatmap": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.16.9.tgz",
"integrity": "sha512-sw1/gOzAyZq6ki7ZocM9KH6BfYuT/yO2zfxW8OMB/8HeMVrM2gPkljSgIX6GYwY5Y83g3ZI+dVPXcp0HNTR0yQ==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.17.1.tgz",
"integrity": "sha512-IlItjyVT9Y3aE3qYml+CEbGpwVrPJu68MYb5UNOp+ms5DEETRH0Z61kKvX/egCVouYznyVrxjdc8SvL8tHqQYg==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"d3-svg-legend": "^1.x",
"d3-tip": "^0.9.1",
@ -18727,16 +18739,16 @@
}
},
"@superset-ui/legacy-plugin-chart-histogram": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.16.9.tgz",
"integrity": "sha512-8g4NXTxRjojIntF/ovDoXKaDws/cg6G4CHtll3fLmr85eXSvJATtYODF+KsjefBmGmfIXNUr0kdIPAjfyprizA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.17.1.tgz",
"integrity": "sha512-awZCVmpXH5LCOOCktZdaj5PrPUBeAWdK/60A6n/oKufZ2x4eoXVLgBpsj3JCS73XcKu3FwhWRHLujE0pZthKhA==",
"requires": {
"@data-ui/histogram": "^0.0.84",
"@data-ui/theme": "^0.0.84",
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@vx/legend": "^0.0.198",
"@vx/responsive": "^0.0.197",
"@vx/responsive": "^0.0.199",
"@vx/scale": "^0.0.197",
"prop-types": "^15.6.2"
},
@ -18766,9 +18778,9 @@
}
},
"@vx/responsive": {
"version": "0.0.197",
"resolved": "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.197.tgz",
"integrity": "sha512-Qv15PJ/Hy79LjyfJ/9E8z+zacKAnD43O2Jg9wvB6PFSNs73xPEDy/mHTYxH+FZv94ruAE3scBO0330W29sQpyg==",
"version": "0.0.199",
"resolved": "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.199.tgz",
"integrity": "sha512-ONrmLUAG+8wzD3cn/EmsuZh6JHeyejqup3ZsV25t04VaVJAVQAJukAfNdH8YiwSJu0zSo+txkBTfrnOmFyQLOw==",
"requires": {
"@types/lodash": "^4.14.146",
"@types/react": "*",
@ -18802,21 +18814,24 @@
}
},
"@superset-ui/legacy-plugin-chart-horizon": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.16.9.tgz",
"integrity": "sha512-l5uCO0w1cCcMeI5lJtwhOLZO1509Fj+OCZuvsRCe/pjMncwH8tAwxVljGZ54YLLIWi9Dqo1WFQvA2BLsjQcv6w==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.17.1.tgz",
"integrity": "sha512-1omJPgUSktLCqBXqDMMqb9dFfflxWGmEdl6lxVPMqqCrlRILdNCd1rdsQFsu1cN90FmZav7AMVj7SLvIHWvNnQ==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3-array": "^2.0.3",
"d3-scale": "^3.0.1",
"prop-types": "^15.6.2"
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-scale": {
"version": "3.2.3",
@ -18833,12 +18848,12 @@
}
},
"@superset-ui/legacy-plugin-chart-map-box": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.16.9.tgz",
"integrity": "sha512-cf7QdN64rAo4UAmzirhHcJMO7IBYvMX+Slu7/LsCX4CnrVmJtO4d+vGFlNS5FaWU+t2A6lVH5QDpSI1WBgcfAA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.17.1.tgz",
"integrity": "sha512-RHI9k3ulGodGjKgX2kBF3muMyTZKCQGPXV6BbNRzV8DJCc6eGrcE1eznC0ipHiy4yBYeKHfMwcWX3jh9dCI/kg==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"immutable": "^3.8.2",
"mapbox-gl": "^0.53.0",
"prop-types": "^15.6.2",
@ -18855,118 +18870,118 @@
}
},
"@superset-ui/legacy-plugin-chart-paired-t-test": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.16.9.tgz",
"integrity": "sha512-YEVJtqn25SWLr0N33BHzm5CjAOuSkwkOrxl05Lmceyf2z2PwHhrCnnLWXRzEEszQ9IXTsbKT8HYJtPkKNFVIWw==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.17.1.tgz",
"integrity": "sha512-WExiHSMvByu8+weNJoKll82cPrhF4zNRnMGzdiYMewJ6TZLN4Ws3ZLR+b2c26BnWQFyA8qXPpsCcQzX9c9WODw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"distributions": "^1.0.0",
"prop-types": "^15.6.2",
"reactable-arc": "0.15.0"
}
},
"@superset-ui/legacy-plugin-chart-parallel-coordinates": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.16.9.tgz",
"integrity": "sha512-zX6uToyBEV5fKh+cpELDQ+xD9c+TtAGqKsc7r1mpY/R2Vfzw7oD5aOrwcxBshtMoJxx72jo9EuC5nzgNQf4+ug==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.17.1.tgz",
"integrity": "sha512-v6HPEyQRKEOhVpydKzVo+HWUDNaYJhgWL/mrr/kDhT+htUPOUqtTqQZ2BsvgpTQiX4qXHUMnAOXAN7eBa4Xf3w==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"prop-types": "^15.7.2"
}
},
"@superset-ui/legacy-plugin-chart-partition": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.16.9.tgz",
"integrity": "sha512-OEmirurMTPAInqMEjGkMQqJDUsM0TMJ4OCFaJ2vtwbvlwk3Fgar/fm/m/qhaLzDLXfTIgb6TyUkxiBCWmmF0iA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.17.1.tgz",
"integrity": "sha512-Zx7lEjgz0N/MQBmXFrhAsjryIl7QzZc5Gi5bXEi9GYiXcDUaZJmLW0cUnJT5Maqgwt3HCtKgCDZEh/SRj+XBsQ==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"d3-hierarchy": "^1.1.8",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-pivot-table": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.16.9.tgz",
"integrity": "sha512-gpEXyC/WlBVeRD2INPx1IfOi3QwmPkr9bdwLfhXe34xU620uj85jO8VKlSU+tGppiyZz6aNaC2WBU4nTRRXUgg==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.17.1.tgz",
"integrity": "sha512-qlXdtaKNQsMibpyJIeQUqaJTLE4Uce9Kn47t9mgB6lCLQc5c+egM9hVwB57P8tUxMBCJePQcjiRIJRnyLKjOTA==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"datatables.net-bs": "^1.10.15",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-rose": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.16.9.tgz",
"integrity": "sha512-T6amU5vtlyjohI065OBmLktNW4aNmVsh8UAxSOzKJBRyVDSk0cs1Ntb6FG6jNZLxe7AYh0YVmnYeLI9IVLs2VA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.17.1.tgz",
"integrity": "sha512-dQykgdgrtOTAq4ck/uZ98R8Vhv4UtercXUlNDMTsiJo5nz3/Ka/4Oz3zBf3Pey+3JrsIOQtJP1vKRKt/j37Zkg==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"nvd3": "1.8.6",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-sankey": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.16.9.tgz",
"integrity": "sha512-Vkauo64wsuRMznDtpqHWPrP6vohnm119wUlWPYk2y9/0e1PgowlRyv6X0RUqWyk2z4/eUXIzGj5YUebqniYjtA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.17.1.tgz",
"integrity": "sha512-gy5COpeeEHllYFuenXwdZr5OZ8bL1g+C16bGbjACG9/kIaF9ShoTN+Ad5cNTepb78Cox+WhmPHKIzbgPybN3Bw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"d3-sankey": "^0.4.2",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-sankey-loop": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.16.9.tgz",
"integrity": "sha512-LtnVsvnoNTrHrOoZcdCuzYX/akCsaiMvWG53KoQis9dsu9+vc4xfKySw0Dct/QpGU+904YbGfFX9qDzh+RCsyw==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.17.1.tgz",
"integrity": "sha512-r46LqceZi1hv6DDiZMinuU/hR+jyAgURcBvXy/5GvEAF+0eVHUzqbQ8SWivmFCNRwVTAEBMYkUa3IKZ6LBeUbw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3-sankey-diagram": "^0.7.3",
"d3-selection": "^1.4.0",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-sunburst": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.16.9.tgz",
"integrity": "sha512-DTOuXy7fPUvwUM8WjiKGmbydcIynAbXlEGdmi/ObLlh4lACaTPCX8IOGc18eJP0G78pxeXpByK9JoEZuCbQyEA==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.17.1.tgz",
"integrity": "sha512-hyP36lNaLBWCKfRXTMTG/uvJZa1bMjyX0jYDRAY/tNVxPBAjhTrB76SW1eShfpugg6baaqys9XrbVkxiKRcFnA==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-treemap": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.16.9.tgz",
"integrity": "sha512-P+IQYjaMrmN2RqmIEJ2V3w8UQG6jxLPGgmsK/KkGMCzl8PAJJtPcRZw2Z/9JGh8u/7B70JCAEL+sRcLQCA/aTQ==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.17.1.tgz",
"integrity": "sha512-z6dQo1ZDb2/drZUJ3nYScBbDXHiIYchtpscYNszyB/jGxJ90ridUniLQicyLxMkjdK4mpuBW9MgidSg0y0I0sw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3-hierarchy": "^1.1.8",
"d3-selection": "^1.4.0",
"prop-types": "^15.6.2"
}
},
"@superset-ui/legacy-plugin-chart-world-map": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.16.9.tgz",
"integrity": "sha512-PtYzSKgiaInMt5NYyAmG4b6acffYvN1W8hetpq8TpeMkhuLzA69D3rsAj72ky/dgy5/n14t8wgdfKyfrrt9c6A==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.17.1.tgz",
"integrity": "sha512-S9XuCVUIbgfCH4sG0PWGMdEc14fzunZIiUZOC2hh2JtLV/vU452XO4a9viTzWFvAY75zHNetgkTtuoCsrQdLOw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"d3": "^3.5.17",
"d3-array": "^2.4.0",
"d3-color": "^1.4.1",
@ -18975,9 +18990,12 @@
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-color": {
"version": "1.4.1",
@ -18987,13 +19005,13 @@
}
},
"@superset-ui/legacy-preset-chart-big-number": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.16.9.tgz",
"integrity": "sha512-Iby3rNcdv+cVy1A/I/Lg/n76v71JdPxKJJc+A4YUil3SalmFFo4mxm0glrX9dex6IYxpZMWbDJKgnHEbhalXlw==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.17.1.tgz",
"integrity": "sha512-961i+DqTNcPNlvH3GAB2ofViEk4CcZFdcjZ/rMdCzlEichmLLrNzKUPfouvhMpMokb4ysEADOkQvE7POlKjDWw==",
"requires": {
"@data-ui/xy-chart": "^0.0.84",
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@types/d3-color": "^1.2.2",
"@types/shortid": "^0.0.29",
"d3-color": "^1.2.3",
@ -19043,34 +19061,128 @@
"nvd3-fork": "^2.0.5",
"prop-types": "^15.6.2",
"urijs": "^1.18.10"
},
"dependencies": {
"@superset-ui/chart-controls": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.16.9.tgz",
"integrity": "sha512-GTwnJx5AhiYqwed3F3FCz+8Yuc56jlLM/g872zoHYQUejnAXGs/Iomeznga6+281DKfsbCO6ptH6qiOZYDH8PA==",
"requires": {
"@superset-ui/core": "0.16.7",
"lodash": "^4.17.15",
"prop-types": "^15.7.2"
}
},
"@superset-ui/core": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.16.7.tgz",
"integrity": "sha512-9i/o9ZC+dJibhoWZnoKGvxMMFcz65LjHuYk+hRspuRWA4qwobcdu64piQpfwuFVhw1yh3cbdxq+OSsNmNX9A9g==",
"requires": {
"@babel/runtime": "^7.1.2",
"@emotion/core": "^10.0.28",
"@emotion/styled": "^10.0.27",
"@types/d3-format": "^1.3.0",
"@types/d3-interpolate": "^1.3.1",
"@types/d3-scale": "^2.1.1",
"@types/d3-time": "^1.0.9",
"@types/d3-time-format": "^2.1.0",
"@types/lodash": "^4.14.149",
"@types/rison": "0.0.6",
"@types/seedrandom": "^2.4.28",
"@vx/responsive": "^0.0.197",
"csstype": "^2.6.4",
"d3-format": "^1.3.2",
"d3-interpolate": "^1.4.0",
"d3-scale": "^3.0.0",
"d3-time": "^1.0.10",
"d3-time-format": "^2.2.0",
"emotion-theming": "^10.0.27",
"fetch-retry": "^4.0.1",
"jed": "^1.1.1",
"lodash": "^4.17.11",
"pretty-ms": "^7.0.0",
"react-error-boundary": "^1.2.5",
"reselect": "^4.0.0",
"rison": "^0.1.1",
"seedrandom": "^3.0.5",
"whatwg-fetch": "^3.0.0"
}
},
"@vx/responsive": {
"version": "0.0.197",
"resolved": "https://registry.npmjs.org/@vx/responsive/-/responsive-0.0.197.tgz",
"integrity": "sha512-Qv15PJ/Hy79LjyfJ/9E8z+zacKAnD43O2Jg9wvB6PFSNs73xPEDy/mHTYxH+FZv94ruAE3scBO0330W29sQpyg==",
"requires": {
"@types/lodash": "^4.14.146",
"@types/react": "*",
"lodash": "^4.17.10",
"prop-types": "^15.6.1",
"resize-observer-polyfill": "1.5.1"
}
},
"d3-array": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-interpolate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
"requires": {
"d3-color": "1"
}
},
"d3-scale": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz",
"integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==",
"requires": {
"d3-array": "^2.3.0",
"d3-format": "1 - 2",
"d3-interpolate": "1.2.0 - 2",
"d3-time": "1 - 2",
"d3-time-format": "2 - 3"
}
},
"d3-time-format": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
"requires": {
"d3-time": "1"
}
}
}
},
"@superset-ui/plugin-chart-echarts": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.16.9.tgz",
"integrity": "sha512-MC1eEq3BLedRR+tL88BnisSUkqBxAi4t79JuGY2q9Lgg+7yh1wgD6bqKkR8JaH3SdqSK2XpG0dPkjHZXqFpkMQ==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.17.1.tgz",
"integrity": "sha512-+PzvoEbeTfrZ+SkM/bldwGljTjy+VBSz/AoPsDEgKmaJ8UZSG7rXQM01X0so7XkD9WRvAMI5q6+uFjL2zfDJlw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@types/echarts": "^4.6.3",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@types/echarts": "^4.9.3",
"@types/mathjs": "^6.0.7",
"echarts": "^5.0.0",
"mathjs": "^8.0.1"
}
},
"@superset-ui/plugin-chart-table": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.16.9.tgz",
"integrity": "sha512-SA6ypwoJq1A9nG/xaI+xRhSRG34omNakgNv3vgeBqCYuZLHwSCf+a/c7liwAA9PhlSTNB7CuOZHC542SVSe6ZQ==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.17.1.tgz",
"integrity": "sha512-Jkf4nAU2usJUQthRMO5dSdeatlUvI+3QYCWujneTXCbR4MMBXhnlePlD0LO5dTteLNBql56rg2SbD10NDIZGZA==",
"requires": {
"@emotion/core": "^10.0.28",
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@types/d3-array": "^2.0.0",
"@types/match-sorter": "^4.0.0",
"@types/react-table": "^7.0.19",
"d3-array": "^2.4.0",
"match-sorter": "^4.1.0",
"match-sorter": "^6.1.0",
"memoize-one": "^5.1.1",
"react-icons": "^3.10.0",
"react-table": "^7.2.1",
@ -19078,37 +19190,23 @@
"xss": "^1.0.6"
},
"dependencies": {
"@babel/runtime": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
"integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
},
"match-sorter": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-4.2.1.tgz",
"integrity": "sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"@babel/runtime": "^7.10.5",
"remove-accents": "0.4.2"
"internmap": "^1.0.0"
}
}
}
},
"@superset-ui/plugin-chart-word-cloud": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.16.9.tgz",
"integrity": "sha512-NWbPAqxxF8V16xH3jxhhJu9HAoU9BWRZktvhKePQeAtFrGZQ79nQzU+tHYivWvVmjn2bcfhg3D5V5rJwysN9Uw==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.17.1.tgz",
"integrity": "sha512-jPz/22L3IwIoQqsHEFqwQTGyYdatednazPB3zGUv1KMzkj4AyU/sd5AsnCCDDC7EL10ylhy9NB8EYk12x5Z7vw==",
"requires": {
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@types/d3-cloud": "^1.2.1",
"@types/d3-scale": "^2.0.2",
"d3-cloud": "^1.2.5",
@ -19118,9 +19216,12 @@
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-scale": {
"version": "3.2.3",
@ -19137,14 +19238,14 @@
}
},
"@superset-ui/preset-chart-xy": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.16.9.tgz",
"integrity": "sha512-hWIuTVcpVINXAlCSEDKKRWiAatx/d15pFmMaaZC7NzpQJ2XfZC6jpCmwgSxbvhbezbduQhwU7DViNINbg2XoZg==",
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.17.1.tgz",
"integrity": "sha512-N1mSF8OE04n+xM8Fh6ZsNLD1ARGnVlh3zzld1YmhasS7rRP8UZ3STGEjLm4IV8mTYeVc+i7+Xg/VI5Fl42Uhow==",
"requires": {
"@data-ui/theme": "^0.0.84",
"@data-ui/xy-chart": "^0.0.84",
"@superset-ui/chart-controls": "0.16.9",
"@superset-ui/core": "0.16.7",
"@superset-ui/chart-controls": "0.17.1",
"@superset-ui/core": "0.17.1",
"@vx/axis": "^0.0.198",
"@vx/legend": "^0.0.198",
"@vx/scale": "^0.0.197",
@ -21002,11 +21103,6 @@
"@types/react": "*"
}
},
"@types/match-sorter": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/match-sorter/-/match-sorter-4.0.0.tgz",
"integrity": "sha512-JK7HNHXZA7i/nEp6fbNAxoX/1j1ysZXmv2/nlkt2UpX1LiUWKLtyt/dMmDTlMPR6t6PkwMmIr2W2AAyu6oELNw=="
},
"@types/mathjs": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/@types/mathjs/-/mathjs-6.0.11.tgz",
@ -21194,6 +21290,16 @@
"@types/react": "*"
}
},
"@types/react-loadable": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/@types/react-loadable/-/react-loadable-5.5.4.tgz",
"integrity": "sha512-otKcjNCfVUzdBMdwOqFITTmBruIXw6GeoZitTBvJ6BMrif8Utu2JLy42GWukNnYI7ewJdncUCooz5Y/1dBz4+w==",
"dev": true,
"requires": {
"@types/react": "*",
"@types/webpack": "*"
}
},
"@types/react-redux": {
"version": "7.1.10",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.10.tgz",
@ -28683,9 +28789,12 @@
},
"dependencies": {
"d3-array": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.9.1.tgz",
"integrity": "sha512-Ob7RdOtkqsjx1NWyQHMFLtCSk6/aKTxDdC4ZIolX+O+mDD2RzrsYgAyc0WGAlfYFVELLSilS7w8BtE3PKM8bHg=="
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz",
"integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-interpolate": {
"version": "2.0.1",
@ -33267,6 +33376,11 @@
}
}
},
"internmap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.0.tgz",
"integrity": "sha512-SdoDWwNOTE2n4JWUsLn4KXZGuZPjPF9yyOGc8bnfWnBQh7BD/l80rzSznKc/r4Y0aQ7z3RTk9X+tV4tHBpu+dA=="
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",

View File

@ -65,34 +65,34 @@
"@babel/runtime-corejs3": "^7.12.5",
"@data-ui/sparkline": "^0.0.84",
"@emotion/core": "^10.0.35",
"@superset-ui/chart-controls": "^0.16.9",
"@superset-ui/core": "^0.16.7",
"@superset-ui/legacy-plugin-chart-calendar": "^0.16.9",
"@superset-ui/legacy-plugin-chart-chord": "^0.16.9",
"@superset-ui/legacy-plugin-chart-country-map": "^0.16.9",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.16.9",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.16.9",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.16.9",
"@superset-ui/legacy-plugin-chart-histogram": "^0.16.9",
"@superset-ui/legacy-plugin-chart-horizon": "^0.16.9",
"@superset-ui/legacy-plugin-chart-map-box": "^0.16.9",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.16.9",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.16.9",
"@superset-ui/legacy-plugin-chart-partition": "^0.16.9",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.16.9",
"@superset-ui/legacy-plugin-chart-rose": "^0.16.9",
"@superset-ui/legacy-plugin-chart-sankey": "^0.16.9",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.16.9",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.16.9",
"@superset-ui/legacy-plugin-chart-treemap": "^0.16.9",
"@superset-ui/legacy-plugin-chart-world-map": "^0.16.9",
"@superset-ui/legacy-preset-chart-big-number": "^0.16.9",
"@superset-ui/chart-controls": "^0.17.1",
"@superset-ui/core": "^0.17.1",
"@superset-ui/legacy-plugin-chart-calendar": "^0.17.1",
"@superset-ui/legacy-plugin-chart-chord": "^0.17.1",
"@superset-ui/legacy-plugin-chart-country-map": "^0.17.1",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.17.1",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.17.1",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.17.1",
"@superset-ui/legacy-plugin-chart-histogram": "^0.17.1",
"@superset-ui/legacy-plugin-chart-horizon": "^0.17.1",
"@superset-ui/legacy-plugin-chart-map-box": "^0.17.1",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.1",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.1",
"@superset-ui/legacy-plugin-chart-partition": "^0.17.1",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.1",
"@superset-ui/legacy-plugin-chart-rose": "^0.17.1",
"@superset-ui/legacy-plugin-chart-sankey": "^0.17.1",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.1",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.17.1",
"@superset-ui/legacy-plugin-chart-treemap": "^0.17.1",
"@superset-ui/legacy-plugin-chart-world-map": "^0.17.1",
"@superset-ui/legacy-preset-chart-big-number": "^0.17.1",
"@superset-ui/legacy-preset-chart-deckgl": "^0.4.1",
"@superset-ui/legacy-preset-chart-nvd3": "^0.16.10",
"@superset-ui/plugin-chart-echarts": "^0.16.9",
"@superset-ui/plugin-chart-table": "^0.16.9",
"@superset-ui/plugin-chart-word-cloud": "^0.16.9",
"@superset-ui/preset-chart-xy": "^0.16.9",
"@superset-ui/plugin-chart-echarts": "^0.17.1",
"@superset-ui/plugin-chart-table": "^0.17.1",
"@superset-ui/plugin-chart-word-cloud": "^0.17.1",
"@superset-ui/preset-chart-xy": "^0.17.1",
"@vx/responsive": "^0.0.195",
"abortcontroller-polyfill": "^1.1.9",
"antd": "^4.9.4",
@ -214,6 +214,7 @@
"@types/react-dom": "^16.9.8",
"@types/react-gravatar": "^2.6.8",
"@types/react-json-tree": "^0.6.11",
"@types/react-loadable": "^5.5.4",
"@types/react-redux": "^7.1.10",
"@types/react-router-dom": "^5.1.5",
"@types/react-select": "^3.0.19",

View File

@ -27,7 +27,7 @@
],
// for supressing errors caused by incompatible @types/react when `npm link`
// Ref: https://github.com/Microsoft/typescript/issues/6496#issuecomment-384786222
"react": ["./node_modules/@types/react"]
"react": ["./node_modules/@types/react", "react"]
},
"skipLibCheck": true,
"sourceMap": true,

View File

@ -65,7 +65,7 @@ from superset.charts.schemas import (
from superset.commands.exceptions import CommandInvalidError
from superset.commands.importers.v1.utils import get_contents_from_bundle
from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod
from superset.exceptions import SupersetSecurityException
from superset.exceptions import QueryObjectValidationError, SupersetSecurityException
from superset.extensions import event_logger
from superset.models.slice import Slice
from superset.tasks.thumbnails import cache_chart_thumbnail
@ -566,9 +566,13 @@ class ChartRestApi(BaseSupersetModelRestApi):
command = ChartDataCommand()
query_context = command.set_query_context(json_body)
command.validate()
except QueryObjectValidationError as error:
return self.response_400(message=error.message)
except ValidationError as error:
return self.response_400(
message=_("Request is incorrect: %(error)s", error=error.messages)
message=_(
"Request is incorrect: %(error)s", error=error.normalized_messages()
)
)
except SupersetSecurityException:
return self.response_401()

View File

@ -22,7 +22,7 @@ from typing import Any, cast, ClassVar, Dict, List, Optional, Union
import numpy as np
import pandas as pd
from flask_babel import gettext as _
from flask_babel import _
from superset import app, db, is_feature_enabled
from superset.annotation_layers.dao import AnnotationLayerDAO
@ -142,7 +142,9 @@ class QueryContext:
"""Converting metrics to numeric when pandas.read_sql cannot"""
for col, dtype in df.dtypes.items():
if dtype.type == np.object_ and col in query_object.metric_names:
df[col] = pd.to_numeric(df[col], errors="coerce")
# soft-convert a metric column to numeric
# will stay as strings if conversion fails
df[col] = df[col].infer_objects()
def get_data(self, df: pd.DataFrame,) -> Union[str, List[Dict[str, Any]]]:
if self.result_format == utils.ChartDataResultFormat.CSV:
@ -153,15 +155,15 @@ class QueryContext:
return df.to_dict(orient="records")
def get_single_payload(
self, query_obj: QueryObject, **kwargs: Any
self, query_obj: QueryObject, force_cached: Optional[bool] = False,
) -> Dict[str, Any]:
"""Returns a payload of metadata and data"""
force_cached = kwargs.get("force_cached", False)
"""Return results payload for a single quey"""
if self.result_type == utils.ChartDataResultType.QUERY:
return {
"query": self.datasource.get_query_str(query_obj.to_dict()),
"language": self.datasource.query_language,
}
if self.result_type == utils.ChartDataResultType.SAMPLES:
row_limit = query_obj.row_limit or math.inf
query_obj = copy.copy(query_obj)
@ -173,10 +175,13 @@ class QueryContext:
query_obj.row_limit = min(row_limit, config["SAMPLES_ROW_LIMIT"])
query_obj.row_offset = 0
query_obj.columns = [o.column_name for o in self.datasource.columns]
payload = self.get_df_payload(query_obj, force_cached=force_cached)
df = payload["df"]
status = payload["status"]
if status != utils.QueryStatus.FAILED:
payload["colnames"] = list(df.columns)
payload["coltypes"] = utils.serialize_pandas_dtypes(df.dtypes)
payload["data"] = self.get_data(df)
del payload["df"]
@ -195,13 +200,19 @@ class QueryContext:
if col not in columns
] + rejected_time_columns
if self.result_type == utils.ChartDataResultType.RESULTS:
if (
self.result_type == utils.ChartDataResultType.RESULTS
and status != utils.QueryStatus.FAILED
):
return {"data": payload["data"]}
return payload
def get_payload(self, **kwargs: Any) -> Dict[str, Any]:
cache_query_context = kwargs.get("cache_query_context", False)
force_cached = kwargs.get("force_cached", False)
def get_payload(
self,
cache_query_context: Optional[bool] = False,
force_cached: Optional[bool] = False,
) -> Dict[str, Any]:
"""Returns the query results with both metadata and data"""
# Get all the payloads from the QueryObjects
query_results = [
@ -310,7 +321,7 @@ class QueryContext:
chart = ChartDAO.find_by_id(annotation_layer["value"])
form_data = chart.form_data.copy()
if not chart:
raise QueryObjectValidationError("The chart does not exist")
raise QueryObjectValidationError(_("The chart does not exist"))
try:
viz_obj = get_viz(
datasource_type=chart.datasource.type,
@ -342,10 +353,9 @@ class QueryContext:
return annotation_data
def get_df_payload( # pylint: disable=too-many-statements,too-many-locals
self, query_obj: QueryObject, **kwargs: Any
self, query_obj: QueryObject, force_cached: Optional[bool] = False,
) -> Dict[str, Any]:
"""Handles caching around the df payload retrieval"""
force_cached = kwargs.get("force_cached", False)
cache_key = self.query_cache_key(query_obj)
logger.info("Cache key: %s", cache_key)
is_loaded = False
@ -387,7 +397,7 @@ class QueryContext:
for col in query_obj.columns
+ query_obj.groupby
+ utils.get_column_names_from_metrics(query_obj.metrics)
if col not in self.datasource.column_names
if col not in self.datasource.column_names and col != DTTM_ALIAS
]
if invalid_columns:
raise QueryObjectValidationError(
@ -446,5 +456,6 @@ class QueryContext:
:raises SupersetSecurityException: If the user cannot access the resource
"""
for query in self.queries:
query.validate()
security_manager.raise_for_access(query_context=self)

View File

@ -28,7 +28,12 @@ from superset import app, is_feature_enabled
from superset.exceptions import QueryObjectValidationError
from superset.typing import Metric
from superset.utils import pandas_postprocessing
from superset.utils.core import DTTM_ALIAS, get_metric_names, json_int_dttm_ser
from superset.utils.core import (
DTTM_ALIAS,
find_duplicates,
get_metric_names,
json_int_dttm_ser,
)
from superset.utils.date_parser import get_since_until, parse_human_timedelta
from superset.views.utils import get_time_range_endpoints
@ -106,6 +111,8 @@ class QueryObject:
):
annotation_layers = annotation_layers or []
metrics = metrics or []
columns = columns or []
groupby = groupby or []
extras = extras or {}
is_sip_38 = is_feature_enabled("SIP_38_VIZ_REARCHITECTURE")
self.annotation_layers = [
@ -126,19 +133,18 @@ class QueryObject:
time_range=time_range,
time_shift=time_shift,
)
# is_timeseries is True if time column is in groupby
# is_timeseries is True if time column is in either columns or groupby
# (both are dimensions)
self.is_timeseries = (
is_timeseries
if is_timeseries is not None
else (DTTM_ALIAS in groupby if groupby else False)
else DTTM_ALIAS in columns + groupby
)
self.time_range = time_range
self.time_shift = parse_human_timedelta(time_shift)
self.post_processing = [
post_proc for post_proc in post_processing or [] if post_proc
]
if not is_sip_38:
self.groupby = groupby or []
# Support metric reference/definition in the format of
# 1. 'metric_name' - name of predefined metric
@ -162,13 +168,16 @@ class QueryObject:
if config["SIP_15_ENABLED"] and "time_range_endpoints" not in self.extras:
self.extras["time_range_endpoints"] = get_time_range_endpoints(form_data={})
self.columns = columns or []
if is_sip_38 and groupby:
self.columns += groupby
logger.warning(
"The field `groupby` is deprecated. Viz plugins should "
"pass all selectables via the `columns` field"
)
self.columns = columns
if is_sip_38:
if groupby:
logger.warning(
"The field `groupby` is deprecated. Viz plugins should "
"pass all selectables via the `columns` field"
)
self.columns += groupby
else:
self.groupby = groupby or []
self.orderby = orderby or []
@ -214,8 +223,34 @@ class QueryObject:
@property
def metric_names(self) -> List[str]:
"""Return metrics names (labels), coerce adhoc metrics to strings."""
return get_metric_names(self.metrics)
@property
def column_names(self) -> List[str]:
"""Return column names (labels). Reserved for future adhoc calculated
columns."""
return self.columns
def validate(
self, raise_exceptions: Optional[bool] = True
) -> Optional[QueryObjectValidationError]:
"""Validate query object"""
error: Optional[QueryObjectValidationError] = None
all_labels = self.metric_names + self.column_names
if len(set(all_labels)) < len(all_labels):
dup_labels = find_duplicates(all_labels)
error = QueryObjectValidationError(
_(
"Duplicate column/metric labels: %(labels)s. Please make "
"sure all columns and metrics have a unique label.",
labels=", ".join(f'"{x}"' for x in dup_labels),
)
)
if error and raise_exceptions:
raise error
return error
def to_dict(self) -> Dict[str, Any]:
query_object_dict = {
"granularity": self.granularity,

View File

@ -939,6 +939,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
and (is_sip_38 or (not is_sip_38 and not groupby))
):
raise QueryObjectValidationError(_("Empty query?"))
metrics_exprs: List[ColumnElement] = []
for metric in metrics:
if utils.is_adhoc_metric(metric):
@ -950,6 +951,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
raise QueryObjectValidationError(
_("Metric '%(metric)s' does not exist", metric=metric)
)
if metrics_exprs:
main_metric_expr = metrics_exprs[0]
else:
@ -960,14 +962,16 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
groupby_exprs_sans_timestamp = OrderedDict()
assert extras is not None
if (is_sip_38 and metrics and columns) or (not is_sip_38 and groupby):
# dedup columns while preserving order
columns_ = columns if is_sip_38 else groupby
assert columns_
groupby = list(dict.fromkeys(columns_))
# filter out the pseudo column __timestamp from columns
columns = columns or []
columns = [col for col in columns if col != utils.DTTM_ALIAS]
if (is_sip_38 and metrics and columns) or (not is_sip_38 and metrics):
# dedup columns while preserving order
columns = columns if is_sip_38 else (groupby or columns)
select_exprs = []
for selected in groupby:
for selected in columns:
# if groupby field/expr equals granularity field/expr
if selected == granularity:
time_grain = extras.get("time_grain_sqla")
@ -979,7 +983,6 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
else:
outer = literal_column(f"({selected})")
outer = self.make_sqla_column_compatible(outer, selected)
groupby_exprs_sans_timestamp[outer.name] = outer
select_exprs.append(outer)
elif columns:
@ -1001,7 +1004,8 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at
if is_timeseries:
timestamp = dttm_col.get_timestamp_expression(time_grain)
select_exprs += [timestamp]
# always put timestamp as the first column
select_exprs.insert(0, timestamp)
groupby_exprs_with_timestamp[timestamp.name] = timestamp
# Use main dttm column to support index with secondary dttm columns.

View File

@ -158,28 +158,22 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
try_remove_schema_from_table_name = True # pylint: disable=invalid-name
run_multiple_statements_as_one = False
# default matching patterns for identifying column types
db_column_types: Dict[utils.GenericDataType, Tuple[Pattern[Any], ...]] = {
# default matching patterns to convert database specific column types to
# more generic types
db_column_types: Dict[utils.GenericDataType, Tuple[Pattern[str], ...]] = {
utils.GenericDataType.NUMERIC: (
re.compile(r"BIT", re.IGNORECASE),
re.compile(r".*DOUBLE.*", re.IGNORECASE),
re.compile(r".*FLOAT.*", re.IGNORECASE),
re.compile(r".*INT.*", re.IGNORECASE),
re.compile(r".*NUMBER.*", re.IGNORECASE),
re.compile(
r".*(DOUBLE|FLOAT|INT|NUMBER|REAL|NUMERIC|DECIMAL|MONEY).*",
re.IGNORECASE,
),
re.compile(r".*LONG$", re.IGNORECASE),
re.compile(r".*REAL.*", re.IGNORECASE),
re.compile(r".*NUMERIC.*", re.IGNORECASE),
re.compile(r".*DECIMAL.*", re.IGNORECASE),
re.compile(r".*MONEY.*", re.IGNORECASE),
),
utils.GenericDataType.STRING: (
re.compile(r".*CHAR.*", re.IGNORECASE),
re.compile(r".*STRING.*", re.IGNORECASE),
re.compile(r".*TEXT.*", re.IGNORECASE),
re.compile(r".*(CHAR|STRING|TEXT).*", re.IGNORECASE),
),
utils.GenericDataType.TEMPORAL: (
re.compile(r".*DATE.*", re.IGNORECASE),
re.compile(r".*TIME.*", re.IGNORECASE),
re.compile(r".*(DATE|TIME).*", re.IGNORECASE),
),
}

View File

@ -373,7 +373,11 @@ class Database(
username = utils.get_username()
def needs_conversion(df_series: pd.Series) -> bool:
return not df_series.empty and isinstance(df_series[0], (list, dict))
return (
not df_series.empty
and isinstance(df_series, pd.Series)
and isinstance(df_series[0], (list, dict))
)
def _log_query(sql: str) -> None:
if log_query:
@ -397,9 +401,9 @@ class Database(
if mutator:
mutator(df)
for k, v in df.dtypes.items():
if v.type == numpy.object_ and needs_conversion(df[k]):
df[k] = df[k].apply(utils.json_dumps_w_dates)
for col, coltype in df.dtypes.to_dict().items():
if coltype == numpy.object_ and needs_conversion(df[col]):
df[col] = df[col].apply(utils.json_dumps_w_dates)
return df

View File

@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
"""Utility functions used across Superset"""
import collections
import decimal
import errno
import functools
@ -37,7 +38,7 @@ from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formatdate
from enum import Enum
from enum import Enum, IntEnum
from timeit import default_timer
from types import TracebackType
from typing import (
@ -55,6 +56,7 @@ from typing import (
Tuple,
Type,
TYPE_CHECKING,
TypeVar,
Union,
)
from urllib.parse import unquote_plus
@ -105,6 +107,8 @@ DTTM_ALIAS = "__timestamp"
JS_MAX_INTEGER = 9007199254740991 # Largest int Java Script can handle 2^53-1
InputType = TypeVar("InputType")
class LenientEnum(Enum):
"""Enums with a `get` method that convert a enum value to `Enum` if it is a
@ -130,14 +134,15 @@ class AnnotationType(str, Enum):
TIME_SERIES = "TIME_SERIES"
class GenericDataType(Enum):
class GenericDataType(IntEnum):
"""
Generic database column type
Generic database column type that fits both frontend and backend.
"""
NUMERIC = 0
STRING = 1
TEMPORAL = 2
BOOLEAN = 3
class ChartDataResultFormat(str, Enum):
@ -1396,6 +1401,21 @@ def get_column_names_from_metrics(metrics: List[Metric]) -> List[str]:
return columns
def serialize_pandas_dtypes(dtypes: List[np.dtype]) -> List[GenericDataType]:
"""Serialize pandas/numpy dtypes to JavaScript types"""
mapping = {
"object": GenericDataType.STRING,
"category": GenericDataType.STRING,
"datetime64[ns]": GenericDataType.TEMPORAL,
"int64": GenericDataType.NUMERIC,
"in32": GenericDataType.NUMERIC,
"float64": GenericDataType.NUMERIC,
"float32": GenericDataType.NUMERIC,
"bool": GenericDataType.BOOLEAN,
}
return [mapping.get(str(x), GenericDataType.STRING) for x in dtypes]
def indexed(
items: List[Any], key: Union[str, Callable[[Any], Any]]
) -> Dict[Any, List[Any]]:
@ -1481,3 +1501,8 @@ def get_time_filter_status( # pylint: disable=too-many-branches
def format_list(items: Sequence[str], sep: str = ", ", quote: str = '"') -> str:
quote_escaped = "\\" + quote
return sep.join(f"{quote}{x.replace(quote, quote_escaped)}{quote}" for x in items)
def find_duplicates(items: Iterable[InputType]) -> List[InputType]:
"""Find duplicate items in an iterable."""
return [item for item, count in collections.Counter(items).items() if count > 1]

View File

@ -16,7 +16,7 @@
# under the License.
import logging
from functools import partial
from typing import Any, Callable, cast, Dict, List, Optional, Set, Tuple, Union
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
import geohash as geohash_lib
import numpy as np
@ -554,29 +554,53 @@ def geodetic_parse(
raise QueryObjectValidationError(_("Invalid geodetic string"))
@validate_column_args("columns")
def contribution(
df: DataFrame, orientation: PostProcessingContributionOrientation
df: DataFrame,
orientation: Optional[
PostProcessingContributionOrientation
] = PostProcessingContributionOrientation.COLUMN,
columns: Optional[List[str]] = None,
rename_columns: Optional[List[str]] = None,
) -> DataFrame:
"""
Calculate cell contibution to row/column total.
Calculate cell contibution to row/column total for numeric columns.
Non-numeric columns will be kept untouched.
If `columns` are specified, only calculate contributions on selected columns.
:param df: DataFrame containing all-numeric data (temporal column ignored)
:param columns: Columns to calculate values from.
:param rename_columns: The new labels for the calculated contribution columns.
The original columns will not be removed.
:param orientation: calculate by dividing cell with row/column total
:return: DataFrame with contributions, with temporal column at beginning if present
:return: DataFrame with contributions.
"""
temporal_series: Optional[Series] = None
contribution_df = df.copy()
if DTTM_ALIAS in df.columns:
temporal_series = cast(Series, contribution_df.pop(DTTM_ALIAS))
if orientation == PostProcessingContributionOrientation.ROW:
contribution_dft = contribution_df.T
contribution_df = (contribution_dft / contribution_dft.sum()).T
else:
contribution_df = contribution_df / contribution_df.sum()
if temporal_series is not None:
contribution_df.insert(0, DTTM_ALIAS, temporal_series)
numeric_df = contribution_df.select_dtypes(include="number")
# verify column selections
if columns:
numeric_columns = numeric_df.columns.tolist()
for col in columns:
if col not in numeric_columns:
raise QueryObjectValidationError(
_(
'Column "%(column)s" is not numeric or does not '
"exists in the query results.",
column=col,
)
)
columns = columns or numeric_df.columns
rename_columns = rename_columns or columns
if len(rename_columns) != len(columns):
raise QueryObjectValidationError(
_("`rename_columns` must have the same length as `columns`.")
)
# limit to selected columns
numeric_df = numeric_df[columns]
axis = 0 if orientation == PostProcessingContributionOrientation.COLUMN else 1
numeric_df = numeric_df / numeric_df.values.sum(axis=axis, keepdims=True)
contribution_df[rename_columns] = numeric_df
return contribution_df

View File

@ -21,13 +21,17 @@ from superset.utils.core import AnnotationType, DTTM_ALIAS
from tests.base_tests import get_table_by_name
query_birth_names = {
"extras": {"where": "", "time_range_endpoints": ["inclusive", "exclusive"]},
"granularity": "ds",
"extras": {
"where": "",
"time_range_endpoints": ["inclusive", "exclusive"],
"time_grain_sqla": "P1D",
},
"groupby": ["name"],
"metrics": [{"label": "sum__num"}],
"order_desc": True,
"orderby": [["sum__num", False]],
"row_limit": 100,
"granularity": "ds",
"time_range": "100 years ago : now",
"timeseries_limit": 0,
"timeseries_limit_metric": None,

View File

@ -524,19 +524,40 @@ class TestPostProcessing(SupersetTestCase):
"b": [1, 9],
}
)
with pytest.raises(QueryObjectValidationError, match="not numeric"):
proc.contribution(df, columns=[DTTM_ALIAS])
with pytest.raises(QueryObjectValidationError, match="same length"):
proc.contribution(df, columns=["a"], rename_columns=["aa", "bb"])
# cell contribution across row
row_df = proc.contribution(df, PostProcessingContributionOrientation.ROW)
self.assertListEqual(df.columns.tolist(), [DTTM_ALIAS, "a", "b"])
self.assertListEqual(series_to_list(row_df["a"]), [0.5, 0.25])
self.assertListEqual(series_to_list(row_df["b"]), [0.5, 0.75])
processed_df = proc.contribution(
df, orientation=PostProcessingContributionOrientation.ROW,
)
self.assertListEqual(processed_df.columns.tolist(), [DTTM_ALIAS, "a", "b"])
self.assertListEqual(processed_df["a"].tolist(), [0.5, 0.25])
self.assertListEqual(processed_df["b"].tolist(), [0.5, 0.75])
# cell contribution across column without temporal column
df.pop(DTTM_ALIAS)
column_df = proc.contribution(df, PostProcessingContributionOrientation.COLUMN)
self.assertListEqual(df.columns.tolist(), ["a", "b"])
self.assertListEqual(series_to_list(column_df["a"]), [0.25, 0.75])
self.assertListEqual(series_to_list(column_df["b"]), [0.1, 0.9])
processed_df = proc.contribution(
df, orientation=PostProcessingContributionOrientation.COLUMN
)
self.assertListEqual(processed_df.columns.tolist(), ["a", "b"])
self.assertListEqual(processed_df["a"].tolist(), [0.25, 0.75])
self.assertListEqual(processed_df["b"].tolist(), [0.1, 0.9])
# contribution only on selected columns
processed_df = proc.contribution(
df,
orientation=PostProcessingContributionOrientation.COLUMN,
columns=["a"],
rename_columns=["pct_a"],
)
self.assertListEqual(processed_df.columns.tolist(), ["a", "b", "pct_a"])
self.assertListEqual(processed_df["a"].tolist(), [1, 3])
self.assertListEqual(processed_df["b"].tolist(), [1, 9])
self.assertListEqual(processed_df["pct_a"].tolist(), [0.25, 0.75])
def test_prophet_valid(self):
pytest.importorskip("fbprophet")

View File

@ -25,7 +25,6 @@ from superset.utils.core import (
AdhocMetricExpressionType,
ChartDataResultFormat,
ChartDataResultType,
FilterOperator,
TimeRangeEndpoint,
)
from tests.base_tests import SupersetTestCase

View File

@ -20,7 +20,6 @@ from typing import Any, Dict, NamedTuple, List, Pattern, Tuple, Union
from unittest.mock import patch
import pytest
import tests.test_app
from superset import db
from superset.connectors.sqla.models import SqlaTable, TableColumn
from superset.db_engine_specs.druid import DruidEngineSpec