Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup Routing #334

Merged
merged 24 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
23579a6
Fix lockfile
Cyberboss Oct 14, 2024
2cb5072
Bump @typescript-eslint/eslint-plugin from 8.8.1 to 8.9.0
dependabot[bot] Oct 15, 2024
8bca1ef
Merge pull request #316 from tgstation/dependabot/npm_and_yarn/typesc…
tgstation-server-ci[bot] Oct 15, 2024
c7d6758
Bump @typescript-eslint/parser from 8.8.1 to 8.9.0
dependabot[bot] Oct 15, 2024
bf468b1
Merge pull request #317 from tgstation/dependabot/npm_and_yarn/typesc…
tgstation-server-ci[bot] Oct 15, 2024
89d25f1
6.4.1
Cyberboss Oct 15, 2024
f1bab5f
Bump @types/node from 22.7.5 to 22.7.6
dependabot[bot] Oct 17, 2024
d0350f5
Bump sass from 1.79.5 to 1.80.1
dependabot[bot] Oct 17, 2024
94f532c
Merge pull request #323 from tgstation/dependabot/npm_and_yarn/types/…
tgstation-server-ci[bot] Oct 17, 2024
a77a3a7
Merge pull request #324 from tgstation/dependabot/npm_and_yarn/sass-1…
tgstation-server-ci[bot] Oct 17, 2024
cfeb6f6
Fix jobs widget not closing on mobile
Cyberboss Oct 18, 2024
2e2e8a4
6.4.2
Cyberboss Oct 18, 2024
798e9ae
Merge branch 'next' into graphql
Cyberboss Oct 19, 2024
75d8618
NotFound component
Cyberboss Oct 19, 2024
08680da
Cleanup configuration viewer items
Cyberboss Oct 19, 2024
54a390c
Setup basic bitch routing
Cyberboss Oct 19, 2024
36e6788
Cleanup context usage
Cyberboss Oct 19, 2024
d148598
Setup protected routing
Cyberboss Oct 19, 2024
535544f
Setup proper protected routes
Cyberboss Oct 19, 2024
412f191
Fix storybook issues
Cyberboss Oct 19, 2024
c947e20
Login mutation stories
Cyberboss Oct 19, 2024
baac7d2
Fix linter issues
Cyberboss Oct 19, 2024
1cc29a8
Ignore this code block in chromatic
Cyberboss Oct 19, 2024
1339477
Strip data-chromatic attributes
Cyberboss Oct 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .storybook/MockRelayEnvironment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export type WithRelayParameters<TQuery extends OperationType, TResolvers = objec
*/
};

export let MockRelayEnvironment = createMockEnvironment();

const AddMockRelayEnvironment = makeDecorator({
name: "AddMockRelayEnvironment",
parameterName: "relay",
Expand All @@ -75,15 +77,15 @@ const AddMockRelayEnvironment = makeDecorator({
return getStory(context) as any;
};

const environment = createMockEnvironment();
MockRelayEnvironment = createMockEnvironment();

const resolver: OperationMockResolver = operation =>
MockPayloadGenerator.generate(operation, mockResolvers);
environment.mock.queueOperationResolver(resolver);
environment.mock.queuePendingOperation(query, variables);
MockRelayEnvironment.mock.queueOperationResolver(resolver);
MockRelayEnvironment.mock.queuePendingOperation(query, variables);

return (
<RelayEnvironmentProvider environment={environment}>
<RelayEnvironmentProvider environment={MockRelayEnvironment}>
<Renderer />
</RelayEnvironmentProvider>
);
Expand Down
3 changes: 2 additions & 1 deletion .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Preview } from "@storybook/react";
import { withRouter } from "storybook-addon-remix-react-router";

import AddConfigDark from "./AddConfigDark";
import AddIntlEn from "./AddIntlEn";
Expand All @@ -15,7 +16,7 @@ const preview: Preview = {
}
}
},
decorators: [AddIntlEn, AddConfigDark, AddMockRelayEnvironment]
decorators: [AddIntlEn, AddConfigDark, AddMockRelayEnvironment, withRouter]
};

