Skip to content

Commit

Permalink
feat: Store filters in dashboard + auth redirection + scrollbar style
Browse files Browse the repository at this point in the history
  • Loading branch information
Loxeris committed Apr 26, 2024
1 parent 9f5edbd commit f3b1c89
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 73 deletions.
29 changes: 16 additions & 13 deletions src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ThemeProvider as MUIThemeProvider } from "@mui/material/styles";
import { useMUITheme } from "@/hooks/theme";
import Dashboard from "@/components/layout/Dashboard";
import ApplicationsProvider from "@/contexts/ApplicationsProvider";
import { OIDCSecure } from "@/components/layout/OIDCSecure";

export default function JobMonitorLayout({
children,
Expand All @@ -17,19 +18,21 @@ export default function JobMonitorLayout({
return (
<section>
<ApplicationsProvider>
<Dashboard>
<MUIThemeProvider theme={theme}>
<CssBaseline />
<Box
sx={{
ml: "5%",
mr: "5%",
}}
>
{children}
</Box>
</MUIThemeProvider>
</Dashboard>
<OIDCSecure>
<Dashboard>
<MUIThemeProvider theme={theme}>
<CssBaseline />
<Box
sx={{
ml: "5%",
mr: "5%",
}}
>
{children}
</Box>
</MUIThemeProvider>
</Dashboard>
</OIDCSecure>
</ApplicationsProvider>
</section>
);
Expand Down
18 changes: 17 additions & 1 deletion src/app/(dashboard)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
"use client";
import React from "react";
import { useSearchParams } from "next/navigation";
import UserDashboard from "@/components/applications/UserDashboard";
import { ApplicationsContext } from "@/contexts/ApplicationsProvider";
import { applicationList } from "@/components/applications/ApplicationList";

export default function Page() {
return <UserDashboard />;
const searchParams = useSearchParams();
const appId = searchParams.get("appId");
const [sections] = React.useContext(ApplicationsContext);

const appType = sections
.find((section) => section.items.some((item) => item.id === appId))
?.items.find((item) => item.id === appId)?.type;

const Component = applicationList.find((app) => app.name === appType)
?.component;

return Component ? <Component /> : <UserDashboard />;
}
6 changes: 1 addition & 5 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Inter } from "next/font/google";
import { OIDCConfigurationProvider } from "@/contexts/OIDCConfigurationProvider";
import { ThemeProvider } from "@/contexts/ThemeProvider";
import Dashboard from "@/components/layout/Dashboard";
import { OIDCSecure } from "@/components/layout/OIDCSecure";

const inter = Inter({ subsets: ["latin"] });

Expand All @@ -24,9 +22,7 @@ export default function RootLayout({
<html lang="en">
<body className={inter.className}>
<OIDCConfigurationProvider>
<ThemeProvider>
<OIDCSecure>{children}</OIDCSecure>
</ThemeProvider>
<ThemeProvider>{children}</ThemeProvider>
</OIDCConfigurationProvider>
</body>
</html>
Expand Down
4 changes: 1 addition & 3 deletions src/components/applications/ApplicationList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ import JobMonitor from "./JobMonitor";
import UserDashboard from "./UserDashboard";

export const applicationList = [
{ name: "Dashboard", path: "/", component: UserDashboard, icon: Dashboard },
{ name: "Dashboard", component: UserDashboard, icon: Dashboard },
{
name: "Job Monitor",
path: "/jobmonitor",
component: JobMonitor,
icon: Monitor,
},
{
name: "File Catalog",
path: "/filecatalog",
component: JobMonitor,
icon: FolderCopy,
},
Expand Down
13 changes: 11 additions & 2 deletions src/components/applications/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { useOIDCContext } from "@/hooks/oidcConfiguration";
import { useMUITheme } from "@/hooks/theme";
import { useMetadata, Metadata } from "@/hooks/metadata";

import { useSearchParamsUtils } from "@/hooks/searchParamsUtils";

/**
* Login form
* @returns a form
Expand All @@ -33,6 +35,8 @@ export function LoginForm() {
const { configuration, setConfiguration } = useOIDCContext();
const { isAuthenticated, login } = useOidc(configuration?.scope);

const { getParam } = useSearchParamsUtils();

// Login if not authenticated
useEffect(() => {
if (configuration && configuration.scope && isAuthenticated === false) {
Expand All @@ -44,9 +48,14 @@ export function LoginForm() {
useEffect(() => {
// Redirect to dashboard if already authenticated
if (isAuthenticated) {
router.push("/");
const redirect = getParam("redirect");
if (redirect) {
router.push(redirect);
} else {
router.push("/");
}
}
}, [isAuthenticated, router]);
}, [getParam, isAuthenticated, router]);

// Get default group
const getDefaultGroup = (data: Metadata | undefined, vo: string): string => {
Expand Down
5 changes: 4 additions & 1 deletion src/components/layout/OIDCSecure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export function OIDCSecure({ children }: OIDCProps) {
useEffect(() => {
// Redirect to login page if not authenticated
if (!isAuthenticated) {
router.push("/auth");
router.push(
"/auth?" +
new URLSearchParams({ redirect: window.location.href }).toString(),
);
}
}, [isAuthenticated, router]);

Expand Down
10 changes: 2 additions & 8 deletions src/components/ui/ApplicationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function AppDialog({
}: {
appDialogOpen: boolean;
setAppDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
handleCreateApp: (name: string, path: string, icon: ComponentType) => void;
handleCreateApp: (name: string, icon: ComponentType) => void;
}) {
const [appType, setAppType] = React.useState("");
return (
Expand All @@ -40,20 +40,14 @@ export default function AppDialog({
onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

const path = applicationList.find((app) => app.name === appType)
?.path;
if (!path) {
console.error("Path not found for application type", appType);
return;
}
const icon = applicationList.find((app) => app.name === appType)
?.icon;
if (!icon) {
console.error("Icon not found for application type", appType);
return;
}

handleCreateApp(appType, path, icon as React.ComponentType<any>);
handleCreateApp(appType, icon as React.ComponentType<any>);

setAppDialogOpen(false);
},
Expand Down
9 changes: 2 additions & 7 deletions src/components/ui/DashboardDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
* @param path - The path of the app.
* @param icon - The icon component for the app.
*/
const handleAppCreation = (
appType: string,
path: string,
icon: ComponentType,
) => {
const handleAppCreation = (appType: string, icon: ComponentType) => {
let group = userSections[userSections.length - 1];
const empty = !group;
if (empty) {
Expand All @@ -217,7 +213,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {

let title = `${appType} ${userSections.reduce(
(sum, group) =>
sum + group.items.filter((item) => item.icon === icon).length,
sum + group.items.filter((item) => item.type === appType).length,
1,
)}`;
while (group.items.some((item) => item.title === title)) {
Expand All @@ -232,7 +228,6 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
)}`,
type: appType,
icon: icon,
path: path,
};
group.items.push(newApp);
if (empty) {
Expand Down
53 changes: 48 additions & 5 deletions src/components/ui/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
Stack,
} from "@mui/material";
import { deepOrange } from "@mui/material/colors";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useSearchParams } from "next/navigation";
import { FilterToolbar } from "./FilterToolbar";
import { Filter } from "@/types/Filter";
import { Column } from "@/types/Column";
Expand Down Expand Up @@ -346,7 +346,8 @@ export function DataTable(props: DataTableProps) {
}>({ mouseX: null, mouseY: null, id: null });
// NextJS router and params
const searchParams = useSearchParams();
const { setParam } = useSearchParamsUtils();
const { getParam, setParam } = useSearchParamsUtils();
const appId = getParam("appId");

const updateFiltersAndUrl = React.useCallback(
(newFilters: Filter[]) => {
Expand All @@ -364,8 +365,28 @@ export function DataTable(props: DataTableProps) {

const [sections, setSections] = React.useContext(ApplicationsContext);
const updateSectionFilters = React.useCallback(
/* TODO */ (newFilters: Filter[]) => {},
[],
(newFilters: Filter[]) => {
const appId = getParam("appId");

const section = sections.find((section) =>
section.items.some((item) => item.id === appId),
);
if (section) {
const newSection = {
...section,
items: section.items.map((item) => {
if (item.id === appId) {
return { ...item, data: { filters: newFilters } };
}
return item;
}),
};
setSections((sections) =>
sections.map((s) => (s.title === section.title ? newSection : s)),
);
}
},
[getParam, sections, setSections],
);

// Handle the application of filters
Expand Down Expand Up @@ -394,6 +415,10 @@ export function DataTable(props: DataTableProps) {
});
};

const item = sections
.find((section) => section.items.some((item) => item.id === appId))
?.items.find((item) => item.id === appId);

if (searchParams.has("filter")) {
// Parse the filters when the component mounts or when the searchParams change
const initialFilters = parseFiltersFromUrl();
Expand All @@ -406,8 +431,26 @@ export function DataTable(props: DataTableProps) {
value: filter.value,
}));
setSearchBody({ search: jsonFilters });
} else if (item?.data?.filters) {
setFilters(item.data.filters);
const jsonFilters = item.data.filters.map(
(filter: {
id: number;
column: string;
operator: string;
value: string;
}) => ({
parameter: filter.column,
operator: filter.operator,
value: filter.value,
}),
);
setSearchBody({ search: jsonFilters });
} else {
setFilters([]);
setSearchBody({ search: [] });
}
}, [searchParams, setFilters, setSearchBody]);
}, [appId, searchParams, sections, setFilters, setSearchBody]);

// Manage sorting
const handleRequestSort = (
Expand Down
47 changes: 36 additions & 11 deletions src/components/ui/DrawerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,23 @@ import {
} from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
import { ThemeProvider as MUIThemeProvider } from "@mui/material/styles";
import { preserveOffsetOnSource } from "@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source";
import { ThemeProvider } from "@/contexts/ThemeProvider";
import { useMUITheme } from "@/hooks/theme";
import { useSearchParamsUtils } from "@/hooks/searchParamsUtils";

export default function DrawerItem({
item: { title, icon, path },
item: { title, id, icon },
index,
groupTitle,
}: {
item: { title: string; icon: React.ComponentType; path: string };
item: { title: string; id: string; icon: React.ComponentType };
index: number;
groupTitle: string;
}) {
const dragRef = React.useRef(null);
const handleRef = React.useRef(null);
const theme = useMUITheme();
const { setParam } = useSearchParamsUtils();

const [closestEdge, setClosestEdge]: any = useState<Edge | null>(null);

Expand All @@ -63,11 +64,7 @@ export default function DrawerItem({
width: source.element.getBoundingClientRect().width,
}}
>
<DrawerItem
item={{ title, icon, path }}
index={index}
groupTitle={groupTitle}
/>
<ItemPreview title={title} icon={icon} />
</div>
</MUIThemeProvider>
</ThemeProvider>,
Expand Down Expand Up @@ -125,15 +122,14 @@ export default function DrawerItem({
},
}),
);
}, [index, groupTitle, icon, path, theme, title]);
}, [index, groupTitle, icon, theme, title, id]);

return (
<>
<ListItemButton
disableGutters
key={title}
component={Link}
href={path}
onClick={() => setParam("appId", id)}
sx={{ pl: 2, borderRadius: 2, pr: 1 }}
ref={dragRef}
>
Expand All @@ -153,3 +149,32 @@ export default function DrawerItem({
</>
);
}

function ItemPreview({
title,
icon,
}: {
title: string;
icon: React.ComponentType;
}) {
return (
<ListItemButton
disableGutters
key={title}
sx={{
pl: 2,
borderRadius: 2,
pr: 1,
backgroundColor: "rgba(100, 100, 100, 0.2)",
}}
>
<ListItemIcon>
<Icon component={icon} />
</ListItemIcon>
<ListItemText primary={title} />
<ListItemIcon sx={{ minWidth: "24px" }}>
<Icon component={DragIndicatorIcon} sx={{ cursor: "grab" }} />
</ListItemIcon>
</ListItemButton>
);
}
Loading

0 comments on commit f3b1c89

Please sign in to comment.