Skip to content

Commit

Permalink
Merge branch 'main' into feat/1495-enhance-parent-tree-big-query
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaopeng0202 committed Sep 19, 2024
2 parents f8d14ba + 8e47d7a commit 4bd1729
Show file tree
Hide file tree
Showing 15 changed files with 680 additions and 98 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/.deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ jobs:
oc_namespace: ${{ vars.OC_NAMESPACE }}
oc_server: ${{ vars.OC_SERVER }}
oc_token: ${{ secrets.OC_TOKEN }}
oc_version: ${{ matrix.oc_version }}
overwrite: ${{ matrix.overwrite }}
parameters:
-p TAG=${{ inputs.tag }}
Expand All @@ -174,7 +173,6 @@ jobs:
oc_namespace: ${{ vars.OC_NAMESPACE }}
oc_server: ${{ vars.OC_SERVER }}
oc_token: ${{ secrets.OC_TOKEN }}
oc_version: "4.13"
overwrite: true
parameters:
-p TAG=${{ inputs.tag }}
Expand Down
57 changes: 19 additions & 38 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,28 @@ import {
import { Amplify } from 'aws-amplify';
import { ClassPrefix } from '@carbon/react';
import { ToastContainer } from 'react-toastify';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { isAxiosError } from 'axios';
import awsconfig from './aws-exports';

import prefix from './styles/classPrefix';
import './styles/custom.scss';
import 'react-toastify/dist/ReactToastify.css';

import Layout from './layout/PrivateLayout';
import Landing from './views/Landing';
import awsconfig from './aws-exports';
import FourOhFour from './views/ErrorViews/FourOhFour';
import LoginOrgSelection from './views/LoginOrgSelection';
import ServiceStatus from './views/ServiceStatus';
import { NavigateProvider } from './contexts/NavigationContext';
import AuthContext from './contexts/AuthContext';
import BrowserRoutes from './routes';
import ROUTES from './routes/constants';
import FourOhFour from './views/FourOhFour';
import ProtectedRoute from './routes/ProtectedRoute';
import { ThemePreference } from './utils/ThemePreference';
import LoginOrgSelection from './views/LoginOrgSelection';
import ServiceStatus from './views/ServiceStatus';
import CustomQueryProvider from './components/CustomQueryProvider';

Amplify.configure(awsconfig);

const HTTP_STATUS_TO_NOT_RETRY = [400, 401, 403, 404];
const MAX_RETRIES = 3;

const queryClient = new QueryClient(
{
defaultOptions: {
queries: {
refetchOnMount: false,
refetchOnWindowFocus: false,
// Do not retry on errors defined above
retry: (failureCount, error) => {
if (failureCount > MAX_RETRIES) {
return false;
}
if (isAxiosError(error)) {
const status = error.response?.status;
if (status && HTTP_STATUS_TO_NOT_RETRY.includes(status)) {
return false;
}
}
return true;
}
}
}
}
);

/**
* Create an app structure containing all the routes.
*
Expand Down Expand Up @@ -120,14 +93,22 @@ const App: React.FC = () => {
return createBrowserRouter(selectedRoutes);
};

const browserRouter = getBrowserRouter();

const handleRedirectTo403 = () => {
browserRouter.navigate('/403');
};

return (
<ClassPrefix prefix={prefix}>
<ThemePreference>
<QueryClientProvider client={queryClient}>
<ToastContainer />
<RouterProvider router={getBrowserRouter()} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
<NavigateProvider onRedirect={handleRedirectTo403}>
<CustomQueryProvider>
<ToastContainer />
<RouterProvider router={browserRouter} />
<ReactQueryDevtools initialIsOpen={false} />
</CustomQueryProvider>
</NavigateProvider>
</ThemePreference>
</ClassPrefix>
);
Expand Down
374 changes: 374 additions & 0 deletions frontend/src/assets/img/SPAR_403_error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
124 changes: 69 additions & 55 deletions frontend/src/components/BCHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Link, useLocation, useNavigate } from 'react-router-dom';

import {
HeaderContainer,
Expand Down Expand Up @@ -37,6 +37,8 @@ const BCHeader = () => {
const [rightPanel, setRightPanel] = useState<RightPanelType>(defaultPanelState);
const [overlay, setOverlay] = useState<boolean>(false);

const location = useLocation();

const windowSize = useWindowSize();

const handleRightPanel = (panel: keyof RightPanelType) => {
Expand Down Expand Up @@ -88,11 +90,17 @@ const BCHeader = () => {
onClick={isSideNavExpanded ? onClickSideNavExpand : null}
>
<SkipToContent />
<HeaderMenuButton
aria-label={componentTexts.openMenu}
onClick={onClickSideNavExpand}
isActive={isSideNavExpanded}
/>
{
!location.pathname.endsWith('/403')
? (
<HeaderMenuButton
aria-label={componentTexts.openMenu}
onClick={onClickSideNavExpand}
isActive={isSideNavExpanded}
/>
)
: null
}
<Link to={HOME_LINK} className="header-link" data-testid="header-name">
{componentTexts.headerTitle}
<span className="header-full-name">{componentTexts.completeTitle}</span>
Expand Down Expand Up @@ -164,62 +172,68 @@ const BCHeader = () => {
)
: null
}
<SideNav
isChildOfHeader
expanded={isSideNavExpanded}
aria-label={componentTexts.sideMenuAriaLabel}
inert={undefined}
className="spar-side-nav"
onClick={isSideNavExpanded ? onClickSideNavExpand : null}
>
<div className="side-nav-top">
{
navItems.map((category) => (
<div key={category.name}>
<SideNavLink className="side-nav-category-name">
{category.name}
{
!location.pathname.endsWith('/403')
? (
<SideNav
isChildOfHeader
expanded={isSideNavExpanded}
aria-label={componentTexts.sideMenuAriaLabel}
inert={undefined}
className="spar-side-nav"
onClick={isSideNavExpanded ? onClickSideNavExpand : null}
>
<div className="side-nav-top">
{
navItems.map((category) => (
<div key={category.name}>
<SideNavLink className="side-nav-category-name">
{category.name}
</SideNavLink>
{
category.items.map((navItem) => (
<SideNavLink
key={navItem.name}
className={navItem.disabled ? 'disabled-side-nav-option' : 'side-nav-option'}
renderIcon={Icons[navItem.icon]}
isActive={window.location.pathname.includes(navItem.link)}
onClick={navItem.disabled ? null : () => navigate(navItem.link)}
>
{navItem.name}
</SideNavLink>
))
}
</div>
))
}
</div>
<div>
{/* Uncomment this section when the support pages are implemented. */}
{/* <SideNavLink className="side-nav-category-name">
{supportItems.name}
</SideNavLink>
{
category.items.map((navItem) => (
supportItems.items.map((supportItem) => (
<SideNavLink
key={navItem.name}
className={navItem.disabled ? 'disabled-side-nav-option' : 'side-nav-option'}
renderIcon={Icons[navItem.icon]}
isActive={window.location.pathname.includes(navItem.link)}
onClick={navItem.disabled ? null : () => navigate(navItem.link)}
key={supportItem.name}
renderIcon={Icons[supportItem.icon]}
className={
supportItem.disabled
? 'disabled-side-nav-option'
: 'side-nav-option'
}
onClick={supportItem.disabled ? null : () => navigate(supportItem.link)}
>
{navItem.name}
{supportItem.name}
</SideNavLink>
))
}
} */}
<PanelSectionName title={VERSION} />
</div>
))
}
</div>
<div>
{/* Uncomment this section when the support pages are implemented. */}
{/* <SideNavLink className="side-nav-category-name">
{supportItems.name}
</SideNavLink>
{
supportItems.items.map((supportItem) => (
<SideNavLink
key={supportItem.name}
renderIcon={Icons[supportItem.icon]}
className={
supportItem.disabled
? 'disabled-side-nav-option'
: 'side-nav-option'
}
onClick={supportItem.disabled ? null : () => navigate(supportItem.link)}
>
{supportItem.name}
</SideNavLink>
))
} */}
<PanelSectionName title={VERSION} />
</div>
</SideNav>
</SideNav>
)
: null
}
</Header>
)}
/>
Expand Down
60 changes: 60 additions & 0 deletions frontend/src/components/CustomQueryProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { ReactNode } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { isAxiosError } from 'axios';

