From 6c654b44035bb4bbb3db9fa3fcdcc3be59954d4d Mon Sep 17 00:00:00 2001 From: Yael Date: Mon, 16 Dec 2024 18:54:43 +0200 Subject: [PATCH 1/2] feat(ws): Add Connect column to workspace table and popup with workspace endpoints Signed-off-by: Yael --- .../pages/Workspaces/WorkspaceEndpoints.tsx | 62 +++++++++++++++++++ .../src/app/pages/Workspaces/Workspaces.tsx | 20 ++++++ workspaces/frontend/src/shared/types.ts | 4 ++ 3 files changed, 86 insertions(+) create mode 100644 workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx diff --git a/workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx b/workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx new file mode 100644 index 00000000..dcc69c0c --- /dev/null +++ b/workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import { + Dropdown, + DropdownItem, + DropdownList, + MenuToggle, + MenuToggleElement, +} from "@patternfly/react-core"; +import { Workspace, WorkspaceState } from "~/shared/types"; + +type EndpointsDropdownProps = { + workspace: Workspace; +}; + +export const EndpointsDropdown: React.FunctionComponent = ({workspace}) => { + const [isOpen, setIsOpen] = React.useState(false); + + const onToggleClick = () => { + setIsOpen(!isOpen); + }; + + const onSelect = ( + _event: React.MouseEvent | undefined, + value: string | number | undefined) => { + setIsOpen(false); + if (typeof value === 'string'){ + openEndpoint(value); + } + }; + + const openEndpoint = (port: string) => { + window.open(`workspace/${workspace.namespace}/${workspace.name}/${port}`, '_blank'); + }; + + return ( + setIsOpen(isOpen)} + toggle={(toggleRef: React.Ref) => ( + Connect + + )} + ouiaId="BasicDropdown" + shouldFocusToggleOnSelect + > + + {workspace.podTemplate.endpoints.map((endpoint) => ( + + {endpoint.displayName} + + ))} + + + ); +}; \ No newline at end of file diff --git a/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx b/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx index fbf54b8d..a9b1c6f3 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx @@ -35,6 +35,7 @@ import { buildKindLogoDictionary } from '~/app/actions/WorkspaceKindsActions'; import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds'; import Filter, { FilteredColumn } from 'shared/components/Filter'; import { formatRam } from 'shared/utilities/WorkspaceResources'; +import { EndpointsDropdown } from '~/app/pages/Workspaces/WorkspaceEndpoints'; export const Workspaces: React.FunctionComponent = () => { /* Mocked workspaces, to be removed after fetching info from backend */ @@ -67,6 +68,12 @@ export const Workspaces: React.FunctionComponent = () => { }, ], }, + endpoints: [ + { + displayName: 'JupyterLab', + port: '7777' + } + ], }, options: { imageConfig: 'jupyterlab_scipy_180', @@ -112,6 +119,16 @@ export const Workspaces: React.FunctionComponent = () => { }, ], }, + endpoints: [ + { + displayName: 'JupyterLab', + port: '8888' + }, + { + displayName: 'Spark Master', + port: '9999' + }, + ], }, options: { imageConfig: 'jupyterlab_scipy_180', @@ -461,6 +478,9 @@ export const Workspaces: React.FunctionComponent = () => { 1 hour ago + + + ({ diff --git a/workspaces/frontend/src/shared/types.ts b/workspaces/frontend/src/shared/types.ts index d7857ced..af2f8124 100644 --- a/workspaces/frontend/src/shared/types.ts +++ b/workspaces/frontend/src/shared/types.ts @@ -116,6 +116,10 @@ export interface Workspace { readOnly: boolean; }[]; }; + endpoints: { + displayName: string; + port: string; + }[]; }; options: { imageConfig: string; From 79a5f0c7305750310a4623541e4e3f2ec950981a Mon Sep 17 00:00:00 2001 From: Yael Date: Thu, 23 Jan 2025 22:57:13 +0200 Subject: [PATCH 2/2] feat(ws): Split the Connect button, such that clicking it opens the default (main) endpoint Signed-off-by: Yael --- ...dpoints.tsx => WorkspaceConnectAction.tsx} | 50 ++++++++++++------- .../src/app/pages/Workspaces/Workspaces.tsx | 12 ++--- 2 files changed, 39 insertions(+), 23 deletions(-) rename workspaces/frontend/src/app/pages/Workspaces/{WorkspaceEndpoints.tsx => WorkspaceConnectAction.tsx} (50%) diff --git a/workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx b/workspaces/frontend/src/app/pages/Workspaces/WorkspaceConnectAction.tsx similarity index 50% rename from workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx rename to workspaces/frontend/src/app/pages/Workspaces/WorkspaceConnectAction.tsx index dcc69c0c..9240a7d4 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/WorkspaceEndpoints.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/WorkspaceConnectAction.tsx @@ -1,51 +1,67 @@ -import React from "react"; +import React from 'react'; import { Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement, -} from "@patternfly/react-core"; -import { Workspace, WorkspaceState } from "~/shared/types"; + MenuToggleAction, +} from '@patternfly/react-core'; +import { Workspace, WorkspaceState } from '~/shared/types'; -type EndpointsDropdownProps = { +type WorkspaceConnectActionProps = { workspace: Workspace; }; -export const EndpointsDropdown: React.FunctionComponent = ({workspace}) => { - const [isOpen, setIsOpen] = React.useState(false); +export const WorkspaceConnectAction: React.FunctionComponent = ({ + workspace, +}) => { + const [open, setIsOpen] = React.useState(false); const onToggleClick = () => { - setIsOpen(!isOpen); + setIsOpen(!open); }; const onSelect = ( _event: React.MouseEvent | undefined, - value: string | number | undefined) => { + value: string | number | undefined, + ) => { setIsOpen(false); - if (typeof value === 'string'){ + if (typeof value === 'string') { openEndpoint(value); } }; + const onClickConnect = () => { + openEndpoint(workspace.podTemplate.endpoints[0].port); + }; + const openEndpoint = (port: string) => { - window.open(`workspace/${workspace.namespace}/${workspace.name}/${port}`, '_blank'); + window.open(`workspace/${workspace.namespace}/${workspace.name}/${port}`, '_blank'); }; return ( setIsOpen(isOpen)} toggle={(toggleRef: React.Ref) => ( Connect - + isExpanded={open} + isFullWidth + isDisabled={workspace.status.state !== WorkspaceState.Running} + splitButtonItems={[ + + Connect + , + ]} + /> )} ouiaId="BasicDropdown" shouldFocusToggleOnSelect @@ -59,4 +75,4 @@ export const EndpointsDropdown: React.FunctionComponent ); -}; \ No newline at end of file +}; diff --git a/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx b/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx index a9b1c6f3..f1d20e14 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx @@ -33,9 +33,9 @@ import { ExpandedWorkspaceRow } from '~/app/pages/Workspaces/ExpandedWorkspaceRo import DeleteModal from '~/shared/components/DeleteModal'; import { buildKindLogoDictionary } from '~/app/actions/WorkspaceKindsActions'; import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds'; +import { WorkspaceConnectAction } from '~/app/pages/Workspaces/WorkspaceConnectAction'; import Filter, { FilteredColumn } from 'shared/components/Filter'; import { formatRam } from 'shared/utilities/WorkspaceResources'; -import { EndpointsDropdown } from '~/app/pages/Workspaces/WorkspaceEndpoints'; export const Workspaces: React.FunctionComponent = () => { /* Mocked workspaces, to be removed after fetching info from backend */ @@ -71,8 +71,8 @@ export const Workspaces: React.FunctionComponent = () => { endpoints: [ { displayName: 'JupyterLab', - port: '7777' - } + port: '7777', + }, ], }, options: { @@ -122,11 +122,11 @@ export const Workspaces: React.FunctionComponent = () => { endpoints: [ { displayName: 'JupyterLab', - port: '8888' + port: '8888', }, { displayName: 'Spark Master', - port: '9999' + port: '9999', }, ], }, @@ -479,7 +479,7 @@ export const Workspaces: React.FunctionComponent = () => { - +