Skip to content

Commit

Permalink
chore(frontend): first part of migration to typescript (#307)
Browse files Browse the repository at this point in the history
  • Loading branch information
shini4i authored Jun 1, 2024
1 parent 6119c19 commit 71044ba
Show file tree
Hide file tree
Showing 29 changed files with 1,313 additions and 1,093 deletions.
488 changes: 199 additions & 289 deletions web/package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"format": "prettier --write \"src/**/*.js\""
"format": "prettier --write \"src/**/*.{js,ts,tsx}\""
},
"eslintConfig": {
"extends": [
Expand All @@ -54,5 +54,12 @@
"last 1 safari version"
]
},
"proxy": "http://localhost:8080"
"proxy": "http://localhost:8080",
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/react": "^18.3.3",
"@types/react-datepicker": "^6.2.0",
"@types/react-dom": "^18.3.0",
"jest": "^29.7.0"
}
}
66 changes: 0 additions & 66 deletions web/src/App.js

This file was deleted.

74 changes: 74 additions & 0 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Box, CircularProgress, createTheme, lighten, ThemeOptions, ThemeProvider } from '@mui/material';

import RecentTasks from './Components/RecentTasks';
import HistoryTasks from './Components/HistoryTasks';
import Layout from './Layout';
import Page404 from './Page404';
import { ErrorProvider } from './ErrorContext';
import TaskView from './Components/TaskView';
import { AuthContext, useAuth } from './Services/Auth';
import { DeployLockProvider } from './Services/DeployLockHandler';

const theme = createTheme({
palette: {
primary: {
main: '#2E3B55',
},
neutral: {
main: 'gray',
},
reason_color: {
main: lighten('#ff9800', 0.5),
},
},
components: {
MuiTableCell: {
styleOverrides: {
root: {
padding: '12px',
},
},
},
},
} as ThemeOptions);

const App: React.FC = () => {
const auth = useAuth();

if (auth.authenticated === null) {
return (
<Box display="flex" justifyContent="center" alignItems="center" height="100vh">
<CircularProgress />
</Box>
);
}

if (auth.authenticated) {
return (
<AuthContext.Provider value={auth}>
<ThemeProvider theme={theme}>
<ErrorProvider>
<DeployLockProvider>
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<RecentTasks />} />
<Route path="/history" element={<HistoryTasks />} />
<Route path="/task/:id" element={<TaskView />} />
</Route>
<Route path="*" element={<Page404 />} />
</Routes>
</BrowserRouter>
</DeployLockProvider>
</ErrorProvider>
</ThemeProvider>
</AuthContext.Provider>
);
}

return null;
};

export default App;
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';