export default preview;
20 changes: 14 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"react-hook-form": "^7.53.0",
"react-intl": "^6.8.0",
"react-relay": "^18.1.0",
"react-router-dom": "^6.27.0",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
"uuid": "^10.0.0",
Expand All @@ -70,13 +71,19 @@
"@chromatic-com/storybook": "2.0.2",
"@eslint/js": "^9.12.0",
"@rollup/pluginutils": "^5.1.2",
"@storybook/addon-essentials": "^8.3.5",
"@storybook/addon-interactions": "^8.3.5",
"@storybook/addon-essentials": "^8.3.6",
"@storybook/addon-interactions": "^8.3.6",
"@storybook/addon-links": "^8.3.5",
"@storybook/blocks": "^8.3.5",
"@storybook/react": "^8.3.5",
"@storybook/react-vite": "^8.3.5",
"@storybook/test": "^8.3.5",
"@storybook/channels": "^8.3.6",
"@storybook/components": "^8.3.6",
"@storybook/core-events": "^8.3.6",
"@storybook/manager-api": "^8.3.6",
"@storybook/preview-api": "^8.3.6",
"@storybook/react": "^8.3.6",
"@storybook/react-vite": "^8.3.6",
"@storybook/test": "^8.3.6",
"@storybook/theming": "^8.3.6",
"@types/node": "^22.7.6",
"@types/react": "^18",
"@types/react-dom": "^18.3.1",
Expand All @@ -99,7 +106,8 @@
"relay-compiler": "^18.1.0",
"relay-test-utils": "^18.1.0",
"rollup-plugin-jsx-remove-attributes": "^2.0.3",
"storybook": "^8.3.5",
"storybook": "^8.3.6",
"storybook-addon-remix-react-router": "^3.0.1",
"tailwindcss": "^3.4.14",
"type-fest": "^4.26.1",
"typescript": "^5.6.3",
Expand Down
13 changes: 8 additions & 5 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import Locales from "../lib/translations/Locales";
import Loading from "./utils/Loading/Loading";
import icolibrary from "./utils/icolibrary";

const RelayEnvironment = lazy(async () => {
await devDelay();
return await import("@/components/core/RelayEnvironment/RelayEnvironment");
});
const Environment = lazy(
async () =>
await devDelay(
() => import("@/components/core/Environment/Environment"),
"Component Load: Environment"
)
);

interface IProps {
preferredLocales: readonly string[];
Expand Down Expand Up @@ -83,7 +86,7 @@ const App = (props: IProps) => {
</div>
</div>
}>
<RelayEnvironment />
<Environment />
</Suspense>
</IntlProvider>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { useContext, useEffect, useMemo } from "react";
import { useEffect, useMemo } from "react";
import { useIntl } from "react-intl";
import { RelayEnvironmentProvider } from "react-relay";

import Layout from "../Layout/Layout";

import Pkg from "@/../package.json";
import ConfigContext from "@/context/config/Context";
import useConfig from "@/context/config/useConfig";
import ErrorsProvider from "@/context/errors/Provider";
import SessionProvider from "@/context/session/Provider";
import CreateRelayEnvironment from "@/lib/CreateRelayEnvironment";

Check failure on line 9 in src/components/core/Environment/Environment.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

There should be at least one empty line between import groups
import Router from "../Router/Router";

Check failure on line 10 in src/components/core/Environment/Environment.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`../Router/Router` import should occur before import of `@/../package.json`

const RelayEnvironment = () => {
const Environment = () => {
const version = Pkg.version;

const intl = useIntl();
Expand All @@ -19,7 +18,7 @@
document.title = intl.formatMessage({ id: "title" }, { version });
});

const config = useContext(ConfigContext);
const config = useConfig();

const { relayEnviroment, setCredentials } = useMemo(
() => CreateRelayEnvironment(config.ApiPath.value),
Expand All @@ -30,7 +29,7 @@
<RelayEnvironmentProvider environment={relayEnviroment}>
<SessionProvider setCredentials={credentials => setCredentials(credentials, false)}>
<ErrorsProvider>
<Layout
<Router
setTemporaryCredentials={credentials => setCredentials(credentials, true)}
/>
</ErrorsProvider>
Expand All @@ -39,4 +38,4 @@
);
};

