Skip to content

Commit

Permalink
RN-619: Added ability to perform manual sync and view sync group logs…
Browse files Browse the repository at this point in the history
… in Admin Panel (#4117)
  • Loading branch information
rohan-bes authored Sep 5, 2022
1 parent 9cfd2d7 commit 3565551
Show file tree
Hide file tree
Showing 31 changed files with 937 additions and 55 deletions.
1 change: 1 addition & 0 deletions packages/admin-panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"axios": "^0.21.1",
"case": "^1.5.3",
"content-disposition-header": "^0.6.0",
"date-fns": "^2.29.2",
"file-saver": "^1.3.3",
"localforage": "^1.5.0",
"lodash.debounce": "^4.0.8",
Expand Down
40 changes: 40 additions & 0 deletions packages/admin-panel/src/logsTable/LogsButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Tupaia MediTrak
* Copyright (c) 2018 Beyond Essential Systems Pty Ltd
*/

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import DescriptionIcon from '@material-ui/icons/Description';
import { IconButton } from '../widgets';
import { openLogsModal } from './actions';

export const LogsButtonComponent = props => {
const { openModal } = props;
return (
<IconButton onClick={openModal}>
<DescriptionIcon />
</IconButton>
);
};

LogsButtonComponent.propTypes = {
openModal: PropTypes.func.isRequired,
};

const mapDispatchToProps = (dispatch, { actionConfig, value: recordId, row }) => ({
openModal: () => {
dispatch(openLogsModal(actionConfig, recordId, row));
},
});

const mergeProps = ({ ...stateProps }, { ...dispatchProps }, { ...ownProps }) => {
return {
...ownProps,
...stateProps,
...dispatchProps,
};
};

export const LogsButton = connect(null, mapDispatchToProps, mergeProps)(LogsButtonComponent);
87 changes: 87 additions & 0 deletions packages/admin-panel/src/logsTable/LogsModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Tupaia MediTrak
* Copyright (c) 2018 Beyond Essential Systems Pty Ltd
*/

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Button, Dialog, DialogFooter, DialogHeader } from '@tupaia/ui-components';
import { changeLogsTablePage, closeLogsModal } from './actions';
import { ModalContentProvider } from '../widgets';
import { LogsTable } from './LogsTable';

export const LogsModalComponent = ({
errorMessage,
logs,
logsCount,
page,
logsPerPage,
onChangeLogsTablePage,
isLoading,
isOpen,
onDismiss,
title,
}) => {
return (
<Dialog onClose={onDismiss} open={isOpen} disableBackdropClick maxWidth="xl">
<DialogHeader onClose={onDismiss} title={title} />
<ModalContentProvider errorMessage={errorMessage} isLoading={isLoading}>
<LogsTable
logs={logs}
logsCount={logsCount}
page={page}
logsPerPage={logsPerPage}
onChangePage={onChangeLogsTablePage}
/>
</ModalContentProvider>
<DialogFooter>
<Button variant="outlined" onClick={onDismiss} disabled={isLoading}>
{errorMessage ? 'Dismiss' : 'Cancel'}
</Button>
</DialogFooter>
</Dialog>
);
};

LogsModalComponent.propTypes = {
errorMessage: PropTypes.string,
isLoading: PropTypes.object.isRequired,
isOpen: PropTypes.bool.isRequired,
onDismiss: PropTypes.func.isRequired,
title: PropTypes.string,
logs: PropTypes.arrayOf(PropTypes.string).isRequired,
logsCount: PropTypes.number.isRequired,
page: PropTypes.number.isRequired,
logsPerPage: PropTypes.number.isRequired,
onChangeLogsTablePage: PropTypes.func.isRequired,
};

LogsModalComponent.defaultProps = {
errorMessage: null,
title: 'Logs',
};

const mapStateToProps = state => ({
...state.logs,
});