function ApplicationsFilter({ value, onChange, appNames }) {
const [applications, setApplications] = useState([]);
interface ApplicationsFilterProps {
value: string | null;
onChange: (newValue: string | null) => void;
appNames: string[];
}

const ApplicationsFilter: React.FC<ApplicationsFilterProps> = ({ value, onChange, appNames }) => {
const [applications, setApplications] = useState<string[]>([]);

useEffect(() => {
setApplications(appNames);
}, [appNames]);

const handleApplicationsChange = (_event, newValue) => {
onChange?.(newValue);
const handleApplicationsChange = (_event: React.ChangeEvent<{}>, newValue: string | null) => {
if (onChange) {
onChange(newValue);
}
};

return (
<Autocomplete
size={'small'}
size="small"
disablePortal
options={applications}
sx={{ width: 220 }}
Expand All @@ -25,12 +32,6 @@ function ApplicationsFilter({ value, onChange, appNames }) {
onChange={handleApplicationsChange}
/>
);
}

ApplicationsFilter.propTypes = {
value: PropTypes.any,
onChange: PropTypes.func,
appNames: PropTypes.array.isRequired
};

export default ApplicationsFilter;
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { forwardRef, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useSearchParams } from 'react-router-dom';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
Expand All @@ -16,45 +15,48 @@ import ApplicationsFilter from './ApplicationsFilter';
import TasksTable, { useTasks } from './TasksTable';
import { useErrorContext } from '../ErrorContext';

const DateRangePickerCustomInput = forwardRef(({ value, onClick }, ref) => (
<TextField
size="small"
sx={{ minWidth: '220px' }}
onClick={onClick}
ref={ref}
value={value}
label="Date range"
/>
));
interface DateRangePickerCustomInputProps {
value: string;
onClick: () => void;
}

DateRangePickerCustomInput.propTypes = {
value: PropTypes.string,
onClick: PropTypes.func.isRequired,
};
const DateRangePickerCustomInput = forwardRef<HTMLInputElement, DateRangePickerCustomInputProps>(
({ value, onClick }, ref) => (
<TextField
size="small"
sx={{ minWidth: '220px' }}
onClick={onClick}
ref={ref}
value={value}
label="Date range"
InputProps={{ readOnly: true }}
/>
)
);

DateRangePickerCustomInput.displayName = 'DateRangePickerCustomInput';

function HistoryTasks() {
interface HistoryTasksProps {}

const HistoryTasks: React.FC<HistoryTasksProps> = () => {
const [searchParams, setSearchParams] = useSearchParams();
const { setError, setSuccess } = useErrorContext();
const { tasks, sortField, setSortField, appNames, refreshTasksInRange, clearTasks } =
useTasks({ setError, setSuccess });
const [currentApplication, setCurrentApplication] = useState(
searchParams.get('app') ?? null,
const [currentApplication, setCurrentApplication] = useState<string | null>(
searchParams.get('app')
);
const [dateRange, setDateRange] = useState([
Number(searchParams.get('start'))
? new Date(Number(searchParams.get('start')) * 1000)
: startOfDay(new Date()),
Number(searchParams.get('end'))
? new Date(Number(searchParams.get('end')) * 1000)
: startOfDay(new Date()),
const [dateRange, setDateRange] = useState<[Date | null, Date | null]>([
searchParams.get('start') ? new Date(Number(searchParams.get('start')) * 1000) : startOfDay(new Date()),
searchParams.get('end') ? new Date(Number(searchParams.get('end')) * 1000) : startOfDay(new Date()),
]);
const [startDate, endDate] = dateRange;
const [currentPage, setCurrentPage] = useState(
searchParams.get('page') ? Number(searchParams.get('page')) : 1,
const [currentPage, setCurrentPage] = useState<number>(
searchParams.get('page') ? Number(searchParams.get('page')) : 1
);

const updateSearchParameters = (start, end, application, page) => {
const params = {
const updateSearchParameters = (start: Date, end: Date, application: string | null, page: number) => {
const params: Record<string, any> = {
start: Math.floor(start.getTime() / 1000),
end: Math.floor(end.getTime() / 1000),
};
Expand All @@ -70,12 +72,12 @@ function HistoryTasks() {
setSearchParams(params);
};

const refreshWithFilters = (start, end, application, page) => {
const refreshWithFilters = (start: Date | null, end: Date | null, application: string | null, page: number) => {
if (start && end) {
refreshTasksInRange(
Math.floor(startOfDay(start).getTime() / 1000),
Math.floor(endOfDay(end).getTime() / 1000),
application,
application
);
updateSearchParameters(start, end, application, page);
} else {
Expand All @@ -84,7 +86,7 @@ function HistoryTasks() {
};

useEffect(() => {
refreshWithFilters(startDate, endDate, currentApplication, currentPage);
refreshWithFilters(startDate!, endDate!, currentApplication, currentPage);
}, [startDate, endDate, currentApplication, currentPage]);

return (
Expand Down Expand Up @@ -117,26 +119,29 @@ function HistoryTasks() {
onChange={value => {
setCurrentApplication(value);
setCurrentPage(1);
refreshWithFilters(startDate, endDate, value, 1);
refreshWithFilters(startDate!, endDate!, value, 1);
}}
setError={setError}
setSuccess={setSuccess}
appNames={appNames}
/>
</Box>
<Box>
<DatePicker
selectsRange={true}
selectsRange
startDate={startDate}
endDate={endDate}
onChange={update => {
onChange={(update: [Date | null, Date | null]) => {
setDateRange(update);
setCurrentPage(1);
refreshWithFilters(update[0], update[1], currentApplication, 1);
}}
maxDate={new Date()}
isClearable={false}
customInput={<DateRangePickerCustomInput />}
customInput={
<DateRangePickerCustomInput
value={`${startDate ? startDate.toLocaleDateString() : ''} - ${endDate ? endDate.toLocaleDateString() : ''}`}
onClick={() => {}}
/>
}
required
/>
</Box>
Expand All @@ -147,7 +152,7 @@ function HistoryTasks() {
title="Reload table"
onClick={() => {
setCurrentPage(1);
refreshWithFilters(startDate, endDate, currentApplication, 1);
refreshWithFilters(startDate!, endDate!, currentApplication, 1);
}}
>
<RefreshIcon />
Expand All @@ -165,16 +170,16 @@ function HistoryTasks() {
onPageChange={page => {
setCurrentPage(page);
updateSearchParameters(
startDate,
endDate,
startDate!,
endDate!,
currentApplication,
page,
page
);
}}
/>
</Box>
</Container>
);
}
};

export default HistoryTasks;
Loading

0 comments on commit 71044ba

Please sign in to comment.