Skip to content

Commit

Permalink
feat(ws): Notebooks 2.0 // Frontend // Workspaces table // Workspace …
Browse files Browse the repository at this point in the history
…redirect status column kubeflow#147

Signed-off-by: root <root@C-PF3RRRR6.>
  • Loading branch information
root authored and root committed Feb 3, 2025
1 parent 055150b commit 6e4a42d
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 15 deletions.
32 changes: 32 additions & 0 deletions workspaces/frontend/src/app/actions/WorkspaceKindsActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,35 @@ export function buildKindLogoDictionary(workspaceKinds: WorkspaceKind[] | []): K
}
return kindLogoDict;
}

type WorkspaceRedirectStatus = Record<
string,
{ to: string; message: string; level: string } | null
>;


/**
* Builds a dictionary of workspace kinds to redirect statuses.
* @param {WorkspaceKind[]} workspaceKinds - The list of workspace kinds.
* @returns {WorkspaceRedirectStatus} A dictionary with kind names as keys and redirect status objects as values.
*/
export function buildWorkspaceRedirectStatus(
workspaceKinds: WorkspaceKind[] | []
): WorkspaceRedirectStatus {
const workspaceRedirectStatus: WorkspaceRedirectStatus = {};
for (const workspaceKind of workspaceKinds) {
// Loop through the `values` array inside `imageConfig`
const redirect = workspaceKind.podTemplate?.options?.imageConfig?.values?.find(
(value) => value.redirect
)?.redirect;
// If redirect exists, extract the necessary properties
workspaceRedirectStatus[workspaceKind.name] = redirect
? {
to: redirect.to,
message: redirect.message.text,
level: redirect.message.level,
}
: null;
}
return workspaceRedirectStatus;
}
109 changes: 94 additions & 15 deletions workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ import {
ActionsColumn,
IActions,
} from '@patternfly/react-table';
import {
InfoCircleIcon,
ExclamationTriangleIcon,
TimesCircleIcon,
QuestionCircleIcon,
CodeIcon,
} from '@patternfly/react-icons';
import { useState } from 'react';
import { CodeIcon } from '@patternfly/react-icons';
import { Workspace, WorkspacesColumnNames, WorkspaceState } from '~/shared/types';
import { WorkspaceDetails } from '~/app/pages/Workspaces/Details/WorkspaceDetails';
import { ExpandedWorkspaceRow } from '~/app/pages/Workspaces/ExpandedWorkspaceRow';
import DeleteModal from '~/shared/components/DeleteModal';
import { buildKindLogoDictionary } from '~/app/actions/WorkspaceKindsActions';
import {
buildKindLogoDictionary,
buildWorkspaceRedirectStatus,
} from '~/app/actions/WorkspaceKindsActions';
import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds';
import Filter, { FilteredColumn } from 'shared/components/Filter';
import { formatRam } from 'shared/utilities/WorkspaceResources';
Expand Down Expand Up @@ -88,6 +97,10 @@ export const Workspaces: React.FunctionComponent = () => {
state: WorkspaceState.Paused,
stateMessage: 'It is paused.',
},
redirectStatus: {
level: 'Info',
text: 'This is informational', // Tooltip text
},
},
{
name: 'My Other Jupyter Notebook',
Expand Down Expand Up @@ -133,15 +146,30 @@ export const Workspaces: React.FunctionComponent = () => {
state: WorkspaceState.Running,
stateMessage: 'It is running.',
},
redirectStatus: {
level: 'Danger',
text: 'This is dangerous',
},
},
];

const [workspaceKinds] = useWorkspaceKinds();
let kindLogoDict: Record<string, string> = {};
kindLogoDict = buildKindLogoDictionary(workspaceKinds);

let workspaceRedirectStatus: Record<
string,
{ to: string; message: string; level: string } | null
> = {}; // Initialize the redirect status dictionary
workspaceRedirectStatus = buildWorkspaceRedirectStatus(workspaceKinds); // Populate the dictionary

console.log('Work Space Kinds:', workspaceKinds);
console.log('Kind Logo Dictionary:', kindLogoDict);
console.log('Workspace Redirect Status:', workspaceRedirectStatus);

