mirror of
https://github.com/apache/superset.git
synced 2026-04-16 14:45:21 +00:00
* Chinese page * Using react-intl-universal to improve multi language in react page * Using react-intl-universal to improve multi language in react page * react_intl_universal * change * change * change * change * change * change * change * merge * multiple page in js * merge * merge * merge * merge * Js Translations * JS Translation * JS Translations * Js translation * JS translations * JS translations * Js translaion * JS en Translation * JS Translation * upgrade document Fixing the damn build (#3179) * Fixing the build * Going deeper [bugfix] only filterable columns should show up in FilterBox list (#3105) * [bugfix] only filterable columns should show up in FilterBox list * Touchups Datasource cannot be empty (#3035) add title description to model view (#3045) * add title description to model view * add missing import Add 'show/hide totals' option to pivot table vis (#3101) [bugfix] numeric value for date fields in table viz (#3036) Bug was present only when using the NOT GROUPED BY option fixes https://github.com/ApacheInfra/superset/issues/3027 fix hive.fetch_logs (#2968) add Zalando to the list of organizations (#3171) docs: fixup installation examples code indentation (#3169) [bugfix] fix bar order (#3180) [bugfix] visualize flow error: 'Metric x is not valid' (#3181) The metric name in the frontend doesn't match the one generated on the backend. It turns out the explore view will default to the first metric so specifying one isn't needed. Fix the segment interval for pulling metadata (#3174) The end of the interval would be on the truncated today date, which means that you will exclude today. If your realtime ingestion job runs shorter than a day, the metadata cannot be pulled from the druid cluster. Bump cryptography to 1.9 (#3065) As 1.7.2 doesn't compile here with openssl 1.1.0f Escaping the user's SQL in the explore view (#3186) * Escaping the user's SQL in the explore view When executing SQL from SQL Lab, we use a lower level API to the database which doesn't require escaping the SQL. When going through the explore view, the stack chain leading to the same method may need escaping depending on how the DBAPI driver is written, and that is the case for Presto (and perhaps other drivers). * Using regex to avoid doubling doubles [sqllab] improve Hive support (#3187) * [sqllab] improve Hive support * Fix "Transport not open" bug * Getting progress bar to show * Bump pyhive to 0.4.0 * Getting [Track Job] button to show * Fix testzz Add BigQuery engine specifications (#3193) As contributed by @mxmzdlv on issue #945 [bugfix] fix merge conflict that broke Hive support (#3196) Adding 'apache' to docs (#3194) [druid] Allow custom druid postaggregators (#3146) * [druid] Allow custom druid postaggregators Also, fix the postaggregation for approxHistogram quantiles so it adds the dependent field and that can show up in the graphs/tables. In general, postAggregators add significant power, we should probably support including custom postAggregators. Plywood has standard postAggregators here, and a customAggregator escape hatch that allows you to define custom postAggregators. This commit adds a similar capability for Superset and a additional field/fields/fieldName breakdown of the typical naming for dependent aggregations, which should make it significantly easier to develop approxHistogram and custom postAggregation-required dashboards. * [druid] Minor style cleanup in tests file. * [druid] Apply code review suggestions * break out CustomPostAggregator into separate class. This just cleans up the creation of the postaggregator a little bit. * minor style issues. * move the function around so the git diff is more readable add combine config for metrics in pivot table (#3086) * add combine config for metrics in pivot table * change method to stack/unstack * update backendSync Autofocus search input in VizTypeControl modal onEnter (#2929) Speed up JS build time (#3203) Also bumping a few related libs JS Translation JS translations js translation fix issue 3204 (#3205) [bugfix] capture Hive job_id pre-url transformation (#3213) js translation fix issue 3204 (#3205) [bugfix] capture Hive job_id pre-url transformation (#3213) [docs] update url in CONTRIBUTING.md (#3212) [sqllab/cosmetics] add margin-top for labels in query history (#3222) [explore] nvd3 sort values in rich tooltip (#3197) [sqllab] fix UI shows 'The query returned no results' momentarily (#3214) this is visible when running async queries between the fetching and success state as the rows are getting cached in the component [explore] DatasourceControl to pick datasource in modal (#3210) * [explore] DatasourceControl to pick datasource in modal Makes it easier to change datasource, also makes it such that the list of all datasources doesn't need to be loaded upfront. * Adding more metadata * Js translation * js tran * js trans * js trans * js tran * js trans * js trans * js tran * js translation * js trans * js translation * try load language pack async * Backend translations things * create language pack inside common data * performance improvement for js i18n. - js bundle should not contain localized content - we populate translation content from server-side, in boostrap.common.language_pack - in client-side, use promise to wrap around translation content. text will be translated after translation content arrived/parsed. - fix linting * fix Timer unit test * 1. add global hook for all tests, to make translation pack avaialble before each test starts. 2. fix unit test for Timer component 3. remove noused method get_locale, and modules 4. fix page reload after user change page language * parse and build i18n dictionary as a module * fix sync-backend task, which should run without DOM
282 lines
10 KiB
JavaScript
282 lines
10 KiB
JavaScript
import shortid from 'shortid';
|
|
import * as actions from './actions';
|
|
import { now } from '../modules/dates';
|
|
import { addToObject, alterInObject, alterInArr, removeFromArr, getFromArr, addToArr }
|
|
from '../reduxUtils';
|
|
import { t } from '../locales';
|
|
|
|
export function getInitialState(defaultDbId) {
|
|
const defaultQueryEditor = {
|
|
id: shortid.generate(),
|
|
title: t('Untitled Query'),
|
|
sql: 'SELECT *\nFROM\nWHERE',
|
|
selectedText: null,
|
|
latestQueryId: null,
|
|
autorun: false,
|
|
dbId: defaultDbId,
|
|
};
|
|
|
|
return {
|
|
alerts: [],
|
|
queries: {},
|
|
databases: {},
|
|
queryEditors: [defaultQueryEditor],
|
|
tabHistory: [defaultQueryEditor.id],
|
|
tables: [],
|
|
queriesLastUpdate: 0,
|
|
activeSouthPaneTab: 'Results',
|
|
};
|
|
}
|
|
|
|
export const sqlLabReducer = function (state, action) {
|
|
const actionHandlers = {
|
|
[actions.ADD_QUERY_EDITOR]() {
|
|
const tabHistory = state.tabHistory.slice();
|
|
tabHistory.push(action.queryEditor.id);
|
|
const newState = Object.assign({}, state, { tabHistory });
|
|
return addToArr(newState, 'queryEditors', action.queryEditor);
|
|
},
|
|
[actions.CLONE_QUERY_TO_NEW_TAB]() {
|
|
const progenitor = state.queryEditors.find(qe =>
|
|
qe.id === state.tabHistory[state.tabHistory.length - 1]);
|
|
const qe = {
|
|
id: shortid.generate(),
|
|
title: t('Copy of %s', progenitor.title),
|
|
dbId: (action.query.dbId) ? action.query.dbId : null,
|
|
schema: (action.query.schema) ? action.query.schema : null,
|
|
autorun: true,
|
|
sql: action.query.sql,
|
|
};
|
|
|
|
return sqlLabReducer(state, actions.addQueryEditor(qe));
|
|
},
|
|
[actions.REMOVE_QUERY_EDITOR]() {
|
|
let newState = removeFromArr(state, 'queryEditors', action.queryEditor);
|
|
// List of remaining queryEditor ids
|
|
const qeIds = newState.queryEditors.map(qe => qe.id);
|
|
const queries = {};
|
|
Object.keys(state.queries).forEach((k) => {
|
|
const query = state.queries[k];
|
|
if (qeIds.indexOf(query.sqlEditorId) > -1) {
|
|
queries[k] = query;
|
|
}
|
|
});
|
|
let tabHistory = state.tabHistory.slice();
|
|
tabHistory = tabHistory.filter(id => qeIds.indexOf(id) > -1);
|
|
newState = Object.assign({}, newState, { tabHistory, queries });
|
|
return newState;
|
|
},
|
|
[actions.REMOVE_QUERY]() {
|
|
const newQueries = Object.assign({}, state.queries);
|
|
delete newQueries[action.query.id];
|
|
return Object.assign({}, state, { queries: newQueries });
|
|
},
|
|
[actions.RESET_STATE]() {
|
|
return Object.assign({}, getInitialState());
|
|
},
|
|
[actions.MERGE_TABLE]() {
|
|
const at = Object.assign({}, action.table);
|
|
let existingTable;
|
|
state.tables.forEach((xt) => {
|
|
if (
|
|
xt.dbId === at.dbId &&
|
|
xt.queryEditorId === at.queryEditorId &&
|
|
xt.schema === at.schema &&
|
|
xt.name === at.name) {
|
|
existingTable = xt;
|
|
}
|
|
});
|
|
if (existingTable) {
|
|
if (action.query) {
|
|
at.dataPreviewQueryId = action.query.id;
|
|
}
|
|
return alterInArr(state, 'tables', existingTable, at);
|
|
}
|
|
at.id = shortid.generate();
|
|
// for new table, associate Id of query for data preview
|
|
at.dataPreviewQueryId = null;
|
|
let newState = addToArr(state, 'tables', at);
|
|
if (action.query) {
|
|
newState = alterInArr(newState, 'tables', at, { dataPreviewQueryId: action.query.id });
|
|
}
|
|
return newState;
|
|
},
|
|
[actions.EXPAND_TABLE]() {
|
|
return alterInArr(state, 'tables', action.table, { expanded: true });
|
|
},
|
|
[actions.REMOVE_DATA_PREVIEW]() {
|
|
const queries = Object.assign({}, state.queries);
|
|
delete queries[action.table.dataPreviewQueryId];
|
|
const newState = alterInArr(state, 'tables', action.table, { dataPreviewQueryId: null });
|
|
return Object.assign(
|
|
{}, newState, { queries });
|
|
},
|
|
[actions.CHANGE_DATA_PREVIEW_ID]() {
|
|
const queries = Object.assign({}, state.queries);
|
|
delete queries[action.oldQueryId];
|
|
|
|
const newTables = [];
|
|
state.tables.forEach((xt) => {
|
|
if (xt.dataPreviewQueryId === action.oldQueryId) {
|
|
newTables.push(Object.assign({}, xt, { dataPreviewQueryId: action.newQuery.id }));
|
|
} else {
|
|
newTables.push(xt);
|
|
}
|
|
});
|
|
return Object.assign(
|
|
{}, state, { queries, tables: newTables, activeSouthPaneTab: action.newQuery.id });
|
|
},
|
|
[actions.COLLAPSE_TABLE]() {
|
|
return alterInArr(state, 'tables', action.table, { expanded: false });
|
|
},
|
|
[actions.REMOVE_TABLE]() {
|
|
return removeFromArr(state, 'tables', action.table);
|
|
},
|
|
[actions.START_QUERY]() {
|
|
let newState = Object.assign({}, state);
|
|
if (action.query.sqlEditorId) {
|
|
const qe = getFromArr(state.queryEditors, action.query.sqlEditorId);
|
|
if (qe.latestQueryId && state.queries[qe.latestQueryId]) {
|
|
const newResults = Object.assign(
|
|
{}, state.queries[qe.latestQueryId].results, { data: [], query: null });
|
|
const q = Object.assign({}, state.queries[qe.latestQueryId], { results: newResults });
|
|
const queries = Object.assign({}, state.queries, { [q.id]: q });
|
|
newState = Object.assign({}, state, { queries });
|
|
}
|
|
} else {
|
|
newState.activeSouthPaneTab = action.query.id;
|
|
}
|
|
newState = addToObject(newState, 'queries', action.query);
|
|
const sqlEditor = { id: action.query.sqlEditorId };
|
|
return alterInArr(newState, 'queryEditors', sqlEditor, { latestQueryId: action.query.id });
|
|
},
|
|
[actions.STOP_QUERY]() {
|
|
return alterInObject(state, 'queries', action.query, { state: 'stopped', results: [] });
|
|
},
|
|
[actions.CLEAR_QUERY_RESULTS]() {
|
|
const newResults = Object.assign({}, action.query.results);
|
|
newResults.data = [];
|
|
return alterInObject(state, 'queries', action.query, { results: newResults, cached: true });
|
|
},
|
|
[actions.REQUEST_QUERY_RESULTS]() {
|
|
return alterInObject(state, 'queries', action.query, { state: 'fetching' });
|
|
},
|
|
[actions.QUERY_SUCCESS]() {
|
|
if (action.query.state === 'stopped') {
|
|
return state;
|
|
}
|
|
let rows;
|
|
if (action.results.data) {
|
|
rows = action.results.data.length;
|
|
}
|
|
const alts = {
|
|
endDttm: now(),
|
|
progress: 100,
|
|
results: action.results,
|
|
rows,
|
|
state: 'success',
|
|
errorMessage: null,
|
|
cached: false,
|
|
};
|
|
return alterInObject(state, 'queries', action.query, alts);
|
|
},
|
|
[actions.QUERY_FAILED]() {
|
|
if (action.query.state === 'stopped') {
|
|
return state;
|
|
}
|
|
const alts = { state: 'failed', errorMessage: action.msg, endDttm: now() };
|
|
return alterInObject(state, 'queries', action.query, alts);
|
|
},
|
|
[actions.SET_ACTIVE_QUERY_EDITOR]() {
|
|
const qeIds = state.queryEditors.map(qe => qe.id);
|
|
if (qeIds.indexOf(action.queryEditor.id) > -1) {
|
|
const tabHistory = state.tabHistory.slice();
|
|
tabHistory.push(action.queryEditor.id);
|
|
return Object.assign({}, state, { tabHistory });
|
|
}
|
|
return state;
|
|
},
|
|
[actions.SET_ACTIVE_SOUTHPANE_TAB]() {
|
|
return Object.assign({}, state, { activeSouthPaneTab: action.tabId });
|
|
},
|
|
[actions.QUERY_EDITOR_SETDB]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { dbId: action.dbId });
|
|
},
|
|
[actions.QUERY_EDITOR_SET_SCHEMA]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { schema: action.schema });
|
|
},
|
|
[actions.QUERY_EDITOR_SET_TITLE]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { title: action.title });
|
|
},
|
|
[actions.QUERY_EDITOR_SET_SQL]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { sql: action.sql });
|
|
},
|
|
[actions.QUERY_EDITOR_SET_SELECTED_TEXT]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { selectedText: action.sql });
|
|
},
|
|
[actions.QUERY_EDITOR_SET_AUTORUN]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { autorun: action.autorun });
|
|
},
|
|
[actions.QUERY_EDITOR_PERSIST_HEIGHT]() {
|
|
return alterInArr(state, 'queryEditors', action.queryEditor, { height: action.currentHeight });
|
|
},
|
|
[actions.ADD_ALERT]() {
|
|
return addToArr(state, 'alerts', action.alert);
|
|
},
|
|
[actions.SET_DATABASES]() {
|
|
const databases = {};
|
|
action.databases.forEach((db) => {
|
|
databases[db.id] = db;
|
|
});
|
|
return Object.assign({}, state, { databases });
|
|
},
|
|
[actions.REMOVE_ALERT]() {
|
|
return removeFromArr(state, 'alerts', action.alert);
|
|
},
|
|
[actions.REFRESH_QUERIES]() {
|
|
let newQueries = Object.assign({}, state.queries);
|
|
// Fetch the updates to the queries present in the store.
|
|
let change = false;
|
|
let queriesLastUpdate = state.queriesLastUpdate;
|
|
for (const id in action.alteredQueries) {
|
|
const changedQuery = action.alteredQueries[id];
|
|
if (!state.queries.hasOwnProperty(id) ||
|
|
state.queries[id].state !== 'stopped') {
|
|
if (changedQuery.changedOn > queriesLastUpdate) {
|
|
queriesLastUpdate = changedQuery.changedOn;
|
|
}
|
|
newQueries[id] = Object.assign({}, state.queries[id], changedQuery);
|
|
change = true;
|
|
}
|
|
}
|
|
if (!change) {
|
|
newQueries = state.queries;
|
|
}
|
|
return Object.assign({}, state, { queries: newQueries, queriesLastUpdate });
|
|
},
|
|
[actions.CREATE_DATASOURCE_STARTED]() {
|
|
return Object.assign({}, state, {
|
|
isDatasourceLoading: true,
|
|
errorMessage: null,
|
|
});
|
|
},
|
|
[actions.CREATE_DATASOURCE_SUCCESS]() {
|
|
return Object.assign({}, state, {
|
|
isDatasourceLoading: false,
|
|
errorMessage: null,
|
|
datasource: action.datasource,
|
|
});
|
|
},
|
|
[actions.CREATE_DATASOURCE_FAILED]() {
|
|
return Object.assign({}, state, {
|
|
isDatasourceLoading: false,
|
|
errorMessage: action.err,
|
|
});
|
|
},
|
|
};
|
|
if (action.type in actionHandlers) {
|
|
return actionHandlers[action.type]();
|
|
}
|
|
return state;
|
|
};
|