diff --git a/src/actions/dashboards.js b/src/actions/dashboards.js index b8c752dcd..fa2528470 100644 --- a/src/actions/dashboards.js +++ b/src/actions/dashboards.js @@ -4,22 +4,23 @@ import { SET_DASHBOARD_STARRED, SET_DASHBOARD_DISPLAY_NAME, SET_DASHBOARD_ITEMS, - getCustomDashboards, sGetDashboardById, sGetDashboardsSortedByStarred, } from '../reducers/dashboards' import { NON_EXISTING_DASHBOARD_ID } from '../reducers/selected' import { sGetUserUsername } from '../reducers/user' import { tSetSelectedDashboardById, acSetSelectedId } from './selected' -import { apiFetchDashboards, apiDeleteDashboard } from '../api/dashboards' +import { apiFetchDashboards } from '../api/fetchAllDashboards' +import { apiDeleteDashboard } from '../api/deleteDashboard' import { getPreferredDashboardId } from '../api/localStorage' import { arrayToIdMap } from '../modules/util' +import { getCustomDashboards } from '../modules/getCustomDashboards' // actions export const acSetDashboards = dashboards => ({ type: SET_DASHBOARDS, - value: arrayToIdMap(getCustomDashboards(dashboards)), + value: arrayToIdMap(dashboards), }) export const acAppendDashboards = dashboards => ({ @@ -55,7 +56,7 @@ export const tFetchDashboards = () => async ( dispatch(acSetDashboards(dashboards)) } -export const tSelectDashboard = id => async (dispatch, getState) => { +export const tSelectDashboard = (id, mode) => async (dispatch, getState) => { try { const state = getState() @@ -72,7 +73,7 @@ export const tSelectDashboard = id => async (dispatch, getState) => { } if (dashboardToSelect) { - dispatch(tSetSelectedDashboardById(dashboardToSelect.id)) + dispatch(tSetSelectedDashboardById(dashboardToSelect.id, mode)) } else { dispatch(acSetSelectedId(NON_EXISTING_DASHBOARD_ID)) } diff --git a/src/actions/selected.js b/src/actions/selected.js index 3bf8baf5d..d8db78d4e 100644 --- a/src/actions/selected.js +++ b/src/actions/selected.js @@ -1,5 +1,5 @@ import i18n from '@dhis2/d2-i18n' -import { getCustomDashboards, sGetDashboardById } from '../reducers/dashboards' +import { sGetDashboardById } from '../reducers/dashboards' import { SET_SELECTED_ID, SET_SELECTED_ISLOADING, @@ -16,12 +16,13 @@ import { acClearItemFilters } from './itemFilters' import { tGetMessages } from '../components/Item/MessagesItem/actions' import { acSetAlertMessage, acClearAlertMessage } from './alert' import { acAddVisualization, acClearVisualizations } from './visualizations' -import { apiFetchDashboard } from '../api/dashboards' +import { apiFetchDashboard } from '../api/fetchDashboard' import { storePreferredDashboardId } from '../api/localStorage' import { apiGetShowDescription } from '../api/description' import { withShape } from '../modules/gridUtil' import { getVisualizationFromItem } from '../modules/item' +import { getCustomDashboards } from '../modules/getCustomDashboards' import { REPORT_TABLE, @@ -64,7 +65,7 @@ export const acClearSelectedItemActiveTypes = () => ({ }) // thunks -export const tSetSelectedDashboardById = id => async ( +export const tSetSelectedDashboardById = (id, mode) => async ( dispatch, getState, dataEngine @@ -127,7 +128,7 @@ export const tSetSelectedDashboardById = id => async ( } try { - const dashboard = await apiFetchDashboard(dataEngine, id) + const dashboard = await apiFetchDashboard(dataEngine, id, mode) return onSuccess(dashboard) } catch (err) { diff --git a/src/api/dashboards.js b/src/api/dashboards.js deleted file mode 100644 index 6860be338..000000000 --- a/src/api/dashboards.js +++ /dev/null @@ -1,68 +0,0 @@ -import arrayClean from 'd2-utilizr/lib/arrayClean' -import { onError, getDashboardFields } from './index' - -export const dashboardsQuery = { - resource: 'dashboards', - params: { - fields: [getDashboardFields(), 'dashboardItems[id]'].join(','), - paging: false, - }, -} - -export const dashboardQuery = { - resource: 'dashboards', - id: ({ id }) => id, - params: { - fields: arrayClean( - getDashboardFields({ - withItems: true, - withFavorite: { withDimensions: false }, - }) - ).join(','), - }, -} - -export const deleteDashboardMutation = { - type: 'delete', - resource: 'dashboards', - id: ({ id }) => id, -} - -// Get "all" dashboards on startup -export const apiFetchDashboards = async dataEngine => { - try { - const dashboardsData = await dataEngine.query({ - dashboards: dashboardsQuery, - }) - - return dashboardsData.dashboards.dashboards - } catch (error) { - onError(error) - } -} - -// Get more info about selected dashboard -export const apiFetchDashboard = async (dataEngine, id) => { - try { - const dashboardData = await dataEngine.query( - { dashboard: dashboardQuery }, - { - variables: { - id, - }, - } - ) - - return dashboardData.dashboard - } catch (error) { - onError(error) - } -} - -export const apiDeleteDashboard = async (dataEngine, id) => { - try { - await dataEngine.mutate(deleteDashboardMutation, { variables: { id } }) - } catch (error) { - onError(error) - } -} diff --git a/src/api/deleteDashboard.js b/src/api/deleteDashboard.js new file mode 100644 index 000000000..64081b161 --- /dev/null +++ b/src/api/deleteDashboard.js @@ -0,0 +1,13 @@ +export const deleteDashboardMutation = { + type: 'delete', + resource: 'dashboards', + id: ({ id }) => id, +} + +export const apiDeleteDashboard = async (dataEngine, id) => { + try { + await dataEngine.mutate(deleteDashboardMutation, { variables: { id } }) + } catch (error) { + console.log('Error: ', error) + } +} diff --git a/src/api/editDashboard.js b/src/api/editDashboard.js index d37d76896..da27802c4 100644 --- a/src/api/editDashboard.js +++ b/src/api/editDashboard.js @@ -1,4 +1,5 @@ -import { apiFetchDashboard } from './dashboards' +import { apiFetchDashboard } from './fetchDashboard' +import { EDIT } from '../components/Dashboard/dashboardModes' export const createDashboardMutation = { resource: 'dashboards', @@ -29,7 +30,7 @@ const generatePayload = (dashboard = {}, data) => { } export const updateDashboard = async (dataEngine, data) => { - const dashboard = await apiFetchDashboard(dataEngine, data.id) + const dashboard = await apiFetchDashboard(dataEngine, data.id, EDIT) const { response } = await dataEngine.mutate(updateDashboardMutation, { variables: { diff --git a/src/api/fetchAllDashboards.js b/src/api/fetchAllDashboards.js new file mode 100644 index 000000000..56dc8cbae --- /dev/null +++ b/src/api/fetchAllDashboards.js @@ -0,0 +1,19 @@ +export const dashboardsQuery = { + resource: 'dashboards', + params: { + fields: ['id', 'displayName', 'favorite~rename(starred)'], + paging: false, + }, +} + +export const apiFetchDashboards = async dataEngine => { + try { + const dashboardsData = await dataEngine.query({ + dashboards: dashboardsQuery, + }) + + return dashboardsData.dashboards.dashboards + } catch (error) { + console.log('Error: ', error) + } +} diff --git a/src/api/fetchDashboard.js b/src/api/fetchDashboard.js new file mode 100644 index 000000000..423d7d826 --- /dev/null +++ b/src/api/fetchDashboard.js @@ -0,0 +1,77 @@ +import arrayClean from 'd2-utilizr/lib/arrayClean' +import { + getIdNameFields, + getListItemFields, + getFavoritesFields, +} from './metadata' +import { isViewMode } from '../components/Dashboard/dashboardModes' + +const getDashboardItemsFields = () => + arrayClean([ + 'id', + 'type', + 'shape', + 'x', + 'y', + 'width~rename(w)', + 'height~rename(h)', + 'messages', + 'text', + 'appKey', + `${getListItemFields().join(',')}`, + `${getFavoritesFields().join(',')}`, + ]) + +const baseDashboardFields = arrayClean([ + 'id', + 'displayName', + 'displayDescription', + 'favorite~rename(starred)', + 'access', + 'restrictFilters', + 'allowedFilters', + `dashboardItems[${getDashboardItemsFields().join(',')}]`, +]) + +export const viewDashboardQuery = { + resource: 'dashboards', + id: ({ id }) => id, + params: { + fields: baseDashboardFields, + }, +} + +export const editDashboardQuery = { + resource: 'dashboards', + id: ({ id }) => id, + params: { + fields: arrayClean([ + ...baseDashboardFields, + `user[${getIdNameFields({ rename: true }).join(',')}]`, + 'name', + 'description', + 'created', + 'lastUpdated', + 'href', // needed for d2-ui-translations-dialog + ]), + }, +} + +// Get more info about selected dashboard +export const apiFetchDashboard = async (dataEngine, id, mode) => { + const query = isViewMode(mode) ? viewDashboardQuery : editDashboardQuery + try { + const dashboardData = await dataEngine.query( + { dashboard: query }, + { + variables: { + id, + }, + } + ) + + return dashboardData.dashboard + } catch (error) { + console.log('Error: ', error) + } +} diff --git a/src/api/index.js b/src/api/index.js deleted file mode 100644 index 2d5b83bb9..000000000 --- a/src/api/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import arrayClean from 'd2-utilizr/lib/arrayClean' -import { - getListItemFields, - getFavoritesFields, - getIdNameFields, -} from './metadata' - -// Helper functions - -export const onError = error => console.log('Error: ', error) - -// Dashboard item -export const getDashboardItemsFields = ({ withFavorite } = {}) => - arrayClean([ - 'id', - 'type', - 'shape', - 'x', - 'y', - 'width~rename(w)', - 'height~rename(h)', - 'messages', - 'text', - 'appKey', - `${getListItemFields().join(',')}`, - withFavorite - ? `${getFavoritesFields({ - withDimensions: withFavorite.withDimensions, - }).join(',')}` - : ``, - ]) - -// Dashboard -export const getDashboardFields = ({ withItems, withFavorite } = {}) => - arrayClean([ - `${getIdNameFields().join(',')}`, - 'description', - 'displayDescription', - 'favorite', - `user[${getIdNameFields({ rename: true }).join(',')}]`, - 'created', - 'lastUpdated', - 'access', - 'href', // needed for d2-ui-translations-dialog, since we don't pass a d2 Model anymore - 'restrictFilters', - 'allowedFilters', - withItems - ? `dashboardItems[${getDashboardItemsFields({ - withFavorite, - }).join(',')}]` - : ``, - ]) diff --git a/src/api/metadata.js b/src/api/metadata.js index 40a079bd6..57f03fc99 100644 --- a/src/api/metadata.js +++ b/src/api/metadata.js @@ -71,12 +71,14 @@ export const getFavoriteFields = ({ withDimensions, withOptions }) => { ]) } -export const getFavoritesFields = ({ withDimensions }) => [ - `reportTable[${getFavoriteFields({ withDimensions }).join(',')}]`, - `chart[${['type', ...getFavoriteFields({ withDimensions })].join(',')}]`, - `map[${getFavoriteFields({ withDimensions }).join(',')}]`, - `eventReport[${getFavoriteFields({ withDimensions }).join(',')}]`, - `eventChart[${getFavoriteFields({ withDimensions }).join(',')}]`, +export const getFavoritesFields = () => [ + `reportTable[${getFavoriteFields({ withDimensions: false }).join(',')}]`, + `chart[${['type', ...getFavoriteFields({ withDimensions: false })].join( + ',' + )}]`, + `map[${getFavoriteFields({ withDimensions: false }).join(',')}]`, + `eventReport[${getFavoriteFields({ withDimensions: false }).join(',')}]`, + `eventChart[${getFavoriteFields({ withDimensions: false }).join(',')}]`, ] // List item diff --git a/src/components/ControlBar/EditBar.js b/src/components/ControlBar/EditBar.js index b13b2749c..bd260ebf0 100644 --- a/src/components/ControlBar/EditBar.js +++ b/src/components/ControlBar/EditBar.js @@ -28,7 +28,8 @@ import { sGetIsNewDashboard, sGetIsPrintPreviewView, } from '../../reducers/editDashboard' -import { apiFetchDashboard } from '../../api/dashboards' +import { apiFetchDashboard } from '../../api/fetchDashboard' +import { EDIT } from '../Dashboard/dashboardModes' import classes from './styles/EditBar.module.css' @@ -53,9 +54,11 @@ const EditBar = props => { useEffect(() => { if (props.dashboardId && !dashboard) { - apiFetchDashboard(dataEngine, props.dashboardId).then(dboard => - setDashboard(dboard) - ) + apiFetchDashboard( + dataEngine, + props.dashboardId, + EDIT + ).then(dboard => setDashboard(dboard)) } }, [props.dashboardId, dashboard]) diff --git a/src/components/ControlBar/__tests__/EditBar.spec.js b/src/components/ControlBar/__tests__/EditBar.spec.js index 388546b5c..1a9a7e9af 100644 --- a/src/components/ControlBar/__tests__/EditBar.spec.js +++ b/src/components/ControlBar/__tests__/EditBar.spec.js @@ -9,14 +9,14 @@ import { useDataEngine } from '@dhis2/app-runtime' import { Router } from 'react-router-dom' import { createMemoryHistory } from 'history' import EditBar from '../EditBar' -import { apiFetchDashboard } from '../../../api/dashboards' +import { apiFetchDashboard } from '../../../api/fetchDashboard' import { acClearEditDashboard } from '../../../actions/editDashboard' const mockStore = configureMockStore() jest.mock('@dhis2/app-runtime-adapter-d2') jest.mock('@dhis2/app-runtime') -jest.mock('../../../api/dashboards') +jest.mock('../../../api/fetchDashboard') jest.mock( '@dhis2/d2-ui-translation-dialog', diff --git a/src/components/Dashboard/Dashboard.js b/src/components/Dashboard/Dashboard.js index f18252233..55554dfe9 100644 --- a/src/components/Dashboard/Dashboard.js +++ b/src/components/Dashboard/Dashboard.js @@ -87,7 +87,7 @@ const Dashboard = ({ useEffect(() => { if (dashboardsLoaded && !dashboardsIsEmpty) { - selectDashboard(routeId) + selectDashboard(routeId, mode) } }, [dashboardsLoaded, dashboardsIsEmpty, routeId, mode]) diff --git a/src/components/Dashboard/__tests__/Dashboard.spec.js b/src/components/Dashboard/__tests__/Dashboard.spec.js index 735108c61..ce2dd1599 100644 --- a/src/components/Dashboard/__tests__/Dashboard.spec.js +++ b/src/components/Dashboard/__tests__/Dashboard.spec.js @@ -11,7 +11,7 @@ import Dashboard from '../Dashboard' import WindowDimensionsProvider from '../../WindowDimensionsProvider' import { NEW, VIEW, EDIT, PRINT, PRINT_LAYOUT } from '../dashboardModes' import { NON_EXISTING_DASHBOARD_ID } from '../../../reducers/selected' -import { apiFetchDashboard } from '../../../api/dashboards' +import { apiFetchDashboard } from '../../../api/fetchDashboard' const middlewares = [thunk] const mockStore = configureMockStore(middlewares) @@ -22,7 +22,7 @@ jest.mock('@dhis2/analytics', () => ({ DIMENSION_ID_ORGUNIT: 'ou', })) jest.mock('@dhis2/app-runtime') -jest.mock('../../../api/dashboards') +jest.mock('../../../api/fetchDashboard') jest.mock( '../PrintLayoutDashboard', () => diff --git a/src/components/__tests__/App.spec.js b/src/components/__tests__/App.spec.js index eb6700f13..6a2db4603 100644 --- a/src/components/__tests__/App.spec.js +++ b/src/components/__tests__/App.spec.js @@ -6,10 +6,10 @@ import { render } from '@testing-library/react' import { useD2 } from '@dhis2/app-runtime-adapter-d2' import { useSystemSettings } from '../SystemSettingsProvider' import { apiFetchDimensions } from '@dhis2/analytics' -import { apiFetchDashboards } from '../../api/dashboards' +import { apiFetchDashboards } from '../../api/fetchAllDashboards' import App from '../App' -jest.mock('../../api/dashboards') +jest.mock('../../api/fetchAllDashboards') jest.mock('../SystemSettingsProvider') jest.mock('@dhis2/analytics') jest.mock('@dhis2/app-runtime-adapter-d2') @@ -36,11 +36,8 @@ test('renders the app', () => { apiFetchDashboards.mockReturnValue([ { id: 'rainbowdash', - name: 'Rainbow Dash', - dashboardItems: [], - user: {}, - created: 'today', - lastUpdated: 'today', + displayName: 'Rainbow Dash', + starred: true, }, ]) apiFetchDimensions.mockReturnValue([{ dimensionType: 'mock' }]) diff --git a/src/modules/getCustomDashboards.js b/src/modules/getCustomDashboards.js new file mode 100644 index 000000000..3462eecde --- /dev/null +++ b/src/modules/getCustomDashboards.js @@ -0,0 +1,24 @@ +import arrayFrom from 'd2-utilizr/lib/arrayFrom' +import { convertBackendItemsToUi } from './uiBackendItemConverter' + +/** + * Returns the array of dashboards, customized for ui + * @function + * @param {Array} data The original dashboard list + * @returns {Array} + */ +export const getCustomDashboards = data => + arrayFrom(data).map(d => ({ + id: d.id, + name: d.name, + displayName: d.displayName, + description: d.description, + displayDescription: d.displayDescription, + starred: d.starred, + created: d.created?.split('T').join(' ').substr(0, 16), + lastUpdated: d.lastUpdated?.split('T').join(' ').substr(0, 16), + access: d.access, + dashboardItems: convertBackendItemsToUi(d.dashboardItems), + restrictFilters: d.restrictFilters, + allowedFilters: d.allowedFilters ?? [], + })) diff --git a/src/reducers/dashboards.js b/src/reducers/dashboards.js index 095c08393..e5047af2a 100644 --- a/src/reducers/dashboards.js +++ b/src/reducers/dashboards.js @@ -1,10 +1,8 @@ /** @module reducers/dashboards */ -import arrayFrom from 'd2-utilizr/lib/arrayFrom' import arraySort from 'd2-utilizr/lib/arraySort' -import { orArray, orObject } from '../modules/util' -import { convertBackendItemsToUi } from '../modules/uiBackendItemConverter' +import { orObject } from '../modules/util' export const SET_DASHBOARDS = 'SET_DASHBOARDS' export const ADD_DASHBOARDS = 'ADD_DASHBOARDS' @@ -153,29 +151,3 @@ export const sGetDashboardsSortedByStarred = state => [ ...arraySort(sGetStarredDashboards(state), 'ASC', 'displayName'), ...arraySort(sGetUnstarredDashboards(state), 'ASC', 'displayName'), ] - -// utils - -/** - * Returns the array of dashboards, customized for ui - * @function - * @param {Array} data The original dashboard list - * @returns {Array} - */ -export const getCustomDashboards = data => - arrayFrom(data).map(d => ({ - id: d.id, - name: d.name, - displayName: d.displayName, - description: d.description, - displayDescription: d.displayDescription, - starred: d.favorite, - owner: d.user.name, - created: d.created.split('T').join(' ').substr(0, 16), - lastUpdated: d.lastUpdated.split('T').join(' ').substr(0, 16), - access: d.access, - numberOfItems: orArray(d.dashboardItems).length, - dashboardItems: convertBackendItemsToUi(d.dashboardItems), - restrictFilters: d.restrictFilters, - allowedFilters: d.allowedFilters ?? [], - }))