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

Routine builder #2080

Merged
merged 4 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/app/custom/translations.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -1098,3 +1098,4 @@
"ejs_variable_list" "Data from a routine is displayed using an HTML template based on EJS syntax. You can use these variables to access data and utils:" "L’affichage des données en provenance d’une routine est réalisé à l’aide d’un template HTML utilisant la syntaxe EJS. Vous pouvez utiliser ces variables pour accéder aux données et aux utilitaires :"
"ejs_data" "Variable containing the routine data" "Variable contenant les données de la routine"
"ejs_lodash" "Variable containing the Lodash function" "Variable contenant les fonctions de Lodash"
"routine_args" "Routine fields" "Champs de la routine"
2 changes: 1 addition & 1 deletion src/app/js/fields/FieldRepresentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function FieldRepresentation({ field, shortMode = false, p: polyglot }) {
}

FieldRepresentation.propTypes = {
field: PropTypes.isRequired,
field: PropTypes.object.isRequired,
shortMode: PropTypes.bool,
p: polyglotPropTypes.isRequired,
};
Expand Down
13 changes: 8 additions & 5 deletions src/app/js/fields/sourceValue/SourceValuePrecomputed.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { fromPrecomputed } from '../../admin/selectors';
import { polyglot as polyglotPropTypes } from '../../propTypes';
import { Autocomplete, Box, Button, TextField } from '@mui/material';
import { toast } from 'react-toastify';
import RoutineCatalogAutocomplete from '../wizard/RoutineCatalogAutocomplete';