const mapDispatchToProps = dispatch => ({
onDismiss: () => dispatch(closeLogsModal()),
onChangeLogsTablePage: page => dispatch(changeLogsTablePage(page)),
dispatch,
});

const mergeProps = ({ ...stateProps }, { dispatch, ...dispatchProps }, { ...ownProps }) => {
return {
...ownProps,
...stateProps,
...dispatchProps,
};
};

export const LogsModal = connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
)(LogsModalComponent);
46 changes: 46 additions & 0 deletions packages/admin-panel/src/logsTable/LogsTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { Table, useTableSorting } from '@tupaia/ui-components';

const StyledTable = styled(Table)`
.MuiTableCell-root {
height: 30px;
}
`;

export const LogsTable = ({ logs, logsCount, page, logsPerPage, onChangePage }) => {
const { sortedData, order, orderBy, sortColumn } = useTableSorting(logs);
return (
<StyledTable
count={logsCount}
page={page}
onChangePage={onChangePage}
rowsPerPage={logsPerPage}
rowsPerPageOptions={[]}
data={sortedData}
order={order}
orderBy={orderBy}
onChangeOrderBy={sortColumn}
columns={[
{ key: 'timestamp', title: 'time', sortable: true, width: '250px', align: 'left' },
{ key: 'message', title: 'message', sortable: false, align: 'left' },
]}
/>
);
};

LogsTable.propTypes = {
logs: PropTypes.arrayOf(
PropTypes.shape({ timestamp: PropTypes.string, message: PropTypes.string }),
).isRequired,
logsCount: PropTypes.number.isRequired,
page: PropTypes.number.isRequired,
logsPerPage: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
};
97 changes: 97 additions & 0 deletions packages/admin-panel/src/logsTable/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Tupaia MediTrak
* Copyright (c) 2018 Beyond Essential Systems Pty Ltd
*/

import { makeSubstitutionsInString } from '../utilities';
import {
LOGS_DATA_FETCH_BEGIN,
LOGS_DATA_FETCH_SUCCESS,
LOGS_DISMISS,
LOGS_ERROR,
LOGS_OPEN,
} from './constants';

const getModalTitle = (titleTemplate, recordData) =>
titleTemplate ? makeSubstitutionsInString(titleTemplate, recordData) : null;

const addQueryParameters = (url, logsPerPage, page) =>
`${url}?limit=${logsPerPage}${page !== undefined ? `&offset=${page * logsPerPage}` : ''}`;

const fetchNewPageOfLogs = async (dispatch, api, logsEndpoint, page, logsPerPage, recordData) => {
const formattedLogsEndpoint = makeSubstitutionsInString(logsEndpoint, recordData);
const finalLogsEndpoint = addQueryParameters(formattedLogsEndpoint, logsPerPage, page);
dispatch({
type: LOGS_DATA_FETCH_BEGIN,
});

try {
const response = await api.get(finalLogsEndpoint);
dispatch({
type: LOGS_DATA_FETCH_SUCCESS,
data: response.body,
page,
});
} catch (error) {
dispatch({
type: LOGS_ERROR,
errorMessage: error.message,
});
}
};

const fetchLogsFirstTime = async (
dispatch,
api,
logsCountEndpoint,
logsEndpoint,
logsPerPage,
recordData,
) => {
const finalLogsCountEndpoint = makeSubstitutionsInString(logsCountEndpoint, recordData);
const formattedLogsEndpoint = makeSubstitutionsInString(logsEndpoint, recordData);
const finalLogsEndpoint = addQueryParameters(formattedLogsEndpoint, logsPerPage);
dispatch({
type: LOGS_DATA_FETCH_BEGIN,
});

try {
const countResponse = await api.get(finalLogsCountEndpoint);
const logsResponse = await api.get(finalLogsEndpoint);
dispatch({
type: LOGS_DATA_FETCH_SUCCESS,
data: { ...countResponse.body, ...logsResponse.body },
});
} catch (error) {
dispatch({
type: LOGS_ERROR,
errorMessage: error.message,
});
}
};

