Skip to content

Commit

Permalink
Merge pull request #4267 from beyondessential/release-2022-47
Browse files Browse the repository at this point in the history
Release 2022-47
  • Loading branch information
rohan-bes authored Nov 22, 2022
2 parents 9ed8e59 + b9f8c83 commit 3e693f0
Show file tree
Hide file tree
Showing 29 changed files with 472 additions and 123 deletions.
2 changes: 2 additions & 0 deletions packages/admin-panel/src/autocomplete/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const mapDispatchToProps = (
parentRecord = {},
allowMultipleValues,
baseFilter,
pageSize,
},
) => ({
onChangeSelection: (event, newSelection, reason) => {
Expand Down Expand Up @@ -188,6 +189,7 @@ const mapDispatchToProps = (
newSearchTerm,
parentRecord,
baseFilter,
pageSize,
),
),
onClearState: () => dispatch(clearState(reduxId)),
Expand Down
3 changes: 2 additions & 1 deletion packages/admin-panel/src/autocomplete/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const changeSearchTerm = (
searchTerm,
parentRecord,
baseFilter = {},
pageSize = MAX_AUTOCOMPLETE_RESULTS,
) => async (dispatch, getState, { api }) => {
const fetchId = generateId();
dispatch({
Expand All @@ -40,7 +41,7 @@ export const changeSearchTerm = (
const filter = convertSearchTermToFilter({ ...baseFilter, [labelColumn]: searchTerm });
const response = await api.get(makeSubstitutionsInString(endpoint, parentRecord), {
filter: JSON.stringify(filter),
pageSize: MAX_AUTOCOMPLETE_RESULTS,
pageSize,
sort: JSON.stringify([`${labelColumn} ASC`]),
columns: JSON.stringify([labelColumn, valueColumn]),
distinct: true,
Expand Down
33 changes: 33 additions & 0 deletions packages/admin-panel/src/pages/resources/EntityTypesPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Tupaia MediTrak
* Copyright (c) 2017 Beyond Essential Systems Pty Ltd
*/

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

const ENTITY_TYPES_ENDPOINT = 'entityTypes';

export const ENTITY_TYPES_COLUMNS = [
{ source: 'id', show: false },
{
Header: 'Type',
source: 'type',
filterable: false,
sortable: false,
},
];

export const EntityTypesPage = ({ getHeaderEl }) => (
<ResourcePage
title="Entity Types"
endpoint={ENTITY_TYPES_ENDPOINT}
columns={ENTITY_TYPES_COLUMNS}
getHeaderEl={getHeaderEl}
/>
);

EntityTypesPage.propTypes = {
getHeaderEl: PropTypes.func.isRequired,
};
8 changes: 4 additions & 4 deletions packages/admin-panel/src/pages/resources/ProjectsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ const NEW_PROJECT_COLUMNS = [
},
{
Header: 'Canonical Types (leave blank for default)',
source: 'entityType',
source: 'entityTypes',
Filter: ArrayFilter,
Cell: ({ value }) => prettyArray(value),
editConfig: {
optionsEndpoint: 'entityTypes',
optionLabelKey: 'entityType',
optionValueKey: 'entityType',
sourceKey: 'entityTypes',
optionLabelKey: 'type',
optionValueKey: 'type',
pageSize: 1000, // entityTypes endpoint doesn't support filtering, so fetch all values
allowMultipleValues: true,
},
},
Expand Down
1 change: 1 addition & 0 deletions packages/admin-panel/src/pages/resources/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

export { CountriesPage } from './CountriesPage';
export { EntitiesPage } from './EntitiesPage';
export { EntityTypesPage } from './EntityTypesPage';
export { PermissionsPage } from './PermissionsPage';
export { PermissionGroupsPage } from './PermissionGroupsPage';
export {
Expand Down
6 changes: 6 additions & 0 deletions packages/admin-panel/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { StrivePage } from './pages/StrivePage';
import {
CountriesPage,
EntitiesPage,
EntityTypesPage,
OptionSetsPage,
PermissionGroupsPage,
PermissionsPage,
Expand Down Expand Up @@ -183,6 +184,11 @@ export const ROUTES = [
to: '/countries',
component: CountriesPage,
},
{
label: 'Entity Types',
to: '/entityTypes',
component: EntityTypesPage,
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const registerInputFields = () => {
allowMultipleValues={props.allowMultipleValues}
parentRecord={props.parentRecord}
baseFilter={props.baseFilter}
pageSize={props.pageSize}
/>
));
registerInputField('json', props => (
Expand Down
21 changes: 0 additions & 21 deletions packages/central-server/src/apiV2/GETEntityTypes.js

This file was deleted.

55 changes: 55 additions & 0 deletions packages/central-server/src/apiV2/entityTypes/GetEntityTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

import { allowNoPermissions } from '../../permissions';
import { GETHandler } from '../GETHandler';

/**
* Custom implementation required for this route as there is no corresponding DatabaseModel for EntityType
* (it's an enum not a table)
*/
export class GetEntityTypes extends GETHandler {
async assertUserHasAccess() {
await this.assertPermissions(allowNoPermissions);
}

async getEntityTypes() {
return this.models.entity.getEntityTypes();
}

async getDbQueryOptions() {
const { limit, page } = this.getPaginationParameters();
const offset = limit * page;

return { limit, offset };
}

async findSingleRecord(recordId) {
const entityTypes = await this.getEntityTypes();
const entityType = entityTypes.find(type => type === recordId);
if (!entityType) {
return undefined;
}

return { id: entityType, type: entityType };
}

async findRecords(criteria, options) {
const { limit, offset } = options;
const entityTypes = await this.getEntityTypes();
if (offset) {
entityTypes.splice(0, offset);
}
if (limit) {
entityTypes.splice(limit);
}
return entityTypes.map(type => ({ id: type, type }));
}

async countRecords() {
const entityTypes = await this.getEntityTypes();
return entityTypes.length;
}
}
6 changes: 6 additions & 0 deletions packages/central-server/src/apiV2/entityTypes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

export { GetEntityTypes } from './GetEntityTypes';
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
constructIsEmptyOr,
constructIsOneOf,
isPlainObject,
constructIsValidEntityType,
} from '@tupaia/utils';

const constructEntityFieldValidators = models => ({
Expand All @@ -17,13 +18,7 @@ const constructEntityFieldValidators = models => ({
sub_district: [],
code: [hasContent],
name: [hasContent],
entity_type: [
hasContent,
cellValue => {
const checkIsOneOf = constructIsOneOf(Object.values(models.entity.types));
checkIsOneOf(cellValue);
},
],
entity_type: [hasContent, constructIsValidEntityType(models.entity)],
attributes: [constructIsEmptyOr(isPlainObject)],
data_service_entity: [constructIsEmptyOr(isPlainObject)],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Copyright (c) 2019 Beyond Essential Systems Pty Ltd
*/

import { constructIsNotPresentOr, hasContent } from '@tupaia/utils';
import { constructListItemsAreOneOf, validateIsYesOrNo } from '../../validatorFunctions';
import { constructIsNotPresentOr, constructIsValidEntityType, hasContent } from '@tupaia/utils';
import { validateIsYesOrNo } from '../../validatorFunctions';
import { ANSWER_TYPES } from '../../../../../database/models/Answer';
import { isEmpty, isYes } from '../../utilities';
import { JsonFieldValidator } from '../JsonFieldValidator';
Expand Down Expand Up @@ -45,7 +45,7 @@ export class EntityConfigValidator extends JsonFieldValidator {
);

return {
type: [hasContent, constructListItemsAreOneOf(Object.values(this.models.entity.types))],
type: [hasContent, constructIsValidEntityType(this.models.entity)],
createNew: [constructIsNotPresentOr(validateIsYesOrNo)],
code: [hasContentIfCanCreateNew, constructIsNotPresentOr(pointsToAnotherQuestion)],
name: [hasContentIfCanCreateNew, constructIsNotPresentOr(pointsToAnotherQuestion)],
Expand Down
4 changes: 2 additions & 2 deletions packages/central-server/src/apiV2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { GETDisasters } from './GETDisasters';
import { GETDataElements, EditDataElements, DeleteDataElements } from './dataElements';
import { GETDataGroups, EditDataGroups, DeleteDataGroups } from './dataGroups';
import { GETDataTables } from './dataTables';
import { GETEntityTypes } from './GETEntityTypes';
import { GETFeedItems } from './GETFeedItems';
import { GETGeographicalAreas } from './GETGeographicalAreas';
import { GETSurveyGroups } from './GETSurveyGroups';
Expand Down Expand Up @@ -90,6 +89,7 @@ import {
GETUserEntityPermissions,
} from './userEntityPermissions';
import { EditEntity, GETEntities, DeleteEntity } from './entities';
import { GetEntityTypes } from './entityTypes';
import { EditAccessRequests, GETAccessRequests } from './accessRequests';
import { postChanges } from './postChanges';
import { changePassword } from './changePassword';
Expand Down Expand Up @@ -190,7 +190,7 @@ apiV2.get('/mapOverlayGroupRelations/:recordId?', useRouteHandler(GETMapOverlayG
apiV2.get('/surveys/:recordId?', useRouteHandler(GETSurveys));
apiV2.get('/countries/:parentRecordId/surveys', useRouteHandler(GETSurveys));
apiV2.get('/countries/:parentRecordId/entities', useRouteHandler(GETEntities));
apiV2.get('/entityTypes', allowAnyone(GETEntityTypes));
apiV2.get('/entityTypes/:recordId?', useRouteHandler(GetEntityTypes));
apiV2.get('/surveyGroups/:recordId?', useRouteHandler(GETSurveyGroups));
apiV2.get('/surveyResponses/:parentRecordId/answers', useRouteHandler(GETAnswers));
apiV2.get('/surveyResponses/:recordId?', useRouteHandler(GETSurveyResponses));
Expand Down
4 changes: 2 additions & 2 deletions packages/central-server/src/apiV2/postChanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import {
constructEveryItem,
takesIdForm,
takesDateForm,
constructIsOneOf,
isNumber,
constructIsValidEntityType,
} from '@tupaia/utils';
import { updateOrCreateSurveyResponse, addSurveyImage } from '../dataAccessors';
import { assertCanSubmitSurveyResponses } from './import/importSurveyResponses/assertCanImportSurveyResponses';
Expand Down Expand Up @@ -216,7 +216,7 @@ const constructEntitiesCreatedValidators = models => ({
code: [hasContent],
parent_id: [takesIdForm],
name: [hasContent],
type: [constructIsOneOf(Object.values(models.entity.types))],
type: [constructIsValidEntityType(models.entity)],
country_code: [hasContent],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import {
isPlainObject,
constructIsEmptyOr,
constructIsOneOf,
constructIsSubSetOf,
isValidPassword,
isNumber,
ValidationError,
constructRecordExistsWithCode,
constructIsValidEntityType,
} from '@tupaia/utils';
import { DATA_SOURCE_SERVICE_TYPES } from '../../database/models/DataElement';

Expand Down Expand Up @@ -128,7 +128,12 @@ export const constructForSingle = (models, recordType) => {
return {
dashboard_id: [constructRecordExistsWithId(models.dashboard)],
child_id: [constructRecordExistsWithId(models.dashboardItem)],
entity_types: [constructIsSubSetOf(Object.values(models.entity.types))],
entity_types: [
async entityTypes => {
const entityTypeValidator = constructIsValidEntityType(models.entity);
await Promise.all(entityTypes.map(entityTypeValidator));
},
],
permission_groups: [
async permissionGroupNames => {
const permissionGroups = await models.permissionGroup.find({
Expand Down Expand Up @@ -255,11 +260,12 @@ export const constructForSingle = (models, recordType) => {
logo_url: [isAString],
entityTypes: [
async selectedEntityTypes => {
console.log(selectedEntityTypes);
if (!selectedEntityTypes) {
return true;
}
const entityDataTypes = await models.entity.types;
const filteredEntityTypes = Object.values(entityDataTypes).filter(type =>
const entityTypes = await models.entity.getEntityTypes();
const filteredEntityTypes = entityTypes.filter(type =>
selectedEntityTypes.includes(type),
);
if (selectedEntityTypes.length !== filteredEntityTypes.length) {
Expand Down
4 changes: 2 additions & 2 deletions packages/data-broker/src/services/superset/getSupersetApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const instances = {};
*/
export const getSupersetApiInstance = async (models, supersetInstance) => {
const { code: serverName, config } = supersetInstance;
const { baseUrl, insecure } = config;
const { baseUrl } = config;

if (!instances[serverName]) {
instances[serverName] = new SupersetApi(serverName, baseUrl, insecure);
instances[serverName] = new SupersetApi(serverName, baseUrl);
}

return instances[serverName];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

import { updateValues } from '../utilities';

var dbm;
var type;
var seed;

/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function (options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
};

const projectCode = 'unfpa';
const previousConfig = {
permanentRegionLabels: true,
projectDashboardHeader: 'Regional',
};
const newConfig = {
tileSets: 'unfpaPopulation',
includeDefaultTileSets: true,
permanentRegionLabels: true,
projectDashboardHeader: 'Regional',
};

exports.up = async function (db) {
await updateValues(db, 'project', { config: newConfig }, { code: projectCode });
};

exports.down = async function (db) {
await updateValues(db, 'project', { config: previousConfig }, { code: projectCode });
};

exports._meta = {
version: 1,
};
Loading

0 comments on commit 3e693f0

Please sign in to comment.