diff --git a/client/src/features/dashboardV2/DashboardV2Sessions.module.scss b/client/src/features/dashboardV2/DashboardV2Sessions.module.scss index 7dedde7b69..d7b01eca25 100644 --- a/client/src/features/dashboardV2/DashboardV2Sessions.module.scss +++ b/client/src/features/dashboardV2/DashboardV2Sessions.module.scss @@ -12,5 +12,6 @@ top: 0; margin-top: 1rem; right: 0; + bottom: auto; } } diff --git a/client/src/features/dashboardV2/DashboardV2Sessions.tsx b/client/src/features/dashboardV2/DashboardV2Sessions.tsx index 53d1dc48f7..72131ea020 100644 --- a/client/src/features/dashboardV2/DashboardV2Sessions.tsx +++ b/client/src/features/dashboardV2/DashboardV2Sessions.tsx @@ -202,9 +202,8 @@ function DashboardSession({ session }: DashboardSessionProps) { {/* NOTE: The session actions button is visually placed within the link card, but its DOM tree is kept separate. */} -
+
diff --git a/client/src/features/sessionsV2/SessionList/Actions.module.scss b/client/src/features/sessionsV2/SessionList/Actions.module.scss new file mode 100644 index 0000000000..4e209e9567 --- /dev/null +++ b/client/src/features/sessionsV2/SessionList/Actions.module.scss @@ -0,0 +1,17 @@ +@import "~bootstrap/scss/functions"; +@import "~bootstrap/scss/variables"; +@import "~bootstrap/scss/variables-dark"; +@import "~bootstrap/scss/maps"; +@import "~bootstrap/scss/mixins"; + +.actionsButton { + bottom: 0; + margin-bottom: 1rem; + + @include media-breakpoint-up(md) { + top: 0; + margin-top: 1rem; + right: 0; + bottom: auto; + } +} diff --git a/client/src/features/sessionsV2/SessionList/SessionItemV2.tsx b/client/src/features/sessionsV2/SessionList/SessionItemV2.tsx index 4f4207977f..fb74e3729f 100644 --- a/client/src/features/sessionsV2/SessionList/SessionItemV2.tsx +++ b/client/src/features/sessionsV2/SessionList/SessionItemV2.tsx @@ -19,13 +19,19 @@ import cx from "classnames"; import { useCallback, useMemo } from "react"; import { CaretRightFill } from "react-bootstrap-icons"; -import { ListGroupItem } from "reactstrap"; +import { Link } from "react-router-dom-v5-compat"; +import { Col, ListGroupItem, Row } from "reactstrap"; import useLocationHash from "../../../utils/customHooks/useLocationHash.hook"; +import { useProject } from "../../ProjectPageV2/ProjectPageContainer/ProjectPageContainer"; +import ActiveSessionButton from "../components/SessionButton/ActiveSessionButton"; import { SessionStatusV2Label } from "../components/SessionStatus/SessionStatus"; +import { getShowSessionUrlByProject } from "../SessionsV2"; import type { SessionLauncher, SessionV2 } from "../sessionsV2.types"; import SessionViewV2 from "../SessionView/SessionViewV2"; +import styles from "./Actions.module.scss"; + interface SessionItemV2Props { launcher: SessionLauncher; session: SessionV2; @@ -35,6 +41,8 @@ export default function SessionItemV2({ launcher, session, }: SessionItemV2Props) { + const { project } = useProject(); + const [hash, setHash] = useLocationHash(); const sessionHash = useMemo( () => `session-v2-${session.name}`, @@ -53,20 +61,44 @@ export default function SessionItemV2({ return ( <> - - - + + + + + + + + + {/* NOTE: This is a placeholder for the session actions button */} +
+ +
+ +
+ + {/* NOTE: The session actions button is visually placed within the link card, but its DOM tree is kept separate. */} +
+ +
0) { + return ; + } + + return ( + + ); +} + +function DisabledLaunchButton() { + const ref = useRef(null); + + return ( + <> + + + + + A session is already running from this launcher + + + ); +} diff --git a/client/src/features/sessionsV2/SessionList/SessionLauncherItem.tsx b/client/src/features/sessionsV2/SessionList/SessionLauncherItem.tsx index 7f98b76110..74e7f9a31a 100644 --- a/client/src/features/sessionsV2/SessionList/SessionLauncherItem.tsx +++ b/client/src/features/sessionsV2/SessionList/SessionLauncherItem.tsx @@ -19,6 +19,7 @@ import cx from "classnames"; import { useCallback, useMemo } from "react"; import { CircleFill } from "react-bootstrap-icons"; +import { Link } from "react-router-dom-v5-compat"; import { Badge, Col, ListGroupItem, Row } from "reactstrap"; import useLocationHash from "../../../utils/customHooks/useLocationHash.hook"; @@ -28,6 +29,9 @@ import type { SessionLauncher } from "../sessionsV2.types"; import SessionLauncherView from "../SessionView/SessionLauncherView"; import SessionItemV2 from "./SessionItemV2"; +import styles from "./Actions.module.scss"; +import SessionLauncherActions from "./SessionLauncherActions"; + interface SessionLauncherItemProps { launcher: SessionLauncher; } @@ -70,59 +74,69 @@ export default function SessionLauncherItem({ return ( <> -
-
+ - -
-
- - - - - - - {name} - - - - + + + - - Ready - - - - - + + {name} + + + + + + Ready + + + + + + {/* NOTE: This is a placeholder for the session actions button */} +
+ +
+ + + + {/* NOTE: The session actions button is visually placed within the link card, but its DOM tree is kept separate. */} +
+ +
{filteredSessions.map((session) => ( @@ -56,7 +62,15 @@ export default function SessionViewV2({
-
{""}
+
+ +

+ +
+

Container image

+ +
diff --git a/client/src/features/sessionsV2/components/SessionButton/ActiveSessionButton.tsx b/client/src/features/sessionsV2/components/SessionButton/ActiveSessionButton.tsx index a57bc65d8f..ef3203bd92 100644 --- a/client/src/features/sessionsV2/components/SessionButton/ActiveSessionButton.tsx +++ b/client/src/features/sessionsV2/components/SessionButton/ActiveSessionButton.tsx @@ -374,7 +374,7 @@ export default function ActiveSessionButton({ return (