import { useNavigateContext } from '../../contexts/NavigationContext';

const HTTP_STATUS_TO_NOT_RETRY = [400, 401, 403, 404];
const MAX_RETRIES = 3;

// Function to generate a QueryClient with error handling
// and redirect, this will guarantee the redirect for all
// requests in the application
const useCustomQueryClient = () => {
const { redirectTo403 } = useNavigateContext();

const queryClient = new QueryClient(
{
defaultOptions: {
queries: {
refetchOnMount: false,
refetchOnWindowFocus: false,
// Do not retry on errors defined above
retry: (failureCount, error) => {
if (failureCount > MAX_RETRIES) {
return false;
}
if (isAxiosError(error)) {
const status = error.response?.status;
if (status && HTTP_STATUS_TO_NOT_RETRY.includes(status)) {
if (status === 403) {
redirectTo403();
}
return false;
}
}
return true;
}
}
}
}
);

return queryClient;
};

interface CustomQueryProviderProps {
children: ReactNode;
}

const CustomQueryProvider = ({ children }: CustomQueryProviderProps) => {
const queryClient = useCustomQueryClient();

return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};

export default CustomQueryProvider;
32 changes: 32 additions & 0 deletions frontend/src/contexts/NavigationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { createContext, useContext, useMemo } from 'react';

