Skip to content

Commit

Permalink
CM-138: User Groups Management implementation (#1)
Browse files Browse the repository at this point in the history
* CM-139: base project configuration, eslint, main route

* CM-139: basic structure of tasks view

* CM-139: basic view of task traiage

* CM-139: basic view of task triage

* CM-139: task preview improvements

* CM-139: import fix

* CM-138: user groups management page and basic searcher

* CM-138: reducer, actions, fetchTaskGroups, searcher

* CM-138: taskExecutorsPicker, taskGroupPage, taskGroupHeadPanel

* CM-138: fetch task group, clear on unmount

* OTC-138: remove package-lock json

* CM-138: implementation of create/update mutation, executors picker fix

* CM-138: removal of console log

* CM-138: filtering, sorting, searching improvements, executorsPicker fixes

* CM-138: create PERFORM_MUTATION and adjust existing logic, constants fix

* CM-138: name of function changed

* CM-138: TaskExecutorsPicker fixes

* CM-138: component name changed - TaskDetailsPage
  • Loading branch information
olewandowski1 authored Jun 27, 2023
1 parent 15162dc commit 71d904b
Show file tree
Hide file tree
Showing 28 changed files with 1,906 additions and 44 deletions.
43 changes: 22 additions & 21 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
{
"parser": "babel-eslint",
"extends": [
"standard",
"standard-react"
],
"env": {
"es6": true
},
"plugins": [
"react"
],
"parserOptions": {
"sourceType": "module"
},
"rules": {
// don't force es6 functions to include space before paren
"space-before-function-paren": 0,

// allow specifying true explicitly for boolean props
"react/jsx-boolean-value": 0
"parser": "babel-eslint",
"extends": [
"standard",
"standard-react"
],
"env": {
"es6": true
},
"plugins": [
"react"
],
"parserOptions": {
"sourceType": "module"
},
"rules": {
// don't force es6 functions to include space before paren
"space-before-function-paren": 0,

// allow specifying true explicitly for boolean props
"react/jsx-boolean-value": 0
}
}
}
26 changes: 26 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"airbnb"
],
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"react/prop-types": "off",
"no-shadow": "off", // disabled due to use of bindActionCreators
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], // disabled due to naming consistency with other modules
"import/no-unresolved": "off", // disable due to module architecture. For modules most references are marked as unresolved
"max-len": ["error", { "code": 120 }]
}
}
16 changes: 8 additions & 8 deletions .github/workflows/CI_and_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
# Runs a single command using the runners shell
- name: get dependences
run: |
node openimis-config.js openimis.json
- name: Install dependencies
run : yarn install
- name: build
run : yarn build
- uses: actions/upload-artifact@v2
with:
name: frontend-node${{ matrix.node-version }}-${{github.run_number}}-${{github.sha}}
path: ./build/*
- name: Check build status
run: |
if [ -d "dist" ]; then
echo "Build successful!"
else
echo "Build failed!"
exit 1
fi
30 changes: 30 additions & 0 deletions .github/workflows/eslint_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: ESLint

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
lint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 14

- name: Install dependencies
run: yarn install

- name: Run ESLint
run: npx eslint src
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"build": "rollup -c",
"start": "rollup -c -w",
"format": "prettier src -w",
"prepare":"npm run build"
"prepare": "npm run build"
},
"peerDependency": {
"react-intl": "^5.8.1"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
Expand All @@ -29,13 +32,12 @@
"@rollup/plugin-json": "^4.0.3",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-url": "^5.0.0",
"moment": "^2.25.3",
"prop-types": "^15.7.2",
"react-autosuggest": "^10.0.2",
"react-intl": "^2.9.0",
"react-router-dom": "^5.2.0",
"redux": "^4.0.5",
"redux-api-middleware": "^3.2.1",
"eslint": "^7.32.0 || ^8.2.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"rollup": "^2.10.0"
},
"files": [
Expand Down
108 changes: 108 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {
graphql,
formatPageQueryWithCount,
formatMutation,
formatGQLString,
decodeId,
graphqlWithVariables,
} from '@openimis/fe-core';
import { ACTION_TYPE, MUTATION_SERVICE } from './reducer';
import {
REQUEST, SUCCESS, ERROR, CLEAR,
} from './utils/action-type';

const TASK_GROUP_PROJECTION = () => [
'id',
'uuid',
'code',
'completionPolicy',
'taskexecutorSet { edges { node { user { id username lastName } } } }',
];

export const formatTaskGroupGQL = (taskGroup) => {
const executors = taskGroup?.executors?.map((executor) => decodeId(executor.id));
const executorsString = executors ? `[${executors.map((executorUuid) => `"${executorUuid}"`).join(', ')}]` : '[]';
const GQLString = `
${taskGroup?.code ? `code: "${formatGQLString(taskGroup.code)}"` : ''}
${taskGroup?.completionPolicy ? `completionPolicy: ${taskGroup.completionPolicy}` : ''}
${taskGroup?.id ? `id: "${decodeId(taskGroup.id)}"` : ''}
${taskGroup?.executors ? `userIds: ${executorsString}` : 'userIds: []'}
`;
return GQLString;
};

const PERFORM_MUTATION = (mutationType, mutationInput, ACTION, clientMutationLabel) => {
const mutation = formatMutation(mutationType, mutationInput, ACTION);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
[REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE[ACTION]), ERROR(ACTION_TYPE.MUTATION)],
{
actionType: ACTION_TYPE[ACTION],
clientMutationId: mutation.clientMutationId,
clientMutationLabel,
requestedDateTime,
},
);
};

export function fetchTaskGroups(modulesManager, params) {
const payload = formatPageQueryWithCount('taskGroup', params, TASK_GROUP_PROJECTION());
return graphql(payload, ACTION_TYPE.SEARCH_TASK_GROUPS);
}

export function fetchTaskGroup(modulesManager, variables) {
return graphqlWithVariables(
`
query getTaskGroup ($taskGroupUuid: ID ) {
taskGroup(id: $taskGroupUuid) {
edges {
node {
id
uuid
code
completionPolicy
taskexecutorSet { edges { node { user { id username lastName } } } },
}
}
}
}
`,
variables,
ACTION_TYPE.GET_TASK_GROUP,
);
}

export const clearTaskGroup = () => (dispatch) => {
dispatch({
type: CLEAR(ACTION_TYPE.GET_TASK_GROUP),
});
};

export function deleteTaskGroup(taskGroup, clientMutationLabel) {
const taskGroupsUuids = `ids: ["${decodeId(taskGroup?.id)}"]`;
return PERFORM_MUTATION(
MUTATION_SERVICE.TASK_GROUP.DELETE,
taskGroupsUuids,
'DELETE_TASK_GROUP',
clientMutationLabel,
);
}

export function createTaskGroup(taskGroup, clientMutationLabel) {
return PERFORM_MUTATION(
MUTATION_SERVICE.TASK_GROUP.CREATE,
formatTaskGroupGQL(taskGroup),
'CREATE_TASK_GROUP',
clientMutationLabel,
);
}

export function updateTaskGroup(taskGroup, clientMutationLabel) {
return PERFORM_MUTATION(
MUTATION_SERVICE.TASK_GROUP.UPDATE,
formatTaskGroupGQL(taskGroup),
'UPDATE_TASK_GROUP',
clientMutationLabel,
);
}
117 changes: 117 additions & 0 deletions src/components/BenefitPlanTasksFilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React from 'react';
import { Grid } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import _debounce from 'lodash/debounce';
import { TextInput } from '@openimis/fe-core';
import {
CONTAINS_LOOKUP, DEFAULT_DEBOUNCE_TIME, EMPTY_STRING, TASK_STATUS_LIST,
} from '../constants';
import StatusPicker from '../pickers/StatusPicker';

const useStyles = makeStyles((theme) => ({
form: {
padding: '0 0 10px 0',
width: '100%',
},
item: {
padding: theme.spacing(1),
},
}));

function BenefitPlanTasksFilter({
filters,
onChangeFilters,
formatMessage,
}) {
const classes = useStyles();

const debouncedOnChangeFilters = _debounce(onChangeFilters, DEFAULT_DEBOUNCE_TIME);

const filterValue = (filterName) => filters?.[filterName]?.value;

const filterTextFieldValue = (filterName) => filters?.[filterName]?.value ?? EMPTY_STRING;

const onChangeStringFilter = (filterName, lookup = null) => (value) => {
if (lookup) {
debouncedOnChangeFilters([
{
id: filterName,
value,
filter: `${filterName}_${lookup}: "${value}"`,
},
]);
} else {
onChangeFilters([
{
id: filterName,
value,
filter: `${filterName}: "${value}"`,
},
]);
}
};

return (
<Grid container className={classes.form}>
<Grid item xs={3} className={classes.item}>
<TextInput
module="tasksManagement"
label="benefitPlanTask.source"
value={filterTextFieldValue('source')}
onChange={onChangeStringFilter('source', CONTAINS_LOOKUP)}
/>
</Grid>
<Grid item xs={3} className={classes.item}>
<TextInput
module="tasksManagement"
label="benefitPlanTask.type"
value={filterTextFieldValue('type')}
onChange={onChangeStringFilter('type', CONTAINS_LOOKUP)}
/>
</Grid>
<Grid item xs={3} className={classes.item}>
<TextInput
module="tasksManagement"
label="benefitPlanTask.entity"
value={filterTextFieldValue('entity')}
onChange={onChangeStringFilter('entity', CONTAINS_LOOKUP)}
/>
</Grid>
<Grid item xs={3} className={classes.item}>
<TextInput
module="tasksManagement"
label="benefitPlanTask.assignee"
value={filterTextFieldValue('assignee')}
onChange={onChangeStringFilter('assignee', CONTAINS_LOOKUP)}
/>
</Grid>
<Grid item xs={3} className={classes.item}>
<TextInput
module="tasksManagement"
label="benefitPlanTask.businessStatus"
value={filterTextFieldValue('businessStatus')}
onChange={onChangeStringFilter('businessStatus', CONTAINS_LOOKUP)}
/>
</Grid>
<Grid item xs={3} className={classes.item}>
<StatusPicker
label="benefitPlanTask.status"
constants={TASK_STATUS_LIST}
withLabel
nullLabel={formatMessage('defaultValue.any')}
withNull
value={filterValue('status')}
onChange={(value) => onChangeFilters([
{
id: 'status',
value,
filter: `status: ${value}`,
},
])}
/>
</Grid>
</Grid>
);
}

export default BenefitPlanTasksFilter;
Loading

0 comments on commit 71d904b

Please sign in to comment.