Skip to content

Commit

Permalink
feat: add routing
Browse files Browse the repository at this point in the history
  • Loading branch information
AKharytonchyk committed Apr 15, 2024
1 parent 7068471 commit d2af933
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 56 deletions.
40 changes: 40 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"@types/node": "^16.18.91",
"@types/react": "^18.2.71",
"@types/react-dom": "^18.2.22",
"lz-string": "^1.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
Expand Down
90 changes: 41 additions & 49 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import React from "react";
import "./App.css";
import { GitService } from "./service/gitService";
import { AppBar, Box, ScopedCssBaseline, Toolbar } from "@mui/material";
import { AppBar, Box, Toolbar } from "@mui/material";
import { SettingsDrawer } from "./SettingsDrawer";
import { Dashboard } from "./components/Dashboard";
import { AuthHeader } from "./components/AuthHeader";
import { UnAuthHeader } from "./components/UnAuthHeader";
import LandingPage from "./pages/LandingPage";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();
import { Outlet } from "react-router-dom";

export const ConfigContext = React.createContext<{
octokit: GitService | null;
repositorySettings: Record<string, boolean>;
handleRepositorySelect: (repository: string, selected: boolean) => void;
}>({ octokit: null, repositorySettings: {}, handleRepositorySelect: () => {} });


function App() {
const [user, setUser] = React.useState<{
login: string;
Expand Down Expand Up @@ -93,51 +90,46 @@ function App() {

return (
<>
<QueryClientProvider client={queryClient}>
<ScopedCssBaseline>
<ConfigContext.Provider
value={{ octokit, repositorySettings, handleRepositorySelect }}
>
<AppBar
position="static"
color="default"
sx={{ position: "fixed", zIndex: 100 }}
>
<Toolbar sx={{ justifyContent: "flex-end" }}>
{!user?.login ? (
<UnAuthHeader setToken={setToken} onLogin={onLogin} />
) : (
<AuthHeader
user={user}
logOut={logOut}
setOpenSettings={setOpenSettings}
/>
)}
</Toolbar>
</AppBar>
<Box
component={"main"}
sx={{
display: "flex",
flexDirection: "column",
gap: 2,
justifyContent: "center",
alignItems: "center",
paddingTop: "4em",
}}
>
{octokit && <Dashboard />}
{!octokit && <LandingPage />}
</Box>
{octokit && (
<SettingsDrawer
opened={openSettings}
onClose={() => setOpenSettings(false)}
<ConfigContext.Provider
value={{ octokit, repositorySettings, handleRepositorySelect }}
>
<AppBar
position="static"
color="default"
sx={{ position: "fixed", zIndex: 100 }}
>
<Toolbar sx={{ justifyContent: "flex-end" }}>
{!user?.login ? (
<UnAuthHeader setToken={setToken} onLogin={onLogin} />
) : (
<AuthHeader
user={user}
logOut={logOut}
setOpenSettings={setOpenSettings}
/>
)}
</ConfigContext.Provider>
</ScopedCssBaseline>
</QueryClientProvider>
</Toolbar>
</AppBar>
<Box
component={"main"}
sx={{
display: "flex",
flexDirection: "column",
gap: 2,
justifyContent: "center",
alignItems: "center",
paddingTop: "4em",
}}
>
<Outlet />
</Box>
{octokit && (
<SettingsDrawer
opened={openSettings}
onClose={() => setOpenSettings(false)}
/>
)}
</ConfigContext.Provider>
</>
);
}
Expand Down
5 changes: 5 additions & 0 deletions src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MultiselectFilter } from "./MultiselectFilter";
import { InputFilter } from "./InputFilter";
import { useQuery } from "@tanstack/react-query";
import { PRLoadingPage } from "../pages/PRLoadingPage";
import { Navigate } from "react-router-dom";

export type DashboardProps = {};

Expand Down Expand Up @@ -80,6 +81,10 @@ export const Dashboard: React.FC<DashboardProps> = () => {
});
}, [data, filter, includeLabels, excludeLabels]);

