Skip to content

Commit

Permalink
fix: Resolve issues highlighted in PR review
Browse files Browse the repository at this point in the history
  • Loading branch information
Loxeris committed May 8, 2024
1 parent e180b96 commit fc9301f
Show file tree
Hide file tree
Showing 17 changed files with 152 additions and 147 deletions.
22 changes: 0 additions & 22 deletions src/app/(dashboard)/jobmonitor/error.tsx

This file was deleted.

7 changes: 0 additions & 7 deletions src/app/(dashboard)/jobmonitor/layout.tsx

This file was deleted.

5 changes: 0 additions & 5 deletions src/app/(dashboard)/jobmonitor/page.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Dashboard from "@/components/layout/Dashboard";
import ApplicationsProvider from "@/contexts/ApplicationsProvider";
import { OIDCSecure } from "@/components/layout/OIDCSecure";

export default function JobMonitorLayout({
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
Expand Down
14 changes: 9 additions & 5 deletions src/app/(dashboard)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ export default function Page() {
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 appType = React.useMemo(() => {
const section = sections.find((section) =>
section.items.some((item) => item.id === appId),
);
return section?.items.find((item) => item.id === appId)?.type;
}, [sections, appId]);

const Component = applicationList.find((app) => app.name === appType)
?.component;
const Component = React.useMemo(() => {
return applicationList.find((app) => app.name === appType)?.component;
}, [appType]);

return Component ? <Component /> : <UserDashboard />;
}
3 changes: 2 additions & 1 deletion src/components/applications/ApplicationList.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Dashboard, FolderCopy, Monitor } from "@mui/icons-material";
import JobMonitor from "./JobMonitor";
import UserDashboard from "./UserDashboard";
import ApplicationConfig from "@/types/ApplicationConfig";

export const applicationList = [
export const applicationList: ApplicationConfig[] = [
{ name: "Dashboard", component: UserDashboard, icon: Dashboard },
{
name: "Job Monitor",
Expand Down
1 change: 1 addition & 0 deletions src/components/layout/OIDCSecure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function OIDCSecure({ children }: OIDCProps) {
if (!isAuthenticated) {
router.push(
"/auth?" +
// URLSearchParams to ensure that auth redirects users to the URL they came from
new URLSearchParams({ redirect: window.location.href }).toString(),
);
}
Expand Down
30 changes: 20 additions & 10 deletions src/components/ui/ApplicationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
Button,
Grid,
Icon,
IconButton,
} from "@mui/material";
import { Close } from "@mui/icons-material";
import { applicationList } from "../applications/ApplicationList";

/**
Expand Down Expand Up @@ -55,10 +57,26 @@ export default function AppDialog({
fullWidth
maxWidth="sm"
>
<DialogTitle id="application-dialog-label">New Application</DialogTitle>
<DialogTitle id="application-dialog-label">
Available applications
</DialogTitle>
<IconButton
aria-label="close"
onClick={() => setAppDialogOpen(false)}
sx={{
position: "absolute",
right: 8,
top: 8,
color: (theme) => theme.palette.grey[500],
}}
>
<Close />
</IconButton>
<DialogContent>
<DialogContentText sx={{ mb: 2 }}>
Choose the type of application you would like to create.
Click on any application to open it in a new instance in the drawer.
Multiple instances of the same application can be opened
simultaneously.
</DialogContentText>
<Grid container spacing={2}>
{applicationList.map((app) => (
Expand All @@ -78,14 +96,6 @@ export default function AppDialog({
))}
</Grid>
</DialogContent>
<DialogActions>
<Button
sx={{ color: "warning.main" }}
onClick={() => setAppDialogOpen(false)}
>
Cancel
</Button>
</DialogActions>
</Dialog>
);
}
50 changes: 36 additions & 14 deletions src/components/ui/DashboardDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { usePathname } from "next/navigation";
import {
Box,
Button,
Expand All @@ -25,10 +24,11 @@ import React, {
} from "react";
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
import Image from "next/image";
import DrawerItemGroup from "./DrawerItemGroup";
import { DiracLogo } from "./DiracLogo";
import AppDialog from "./ApplicationDialog";
import { ApplicationsContext } from "@/contexts/ApplicationsProvider";
import { useMUITheme } from "@/hooks/theme";

interface DashboardDrawerProps {
variant: "permanent" | "temporary";
Expand All @@ -45,15 +45,12 @@ interface DashboardDrawerProps {
* @returns {JSX.Element} The rendered DashboardDrawer component.
*/
export default function DashboardDrawer(props: DashboardDrawerProps) {
// Get the current URL
const pathname = usePathname();
// Determine the container for the Drawer based on whether the window object exists.
const container =
window !== undefined ? () => window.document.body : undefined;
// Check if the drawer is in "temporary" mode.
const isTemporary = props.variant === "temporary";

// Wether the modal for Application Creation is open
// Whether the modal for Application Creation is open
const [appDialogOpen, setAppDialogOpen] = useState(false);

const [contextMenu, setContextMenu] = React.useState<{
Expand All @@ -73,7 +70,10 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
// Each section has an associated icon and path.
const [userSections, setSections] = useContext(ApplicationsContext);

const theme = useMUITheme();

useEffect(() => {
// Handle changes to sections when drag and drop occurs.
return monitorForElements({
onDrop({ source, location }) {
const target = location.current.dropTargets[0];
Expand All @@ -84,6 +84,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
const targetData = target.data;

if (location.current.dropTargets.length == 2) {
// If the target is an item
const groupTitle = targetData.title;
const closestEdgeOfTarget = extractClosestEdge(targetData);
const targetIndex = targetData.index as number;
Expand All @@ -105,6 +106,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
destinationIndex,
);
} else {
// If the target is a group
const groupTitle = targetData.title;
const sourceGroup = userSections.find(
(group) => group.title == sourceData.title,
Expand Down Expand Up @@ -140,13 +142,13 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
destinationIndex &&
sourceIndex < destinationIndex
) {
destinationIndex -= 1;
destinationIndex -= 1; // Corrects the index within the same group if needed
}
if (
sourceGroup.title === destinationGroup.title &&
(destinationIndex == null || sourceIndex === destinationIndex)
) {
return;
return; // Nothing to do
}

if (sourceGroup.title === destinationGroup.title) {
Expand Down Expand Up @@ -195,8 +197,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
/**
* Handles the creation of a new app in the dashboard drawer.
*
* @param appName - The name of the app.
* @param path - The path of the app.
* @param appType - The type of the app to be created.
* @param icon - The icon component for the app.
*/
const handleAppCreation = (appType: string, icon: ComponentType) => {
Expand Down Expand Up @@ -361,8 +362,20 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
style={{ display: "flex", flexDirection: "column", height: "100%" }}
>
{/* Display the logo in the toolbar section of the drawer. */}
<Toolbar>
<DiracLogo />
<Toolbar
sx={{
position: "sticky",
top: "0",
zIndex: 1,
backgroundColor: theme.palette.background.default,
}}
>
<Image
src="/DIRAC-logo.png"
alt="DIRAC logo"
width={150}
height={45}
/>
</Toolbar>
{/* Map over user sections and render them as list items in the drawer. */}
<List>
Expand All @@ -380,8 +393,17 @@ export default function DashboardDrawer(props: DashboardDrawerProps) {
</ListItem>
))}
</List>
{/* Render a link to documentation, positioned at the bottom of the drawer. */}
<List sx={{ mt: "auto" }}>

{/* Render a link to documentation and a button to add applications, positioned at the bottom of the drawer. */}
<List
sx={{
mt: "auto",
position: "sticky",
bottom: "0",
zIndex: 1,
backgroundColor: theme.palette.background.default,
}}
>
<ListItem key={"Add application"}>
<ListItemButton onClick={() => setAppDialogOpen(true)}>
<ListItemIcon>
Expand Down
16 changes: 0 additions & 16 deletions src/components/ui/DiracLogo.tsx

This file was deleted.

29 changes: 27 additions & 2 deletions src/components/ui/DrawerItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import Link from "next/link";
import {
ListItemButton,
ListItemIcon,
Expand All @@ -25,6 +24,14 @@ import { ThemeProvider } from "@/contexts/ThemeProvider";
import { useMUITheme } from "@/hooks/theme";
import { useSearchParamsUtils } from "@/hooks/searchParamsUtils";

/**
* Represents a drawer item component.
*
* @param item - The item object containing the title, id, and icon.
* @param index - The index of the item.
* @param groupTitle - The title of the group.
* @returns The rendered JSX for the drawer item.
*/
export default function DrawerItem({
item: { title, id, icon },
index,
Expand All @@ -34,11 +41,13 @@ export default function DrawerItem({
index: number;
groupTitle: string;
}) {
// Ref to use for the draggable element
const dragRef = React.useRef(null);
// Ref to use for the handle of the draggable element, must be a child of the draggable element
const handleRef = React.useRef(null);
const theme = useMUITheme();
const { setParam } = useSearchParamsUtils();

// Represents the closest edge to the mouse cursor
const [closestEdge, setClosestEdge]: any = useState<Edge | null>(null);

useEffect(() => {
Expand All @@ -47,16 +56,21 @@ export default function DrawerItem({
const handleItem = handleRef.current;

return combine(
// makes the item draggable
draggable({
element: element,
dragHandle: handleItem,
// Sets the initial data for the drag and drop interaction
getInitialData: () => ({ index, title: groupTitle }),
// Sets a lightweight version of the real item as a preview
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
setCustomNativeDragPreview({
nativeSetDragImage,
render: ({ container }) => {
const root = createRoot(container);
root.render(
// Wraps the preview in the theme provider to ensure the correct theme is applied
// This is necessary because the preview is rendered outside the main app
<ThemeProvider>
<MUIThemeProvider theme={theme}>
<div
Expand All @@ -71,6 +85,7 @@ export default function DrawerItem({
);
return () => root.unmount();
},
// Seamless transition between the preview and the real element
getOffset: ({ container }) => {
const elementPos = source.element.getBoundingClientRect();
const x = location.current.input.pageX - elementPos.x;
Expand All @@ -80,6 +95,7 @@ export default function DrawerItem({
});
},
}),
// Makes the item a target for dragged elements. Attach the closest edge data and highlight the destination when hovering over the item
dropTargetForElements({
element: element,
getData: ({ input, element }) => {
Expand Down Expand Up @@ -150,6 +166,15 @@ export default function DrawerItem({
);
}

/**
* Lightweight preview of an item in the drawer.
* Used when dragging an item to give a visual representation of it with minimal resources.
*
* @param {Object} props - The component props.
* @param {string} props.title - The title of the item.
* @param {React.ComponentType} props.icon - The icon component for the item.
* @returns {JSX.Element} The rendered item preview.
*/
function ItemPreview({
title,
icon,
Expand Down
Loading

0 comments on commit fc9301f

Please sign in to comment.