Skip to content

Commit

Permalink
Merge pull request #4178 from beyondessential/release-2022-38
Browse files Browse the repository at this point in the history
  • Loading branch information
rohan-bes authored Sep 20, 2022
2 parents bfe1ad5 + 511980d commit 87ff57d
Show file tree
Hide file tree
Showing 219 changed files with 6,456 additions and 1,658 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"packages/api-client/**",
"packages/data-api/**",
"packages/data-lake-api/**",
"packages/data-table-server/**",
"packages/entity-server/**",
"packages/indicators/**",
"packages/lesmis-server/**",
Expand Down
2 changes: 2 additions & 0 deletions codeship-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
command: './packages/devops/scripts/ci/testBackend.sh admin-panel-server'
- name: Test central-server
command: './packages/devops/scripts/ci/testBackend.sh central-server'
- name: Test data-table-server
command: './packages/devops/scripts/ci/testBackend.sh data-table-server'
- name: Test entity-server
command: './packages/devops/scripts/ci/testBackend.sh entity-server'
- name: Test lesmis-server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,27 @@ describe('DashboardVisualisationExtractor', () => {
},
});
});

it('can get a draft report which uses a custom report', () => {
const extractor = new DashboardVisualisationExtractor(
{
code: 'viz',
data: { customReport: 'custom' },
presentation: {},
},
yup.object(),
draftReportValidator,
);

const report = extractor.getReport();

expect(report).toEqual({
code: 'viz',
config: {
customReport: 'custom',
},
});
});
});