interface NavigateContextType {
redirectTo403: Function;
}

const NavigationContext = createContext<NavigateContextType | undefined>(undefined);

// This a navigation provider, where a a context will be used to access the useNavigate
// without necessarily being inside a router context
export const NavigateProvider: React.FC<{
children: React.ReactNode,
onRedirect: () => void
}> = ({ children, onRedirect }) => {
const value = useMemo(() => ({ redirectTo403: onRedirect }), [onRedirect]);

return (
<NavigationContext.Provider value={value}>
{children}
</NavigationContext.Provider>
);
};

export const useNavigateContext = () => {
const context = useContext(NavigationContext);

if (!context) {
throw new Error('useNavigateContext must be used within a NavigateProvider');
}

return context;
};
1 change: 1 addition & 0 deletions frontend/src/routes/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const ROUTES = {
MY_SEEDLOTS: '/seedlots/my-seedlots',
TSC_SEEDLOTS_TABLE: '/seedlots/tsc-admin-seedlots',
FOUR_OH_FOUR: '/404',
FOUR_OH_THREE: '/403',
SERVICE_STATUS: '/service-status'
};

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import SeedlotDetails from '../views/Seedlot/SeedlotDetails';
import SeedlotReview from '../views/Seedlot/SeedlotReview';
import SeedlotRegFormClassA from '../views/Seedlot/SeedlotRegFormClassA';
import ReviewSeedlots from '../views/Seedlot/ReviewSeedlots';
import FourOhThree from '../views/ErrorViews/FourOhThree';

const BrowserRoutes: Array<RouteObject> = [
// Ensures that root paths get redirected to
Expand Down Expand Up @@ -90,6 +91,12 @@ const BrowserRoutes: Array<RouteObject> = [
element: (
<ReviewSeedlots />
)
},
{
path: ROUTES.FOUR_OH_THREE,
element: (
<FourOhThree />
)
}
];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { Link } from 'react-router-dom';
import ROUTES from '../../routes/constants';
import ROUTES from '../../../routes/constants';

import mysteryImg from '../../assets/img/404-mystery.png';
import mysteryImg from '../../../assets/img/404-mystery.png';

import './styles.scss';

Expand Down
File renamed without changes.
Loading

0 comments on commit 4bd1729

Please sign in to comment.