Skip to content

Commit

Permalink
Refactor duplicate code (#289)
Browse files Browse the repository at this point in the history
* Refactor reduction history

* Add in symbols

* Tidy imports

* Fix linting warnings

* Delete ReductionHistory.tsx

* Prettier formatting

* Fix column spacing

* Rename to job from reduction

* Add sticky headers

* Fix rendering for extra column

* Disable prop-types warning

* Add run type logic

* Add underline

* Add reductions page navigation

* Remove import

* Remove file icons

* Refactor API requests logic

* Add order_by param

* Remove unused imports
  • Loading branch information
Dagonite authored Sep 19, 2024
1 parent 437a26f commit 30f3568
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 149 deletions.
86 changes: 20 additions & 66 deletions src/Jobs/JobsAll.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,50 @@
// React components
import React, { useCallback, useEffect, useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';

// Material UI components
import { useTheme } from '@mui/material/styles';
import { TableCell } from '@mui/material';
import { SelectChangeEvent } from '@mui/material';

// Local data
import JobsBase, { Job, headerStyles } from './JobsBase';
import JobsBase, { useFetchJobs, useFetchTotalCount, Job, headerStyles } from './JobsBase';

const JobsAll: React.FC = () => {
const fiaApiUrl = process.env.REACT_APP_FIA_REST_API_URL;
const theme = useTheme();
const history = useHistory();

const [jobs, setJobs] = useState<Job[]>([]);
const [totalRows, setTotalRows] = useState(0);
const [currentPage, setCurrentPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [orderDirection, setOrderDirection] = useState<'asc' | 'desc'>('desc');
const [orderBy, setOrderBy] = useState<string>('run_start');
const [selectedInstrument, setSelectedInstrument] = useState<string>('ALL');

const fetchTotalCount = useCallback(async (): Promise<void> => {
try {
const response = await fetch(`${fiaApiUrl}/jobs/count`);
const data = await response.json();
setTotalRows(data.count);
} catch (error) {
console.error('Error fetching run count:', error);
}
}, [fiaApiUrl]);

const fetchJobs = useCallback(async (): Promise<void> => {
try {
const token = localStorage.getItem('scigateway:token');
const offset = currentPage * rowsPerPage;
const query = `limit=${rowsPerPage}&offset=${offset}&order_direction=${orderDirection}&include_run=true`;
const response = await fetch(`${fiaApiUrl}/jobs?${query}`, {
method: 'GET',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
});
const data = await response.json();

setJobs(data);
} catch (error) {
console.error('Error fetching reductions:', error);
}
}, [currentPage, rowsPerPage, orderDirection, fiaApiUrl]);

useEffect(() => {
fetchTotalCount();
fetchJobs();
}, [fetchTotalCount, fetchJobs]);

const handleInstrumentChange = (event: SelectChangeEvent<string>): void => {
const newInstrument = event.target.value;
setSelectedInstrument(newInstrument);
setCurrentPage(0);
history.push(`/reduction-history/${newInstrument}`);
};

const handleChangePage = (event: unknown, newPage: number): void => {
setCurrentPage(newPage);
};

const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
setRowsPerPage(parseInt(event.target.value, 10));
setCurrentPage(0);
};

const handleSort = (property: string): void => {
const isAsc = orderBy === property && orderDirection === 'asc';
setOrderDirection(isAsc ? 'desc' : 'asc');
setOrderBy(property);
setCurrentPage(0);
};
const offset = currentPage * rowsPerPage;
const query = `limit=${rowsPerPage}&offset=${offset}&order_by=${orderBy}&order_direction=${orderDirection}&include_run=true`;
const token = localStorage.getItem('scigateway:token');
const fetchJobs = useFetchJobs(`${fiaApiUrl}/jobs`, query, setJobs, token);
const fetchTotalCount = useFetchTotalCount(`${fiaApiUrl}/jobs/count`, setTotalRows);

return (
<JobsBase
selectedInstrument={selectedInstrument}
handleInstrumentChange={handleInstrumentChange}
selectedInstrument="ALL"
handleInstrumentChange={undefined}
jobs={jobs}
totalRows={totalRows}
currentPage={currentPage}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
handleSort={handleSort}
handleChangePage={(_, newPage) => setCurrentPage(newPage)}
handleChangeRowsPerPage={(e) => setRowsPerPage(parseInt(e.target.value, 10))}
handleSort={(property) => {
const isAsc = orderBy === property && orderDirection === 'asc';
setOrderDirection(isAsc ? 'desc' : 'asc');
setOrderBy(property);
setCurrentPage(0);
}}
orderBy={orderBy}
orderDirection={orderDirection}
fetchJobs={fetchJobs}
fetchTotalCount={fetchTotalCount}
customHeaders={<TableCell sx={{ width: '10%', ...headerStyles(theme) }}>Instrument</TableCell>}
customRowCells={(job: Job) => (
<TableCell sx={{ width: '10%' }}>
Expand Down
47 changes: 46 additions & 1 deletion src/Jobs/JobsBase.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// React components
import React, { useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import ReactGA from 'react-ga4';

// Material UI components
Expand Down Expand Up @@ -86,6 +86,42 @@ export interface Job {
};
}

export const useFetchJobs = (
apiUrl: string,
queryParams: string,
setJobs: React.Dispatch<React.SetStateAction<Job[]>>,
token: string | null
): (() => Promise<void>) => {
return useCallback(async () => {
try {
const headers: { [key: string]: string } = { 'Content-Type': 'application/json' };
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(`${apiUrl}?${queryParams}`, { method: 'GET', headers });
const data = await response.json();
setJobs(data);
} catch (error) {
console.error('Error fetching jobs:', error);
}
}, [apiUrl, queryParams, token, setJobs]);
};

export const useFetchTotalCount = (
apiUrl: string,
setTotalRows: React.Dispatch<React.SetStateAction<number>>
): (() => Promise<void>) => {
return useCallback(async () => {
try {
const response = await fetch(apiUrl);
const data = await response.json();
setTotalRows(data.count);
} catch (error) {
console.error('Error fetching total count:', error);
}
}, [apiUrl, setTotalRows]);
};

interface JobsBaseProps {
selectedInstrument: string;
handleInstrumentChange?: (event: SelectChangeEvent<string>, child: React.ReactNode) => void;
Expand All @@ -101,6 +137,8 @@ interface JobsBaseProps {
customHeaders?: React.ReactNode;
customRowCells?: (Job: Job) => React.ReactNode;
children?: React.ReactNode;
fetchJobs: () => Promise<void>;
fetchTotalCount: () => Promise<void>;
maxHeight?: number;
}

Expand All @@ -119,6 +157,8 @@ const JobsBase: React.FC<JobsBaseProps> = ({
customHeaders,
customRowCells,
children,
fetchJobs,
fetchTotalCount,
maxHeight = 624,
}) => {
const theme = useTheme();
Expand All @@ -127,6 +167,11 @@ const JobsBase: React.FC<JobsBaseProps> = ({
const customColumnCount = customHeaders ? 1 : 0;
const totalColumnCount = baseColumnCount + customColumnCount;

useEffect(() => {
fetchTotalCount();
fetchJobs();
}, [fetchTotalCount, fetchJobs]);

const DATA_VIEWER_URL = process.env.REACT_APP_FIA_DATA_VIEWER_URL;

const openValueEditor = (jobId: number): void => {
Expand Down
109 changes: 27 additions & 82 deletions src/Jobs/JobsGeneral.tsx
Original file line number Diff line number Diff line change
@@ -1,113 +1,58 @@
// React components
import React, { useCallback, useEffect, useState } from 'react';
import React, { useState } from 'react';
import { Link, useHistory, useParams } from 'react-router-dom';

// Material UI components
import { SelectChangeEvent, Typography } from '@mui/material';
import { Typography } from '@mui/material';
import { ArrowBack } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';

// Local data
import JobsBase, { Job } from './JobsBase';
import { instruments } from '../InstrumentData';
import JobsBase, { useFetchJobs, useFetchTotalCount, Job } from './JobsBase';

const JobsGeneral: React.FC = () => {
const fiaApiUrl = process.env.REACT_APP_FIA_REST_API_URL;
const { instrumentName } = useParams<{ instrumentName: string }>();
const history = useHistory();
const theme = useTheme();

const [job, setJobs] = useState<Job[]>([]);
const [jobs, setJobs] = useState<Job[]>([]);
const [totalRows, setTotalRows] = useState(0);
const [selectedInstrument, setSelectedInstrument] = useState<string>(instrumentName || instruments[0].name);
const [selectedInstrument, setSelectedInstrument] = useState(instrumentName);
const [currentPage, setCurrentPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [orderDirection, setOrderDirection] = useState<'asc' | 'desc'>('desc');
const [orderBy, setOrderBy] = useState<string>('run_start');

useEffect(() => {
if (instrumentName && instruments.some((i) => i.name === instrumentName)) {
setSelectedInstrument(instrumentName);
} else {
setSelectedInstrument(instruments[0].name);
history.replace(`/reduction-history/${instruments[0].name}`);
}
}, [instrumentName, history]);

const fetchTotalCount = useCallback(async (): Promise<void> => {
try {
const response = await fetch(`${fiaApiUrl}/instrument/${selectedInstrument}/jobs/count`);
const data = await response.json();
setTotalRows(data.count);
} catch (error) {
console.error('Error fetching run count:', error);
}
}, [selectedInstrument, fiaApiUrl]);

const fetchReductions = useCallback(async (): Promise<void> => {
try {
const isDev = process.env.REACT_APP_DEV_MODE === 'true';
const token = isDev ? null : localStorage.getItem('scigateway:token');
const offset = currentPage * rowsPerPage;
const query = `limit=${rowsPerPage}&offset=${offset}&order_by=${orderBy}&order_direction=${orderDirection}&include_run=true`;
const headers: { [key: string]: string } = { 'Content-Type': 'application/json' };
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(`${fiaApiUrl}/instrument/${selectedInstrument}/jobs?${query}`, {
method: 'GET',
headers,
});
const data = await response.json();
setJobs(data);
} catch (error) {
console.error('Error fetching reductions:', error);
}
}, [selectedInstrument, currentPage, rowsPerPage, orderBy, orderDirection, fiaApiUrl]);

useEffect(() => {
fetchTotalCount();
fetchReductions();
}, [fetchTotalCount, fetchReductions]);

const handleInstrumentChange = (event: SelectChangeEvent<string>): void => {
const newInstrument = event.target.value;
setSelectedInstrument(newInstrument);
setCurrentPage(0);
history.push(`/reduction-history/${newInstrument}`);
fetchTotalCount();
fetchReductions();
};

const handleSort = (property: string): void => {
const isAsc = orderBy === property && orderDirection === 'asc';
setOrderDirection(isAsc ? 'desc' : 'asc');
setOrderBy(property);
setCurrentPage(0);
};

const handleChangePage = (event: unknown, newPage: number): void => {
setCurrentPage(newPage);
};

const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>): void => {
setRowsPerPage(parseInt(event.target.value, 10));
setCurrentPage(0);
};
const offset = currentPage * rowsPerPage;
const query = `limit=${rowsPerPage}&offset=${offset}&order_by=${orderBy}&order_direction=${orderDirection}&include_run=true`;
const token = localStorage.getItem('scigateway:token');
const fetchJobs = useFetchJobs(`${fiaApiUrl}/instrument/${selectedInstrument}/jobs`, query, setJobs, token);
const fetchTotalCount = useFetchTotalCount(`${fiaApiUrl}/instrument/${selectedInstrument}/jobs/count`, setTotalRows);

return (
<JobsBase
selectedInstrument={selectedInstrument}
handleInstrumentChange={handleInstrumentChange}
jobs={job}
handleInstrumentChange={(event) => {
const newInstrument = event.target.value;
setSelectedInstrument(newInstrument);
setCurrentPage(0);
history.push(`/reduction-history/${newInstrument}`);
}}
jobs={jobs}
totalRows={totalRows}
currentPage={currentPage}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
handleSort={handleSort}
handleChangePage={(_, newPage) => setCurrentPage(newPage)}
handleChangeRowsPerPage={(e) => setRowsPerPage(parseInt(e.target.value, 10))}
handleSort={(property) => {
const isAsc = orderBy === property && orderDirection === 'asc';
setOrderDirection(isAsc ? 'desc' : 'asc');
setOrderBy(property);
setCurrentPage(0);
}}
orderBy={orderBy}
orderDirection={orderDirection}
fetchJobs={fetchJobs}
fetchTotalCount={fetchTotalCount}
>
<Typography
variant="body1"
Expand Down

0 comments on commit 30f3568

Please sign in to comment.