Skip to content

Commit f22890d

Browse files
authored
feat(ws): Notebooks 2.0 // Frontend // Workspaces table // Workspace redirect status column #147 (#191)
Signed-off-by: Asaad Balum <[email protected]>
1 parent 6d04cff commit f22890d

File tree

3 files changed

+127
-16
lines changed

3 files changed

+127
-16
lines changed

workspaces/frontend/src/app/actions/WorkspaceKindsActions.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,34 @@ export function buildKindLogoDictionary(workspaceKinds: WorkspaceKind[] | []): K
1919
}
2020
return kindLogoDict;
2121
}
22+
23+
type WorkspaceRedirectStatus = Record<
24+
string,
25+
{ to: string; message: string; level: string } | null
26+
>;
27+
28+
/**
29+
* Builds a dictionary of workspace kinds to redirect statuses.
30+
* @param {WorkspaceKind[]} workspaceKinds - The list of workspace kinds.
31+
* @returns {WorkspaceRedirectStatus} A dictionary with kind names as keys and redirect status objects as values.
32+
*/
33+
export function buildWorkspaceRedirectStatus(
34+
workspaceKinds: WorkspaceKind[] | [],
35+
): WorkspaceRedirectStatus {
36+
const workspaceRedirectStatus: WorkspaceRedirectStatus = {};
37+
for (const workspaceKind of workspaceKinds) {
38+
// Loop through the `values` array inside `imageConfig`
39+
const redirect = workspaceKind.podTemplate.options.imageConfig.values.find(
40+
(value) => value.redirect,
41+
)?.redirect;
42+
// If redirect exists, extract the necessary properties
43+
workspaceRedirectStatus[workspaceKind.name] = redirect
44+
? {
45+
to: redirect.to,
46+
message: redirect.message.text,
47+
level: redirect.message.level,
48+
}
49+
: null;
50+
}
51+
return workspaceRedirectStatus;
52+
}

workspaces/frontend/src/app/pages/Workspaces/Workspaces.tsx

Lines changed: 90 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,22 @@ import {
2525
ActionsColumn,
2626
IActions,
2727
} from '@patternfly/react-table';
28+
import {
29+
InfoCircleIcon,
30+
ExclamationTriangleIcon,
31+
TimesCircleIcon,
32+
QuestionCircleIcon,
33+
CodeIcon,
34+
} from '@patternfly/react-icons';
2835
import { useState } from 'react';
29-
import { CodeIcon } from '@patternfly/react-icons';
3036
import { Workspace, WorkspacesColumnNames, WorkspaceState } from '~/shared/types';
3137
import { WorkspaceDetails } from '~/app/pages/Workspaces/Details/WorkspaceDetails';
3238
import { ExpandedWorkspaceRow } from '~/app/pages/Workspaces/ExpandedWorkspaceRow';
3339
import DeleteModal from '~/shared/components/DeleteModal';
34-
import { buildKindLogoDictionary } from '~/app/actions/WorkspaceKindsActions';
40+
import {
41+
buildKindLogoDictionary,
42+
buildWorkspaceRedirectStatus,
43+
} from '~/app/actions/WorkspaceKindsActions';
3544
import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds';
3645
import { WorkspaceConnectAction } from '~/app/pages/Workspaces/WorkspaceConnectAction';
3746
import { WorkspaceStartActionModal } from '~/app/pages/Workspaces/workspaceActions/WorkspaceStartActionModal';
@@ -107,6 +116,10 @@ export const Workspaces: React.FunctionComponent = () => {
107116
state: WorkspaceState.Paused,
108117
stateMessage: 'It is paused.',
109118
},
119+
redirectStatus: {
120+
level: 'Info',
121+
text: 'This is informational', // Tooltip text
122+
},
110123
},
111124
{
112125
name: 'My Other Jupyter Notebook',
@@ -162,15 +175,26 @@ export const Workspaces: React.FunctionComponent = () => {
162175
state: WorkspaceState.Running,
163176
stateMessage: 'It is running.',
164177
},
178+
redirectStatus: {
179+
level: 'Danger',
180+
text: 'This is dangerous',
181+
},
165182
},
166183
];
167184

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

