Commit d9701224 authored by Maksym Tishchenko's avatar Maksym Tishchenko
Browse files

Genesys requests for material

parent c15ce3d6
......@@ -969,6 +969,31 @@
"equals": "Equals",
"contains": "Contains",
"startsWith": "Starts with"
},
"MaterialSubRequest": {
"uuid": "UUID",
"version": "Version",
"active": "Active",
"state": "State",
"instCode": "Institute",
"instEmail": "Institute email",
"sourceRequest": "Source request",
"lastReminderDate": "Last reminder date"
},
"RequestInfo": {
"email": "Email",
"purposeType": "Purpose type",
"preacceptSMTA": "Pre accept SMTA",
"notes": "Notes",
"internalRequest": "Internal Request"
},
"GenesysConfig": {
"genesysUrl": "Genesys URL",
"clientId": "Client ID",
"clientSecret": "Client secret",
"origin": "Origin",
"debug": "Debug",
"instCode": "Institute"
}
}
}
\ No newline at end of file
......@@ -957,5 +957,30 @@
"equals": "Equals",
"contains": "Contains",
"startsWith": "Starts with"
},
"MaterialSubRequest": {
"uuid": "UUID",
"version": "Version",
"active": "Active",
"state": "State",
"instCode": "Institute",
"instEmail": "Institute email",
"sourceRequest": "Source request",
"lastReminderDate": "Last reminder date"
},
"RequestInfo": {
"email": "Email",
"purposeType": "Purpose type",
"preacceptSMTA": "Pre accept SMTA",
"notes": "Notes",
"internalRequest": "Internal Request"
},
"GenesysConfig": {
"genesysUrl": "Genesys URL",
"clientId": "Client ID",
"clientSecret": "Client secret",
"origin": "Origin",
"debug": "Debug",
"instCode": "Institute"
}
}
......@@ -116,6 +116,7 @@ class GenesysService {
* listAccessions at /api/v1/genesys/accessions
*
* @param authenticationToken undefined
* @param filter
* @param page undefined
* @param xhrConfig additional xhr config
*/
......@@ -129,7 +130,7 @@ class GenesysService {
}, {});
const apiUrl = URL_LIST_ACCESSIONS + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { ...filter };
const content = { data: filter };
return this._axios.request({
...xhrConfig,
......
......@@ -868,12 +868,20 @@
"request": {
"navigation": {
"checklist": "Verify request items",
"retrieve": "Retrieval list"
"retrieve": "Retrieval list",
"genesys": {
"request": "Genesys requests"
}
},
"browse": {
"title": "One request for material",
"title_plural": "{{count,number}} requests for material"
},
"genesysRequestBrowse": {
"title": "One material sub request",
"title_plural": "{{count,number}} material sub requests",
"list": "Material sub requests"
},
"public": {
"p": {
"request": {
......@@ -891,6 +899,10 @@
"sameAsRequestor": "The same as Requestor",
"sameAsFinalRecipient": "The same as final recipient"
},
"genesysConfig": {
"unableToConnect": "Unable to connect to genesys, please update config",
"updateConfig": "Update config"
},
"edit": {
"title": "New Request"
},
......@@ -906,6 +918,9 @@
"c": {
"filters": {
"text": "Full-text search"
},
"genesysRequestDetailsDialog": {
"title": "Material sub request details"
}
}
},
......
......@@ -40,6 +40,11 @@ function RequestMenu({ currentPath }: { currentPath: string }): JSX.Element {
<ListItemText primary={ t('request.navigation.retrieve') } />
</ListItem>
</Link>
<Link to="/dist/genesys/request">
<ListItem button className={ currentPath?.match('^/dist/genesys/request(/[0-9]+$|$)') && classes.selectedRoute }>
<ListItemText primary={ t('request.navigation.genesys.request') } />
</ListItem>
</Link>
</List>
);
}
......
......@@ -32,6 +32,13 @@ const requestRoutes: IRoute[] = [
}),
path: '/retrieve',
},
{
exact: true,
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "dist" */ 'request/ui/GenesysRequestBrowsePage'),
}),
path: '/genesys/request',
},
];
export { requestRoutes };
{
"navigation": {
"checklist": "Verify request items",
"retrieve": "Retrieval list"
"retrieve": "Retrieval list",
"genesys": {
"request": "Genesys requests"
}
},
"browse": {
"title": "One request for material",
"title_plural": "{{count,number}} requests for material"
},
"genesysRequestBrowse": {
"title": "One material sub request",
"title_plural": "{{count,number}} material sub requests",
"list": "Material sub requests"
},
"public": {
"p": {
"request": {
......@@ -24,6 +32,10 @@
"sameAsRequestor": "The same as Requestor",
"sameAsFinalRecipient": "The same as final recipient"
},
"genesysConfig": {
"unableToConnect": "Unable to connect to genesys, please update config",
"updateConfig": "Update config"
},
"edit": {
"title": "New Request"
},
......@@ -39,6 +51,9 @@
"c": {
"filters": {
"text": "Full-text search"
},
"genesysRequestDetailsDialog": {
"title": "Material sub request details"
}
}
},
......
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { WithTranslation, withTranslation } from 'react-i18next';
// Action
import { showSnackbar } from '@gringlobal-ce/client/action/snackbar';
// Model
import { GenesysConfig } from '@gringlobal-ce/client/model/genesys';
import { IPageRequest, Page, SortDirection } from '@gringlobal-ce/client/model/page';
// Ui
import ContentHeader from '@gringlobal-ce/client/ui/common/heading/ContentHeader';
import Table, { TextAlign, Renderers } from '@gringlobal-ce/client/ui/common/table/Table';
import { CooperatorOwnedTableConfiguration as TableConfiguration } from '@gringlobal-ce/client/ui/common/table/TableConfiguration';
import PageTitle from '@gringlobal-ce/client/ui/common/PageTitle';
import { GenesysService } from '@gringlobal-ce/client/service';
import GenesysConfigForm from 'request/ui/c/GenesysConfigForm';
import { UserRole } from '@gringlobal-ce/client/model/gringlobal/SysUser';
import Authorize from '@gringlobal-ce/client/ui/common/authorized/Authorize';
import GenesysRequestDetailsDialog from 'request/ui/c/GenesysRequestDetailsDialog';
import MaterialSubRequest from '@gringlobal-ce/client/model/genesys/MaterialSubRequest';
interface IGenesysBrowsePageProps extends React.ClassAttributes<any>, WithTranslation {
showSnackbar: (snack: string) => void;
}
export const GenesysRequestTableDefaultConfig = {
defaultColumns: [
'id',
'uuid',
'version',
'active',
'state',
'instCode',
'instEmail',
'sourceRequest',
'lastReminderDate',
],
ignoredColumns: [
'body',
],
defaultColumnSettings: {
id: { readonly: true, align: TextAlign.right },
version: { align: TextAlign.right },
state: { align: TextAlign.right },
},
columnRenderers: {
uuid: ({ value, actions, row }: { value: string, actions: {[key: string]: (...args) => void}, row: MaterialSubRequest }): JSX.Element =>
<a onClick={ () => actions.openRequestDetails(row) }>
{ value }
</a>,
lastReminderDate: Renderers.DATE_RENDERER,
version: Renderers.NUMBER_RENDERER,
state: Renderers.NUMBER_RENDERER,
},
};
const GenesysRequestTableConfig = new TableConfiguration(GenesysRequestTableDefaultConfig);
class GenesysBrowsePage extends React.Component<IGenesysBrowsePageProps> {
public state = {
genesysConfigDialogIsOpen: false,
requestDetailsDialogIsOpen: false,
config: null,
token: null,
materialSubRequestList: null,
selectedRequest: null
};
public componentDidMount() {
const { showSnackbar, t } = this.props;
GenesysService.connect().then((token) => {
console.log('success, load requests now')
this.setState({ token })
this.loadRequests();
}).catch((e) => {
console.log('error, unable to connect to genesys', e)
showSnackbar(t('request.public.p.genesysConfig.unableToConnect'))
GenesysService.getConfig().then((config) => {
this.setState({ config })
this.openGenesysConfigDialog();
})
});
}
private onSortChange = (sortBy: string, dir: SortDirection) => {
const { materialSubRequestList } = this.state;
this.loadMore(Page.sort(materialSubRequestList, sortBy, dir));
};
private loadRequests = (pageR: IPageRequest = { page: 0, size: 100 }) => {
const { materialSubRequestList, token } = this.state;
if (!token) {
console.error('No token while loading material sub requests')
return
}
GenesysService.listRequests(token, pageR).then((data) => {
this.setState({ materialSubRequestList: Page.merge(materialSubRequestList, data) })
})
}
private loadMore = (list?): void => {
const { materialSubRequestList } = this.state;
this.loadRequests(Page.nextPage(list ?? materialSubRequestList));
};
private handleSubmitConfig = (formData: GenesysConfig) => {
const { showSnackbar, t } = this.props;
GenesysService.putConfig(formData).then((config) => {
this.setState({ config })
GenesysService.connect().then((token) => {
this.setState({ token })
this.loadRequests();
this.closeGenesysConfigDialog();
}).catch((e) => {
console.log("Unable to connect", e)
showSnackbar(t('request.public.p.genesysConfig.unableToConnect'))
})
}).catch((e) => {
console.log("Unable to update genesys config", e)
})
};
private openGenesysConfigDialog = () => {
this.setState({ genesysConfigDialogIsOpen: true });
};
private closeGenesysConfigDialog = () => {
this.setState({ genesysConfigDialogIsOpen: false });
};
private openRequestDetailsDialog = (request: MaterialSubRequest) => {
this.setState({ requestDetailsDialogIsOpen: true, selectedRequest: request });
};
private closeRequestDetailsDialog = () => {
this.setState({ requestDetailsDialogIsOpen: false });
};
public render() {
const { t } = this.props;
const { genesysConfigDialogIsOpen, config, materialSubRequestList, requestDetailsDialogIsOpen, selectedRequest, token } = this.state;
const columns = GenesysRequestTableConfig.getColumns(materialSubRequestList?.content?.[0] ?? null);
return (
<>
<PageTitle title={ materialSubRequestList?.totalElements
? t('request.genesysRequestBrowse.title', { count: materialSubRequestList.totalElements })
: t('request.genesysRequestBrowse.list') }
/>
<ContentHeader title={ materialSubRequestList?.totalElements
? t('request.genesysRequestBrowse.title', { count: materialSubRequestList.totalElements })
: t('request.genesysRequestBrowse.list') }
/>
<Table
tableKey="genesys-request-list"
type={ 'MaterialSubRequest' }
columns={ columns }
data={ materialSubRequestList?.content }
tableConfig={ GenesysRequestTableConfig }
total={ materialSubRequestList?.content && materialSubRequestList.totalElements }
loadMore={ this.loadMore }
sort={ materialSubRequestList?.sort }
onSortChange={ this.onSortChange }
actions={ { openRequestDetails: this.openRequestDetailsDialog } }
/>
<Authorize roles={ [ UserRole.ADMINISTRATOR ] }>
<GenesysConfigForm
isOpen={ genesysConfigDialogIsOpen }
onClose={ this.closeGenesysConfigDialog }
onSubmit={ this.handleSubmitConfig }
formId='genesys-config-form'
title={ t('request.public.p.genesysConfig.updateConfig') }
initialValues={ config }
/>
</Authorize>
<GenesysRequestDetailsDialog
selectedRequest={ selectedRequest }
token={ token }
isOpen={ requestDetailsDialogIsOpen }
onClose={ this.closeRequestDetailsDialog }
/>
</>
);
}
}
const mapDispatchToProps = (dispatch) => bindActionCreators({
showSnackbar
}, dispatch);
export default compose(
connect(null, mapDispatchToProps),
withTranslation(),
)(GenesysBrowsePage);
import * as React from 'react';
import { Form, Field, FormProps, FormRenderProps } from 'react-final-form';
import { withTranslation, WithTranslation } from 'react-i18next';
// Model
// import OrderRequest from '@gringlobal-ce/client/model/gringlobal/OrderRequest';
// UI
import { TextField } from '@gringlobal-ce/client/ui/common/form/TextField';
import { Grid } from '@material-ui/core';
import { withStyles, WithStyles } from '@material-ui/core/styles';
// Utils
import { required } from '@gringlobal-ce/client/utilities/validators';
import withDialog from 'ui/common/withDialog';
import { YesNoSwitch } from '@gringlobal-ce/client/ui/common/form/Toggle';
const styles = (theme) => ({
textField: {
},
});
const GenesysConfigForm = ({ t, onSubmit, initialValues, classes }: FormProps & WithTranslation & WithStyles) =>
<Form
initialValues={ initialValues }
onSubmit={ onSubmit }
>
{ (props: FormRenderProps & WithStyles) => (
<form onSubmit={ props.handleSubmit } id="genesys-config-form">
<Grid container spacing={ 4 }>
{ [ 'genesysUrl', 'clientId', 'clientSecret', 'origin', 'instCode' ].map((property) => (
<Grid key={ property } item xs={ 12 } sm={ 6 }>
<Field
placeholder={ t(`client:model.GenesysConfig.${property}`, `client:model._.${property}`) }
name={ property }
type="text"
component={ TextField }
label={ t(`client:model.GenesysConfig.${property}`, `client:model._.${property}`) }
validate={ required }
/>
</Grid>
)) }
<Grid item xs={ 12 } sm={ 6 }>
<Field
name="debug"
component={ YesNoSwitch }
labelPlacement="end"
label={ t('client:model.GenesysConfig.debug') }
/>
</Grid>
</Grid>
</form>
)}
</Form>;
export default withDialog(withStyles(styles)(withTranslation()(GenesysConfigForm)));
import * as React from 'react';
import { connect } from 'react-redux';
import { WithTranslation, withTranslation } from 'react-i18next';
// model
import MaterialSubRequest from '@gringlobal-ce/client/model/genesys/MaterialSubRequest';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import { bindActionCreators } from 'redux';
import { Properties, PropertiesItem } from '@gringlobal-ce/client/ui/common/Properties';
import Number from '@gringlobal-ce/client/ui/common/Number';
import PrettyDate from '@gringlobal-ce/client/ui/common/time/PrettyDate';
import { GenesysService } from '@gringlobal-ce/client/service';
import { showSnackbar } from '@gringlobal-ce/client/action/snackbar';
import GenesysAccessionFilter from '@gringlobal-ce/client/model/genesys/AccessionFilter';
import { FilteredPage, IPageRequest } from '@gringlobal-ce/client/model/page';
interface IGenesysRequestDetailsDialogProps extends React.ClassAttributes<any>, WithTranslation {
selectedRequest: MaterialSubRequest;
token: string;
isOpen: boolean;
onClose: () => void;
showSnackbar: (error: string) => void;
}
class GenesysRequestDetailsDialog extends React.Component<IGenesysRequestDetailsDialogProps, any> {
public state = {
accessionList: null
}
public componentDidUpdate(prevProps: Readonly<IGenesysRequestDetailsDialogProps>) {
const { isOpen, selectedRequest } = this.props;
const ids = selectedRequest?.body?.accessionIds;
if (isOpen === true && prevProps.isOpen === false && ids) {
this.loadAccessions({ id: ids })
}
}
private loadAccessions = (filter: Partial<GenesysAccessionFilter> = {}, pageR: IPageRequest = { page: 0, size: 100 }) => {
const { token, showSnackbar } = this.props;
const { accessionList } = this.state;
GenesysService.listAccessions(token, filter, pageR).then((data) => {
this.setState({ accessionList: FilteredPage.merge(accessionList, data) })
}).catch((e) => {
showSnackbar(e.data && e.data.error || e.toString());
});
}
// private loadMore = (list?): void => {
// const { accessionList } = this.state;
// this.loadAccessions(list?.filter ?? accessionList.filter, Page.nextPage(list ?? accessionList));
// };
public render() {
const { selectedRequest, isOpen, t, onClose } = this.props;
return (
<div>
{ isOpen &&
<Dialog
open={ isOpen }
onClose={ onClose }
maxWidth="md"
fullWidth
disableEnforceFocus
>
<DialogTitle>{ t('request.public.c.genesysRequestDetailsDialog.title') }</DialogTitle>
<DialogContent>
<Properties>
{ selectedRequest.version !== null &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.version') }>
<Number value={ selectedRequest.version } />
</PropertiesItem>
}
{ selectedRequest.active &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.active') }>
{ selectedRequest.active ? t('common:label.yes') : t('common:label.no') }
</PropertiesItem>
}
{ selectedRequest.state !== null &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.state') }>
<Number value={ selectedRequest.state } />
</PropertiesItem>
}
{ selectedRequest.body?.requestInfo?.email &&
<PropertiesItem title={ t('client:model.RequestInfo.email') }>
{ selectedRequest.body?.requestInfo?.email }
</PropertiesItem>
}
{ selectedRequest.body?.requestInfo?.purposeType !== null &&
<PropertiesItem title={ t('client:model.RequestInfo.purposeType') }>
<Number value={ selectedRequest.body?.requestInfo?.purposeType } />
</PropertiesItem>
}
{ selectedRequest.body?.requestInfo?.preacceptSMTA &&
<PropertiesItem title={ t('client:model.RequestInfo.preacceptSMTA') }>
{ selectedRequest.body?.requestInfo?.preacceptSMTA ? t('common:label.yes') : t('common:label.no') }
</PropertiesItem>
}
{ selectedRequest.body?.requestInfo?.internalRequest &&
<PropertiesItem title={ t('client:model.RequestInfo.internalRequest') }>
{ selectedRequest.body?.requestInfo?.internalRequest ? t('common:label.yes') : t('common:label.no') }
</PropertiesItem>
}
{ selectedRequest.body?.requestInfo?.notes &&
<PropertiesItem title={ t('client:model.RequestInfo.notes') }>
{ selectedRequest.body?.requestInfo?.notes }
</PropertiesItem>
}
{ selectedRequest.instCode &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.instCode') }>
{ selectedRequest.instCode }
</PropertiesItem>
}
{ selectedRequest.instEmail &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.instEmail') }>
{ selectedRequest.instEmail }
</PropertiesItem>
}
{ selectedRequest.lastReminderDate &&
<PropertiesItem title={ t('client:model.MaterialSubRequest.lastReminderDate') }>
<PrettyDate value={ selectedRequest.lastReminderDate } />
</PropertiesItem>
}
{ selectedRequest.createdBy &&