mirror of
https://github.com/apache/superset.git
synced 2026-05-07 17:04:58 +00:00
add loading log for dash and exploreview breakdown whole page load action to multiple charts loading events and render events
206 lines
6.7 KiB
JavaScript
206 lines
6.7 KiB
JavaScript
import { combineReducers } from 'redux';
|
|
import d3 from 'd3';
|
|
import shortid from 'shortid';
|
|
|
|
import charts, { chart } from '../chart/chartReducer';
|
|
import * as actions from './actions';
|
|
import { getParam } from '../modules/utils';
|
|
import { alterInArr, removeFromArr } from '../reduxUtils';
|
|
import { applyDefaultFormData } from '../explore/stores/store';
|
|
import { getColorFromScheme } from '../modules/colors';
|
|
|
|
export function getInitialState(bootstrapData) {
|
|
const { user_id, datasources, common } = bootstrapData;
|
|
delete common.locale;
|
|
delete common.language_pack;
|
|
|
|
const dashboard = { ...bootstrapData.dashboard_data };
|
|
let filters = {};
|
|
try {
|
|
// allow request parameter overwrite dashboard metadata
|
|
filters = JSON.parse(getParam('preselect_filters') || dashboard.metadata.default_filters);
|
|
} catch (e) {
|
|
//
|
|
}
|
|
|
|
// Priming the color palette with user's label-color mapping provided in
|
|
// the dashboard's JSON metadata
|
|
if (dashboard.metadata && dashboard.metadata.label_colors) {
|
|
const colorMap = dashboard.metadata.label_colors;
|
|
for (const label in colorMap) {
|
|
getColorFromScheme(label, null, colorMap[label]);
|
|
}
|
|
}
|
|
|
|
dashboard.posDict = {};
|
|
dashboard.layout = [];
|
|
if (dashboard.position_json) {
|
|
dashboard.position_json.forEach((position) => {
|
|
dashboard.posDict[position.slice_id] = position;
|
|
});
|
|
}
|
|
dashboard.slices.forEach((slice, index) => {
|
|
const sliceId = slice.slice_id;
|
|
let pos = dashboard.posDict[sliceId];
|
|
if (!pos) {
|
|
pos = {
|
|
col: (index * 4 + 1) % 12,
|
|
row: Math.floor((index) / 3) * 4,
|
|
size_x: 4,
|
|
size_y: 4,
|
|
};
|
|
}
|
|
|
|
dashboard.layout.push({
|
|
i: String(sliceId),
|
|
x: pos.col - 1,
|
|
y: pos.row,
|
|
w: pos.size_x,
|
|
minW: 2,
|
|
h: pos.size_y,
|
|
});
|
|
});
|
|
|
|
// will use charts action/reducers to handle chart render
|
|
const initCharts = {};
|
|
dashboard.slices.forEach((slice) => {
|
|
const chartKey = 'slice_' + slice.slice_id;
|
|
initCharts[chartKey] = { ...chart,
|
|
chartKey,
|
|
slice_id: slice.slice_id,
|
|
form_data: slice.form_data,
|
|
formData: applyDefaultFormData(slice.form_data),
|
|
};
|
|
});
|
|
|
|
// also need to add formData for dashboard.slices
|
|
dashboard.slices = dashboard.slices.map(slice =>
|
|
({ ...slice, formData: applyDefaultFormData(slice.form_data) }),
|
|
);
|
|
|
|
return {
|
|
charts: initCharts,
|
|
dashboard: { filters, dashboard, userId: user_id, datasources, common, editMode: false },
|
|
};
|
|
}
|
|
|
|
export const dashboard = function (state = {}, action) {
|
|
const actionHandlers = {
|
|
[actions.UPDATE_DASHBOARD_TITLE]() {
|
|
const newDashboard = { ...state.dashboard, dashboard_title: action.title };
|
|
return { ...state, dashboard: newDashboard };
|
|
},
|
|
[actions.UPDATE_DASHBOARD_LAYOUT]() {
|
|
const newDashboard = { ...state.dashboard, layout: action.layout };
|
|
return { ...state, dashboard: newDashboard };
|
|
},
|
|
[actions.REMOVE_SLICE]() {
|
|
const key = String(action.slice.slice_id);
|
|
const newLayout = state.dashboard.layout.filter(reactPos => (reactPos.i !== key));
|
|
const newDashboard = removeFromArr(state.dashboard, 'slices', action.slice, 'slice_id');
|
|
// if this slice is a filter
|
|
const newFilter = { ...state.filters };
|
|
let refresh = false;
|
|
if (state.filters[key]) {
|
|
delete newFilter[key];
|
|
refresh = true;
|
|
}
|
|
return {
|
|
...state,
|
|
dashboard: { ...newDashboard, layout: newLayout },
|
|
filters: newFilter,
|
|
refresh,
|
|
};
|
|
},
|
|
[actions.TOGGLE_FAVE_STAR]() {
|
|
return { ...state, isStarred: action.isStarred };
|
|
},
|
|
[actions.SET_EDIT_MODE]() {
|
|
return { ...state, editMode: action.editMode };
|
|
},
|
|
[actions.TOGGLE_EXPAND_SLICE]() {
|
|
const updatedExpandedSlices = { ...state.dashboard.metadata.expanded_slices };
|
|
const sliceId = action.slice.slice_id;
|
|
if (action.isExpanded) {
|
|
updatedExpandedSlices[sliceId] = true;
|
|
} else {
|
|
delete updatedExpandedSlices[sliceId];
|
|
}
|
|
const metadata = { ...state.dashboard.metadata, expanded_slices: updatedExpandedSlices };
|
|
const newDashboard = { ...state.dashboard, metadata };
|
|
return { ...state, dashboard: newDashboard };
|
|
},
|
|
|
|
// filters
|
|
[actions.ADD_FILTER]() {
|
|
const selectedSlice = state.dashboard.slices
|
|
.find(slice => (slice.slice_id === action.sliceId));
|
|
if (!selectedSlice) {
|
|
return state;
|
|
}
|
|
|
|
let filters = state.filters;
|
|
const { sliceId, col, vals, merge, refresh } = action;
|
|
const filterKeys = ['__from', '__to', '__time_col',
|
|
'__time_grain', '__time_origin', '__granularity'];
|
|
if (filterKeys.indexOf(col) >= 0 ||
|
|
selectedSlice.formData.groupby.indexOf(col) !== -1) {
|
|
let newFilter = {};
|
|
if (!(sliceId in filters)) {
|
|
// Straight up set the filters if none existed for the slice
|
|
newFilter = { [col]: vals };
|
|
} else if (filters[sliceId] && !(col in filters[sliceId]) || !merge) {
|
|
newFilter = { ...filters[sliceId], [col]: vals };
|
|
// d3.merge pass in array of arrays while some value form filter components
|
|
// from and to filter box require string to be process and return
|
|
} else if (filters[sliceId][col] instanceof Array) {
|
|
newFilter[col] = d3.merge([filters[sliceId][col], vals]);
|
|
} else {
|
|
newFilter[col] = d3.merge([[filters[sliceId][col]], vals])[0] || '';
|
|
}
|
|
filters = { ...filters, [sliceId]: newFilter };
|
|
}
|
|
return { ...state, filters, refresh };
|
|
},
|
|
[actions.CLEAR_FILTER]() {
|
|
const newFilters = { ...state.filters };
|
|
delete newFilters[action.sliceId];
|
|
return { ...state, filter: newFilters, refresh: true };
|
|
},
|
|
[actions.REMOVE_FILTER]() {
|
|
const { sliceId, col, vals, refresh } = action;
|
|
const excluded = new Set(vals);
|
|
const valFilter = val => !excluded.has(val);
|
|
|
|
let filters = state.filters;
|
|
// Have to be careful not to modify the dashboard state so that
|
|
// the render actually triggers
|
|
if (sliceId in state.filters && col in state.filters[sliceId]) {
|
|
const newFilter = filters[sliceId][col].filter(valFilter);
|
|
filters = { ...filters, [sliceId]: newFilter };
|
|
}
|
|
return { ...state, filters, refresh };
|
|
},
|
|
|
|
// slice reducer
|
|
[actions.UPDATE_SLICE_NAME]() {
|
|
const newDashboard = alterInArr(
|
|
state.dashboard, 'slices',
|
|
action.slice, { slice_name: action.sliceName },
|
|
'slice_id');
|
|
return { ...state, dashboard: newDashboard };
|
|
},
|
|
};
|
|
|
|
if (action.type in actionHandlers) {
|
|
return actionHandlers[action.type]();
|
|
}
|
|
return state;
|
|
};
|
|
|
|
export default combineReducers({
|
|
charts,
|
|
dashboard,
|
|
impressionId: () => (shortid.generate()),
|
|
});
|