Skip to content

Commit

Permalink
Add context handling
Browse files Browse the repository at this point in the history
  • Loading branch information
itaigilo committed Sep 8, 2024
1 parent d85156d commit d20503f
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 130 deletions.
29 changes: 0 additions & 29 deletions webui/src/lib/components/darkModeToggle.jsx

This file was deleted.

26 changes: 26 additions & 0 deletions webui/src/lib/components/darkModeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, {FC, useContext} from "react";
import {DarkModeSwitch} from "react-toggle-dark-mode";
import {AppActionType, AppContext} from "../hooks/appContext";

const DarkModeToggle: FC = () => {
const {state, dispatch} = useContext(AppContext);

const toggleDarkMode = (isOn: boolean) => {
dispatch({
type: AppActionType.setDarkMode,
value: isOn,
});
};

return (
<DarkModeSwitch
style={{marginRight: '2rem'}}
checked={state.settings.darkMode}
onChange={toggleDarkMode}
size={28}
sunColor={"white"}
/>
);
};

export default DarkModeToggle;
27 changes: 6 additions & 21 deletions webui/src/lib/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,24 @@
import React, {FC, useState} from "react";
import React, {FC, useContext, useState} from "react";
import { Outlet, useOutletContext } from "react-router-dom";
import { StorageConfigProvider } from "../hooks/storageConfig";

import TopNav from './navbar';
import { AppContext } from "../hooks/appContext";

type LayoutOutletContext = [(isLoggedIn: boolean) => void];

function applyDarkThemeWhenChanged() {
const keyIsDarkMode = "is_dark_mode";

function setDarkThemeFromLocalStorage() {
const isDarkMode = window.localStorage.getItem(keyIsDarkMode) === String(true)
document.documentElement.setAttribute('data-bs-theme', isDarkMode ? 'dark' : 'light')
}

setDarkThemeFromLocalStorage(); // initial set of Dark Mode

window.addEventListener("storage", (event) => {
if (event.key === keyIsDarkMode) {
setDarkThemeFromLocalStorage();
}
});
}