describe('getReport() - legacyReport', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { QueryParameters, ApiConnection, RequestBody } from '@tupaia/server-boilerplate';

const { REPORT_API_URL = 'http://localhost:8030/v2' } = process.env;
const { REPORT_API_URL = 'http://localhost:8030/v1' } = process.env;

/**
* @deprecated use @tupaia/api-client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ export class DashboardVisualisationExtractor<
const { code, permissionGroup, data, presentation } = this.visualisation;
const validatedData = baseVisualisationDataValidator.validateSync(data);

if (validatedData.customReport) {
return {
config: {
customReport: validatedData.customReport,
},
code,
permissionGroup,
};
}

const { fetch: vizFetch, aggregate, transform } = validatedData;

const fetch = omitBy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@
* Copyright (c) 2017 - 2021 Beyond Essential Systems Pty Ltd
*/

import { LegacyReport, Report} from '../types';
import { LegacyReport, Report } from '../types';
import { extractDataFromReport } from '../utils';
import { DashboardItem, DashboardViz, DashboardVizResource } from './types';

const getData = (report: Report) => {
const { config } = report;
const { fetch, transform } = config;
const { aggregations, ...restOfFetch } = fetch;
return { fetch: restOfFetch, aggregate: aggregations, transform };
};

const getLegacyData = (report: LegacyReport) => {
const { dataBuilder, config, dataServices } = report;
return { dataBuilder, config, dataServices };
Expand All @@ -24,20 +18,22 @@ const getPresentation = (dashboardItem: DashboardItem, report: Report | LegacyRe
const { type, name, ...config } = dashboardItemConfig;

const presentation: Record<string, unknown> = { type, ...config };
if (!dashboardItem.legacy) {
if (!dashboardItem.legacy && 'output' in reportConfig) {
presentation.output = reportConfig.output;
}

return presentation;
};

export function combineDashboardVisualisation(visualisationResource: DashboardVizResource): DashboardViz {
export function combineDashboardVisualisation(
visualisationResource: DashboardVizResource,
): DashboardViz {
const { dashboardItem, report } = visualisationResource;
const { id, code, config, legacy } = dashboardItem;
const { name } = config;
const data = dashboardItem.legacy
? getLegacyData(report as LegacyReport)
: getData(report as Report);
: extractDataFromReport(report as Report);
const presentation = getPresentation(dashboardItem, report);

const visualisation: Record<string, unknown> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,33 @@
*/

import { ValidationError } from '@tupaia/utils';
import { LegacyReport, Report} from '../types';
import { LegacyReport, Report } from '../types';
import { extractDataFromReport } from '../utils';
import { MapOverlay, MapOverlayViz, MapOverlayVizResource } from './types';

// TODO: DRY
const getData = (report: Report) => {
const { config } = report;
const { fetch, transform } = config;
const { aggregations, ...restOfFetch } = fetch;
return { fetch: restOfFetch, aggregate: aggregations, transform };
};

const getPresentation = (mapOverlay: MapOverlay, report: Report | LegacyReport) => {
const { config: reportConfig } = report;
const { config } = mapOverlay;

const presentation = config;
if (!mapOverlay.legacy) {
if (!mapOverlay.legacy && 'output' in reportConfig) {
presentation.output = reportConfig.output;
}

return presentation;
};

export function combineMapOverlayVisualisation(visualisationResource: MapOverlayVizResource): MapOverlayViz {
export function combineMapOverlayVisualisation(
visualisationResource: MapOverlayVizResource,
): MapOverlayViz {
const { mapOverlay, report } = visualisationResource;

if (mapOverlay.legacy) {
throw new ValidationError('Legacy map overlay viz not supported');
}

const { config, permissionGroup: mapOverlayPermissionGroup, ...rest } = mapOverlay;
const data = getData(report);
const data = extractDataFromReport(report);
const presentation = getPresentation(mapOverlay, report);

const visualisation: Record<string, unknown> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ const dateSpecsValidator = polymorphic({
string: yup.string().min(4),
});

export const configValidator = yup.object().shape({
const customReportConfigValidator = yup.object().shape({
customReport: yup.string().required(),
});

const standardConfigValidator = yup.object().shape({
fetch: yup
.object()
.shape(
Expand All @@ -70,3 +74,14 @@ export const configValidator = yup.object().shape({
transform: yup.array().required(),
output: yup.object(),
});

// TODO: Consolidate this and the validator in @tupaia/report-server in a common @tupaia/types package
export const configValidator = yup.lazy<
typeof standardConfigValidator | typeof customReportConfigValidator
>((config: unknown) => {
if (typeof config === 'object' && config && 'customReport' in config) {
return customReportConfigValidator;
}

return standardConfigValidator;
});
8 changes: 4 additions & 4 deletions packages/admin-panel-server/src/viz-builder/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (c) 2017 - 2021 Beyond Essential Systems Pty Ltd
*/

import { ReportConfig } from '@tupaia/report-server';
import { ReportConfig, StandardOrCustomReportConfig } from '@tupaia/report-server';

export type VizData = {
dataElements: ReportConfig['fetch']['dataElements'];
Expand All @@ -22,7 +22,7 @@ export enum PreviewMode {
export type Report = {
code: string;
permissionGroup: string;
config: ReportConfig;
config: StandardOrCustomReportConfig;
};

export type LegacyReport = {
Expand All @@ -47,7 +47,7 @@ export type CamelKeysToSnake<T extends Record<string, unknown>> = {
export type ExpandType<T> = T extends Record<string, unknown>
? T extends infer O
? {
[K in keyof O]: ExpandType<O[K]>;
}
[K in keyof O]: ExpandType<O[K]>;
}
: never
: T;
18 changes: 18 additions & 0 deletions packages/admin-panel-server/src/viz-builder/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

import { Report } from './types';

// Used when combining the report and dashboardItem/mapOverlay
export const extractDataFromReport = (report: Report) => {
const { config } = report;
if ('customReport' in config) {
return { customReport: config.customReport };
}

const { fetch, transform } = config;
const { aggregations, ...restOfFetch } = fetch;
return { fetch: restOfFetch, aggregate: aggregations, transform };
};
18 changes: 16 additions & 2 deletions packages/admin-panel-server/src/viz-builder/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,24 @@ export const baseVisualisationValidator = yup.object().shape({
data: yup.object().required(),
});

export const baseVisualisationDataValidator = yup.object().shape({
const baseCustomReportDataValidator = yup.object().shape({
customReport: yup.string().required(),
});

const baseStandardReportDataValidator = yup.object().shape({
fetch: yup.object().required(),
});

export const baseVisualisationDataValidator = yup.lazy<
typeof baseStandardReportDataValidator | typeof baseCustomReportDataValidator
>((dataConfig: unknown) => {
if (typeof dataConfig === 'object' && dataConfig && 'customReport' in dataConfig) {
return baseCustomReportDataValidator;
}

return baseStandardReportDataValidator;
});

export const draftReportValidator = yup.object().shape({
code: yup.string().required('Requires "code" for the visualisation'),
config: configValidator,
Expand All @@ -24,4 +38,4 @@ export const legacyReportValidator = yup.object().shape({
dataBuilder: yup.string().required(),
config: yup.object().required(),
dataServices: yup.array().of(yup.object().shape({ isDataRegional: yup.boolean() })),
});
});
21 changes: 17 additions & 4 deletions packages/admin-panel/src/VizBuilderApp/components/Panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const Panel = () => {
] = useVizConfig();

const {
visualisation: { data: finalData },
visualisation: { data: vizData },
} = useVisualisation();

const handleChange = (event, newValue) => {
Expand All @@ -108,6 +108,19 @@ export const Panel = () => {
return tab !== tabId && hasDataError;
};

const isCustomReport = 'customReport' in vizData;
// Custom report vizes don't support any configuration so just show the name
if (isCustomReport) {
return (
<Container>
<PanelNav>
<>Custom Report: {vizData.customReport}</>
<PlayButton />
</PanelNav>
</Container>
);
}

return (
<Container>
<PanelNav>
Expand All @@ -128,7 +141,7 @@ export const Panel = () => {
<TabPanel isSelected={tab === 0} Panel={PanelTabPanel}>
{jsonToggleEnabled ? (
<JsonEditor
value={finalData.fetch}
value={vizData.fetch}
onChange={value => setTabValue('fetch', value)}
onInvalidChange={handleInvalidChange}
/>
Expand All @@ -144,7 +157,7 @@ export const Panel = () => {
<TabPanel isSelected={tab === 1} Panel={PanelTabPanel}>
{jsonToggleEnabled ? (
<JsonEditor
value={finalData.aggregate}
value={vizData.aggregate}
onChange={value => setTabValue('aggregate', value)}
onInvalidChange={handleInvalidChange}
/>
Expand All @@ -161,7 +174,7 @@ export const Panel = () => {
<TabPanel isSelected={tab === 2} Panel={PanelTabPanel}>
{jsonToggleEnabled ? (
<JsonEditor
value={finalData.transform}
value={vizData.transform}
onChange={value => setTabValue('transform', value)}
onInvalidChange={handleInvalidChange}
/>
Expand Down
4 changes: 4 additions & 0 deletions packages/admin-panel/src/VizBuilderApp/context/VizConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ const useConfigStore = () => {
const setProject = value => dispatch({ type: SET_PROJECT, value });
const setTestData = value => dispatch({ type: SET_TEST_DATA, value });
const setVisualisation = value => {
if (!value.data.transform) {
return dispatch({ type: SET_VISUALISATION, value });
}

const { transform } = value.data;
const sanitisedTransform = transform.map(conf =>
typeof conf === 'string' ? { transform: conf, alias: true } : conf,
Expand Down
55 changes: 55 additions & 0 deletions packages/admin-panel/src/pages/resources/DataTablesPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Tupaia
* Copyright (c) 2017 - 2021 Beyond Essential Systems Pty Ltd
*/

import React from 'react';
import PropTypes from 'prop-types';
import { ResourcePage } from './ResourcePage';

const DATA_TABLES_ENDPOINT = 'dataTables';

const FIELDS = [
{
Header: 'Code',
source: 'code',
type: 'tooltip',
},
{
Header: 'Description',
source: 'description',
},
{
Header: 'Type',
source: 'type',
},
{
Header: 'Config',
source: 'config',
type: 'jsonTooltip',
editConfig: { type: 'jsonEditor' },
},
{
Header: 'Permission groups',
source: 'permission_groups',
type: 'tooltip',
editConfig: {
type: 'jsonArray',
},
},
];

const COLUMNS = [...FIELDS];

export const DataTablesPage = ({ getHeaderEl }) => (
<ResourcePage
title="Data-Tables"
endpoint={DATA_TABLES_ENDPOINT}
columns={COLUMNS}
getHeaderEl={getHeaderEl}
/>
);

DataTablesPage.propTypes = {
getHeaderEl: PropTypes.func.isRequired,
};
Loading

0 comments on commit 87ff57d

Please sign in to comment.