Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CM-138: User Groups Management implementation #1

Merged
merged 18 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
119 changes: 119 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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;
};

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 } } } },
dborowiecki marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
`,
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)}"]`;
const mutation = formatMutation(MUTATION_SERVICE.TASK_GROUP.DELETE, taskGroupsUuids, clientMutationLabel);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
[REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE.DELETE_TASK_GROUP), ERROR(ACTION_TYPE.MUTATION)],
{
actionType: ACTION_TYPE.DELETE_TASK_GROUP,
clientMutationId: mutation.clientMutationId,
clientMutationLabel,
requestedDateTime,
},
);
}

export function createTaskGroup(taskGroup, clientMutationLabel) {
const mutation = formatMutation(
MUTATION_SERVICE.TASK_GROUP.CREATE,
formatTaskGroupGQL(taskGroup),
clientMutationLabel,
);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
[REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE.CREATE_TASK_GROUP), ERROR(ACTION_TYPE.MUTATION)],
{
actionType: ACTION_TYPE.CREATE_TASK_GROUP,
clientMutationId: mutation.clientMutationId,
clientMutationLabel,
requestedDateTime,
},
);
}

export function updateTaskGroup(taskGroup, clientMutationLabel) {
const mutation = formatMutation(
MUTATION_SERVICE.TASK_GROUP.UPDATE,
formatTaskGroupGQL(taskGroup),
clientMutationLabel,
);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
[REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE.UPDATE_TASK_GROUP), ERROR(ACTION_TYPE.MUTATION)],
{
actionType: ACTION_TYPE.UPDATE_TASK_GROUP,
clientMutationId: mutation.clientMutationId,
clientMutationLabel,
requestedDateTime,
},
);
dborowiecki marked this conversation as resolved.
Show resolved Hide resolved
}
117 changes: 117 additions & 0 deletions src/components/BenefitPlanTasksFilter.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added as a contribution from the benefit plan js to the TaskManagement view ContributionPoint. Same goes for BenefitPlanTaskSearcher.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving all benefit plan logic to the other modules will be handled in scope of the CM-139.

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