export default RelayEnvironment;
export default Environment;
6 changes: 3 additions & 3 deletions src/components/core/ErrorViewer/ErrorViewer.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, waitFor, within } from "@storybook/test";
import { useContext, useEffect } from "react";
import { useEffect } from "react";

import ErrorViewer from "./ErrorViewer";

import { ErrorMessageSingleFragment$data } from "@/components/graphql/__generated__/ErrorMessageSingleFragment.graphql";
import ErrorsContext from "@/context/errors/Context";
import ErrorsProvider from "@/context/errors/Provider";
import useErrors from "@/context/errors/useErrors";
import sleep from "@/lib/sleep";

interface IArgs {
errors?: (ErrorMessageSingleFragment$data | Error)[];
}

const InnerTestComponent = (props: IArgs) => {
const context = useContext(ErrorsContext);
const context = useErrors();

useEffect(() => {
context.addErrors(props.errors ?? []);
Expand Down
6 changes: 2 additions & 4 deletions src/components/core/ErrorViewer/ErrorViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useContext } from "react";

import ErrorCard from "@/components/utils/ErrorCard/ErrorCard";
import ErrorsContext from "@/context/errors/Context";
import useErrors from "@/context/errors/useErrors";

const ErrorViewer = () => {
const context = useContext(ErrorsContext);
const context = useErrors();

return (
<>
Expand Down
27 changes: 13 additions & 14 deletions src/components/core/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import Loading from "@/components/utils/Loading/Loading";

Check failure on line 1 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

There should be at least one empty line between import groups
import ErrorViewer from "../ErrorViewer/ErrorViewer";

Check failure on line 2 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`../ErrorViewer/ErrorViewer` import should occur before import of `@/components/utils/Loading/Loading`
import Logo from "../Logo/Logo";

Check failure on line 3 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`../Logo/Logo` import should occur before import of `@/components/utils/Loading/Loading`
import Navbar from "../Navbar/Navbar";

Check failure on line 4 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`../Navbar/Navbar` import should occur before import of `@/components/utils/Loading/Loading`
import ReportIssue from "../ReportIssue/ReportIssue";

Check failure on line 5 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`../ReportIssue/ReportIssue` import should occur before import of `@/components/utils/Loading/Loading`
import Router from "../Router/Router";

import ErrorBoundary from "@/components/utils/ErrorBoundary/ErrorBoundary";

Check failure on line 7 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

There should be at least one empty line between import groups
import { ICredentials } from "@/lib/Credentials";
import { Suspense } from "react";

Check failure on line 8 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`react` import should occur before import of `@/components/utils/Loading/Loading`
import { Outlet } from "react-router-dom";

Check failure on line 9 in src/components/core/Layout/Layout.tsx

View workflow job for this annotation

GitHub Actions / Run Linter (20.x)

`react-router-dom` import should occur before import of `@/components/utils/Loading/Loading`

interface IProps {
setTemporaryCredentials: (credentials: ICredentials) => void;
}

const Layout = (props: IProps) => {
const Layout = () => {
return (
<ErrorBoundary>
<>
<Navbar />
<div className="mt-20">
<div className="grid grid-cols-8">
<div className="col-start-3 col-end-7">
<div className="mt-20 grid grid-cols-8">
<div className="lg:col-start-2 lg:col-end-8">
<ErrorBoundary>
<ErrorViewer />
</div>
<Suspense fallback={<Loading />}>
<Outlet />
</Suspense>
</ErrorBoundary>
</div>
<Router setTemporaryCredentials={props.setTemporaryCredentials} />
</div>
<ReportIssue />
<Logo />
</ErrorBoundary>
</>
);
};

Expand Down
24 changes: 10 additions & 14 deletions src/components/core/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,31 @@ import { useState } from "react";

import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { Link } from "react-router-dom";

const Navbar = () => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);

const navItems = [
{ name: "Home", href: "/" },
{ name: "About", href: "/about" },
{ name: "Services", href: "/services" },
{ name: "Contact", href: "/contact" }
];
const navItems = [{ name: "Configuration", href: "/config" }];

return (
<nav className="fixed top-0 left-0 right-0 z-50 bg-primary shadow-md">
<div className="container mx-1 px-4 sm:px-6 bg-primary shadow-md">
<div className="flex items-center justify-between h-16">
<div className="flex items-center">
<a href="/" className="text-xl font-bold text-white">
<Link to="/" className="text-xl font-bold text-white">
tgstation-server
</a>
</Link>
</div>
<div className="hidden md:block">
<div className="ml-10 flex items-baseline space-x-4">
{navItems.map(item => (
<a
<Link
key={item.name}
href={item.href}
to={item.href}
className="text-white hover:bg-primary hover:text-primary-foreground px-3 py-2 rounded-md text-sm font-medium transition-colors duration-200">
{item.name}
</a>
</Link>
))}
</div>
</div>
Expand All @@ -57,13 +53,13 @@ const Navbar = () => {
className="w-[240px] sm:w-[300px] bg-primary">
<nav className="flex flex-col space-y-4 mt-6">
{navItems.map(item => (
<a
<Link
key={item.name}
href={item.href}
to={item.href}
className="text-white hover:bg-primary hover:text-primary-foreground px-3 py-2 rounded-md text-base font-medium transition-colors duration-200"
onClick={() => setIsMobileMenuOpen(false)}>
{item.name}
</a>
</Link>
))}
</nav>
</SheetContent>
Expand Down
13 changes: 13 additions & 0 deletions src/components/core/NotFound/NotFound.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Meta, StoryObj } from "@storybook/react";

import NotFound from "./NotFound";
const config: Meta<typeof NotFound> = {
component: NotFound,
title: "Core/Not Found"
};

export default config;

type Story = StoryObj<typeof config>;

export const Default: Story = {};
27 changes: 27 additions & 0 deletions src/components/core/NotFound/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Pkg from "@/../package.json";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { FormattedMessage } from "react-intl";

const NotFound = () => (
<Card className="bg-transparent text-transparent-foreground mb-4">
<CardHeader>
<CardTitle>
<FormattedMessage id="error.somethingwentwrong" />
</CardTitle>
<CardDescription>
<FormattedMessage id="error.notfound" />
</CardDescription>
</CardHeader>
<CardContent>
<div className="bg-transparent text-danger">
<code className="block whitespace-pre-wrap">
{`Webpanel Version: ${Pkg.version}\nWebpanel Mode: ${
import.meta.env.VITE_DEV_MODE ? "DEV" : "PROD"
}\nCurrent route: ${window.location.toString()}`}
</code>
</div>
</CardContent>
</Card>
);

export default NotFound;
16 changes: 16 additions & 0 deletions src/components/core/Router/ProtectedRoute/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ILocationState from "@/components/routed/Login/LocationState";
import useSession from "@/context/session/useSession";
import { Navigate, Outlet, useLocation } from "react-router-dom";

const ProtectedRoute = () => {
const session = useSession();
const location = useLocation();
if (session.currentSession == null) {
const state: ILocationState = { from: location };
return <Navigate to="/login" state={state} />;
}

return <Outlet />;
};

export default ProtectedRoute;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useRouteError } from "react-router-dom";

const RethrowRouteError = () => {
const error = useRouteError();
throw error;
};

export default RethrowRouteError;
Loading
Loading