if (!localStorage.getItem("token")){
return <Navigate to="/login" />;
}

return (
<Box padding={2} width={"calc(100vw - 2em)"}>
{isLoading && <PRLoadingPage />}
Expand Down
41 changes: 41 additions & 0 deletions src/components/MissingCoverageErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from "react";
import { Alert, Box } from "@mui/material";

const ErrorMessage: React.FC<{ showError: boolean }> = ({ showError }) => {
if (!showError) return null;

return (
<Box sx={{ margin: 2 }}>
<Alert severity="error">
<strong>No coverage data found!</strong>
<br />
Please ensure that you have generated a <code>coverage.json</code> file
using Jest with the <code>json-summary</code> reporter. The expected
JSON structure should resemble the following:
<pre>
{JSON.stringify(
{
"your-repository-name": {
lines: { total: 100, covered: 50, skipped: 0, pct: 50 },
statements: { total: 200, covered: 100, skipped: 0, pct: 50 },
functions: { total: 20, covered: 10, skipped: 0, pct: 50 },
branches: { total: 30, covered: 15, skipped: 0, pct: 50 },
},
// Additional repositories can follow the same structure
},
null,
2
)}
</pre>
To generate this file, add the following configuration to your Jest
setup:
<pre>{`"jest": {
"collectCoverage": true,
"coverageReporters": ["json-summary"]
}`}</pre>
</Alert>
</Box>
);
};

export default ErrorMessage;
56 changes: 56 additions & 0 deletions src/hooks/useFilterParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from "react";
import {
compressToEncodedURIComponent,
decompressFromEncodedURIComponent,
} from "lz-string";
import { useSearchParams } from "react-router-dom";

export const useFilterParams = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [filter, setFilter] = React.useState<string>("");
const [includeLabels, setIncludeLabels] = React.useState<string[]>([]);
const [excludeLabels, setExcludeLabels] = React.useState<string[]>([]);

React.useEffect(() => {
const incParam = searchParams.get("inc") ?? "";
const excParam = searchParams.get("exc") ?? "";
const filterParam = searchParams.get("filter") ?? "";

if (incParam) {
setIncludeLabels(decompressFromEncodedURIComponent(incParam).split(","));
}
if (excParam) {
setExcludeLabels(decompressFromEncodedURIComponent(excParam).split(","));
}
if (filterParam) {
setFilter(decompressFromEncodedURIComponent(filterParam));
}
}, [searchParams]);

const updateSearchParams = React.useCallback(
(value: string | string[], type: "inc" | "exc" | "filter") => {
const newSearchParams = new URLSearchParams(searchParams);

if (Array.isArray(value) && value.length === 0) {
newSearchParams.delete(type);
} else if (value) {
const compressedValue = Array.isArray(value)
? compressToEncodedURIComponent(value.join(","))
: compressToEncodedURIComponent(value);
newSearchParams.set(type, compressedValue);
}

setSearchParams(newSearchParams);
},
[searchParams, setSearchParams]
);

return {
filter,
setFilter: (value: string) => updateSearchParams(value, "filter"),
includeLabels,
setIncludeLabels: (labels: string[]) => updateSearchParams(labels, "inc"),
excludeLabels,
setExcludeLabels: (labels: string[]) => updateSearchParams(labels, "exc"),
};
};
45 changes: 38 additions & 7 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ScopedCssBaseline } from "@mui/material";
import LandingPage from "./pages/LandingPage";
import { Coverage } from "./pages/Coverage";
import { Dashboard } from "./components/Dashboard";

const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "/",
element: <Dashboard />,
},
{
path: "/login",
element: <LandingPage />,
}, {
path: "/coverage",
element: <Coverage />,
}
],
},
]);
const queryClient = new QueryClient();

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
<QueryClientProvider client={queryClient}>
<ScopedCssBaseline>
<RouterProvider router={router} />
</ScopedCssBaseline>
</QueryClientProvider>
</React.StrictMode>
);

Expand Down
Loading

0 comments on commit d2af933

Please sign in to comment.