Skip to content

Commit

Permalink
refactor(ui): Change to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
pando85 committed Jan 21, 2024
1 parent d2c9703 commit b97db66
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 51 deletions.
6 changes: 6 additions & 0 deletions server/web/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions server/web/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,11 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/node": "^20.11.5",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"typescript": "^5.3.3"
}
}
File renamed without changes.
39 changes: 17 additions & 22 deletions server/web/ui/src/App.js → server/web/ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
// App.js
// App.tsx

import React, { useState } from 'react';
import { BrowserRouter as Router, Route, Routes, Navigate, Link } from 'react-router-dom';
import { Visibility, VisibilityOff } from '@mui/icons-material';
import JobTable from './JobTable';
import './App.css';

const App: React.FC = () => {
const [token, setToken] = useState<string>('');
const [showToken, setShowToken] = useState<boolean>(false);
const [showJobTable, setShowJobTable] = useState<boolean>(false);

const App = () => {
const [token, setToken] = useState('');
const [showToken, setShowToken] = useState(false);
const [showJobTable, setShowJobTable] = useState(false);

const handleTokenInput = (event) => {
const handleTokenInput = (event: React.ChangeEvent<HTMLInputElement>) => {
setToken(event.target.value);
};


const handleTokenSubmit = (event) => {
const handleTokenSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (token) {
setShowJobTable(true);
Expand All @@ -28,11 +26,9 @@ const App = () => {
setShowToken((prevShowToken) => !prevShowToken);
};

const Jobs = () => (
const Jobs: React.FC = () => (
<div className="contentContainer">
{showJobTable && (
<JobTable token={token} setShowJobTable={setShowJobTable}/>
)}
{showJobTable && <JobTable token={token} setShowJobTable={setShowJobTable} />}
</div>
);

Expand All @@ -50,9 +46,11 @@ const App = () => {
</Link>
</div>
</div>
<div className='navBar'>
<div className="navBar">
<nav className="navItems">
<Link to="/jobs" className="navItem">Jobs</Link>
<Link to="/jobs" className="navItem">
Jobs
</Link>
</nav>
</div>
</header>
Expand All @@ -64,17 +62,14 @@ const App = () => {
<p>Please enter your token:</p>
<div className="passwordInputContainer">
<input
className='passwordInput'
className="passwordInput"
type={showToken ? 'text' : 'password'}
value={token}
onChange={handleTokenInput}
/>
<div className='passwordInputSuffix'>
<div className="passwordInputSuffix">
{showToken ? (
<VisibilityOff
className="eyeIcon"
onClick={handleToggleShowToken}
/>
<VisibilityOff className="eyeIcon" onClick={handleToggleShowToken} />
) : (
<Visibility className="eyeIcon" onClick={handleToggleShowToken} />
)}
Expand All @@ -85,7 +80,7 @@ const App = () => {
</div>
)}
<Routes>
<Route path="/" component={() => <Navigate to="/jobs" replace />} />
<Route path="/" element={<Navigate to="/jobs" replace />} />
<Route path="/jobs" element={<Jobs />} />
</Routes>
</div>
Expand Down
70 changes: 43 additions & 27 deletions server/web/ui/src/JobTable.js → server/web/ui/src/JobTable.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
// JobTable.js
// JobTable.tsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Table, TableBody, TableCell, TableHead, TableRow, CircularProgress, Typography, Button } from '@mui/material';
import { Info, QuestionMark, Task, VideoSettings } from '@mui/icons-material';

import './JobTable.css';

const JobTable = ({ token, setShowJobTable }) => {
const [jobs, setJobs] = useState([]);
const [selectedJob, setSelectedJob] = useState(null);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const [fetchedDetails, setFetchedDetails] = useState(new Set());
interface Job {
id: string;
sourcePath: string;
destinationPath: string;
status: string;
status_message: string;
}

interface JobTableProps {
token: string;
setShowJobTable: React.Dispatch<React.SetStateAction<boolean>>;
}

const JobTable: React.FC<JobTableProps> = ({ token, setShowJobTable }) => {
const [jobs, setJobs] = useState<Job[]>([]);
const [selectedJob, setSelectedJob] = useState<Job | null>(null);
const [page, setPage] = useState<number>(1);
const [loading, setLoading] = useState<boolean>(false);
const [fetchedDetails, setFetchedDetails] = useState<Set<string>>(new Set());

useEffect(() => {
const fetchJobs = async () => {
Expand All @@ -35,10 +48,7 @@ const JobTable = ({ token, setShowJobTable }) => {

useEffect(() => {
const handleScroll = () => {
if (
window.innerHeight + window.scrollY >=
document.body.offsetHeight - 100
) {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
setPage((prevPage) => prevPage + 1);
}
};
Expand All @@ -51,40 +61,46 @@ const JobTable = ({ token, setShowJobTable }) => {
}, []);

useEffect(() => {
const fetchJobDetails = async (jobId) => {
const fetchJobDetails = async (jobId: string) => {
if (!fetchedDetails.has(jobId)) {
try {
const response = await axios.get(`/api/v1/job/`, {
params: { token, uuid: jobId },
});
const enrichedJob = {
...jobs.find((job) => job.id === jobId),
sourcePath: response.data.sourcePath,
destinationPath: response.data.destinationPath,
status: response.data.status,
status_message: response.data.status_message,
};
setJobs((prevJobs) =>
prevJobs.map((job) =>
job.id === jobId ? enrichedJob : job
)
);

const foundJob = jobs.find((job) => job.id === jobId);

if (foundJob) {
const enrichedJob: Job = {
...foundJob,
sourcePath: response.data.sourcePath,
destinationPath: response.data.destinationPath,
status: response.data.status,
status_message: response.data.status_message,
};

setJobs((prevJobs) =>
prevJobs.map((job) => (job.id === jobId ? enrichedJob : job))
);
}

setFetchedDetails((prevSet) => new Set(prevSet.add(jobId)));
} catch (error) {
console.error(`Error fetching details for job ${jobId}:`, error);
}
}
};


// Fetch details for each job when they are rendered in the table
jobs.forEach((job) => fetchJobDetails(job.id));
}, [token, jobs, fetchedDetails]);

const handleRowClick = (jobId) => {
setSelectedJob(jobs.find((job) => job.id === jobId));
const handleRowClick = (jobId: string) => {
setSelectedJob(jobs.find((job) => job.id === jobId) || null);
};

const getStatusColor = (status) => {
const getStatusColor = (status: string): string => {
switch (status) {
case 'completed':
return 'green';
Expand Down
3 changes: 2 additions & 1 deletion server/web/ui/src/index.js → server/web/ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
const root: ReactDOM.Root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<App />
Expand All @@ -15,3 +15,4 @@ root.render(
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const reportWebVitals = onPerfEntry => {
import { ReportHandler } from 'web-vitals';

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
Expand Down
File renamed without changes.
28 changes: 28 additions & 0 deletions server/web/ui/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"noFallthroughCasesInSwitch": true
},
"include": [
"src",
"test",
"react-app-env.d.ts"
]
}

0 comments on commit b97db66

Please sign in to comment.