// Table columns
const columnNames: WorkspacesColumnNames = {
redirectStatus: 'Redirect Status',
name: 'Name',
kind: 'Kind',
image: 'Image',
Expand Down Expand Up @@ -234,18 +262,20 @@ export const Workspaces: React.FunctionComponent = () => {
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);

const getSortableRowValues = (workspace: Workspace): (string | number)[] => {
const { name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity } = {
name: workspace.name,
kind: workspace.kind,
image: workspace.options.imageConfig,
podConfig: workspace.options.podConfig,
state: WorkspaceState[workspace.status.state],
homeVol: workspace.podTemplate.volumes.home,
cpu: workspace.cpu,
ram: workspace.ram,
lastActivity: workspace.status.activity.lastActivity,
};
return [name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity];
const { redirectStatus, name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity } =
{
redirectStatus: '',
name: workspace.name,
kind: workspace.kind,
image: workspace.options.imageConfig,
podConfig: workspace.options.podConfig,
state: WorkspaceState[workspace.status.state],
homeVol: workspace.podTemplate.volumes.home,
cpu: workspace.cpu,
ram: workspace.ram,
lastActivity: workspace.status.activity.lastActivity,
};
return [redirectStatus, name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity];
};

let sortedWorkspaces = workspaces;
Expand Down Expand Up @@ -349,6 +379,43 @@ export const Workspaces: React.FunctionComponent = () => {
| 'yellow'
)[] = ['green', 'orange', 'yellow', 'blue', 'red', 'purple'];

// Redirect Status Icons

const getRedirectStatusIcon = (level: string | undefined, message: string) => {
switch (level) {
case 'Info':
return (
<Tooltip content={message}>
<InfoCircleIcon color="blue" aria-hidden="true" />
</Tooltip>
);
case 'Warning':
return (
<Tooltip content={message}>
<ExclamationTriangleIcon color="orange" aria-hidden="true" />
</Tooltip>
);
case 'Danger':
return (
<Tooltip content={message}>
<TimesCircleIcon color="red" aria-hidden="true" />
</Tooltip>
);
case undefined:
return (
<Tooltip content={message}>
<QuestionCircleIcon color="gray" aria-hidden="true" />
</Tooltip>
);
default:
return (
<Tooltip content={`Invalid level: ${level}`}>
<QuestionCircleIcon color="gray" aria-hidden="true" />
</Tooltip>
);
}
};

// Pagination

const [page, setPage] = React.useState(1);
Expand Down Expand Up @@ -404,7 +471,10 @@ export const Workspaces: React.FunctionComponent = () => {
<Tr>
<Th />
{Object.values(columnNames).map((columnName, index) => (
<Th key={`${columnName}-col-name`} sort={getSortParams(index)}>
<Th
key={`${columnName}-col-name`}
sort={columnName !== 'Redirect Status' ? getSortParams(index) : undefined}
>
{columnName}
</Th>
))}
Expand All @@ -427,6 +497,15 @@ export const Workspaces: React.FunctionComponent = () => {
setWorkspaceExpanded(workspace, !isWorkspaceExpanded(workspace)),
}}
/>
<Td dataLabel={columnNames.redirectStatus}>
{workspaceRedirectStatus[workspace.kind]
? getRedirectStatusIcon(
workspaceRedirectStatus[workspace.kind]?.level,
workspaceRedirectStatus[workspace.kind]?.message ||
'No API response available',
)
: getRedirectStatusIcon(undefined, 'No API response available')}
</Td>
<Td dataLabel={columnNames.name}>{workspace.name}</Td>
<Td dataLabel={columnNames.kind}>
{kindLogoDict[workspace.kind] ? (
Expand Down
5 changes: 5 additions & 0 deletions workspaces/frontend/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ export interface Workspace {
podConfig: string;
};
status: WorkspaceStatus;
redirectStatus: {
level: "Info" | "Warning" | "Danger";
text: string;
};
}

export type WorkspacesColumnNames = {
Expand All @@ -134,4 +138,5 @@ export type WorkspacesColumnNames = {
cpu: string;
ram: string;
lastActivity: string;
redirectStatus: string;
};

0 comments on commit 6e4a42d

Please sign in to comment.