export const openLogsModal = (
{ logsEndpoint, logsCountEndpoint, logsPerPage, title },
recordId,
recordData,
) => async (dispatch, getState, { api }) => {
await fetchLogsFirstTime(dispatch, api, logsCountEndpoint, logsEndpoint, logsPerPage, recordData);
dispatch({
type: LOGS_OPEN,
recordData,
recordId,
logsEndpoint,
logsCountEndpoint,
logsPerPage,
title: getModalTitle(title, recordData),
});
};

export const changeLogsTablePage = page => async (dispatch, getState, { api }) => {
const { logsEndpoint, logsPerPage, recordData } = getState().logs;
await fetchNewPageOfLogs(dispatch, api, logsEndpoint, page, logsPerPage, recordData);
};

export const closeLogsModal = () => ({
type: LOGS_DISMISS,
});
10 changes: 10 additions & 0 deletions packages/admin-panel/src/logsTable/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Tupaia MediTrak
* Copyright (c) 2018 Beyond Essential Systems Pty Ltd
*/

export const LOGS_DATA_FETCH_BEGIN = 'LOGS_DATA_FETCH_BEGIN';
export const LOGS_DATA_FETCH_SUCCESS = 'LOGS_DATA_FETCH_SUCCESS';
export const LOGS_DISMISS = 'LOGS_DISMISS';
export const LOGS_ERROR = 'LOGS_ERROR';
export const LOGS_OPEN = 'LOGS_OPEN';
8 changes: 8 additions & 0 deletions packages/admin-panel/src/logsTable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

export { LogsButton } from './LogsButton';
export { LogsModal } from './LogsModal';
export { reducer } from './reducer';
48 changes: 48 additions & 0 deletions packages/admin-panel/src/logsTable/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Tupaia MediTrak
* Copyright (c) 2018 Beyond Essential Systems Pty Ltd
*/

import { createReducer } from '../utilities';
import {
LOGS_DATA_FETCH_BEGIN,
LOGS_DATA_FETCH_SUCCESS,
LOGS_DISMISS,
LOGS_ERROR,
LOGS_OPEN,
} from './constants';

const defaultState = {
errorMessage: '',
isLoading: false,
isOpen: false,
logs: [],
logCount: null,
page: 0,
logsPerPage: 10,
recordId: null,
recordData: null,
};

const stateChanges = {
[LOGS_DATA_FETCH_BEGIN]: payload => ({
isLoading: true,
...payload,
}),
[LOGS_DATA_FETCH_SUCCESS]: payload => {
const { data, ...restOfPayload } = payload;
return { isLoading: false, ...data, ...restOfPayload };
},
[LOGS_DISMISS]: () => ({
...defaultState,
}),
[LOGS_ERROR]: (payload, { errorMessage }) => {
if (errorMessage) {
return { errorMessage: defaultState.errorMessage }; // If there is an error, dismiss it
}
return defaultState; // If no error, dismiss the whole modal and clear its state
},
[LOGS_OPEN]: payload => ({ ...payload, isOpen: true }),
};

export const reducer = createReducer(defaultState, stateChanges);
2 changes: 2 additions & 0 deletions packages/admin-panel/src/pages/resources/ResourcePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DataFetchingTable } from '../../table';
import { EditModal } from '../../editor';
import { Header, PageBody } from '../../widgets';
import { usePortalWithCallback } from '../../utilities';
import { LogsModal } from '../../logsTable';

const Container = styled(PageBody)`
overflow: auto;
Expand Down Expand Up @@ -57,6 +58,7 @@ export const ResourcePage = ({
/>
</Container>
<EditModal onProcessDataForSave={onProcessDataForSave} displayUsedBy={displayUsedBy} />
<LogsModal />
</>
);
};
Expand Down
Loading

0 comments on commit 3565551

Please sign in to comment.