189+
let workspaceRedirectStatus: Record<
190+
string,
191+
{ to: string; message: string; level: string } | null
192+
> = {}; // Initialize the redirect status dictionary
193+
workspaceRedirectStatus = buildWorkspaceRedirectStatus(workspaceKinds); // Populate the dictionary
194+
172195
// Table columns
173196
const columnNames: WorkspacesColumnNames = {
197+
redirectStatus: 'Redirect Status',
174198
name: 'Name',
175199
kind: 'Kind',
176200
image: 'Image',
@@ -266,18 +290,20 @@ export const Workspaces: React.FunctionComponent = () => {
266290
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | null>(null);
267291

268292
const getSortableRowValues = (workspace: Workspace): (string | number)[] => {
269-
const { name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity } = {
270-
name: workspace.name,
271-
kind: workspace.kind,
272-
image: workspace.options.imageConfig,
273-
podConfig: workspace.options.podConfig,
274-
state: WorkspaceState[workspace.status.state],
275-
homeVol: workspace.podTemplate.volumes.home,
276-
cpu: workspace.cpu,
277-
ram: workspace.ram,
278-
lastActivity: workspace.status.activity.lastActivity,
279-
};
280-
return [name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity];
293+
const { redirectStatus, name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity } =
294+
{
295+
redirectStatus: '',
296+
name: workspace.name,
297+
kind: workspace.kind,
298+
image: workspace.options.imageConfig,
299+
podConfig: workspace.options.podConfig,
300+
state: WorkspaceState[workspace.status.state],
301+
homeVol: workspace.podTemplate.volumes.home,
302+
cpu: workspace.cpu,
303+
ram: workspace.ram,
304+
lastActivity: workspace.status.activity.lastActivity,
305+
};
306+
return [redirectStatus, name, kind, image, podConfig, state, homeVol, cpu, ram, lastActivity];
281307
};
282308

283309
let sortedWorkspaces = workspaces;
@@ -436,6 +462,43 @@ export const Workspaces: React.FunctionComponent = () => {
436462
| 'yellow'
437463
)[] = ['green', 'orange', 'yellow', 'blue', 'red', 'purple'];
438464

465+
// Redirect Status Icons
466+
467+
const getRedirectStatusIcon = (level: string | undefined, message: string) => {
468+
switch (level) {
469+
case 'Info':
470+
return (
471+
<Tooltip content={message}>
472+
<InfoCircleIcon color="blue" aria-hidden="true" />
473+
</Tooltip>
474+
);
475+
case 'Warning':
476+
return (
477+
<Tooltip content={message}>
478+
<ExclamationTriangleIcon color="orange" aria-hidden="true" />
479+
</Tooltip>
480+
);
481+
case 'Danger':
482+
return (
483+
<Tooltip content={message}>
484+
<TimesCircleIcon color="red" aria-hidden="true" />
485+
</Tooltip>
486+
);
487+
case undefined:
488+
return (
489+
<Tooltip content={message}>
490+
<QuestionCircleIcon color="gray" aria-hidden="true" />
491+
</Tooltip>
492+
);
493+
default:
494+
return (
495+
<Tooltip content={`Invalid level: ${level}`}>
496+
<QuestionCircleIcon color="gray" aria-hidden="true" />
497+
</Tooltip>
498+
);
499+
}
500+
};
501+
439502
// Pagination
440503

441504
const [page, setPage] = React.useState(1);
@@ -494,7 +557,10 @@ export const Workspaces: React.FunctionComponent = () => {
494557
<Tr>
495558
<Th />
496559
{Object.values(columnNames).map((columnName, index) => (
497-
<Th key={`${columnName}-col-name`} sort={getSortParams(index)}>
560+
<Th
561+
key={`${columnName}-col-name`}
562+
sort={columnName !== 'Redirect Status' ? getSortParams(index) : undefined}
563+
>
498564
{columnName}
499565
</Th>
500566
))}
@@ -517,6 +583,15 @@ export const Workspaces: React.FunctionComponent = () => {
517583
setWorkspaceExpanded(workspace, !isWorkspaceExpanded(workspace)),
518584
}}
519585
/>
586+
<Td dataLabel={columnNames.redirectStatus}>
587+
{workspaceRedirectStatus[workspace.kind]
588+
? getRedirectStatusIcon(
589+
workspaceRedirectStatus[workspace.kind]?.level,
590+
workspaceRedirectStatus[workspace.kind]?.message ||
591+
'No API response available',
592+
)
593+
: getRedirectStatusIcon(undefined, 'No API response available')}
594+
</Td>
520595
<Td dataLabel={columnNames.name}>{workspace.name}</Td>
521596
<Td dataLabel={columnNames.kind}>
522597
{kindLogoDict[workspace.kind] ? (

workspaces/frontend/src/shared/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export interface WorkspaceKind {
3838
pythonVersion: string;
3939
};
4040
hidden: true;
41-
redirect: {
41+
redirect?: {
4242
to: string;
4343
message: {
4444
text: string;
@@ -126,6 +126,10 @@ export interface Workspace {
126126
podConfig: string;
127127
};
128128
status: WorkspaceStatus;
129+
redirectStatus: {
130+
level: 'Info' | 'Warning' | 'Danger';
131+
text: string;
132+
};
129133
}
130134

131135
export type WorkspacesColumnNames = {
@@ -138,4 +142,5 @@ export type WorkspacesColumnNames = {
138142
cpu: string;
139143
ram: string;
140144
lastActivity: string;
145+
redirectStatus: string;
141146
};

0 commit comments

Comments
 (0)