mirror of
https://github.com/apache/superset.git
synced 2026-04-22 01:24:43 +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
260 lines
8.1 KiB
JavaScript
260 lines
8.1 KiB
JavaScript
/* eslint camel-case: 0 */
|
|
import $ from 'jquery';
|
|
import Mustache from 'mustache';
|
|
import vizMap from '../../visualizations/main';
|
|
import { getExploreUrl } from '../explore/exploreUtils';
|
|
import { applyDefaultFormData } from '../explore/stores/store';
|
|
import { t } from '../locales';
|
|
|
|
const utils = require('./utils');
|
|
|
|
/* eslint wrap-iife: 0 */
|
|
const px = function (state) {
|
|
let slice;
|
|
const timeout = state.common.conf.SUPERSET_WEBSERVER_TIMEOUT;
|
|
function getParam(name) {
|
|
/* eslint no-useless-escape: 0 */
|
|
const formattedName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
|
const regex = new RegExp('[\\?&]' + formattedName + '=([^&#]*)');
|
|
const results = regex.exec(location.search);
|
|
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
|
}
|
|
function initFavStars() {
|
|
const baseUrl = '/superset/favstar/';
|
|
// Init star behavihor for favorite
|
|
function show() {
|
|
if ($(this).hasClass('selected')) {
|
|
$(this).html('<i class="fa fa-star"></i>');
|
|
} else {
|
|
$(this).html('<i class="fa fa-star-o"></i>');
|
|
}
|
|
}
|
|
$('.favstar')
|
|
.attr('title', t('Click to favorite/unfavorite'))
|
|
.css('cursor', 'pointer')
|
|
.each(show)
|
|
.each(function () {
|
|
let url = baseUrl + $(this).attr('class_name');
|
|
const star = this;
|
|
url += '/' + $(this).attr('obj_id') + '/';
|
|
$.getJSON(url + 'count/', function (data) {
|
|
if (data.count > 0) {
|
|
$(star).addClass('selected').each(show);
|
|
}
|
|
});
|
|
})
|
|
.click(function () {
|
|
$(this).toggleClass('selected');
|
|
let url = baseUrl + $(this).attr('class_name');
|
|
url += '/' + $(this).attr('obj_id') + '/';
|
|
if ($(this).hasClass('selected')) {
|
|
url += 'select/';
|
|
} else {
|
|
url += 'unselect/';
|
|
}
|
|
$.get(url);
|
|
$(this).each(show);
|
|
})
|
|
.tooltip();
|
|
}
|
|
const Slice = function (data, datasource, controller) {
|
|
const token = $('#token_' + data.slice_id);
|
|
const controls = $('#controls_' + data.slice_id);
|
|
const containerId = 'con_' + data.slice_id;
|
|
const selector = '#' + containerId;
|
|
const container = $(selector);
|
|
const sliceId = data.slice_id;
|
|
const formData = applyDefaultFormData(data.form_data);
|
|
slice = {
|
|
data,
|
|
formData,
|
|
container,
|
|
containerId,
|
|
datasource,
|
|
selector,
|
|
getWidgetHeader() {
|
|
return this.container.parents('div.widget').find('.chart-header');
|
|
},
|
|
render_template(s) {
|
|
const context = {
|
|
width: this.width,
|
|
height: this.height,
|
|
};
|
|
return Mustache.render(s, context);
|
|
},
|
|
jsonEndpoint(data) {
|
|
return this.endpoint(data, 'json');
|
|
},
|
|
endpoint(data, endpointType = 'json') {
|
|
let endpoint = getExploreUrl(data, endpointType, this.force);
|
|
if (endpoint.charAt(0) !== '/') {
|
|
// Known issue for IE <= 11:
|
|
// https://connect.microsoft.com/IE/feedbackdetail/view/1002846/pathname-incorrect-for-out-of-document-elements
|
|
endpoint = '/' + endpoint;
|
|
}
|
|
return endpoint;
|
|
},
|
|
d3format(col, number) {
|
|
// uses the utils memoized d3format function and formats based on
|
|
// column level defined preferences
|
|
let format = '.3s';
|
|
if (this.datasource.column_formats[col]) {
|
|
format = this.datasource.column_formats[col];
|
|
}
|
|
return utils.d3format(format, number);
|
|
},
|
|
/* eslint no-shadow: 0 */
|
|
always(data) {
|
|
if (data && data.query) {
|
|
slice.viewSqlQuery = data.query;
|
|
}
|
|
},
|
|
done(payload) {
|
|
Object.assign(data, payload);
|
|
|
|
token.find('img.loading').hide();
|
|
container.fadeTo(0.5, 1);
|
|
container.show();
|
|
|
|
$('.query-and-save button').removeAttr('disabled');
|
|
this.always(data);
|
|
controller.done(this);
|
|
},
|
|
getErrorMsg(xhr) {
|
|
let msg = '';
|
|
if (!xhr.responseText) {
|
|
const status = xhr.status;
|
|
if (status === 0) {
|
|
// This may happen when the worker in gunicorn times out
|
|
msg += (
|
|
t('The server could not be reached. You may want to ' +
|
|
'verify your connection and try again.'));
|
|
} else {
|
|
msg += (t('An unknown error occurred. (Status: %s )', status));
|
|
}
|
|
}
|
|
return msg;
|
|
},
|
|
error(msg, xhr) {
|
|
let errorMsg = msg;
|
|
token.find('img.loading').hide();
|
|
container.fadeTo(0.5, 1);
|
|
let errHtml = '';
|
|
let o;
|
|
try {
|
|
o = JSON.parse(msg);
|
|
if (o.error) {
|
|
errorMsg = o.error;
|
|
}
|
|
} catch (e) {
|
|
// pass
|
|
}
|
|
if (errorMsg) {
|
|
errHtml += `<div class="alert alert-danger">${errorMsg}</div>`;
|
|
}
|
|
if (xhr) {
|
|
if (xhr.statusText === 'timeout') {
|
|
errHtml += (
|
|
'<div class="alert alert-warning">' +
|
|
'Query timeout - visualization query are set to time out ' +
|
|
`at ${timeout} seconds.</div>`);
|
|
} else {
|
|
const extendedMsg = this.getErrorMsg(xhr);
|
|
if (extendedMsg) {
|
|
errHtml += `<div class="alert alert-danger">${extendedMsg}</div>`;
|
|
}
|
|
}
|
|
}
|
|
container.html(errHtml);
|
|
container.show();
|
|
$('span.query').removeClass('disabled');
|
|
$('.query-and-save button').removeAttr('disabled');
|
|
this.always(o);
|
|
controller.error(this);
|
|
},
|
|
clearError() {
|
|
$(selector + ' div.alert').remove();
|
|
},
|
|
width() {
|
|
return container.width();
|
|
},
|
|
height() {
|
|
let others = 0;
|
|
const widget = container.parents('.widget');
|
|
const sliceDescription = widget.find('.slice_description');
|
|
if (sliceDescription.is(':visible')) {
|
|
others += widget.find('.slice_description').height() + 25;
|
|
}
|
|
others += widget.find('.chart-header').height();
|
|
return widget.height() - others - 10;
|
|
},
|
|
bindResizeToWindowResize() {
|
|
let resizeTimer;
|
|
const slice = this;
|
|
$(window).on('resize', function () {
|
|
clearTimeout(resizeTimer);
|
|
resizeTimer = setTimeout(function () {
|
|
slice.resize();
|
|
}, 500);
|
|
});
|
|
},
|
|
render(force) {
|
|
if (force === undefined) {
|
|
this.force = false;
|
|
} else {
|
|
this.force = force;
|
|
}
|
|
const formDataExtra = Object.assign({}, formData);
|
|
const extraFilters = controller.effectiveExtraFilters(sliceId);
|
|
formDataExtra.filters = formDataExtra.filters.concat(extraFilters);
|
|
controls.find('a.exploreChart').attr('href', getExploreUrl(formDataExtra));
|
|
controls.find('a.exportCSV').attr('href', getExploreUrl(formDataExtra, 'csv'));
|
|
token.find('img.loading').show();
|
|
container.fadeTo(0.5, 0.25);
|
|
container.css('height', this.height());
|
|
$.ajax({
|
|
url: this.jsonEndpoint(formDataExtra),
|
|
timeout: timeout * 1000,
|
|
success: (queryResponse) => {
|
|
try {
|
|
vizMap[formData.viz_type](this, queryResponse);
|
|
this.done(queryResponse);
|
|
} catch (e) {
|
|
this.error(t('An error occurred while rendering the visualization: %s', e));
|
|
}
|
|
},
|
|
error: (err) => {
|
|
this.error(err.responseText, err);
|
|
},
|
|
});
|
|
},
|
|
resize() {
|
|
this.render();
|
|
},
|
|
addFilter(col, vals, merge = true, refresh = true) {
|
|
controller.addFilter(sliceId, col, vals, merge, refresh);
|
|
},
|
|
setFilter(col, vals, refresh = true) {
|
|
controller.setFilter(sliceId, col, vals, refresh);
|
|
},
|
|
getFilters() {
|
|
return controller.filters[sliceId];
|
|
},
|
|
clearFilter() {
|
|
controller.clearFilter(sliceId);
|
|
},
|
|
removeFilter(col, vals) {
|
|
controller.removeFilter(sliceId, col, vals);
|
|
},
|
|
};
|
|
return slice;
|
|
};
|
|
// Export public functions
|
|
return {
|
|
getParam,
|
|
initFavStars,
|
|
Slice,
|
|
};
|
|
};
|
|
module.exports = px;
|