const SourceValuePrecomputed = ({
precomputedData,
Expand Down Expand Up @@ -97,14 +98,15 @@ const SourceValuePrecomputed = ({
)}
onChange={handleChangePrecomputed}
/>

<Box display="flex" alignItems="center">
<TextField
fullWidth
placeholder={polyglot.t('enter_a_routine_value')}
label={polyglot.t('routine_value')}
<RoutineCatalogAutocomplete
onChange={handleChangeRoutine}
value={valueInput}
currentValue={valueInput}
label={polyglot.t('enter_a_routine_value')}
precomputed
/>

<Box style={{ marginLeft: '10px', height: '56px' }}>
<Button
variant="contained"
Expand All @@ -115,6 +117,7 @@ const SourceValuePrecomputed = ({
<ListAltIcon fontSize="medium" />
</Button>
</Box>

<RoutineCatalog
isOpen={openRoutineCatalog}
handleClose={() => setOpenRoutineCatalog(false)}
Expand Down
169 changes: 126 additions & 43 deletions src/app/js/fields/sourceValue/SourceValueRoutine.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,154 @@
import React from 'react';
import compose from 'recompose/compose';
import { compose } from 'recompose';
import ListAltIcon from '@mui/icons-material/ListAlt';
import PropTypes from 'prop-types';
import RoutineCatalog from '../wizard/RoutineCatalog';
import translate from 'redux-polyglot/translate';
import { polyglot as polyglotPropTypes } from '../../propTypes';
import { Box, Button, TextField } from '@mui/material';
import { Box, Button } from '@mui/material';
import { fromFields } from '../../sharedSelectors';
import { loadField } from '../index';
import { connect } from 'react-redux';
import { getFieldForSpecificScope } from '../../../../common/scope';
import SearchAutocomplete from '../../admin/Search/SearchAutocomplete';
import RoutineCatalogAutocomplete from '../wizard/RoutineCatalogAutocomplete';

const SourceValueRoutine = ({
fields,
updateDefaultValueTransformers,
value,
p: polyglot,
}) => {
const [openRoutineCatalog, setOpenRoutineCatalog] = React.useState(false);
const [valueInput, setValueInput] = React.useState(value || '');
const handleChange = (event) => {
setValueInput(event.target.value);
const transformers = [
{
operation: 'ROUTINE',
args: [
{
name: 'value',
type: 'string',
value: event.target.value,
},
],
},
];
const [routine, setRoutine] = React.useState('');
const [routineArgs, setRoutineArgs] = React.useState([]);
const [routineFields, setRoutineFields] = React.useState([]);
const [first, setFirst] = React.useState(true);

updateDefaultValueTransformers(transformers);
const fieldsResource = React.useMemo(
() => getFieldForSpecificScope(fields, 'collection'),
[fields],
);

React.useEffect(() => {
if (typeof value === 'string') {
setRoutine(value.split('/').slice(0, 4).join('/'));
const args = value.split('/').slice(4);
setRoutineArgs(args);
setRoutineFields(
fieldsResource.filter((field) => {
return args.includes(field.name);
}),
);
}
}, [value]);

React.useEffect(() => {
if (!first) {
const finalRoutine = [routine, ...routineArgs].join('/');
const transformers = [
{
operation: 'ROUTINE',
args: [
{
name: 'value',
type: 'string',
value: finalRoutine,
},
],
},
];
updateDefaultValueTransformers(transformers);
} else {
setFirst(false);
}
}, [routine, routineArgs]);

const handleRoutineChange = (event) => {
setRoutine(event.target.value);
setRoutineFields([]);
setRoutineArgs([]);
};

const handleRoutineFieldsChange = (event, newValue) => {
setRoutineFields(newValue);
setRoutineArgs(newValue.map((field) => field.name));
};

return (
<Box mt={5} display="flex" alignItems="center">
<TextField
fullWidth
placeholder={polyglot.t('enter_a_routine_value')}
label={polyglot.t('routine_value')}
onChange={handleChange}
value={valueInput}
multiline
/>
<Box style={{ marginLeft: '10px', height: '56px' }}>
<Button
variant="contained"
color="primary"
onClick={() => setOpenRoutineCatalog(true)}
sx={{ height: '100%' }}
>
<ListAltIcon fontSize="medium" />
</Button>
<Box mt={4} sx={{ flexGrow: 1, overflow: 'hidden', px: 3 }}>
<Box
sx={{ width: '100%' }}
mt={1}
display="flex"
alignItems="center"
>
<RoutineCatalogAutocomplete
onChange={handleRoutineChange}
currentValue={routine}
label={polyglot.t('enter_a_routine_value')}
/>

<Box style={{ marginLeft: '10px', height: '56px' }}>
<Button
variant="contained"
color="primary"
onClick={() => setOpenRoutineCatalog(true)}
sx={{ height: '100%' }}
>
<ListAltIcon fontSize="medium" />
</Button>
</Box>

<RoutineCatalog
isOpen={openRoutineCatalog}
handleClose={() => setOpenRoutineCatalog(false)}
onChange={handleRoutineChange}
currentValue={value}
/>
</Box>

<Box
sx={{ width: '100%' }}
mt={1}
display="flex"
alignItems="center"
>
<SearchAutocomplete
testId="autocomplete_routine_args"
translation={polyglot.t('routine_args')}
fields={fieldsResource}
onChange={handleRoutineFieldsChange}
value={routineFields}
multiple
clearText={polyglot.t('clear')}
/>
</Box>
<RoutineCatalog
isOpen={openRoutineCatalog}
handleClose={() => setOpenRoutineCatalog(false)}
onChange={handleChange}
currentValue={value}
/>
</Box>
);
};

const mapStateToProps = (state) => {
return {
// sort by label asc
fields: fromFields
.getFields(state)
.sort((a, b) => a.label.localeCompare(b.label)),
};
};

const mapDispatchToProps = {
loadField,
};

SourceValueRoutine.propTypes = {
fields: PropTypes.arrayOf(PropTypes.object).isRequired,
p: polyglotPropTypes.isRequired,
updateDefaultValueTransformers: PropTypes.func.isRequired,
value: PropTypes.string,
};

export default compose(translate)(SourceValueRoutine);
export default compose(
translate,
connect(mapStateToProps, mapDispatchToProps),
)(SourceValueRoutine);
Loading
Loading