const Layout: FC<{logged: boolean}> = ({ logged }) => {
const [isLogged, setIsLogged] = useState(logged ?? true);

applyDarkThemeWhenChanged();
// handle global dark mode here
const {state} = useContext(AppContext);
document.documentElement.setAttribute('data-bs-theme', state.settings.darkMode ? 'dark' : 'light')

return (
<>
<TopNav logged={isLogged}/>
<div className="main-app">
<StorageConfigProvider>
<Outlet context={[setIsLogged] satisfies LayoutOutletContext} />
<Outlet context={[setIsLogged] satisfies LayoutOutletContext}/>
</StorageConfigProvider>
</div>
</>
Expand Down
63 changes: 63 additions & 0 deletions webui/src/lib/hooks/appContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, {createContext, useReducer} from "react";

type AppContextType = {
settings: AppContext;
};

type AppContext = {
darkMode: boolean;
};

const localStorageKeys = {
darkMode: 'darkMode',
};

enum AppActionType {
setDarkMode = 'setDarkMode',
}

interface Action {
type: AppActionType;
value: boolean;
}

const initialLocalSettings: AppContext = {
darkMode: window.localStorage.getItem(localStorageKeys.darkMode) === String(true),
};

const initialAppContext: AppContextType = {
settings: initialLocalSettings,
};

const appContextReducer = (state: AppContextType, action: Action) => {
switch (action.type) {
case AppActionType.setDarkMode:
window.localStorage.setItem(localStorageKeys.darkMode, String(action.value));
return {...state, settings: {...state.settings, darkMode: action.value}};
default:
return state;
}
}

type ContextType = {
state: AppContextType,
dispatch: React.Dispatch<Action>,
};

const AppContext = createContext<ContextType>({
state: initialAppContext,
dispatch: () => null
});

// @ts-expect-error - it doesn't like the "children" prop
const WithAppContext: React.FC = ({ children }) => {
const [state, dispatch] = useReducer(appContextReducer, initialAppContext);

return (
<AppContext.Provider value={{state, dispatch}}>
{children}
</AppContext.Provider>
)
}

export {WithAppContext, AppContext, AppActionType};
159 changes: 81 additions & 78 deletions webui/src/pages/index.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React from "react";

import {
BrowserRouter as Router,
Routes,
Route,
Navigate,
BrowserRouter as Router,
Routes,
Route,
Navigate,
} from "react-router-dom";
import { WithLoginConfigContext } from "../lib/hooks/conf";
import {WithLoginConfigContext} from "../lib/hooks/conf";

// pages
import RepositoriesPage from "./repositories";
import { RepositoryPageLayout } from "../lib/components/repository/layout.jsx";
import {RepositoryPageLayout} from "../lib/components/repository/layout.jsx";
import RepositoryObjectsPage from "./repositories/repository/objects";
import RepositoryObjectsViewPage from "./repositories/repository/objectViewer";
import RepositoryChangesPage from "./repositories/repository/changes";
Expand All @@ -23,7 +23,7 @@ import RepositoryActionsPage from "./repositories/repository/actions";
import RepositoryGeneralSettingsPage from "./repositories/repository/settings/general";
import RepositoryRetentionPage from "./repositories/repository/settings/retention";
import RepositorySettingsBranchesPage from "./repositories/repository/settings/branches";
import { SettingsLayout } from "./repositories/repository/settings/layout";
import {SettingsLayout} from "./repositories/repository/settings/layout";
import Layout from "../lib/components/layout";
import CredentialsPage from "./auth/credentials";
import GroupsPage from "./auth/groups";
Expand All @@ -39,78 +39,81 @@ import PolicyPage from "./auth/policies/policy";
import LoginPage from "./auth/login";
import ActivateInvitedUserPage from "./auth/users/create-user-with-password";
import Setup from "./setup";
import { AuthLayout } from "../lib/components/auth/layout";
import {AuthLayout} from "../lib/components/auth/layout";
import RepositoryActionPage from "./repositories/repository/actions/run";
import {WithAppContext} from "../lib/hooks/appContext";

export const IndexPage = () => {
return (
<Router>
<WithLoginConfigContext>
<Routes>
<Route index element={<Navigate to="/repositories" />} />
<Route path="repositories" element={<Layout logged={true} />}>
<Route index element={<RepositoriesPage />} />
<Route path=":repoId" element={<RepositoryPageLayout />}>
<Route path="objects" element={<RepositoryObjectsPage />} />
<Route path="object" element={<RepositoryObjectsViewPage />} />
<Route path="changes" element={<RepositoryChangesPage />} />
<Route path="commits">
<Route index element={<RepositoryCommitsPage/>} />
<Route path=":commitId" element={<RepositoryCommitPage/>} />
</Route>
<Route path="branches" element={<RepositoryBranchesPage />} />
<Route path="tags" element={<RepositoryTagsPage />} />
<Route path="compare/*" element={<RepositoryComparePage />} />
<Route path="actions">
<Route index element={<RepositoryActionsPage />} />
<Route path=":runId" element={<RepositoryActionPage />} />
</Route>
<Route path="settings" element={<SettingsLayout />}>
<Route index element={<Navigate to="general" />} />
<Route path="general" element={<RepositoryGeneralSettingsPage />} />
<Route path="retention" element={<RepositoryRetentionPage />} />
<Route path="branches" element={<RepositorySettingsBranchesPage />} />
</Route>
<Route index element={<Navigate to="objects" />} />
</Route>
</Route>
<Route path="auth" element={<Layout logged={false} />}>
<Route index element={<Navigate to="credentials" />} />
<Route path="login" element={<LoginPage />} />
<Route path="users/create" element={<ActivateInvitedUserPage />} />
<Route element={<AuthLayout />}>
<Route path="credentials" element={<CredentialsPage />} />
<Route path="users" element={<UsersIndexPage />}>
<Route index element={<UsersPage />} />
<Route path=":userId">
<Route index element={<Navigate to="groups" />} />
<Route path="groups" element={<UserGroupsPage />} />
<Route exact path="policies" element={<UserPoliciesPage />} />
<Route exact path="policies/effective" element={<UserEffectivePoliciesPage />} />
<Route exact path="credentials" element={<UserCredentialsPage />} />
</Route>
</Route>
<Route path="groups">
<Route index element={<GroupsPage />} />
<Route path=":groupId">
<Route index element={<Navigate to="members" />} />
<Route path="members" element={<GroupMembersPage />} />
<Route path="policies" element={<GroupPoliciesPage />} />
</Route>
</Route>
<Route path="policies">
<Route index element={<PoliciesPage />} />
<Route path=":policyId" element={<PolicyPage />} />
</Route>
</Route>
</Route>
<Route path="/setup" element={<Layout logged={false} />}>
<Route index element={<Setup />} />
<Route path="*" element={<Setup />} />
</Route>
<Route path="*" element={<Navigate to="/repositories" replace />} />
</Routes>
</WithLoginConfigContext>
</Router>
);
return (
<Router>
<WithAppContext>
<WithLoginConfigContext>
<Routes>
<Route index element={<Navigate to="/repositories"/>}/>
<Route path="repositories" element={<Layout logged={true}/>}>
<Route index element={<RepositoriesPage/>}/>
<Route path=":repoId" element={<RepositoryPageLayout/>}>
<Route path="objects" element={<RepositoryObjectsPage/>}/>
<Route path="object" element={<RepositoryObjectsViewPage/>}/>
<Route path="changes" element={<RepositoryChangesPage/>}/>
<Route path="commits">
<Route index element={<RepositoryCommitsPage/>}/>
<Route path=":commitId" element={<RepositoryCommitPage/>}/>
</Route>
<Route path="branches" element={<RepositoryBranchesPage/>}/>
<Route path="tags" element={<RepositoryTagsPage/>}/>
<Route path="compare/*" element={<RepositoryComparePage/>}/>
<Route path="actions">
<Route index element={<RepositoryActionsPage/>}/>
<Route path=":runId" element={<RepositoryActionPage/>}/>
</Route>
<Route path="settings" element={<SettingsLayout/>}>
<Route index element={<Navigate to="general"/>}/>
<Route path="general" element={<RepositoryGeneralSettingsPage/>}/>
<Route path="retention" element={<RepositoryRetentionPage/>}/>
<Route path="branches" element={<RepositorySettingsBranchesPage/>}/>
</Route>
<Route index element={<Navigate to="objects"/>}/>
</Route>
</Route>
<Route path="auth" element={<Layout logged={false}/>}>
<Route index element={<Navigate to="credentials"/>}/>
<Route path="login" element={<LoginPage/>}/>
<Route path="users/create" element={<ActivateInvitedUserPage/>}/>
<Route element={<AuthLayout/>}>
<Route path="credentials" element={<CredentialsPage/>}/>
<Route path="users" element={<UsersIndexPage/>}>
<Route index element={<UsersPage/>}/>
<Route path=":userId">
<Route index element={<Navigate to="groups"/>}/>
<Route path="groups" element={<UserGroupsPage/>}/>
<Route exact path="policies" element={<UserPoliciesPage/>}/>
<Route exact path="policies/effective" element={<UserEffectivePoliciesPage/>}/>
<Route exact path="credentials" element={<UserCredentialsPage/>}/>
</Route>
</Route>
<Route path="groups">
<Route index element={<GroupsPage/>}/>
<Route path=":groupId">
<Route index element={<Navigate to="members"/>}/>
<Route path="members" element={<GroupMembersPage/>}/>
<Route path="policies" element={<GroupPoliciesPage/>}/>
</Route>
</Route>
<Route path="policies">
<Route index element={<PoliciesPage/>}/>
<Route path=":policyId" element={<PolicyPage/>}/>
</Route>
</Route>
</Route>
<Route path="/setup" element={<Layout logged={false}/>}>
<Route index element={<Setup/>}/>
<Route path="*" element={<Setup/>}/>
</Route>
<Route path="*" element={<Navigate to="/repositories" replace/>}/>
</Routes>
</WithLoginConfigContext>
</WithAppContext>
</Router>
);
};
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import React from "react";
import React, {useContext} from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { github as syntaxHighlightStyle } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { dark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import {AppContext} from "../../../../lib/hooks/appContext";

export const CustomMarkdownCodeComponent = ({
inline,
className,
children,
...props
}) => {
const {state} = useContext(AppContext);
const hasLang = /language-(\w+)/.exec(className || "");

return !inline && hasLang ? (
<SyntaxHighlighter
style={syntaxHighlightStyle}
style={state.settings.darkMode ? dark : syntaxHighlightStyle}
language={hasLang[1]}
PreTag="div"
className="codeStyle"
Expand Down

0 comments on commit d20503f

Please sign in to comment.