Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task/WP-673: Interactive Modal Redesign #1456

Merged
merged 16 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/modules/_hooks/src/workspace/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from './useGetJobs';
export * from './usePostJobs';
export * from './types';
export * from './useGetAllocations';
export * from './useInteractiveModalContext';
20 changes: 20 additions & 0 deletions client/modules/_hooks/src/workspace/useInteractiveModalContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { createContext, useContext } from 'react';

type TInteractiveModalDetails = {
show: boolean;
interactiveSessionLink?: string;
message?: string;
openedBySubmit?: boolean;
};

export type TInteractiveModalContext = [
TInteractiveModalDetails,
React.Dispatch<React.SetStateAction<TInteractiveModalDetails>>
];

export const InteractiveModalContext =
createContext<TInteractiveModalContext | null>(null);

export const useInteractiveModalContext = () => {
return useContext(InteractiveModalContext);
};
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,9 @@ export const AppsSubmissionDetails: React.FC<{
htmlType="submit"
disabled={!isValid}
loading={isSubmitting}
style={{ width: 120 }}
style={{ width: 130 }}
>
Submit Job
{definition.notes.isInteractive ? 'Launch Session' : 'Submit Job'}
</PrimaryButton>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
TJobBody,
useGetAllocationsSuspense,
TTapisJob,
useInteractiveModalContext,
TInteractiveModalContext,
} from '@client/hooks';
import { AppsSubmissionDetails } from '../AppsSubmissionDetails/AppsSubmissionDetails';
import { AppsWizard } from '../AppsWizard/AppsWizard';
Expand Down Expand Up @@ -73,6 +75,9 @@
data: TTapisJob;
};

const [, setInteractiveModalDetails] =
useInteractiveModalContext() as TInteractiveModalContext;

const { definition, license, defaultSystemNeedsKeys } = app;

const defaultStorageHost = defaultStorageSystem.host;
Expand Down Expand Up @@ -129,7 +134,7 @@
),
outputs: outputs.defaults,
}),
[definition, jobData]

Check warning on line 137 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useMemo has missing dependencies: 'appId', 'appVersion', 'configuration.defaults', 'fileInputs.defaults', 'outputs.defaults', and 'parameterSet.defaults'. Either include them or remove the dependency array
);

let missingAllocation: string | undefined;
Expand Down Expand Up @@ -219,7 +224,7 @@

const initialSteps = useMemo(
() => getSteps(),
[

Check warning on line 227 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useMemo has a missing dependency: 'getSteps'. Either include it or remove the dependency array
fileInputs.fields,
parameterSet.fields,
configuration.fields,
Expand All @@ -241,7 +246,7 @@
const newSteps = getSteps();
setSteps(newSteps);
setCurrent(getInitialCurrentStep(newSteps));
}, [initialValues]);

Check warning on line 249 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useEffect has missing dependencies: 'getInitialCurrentStep', 'getSteps', and 'reset'. Either include them or remove the dependency array

// Queue dependency handler.
const queueValue = watch('configuration.execSystemLogicalQueue');
Expand Down Expand Up @@ -289,7 +294,7 @@
configuration: updatedFields,
}));
}
}, [queueValue, setValue]);

Check warning on line 297 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook React.useEffect has missing dependencies: 'allocations', 'definition', 'execSystems', and 'getValues'. Either include them or remove the dependency array

// TODO: DES-2916: Use Zod's superRefine feature instead of manually updating schema and tracking schema changes.
React.useEffect(() => {
Expand Down Expand Up @@ -328,7 +333,7 @@
};

setSteps(updatedSteps);
}, [fields]);

Check warning on line 336 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useEffect has a missing dependency: 'steps'. Either include it or remove the dependency array

// next step transition does not block on invalid fields
const handleNextStep = useCallback(async () => {
Expand All @@ -338,11 +343,11 @@
await methods.trigger(stepFields);
const nextPage = steps[current].nextPage;
nextPage && setCurrent(nextPage);
}, [current, methods]);

Check warning on line 346 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useCallback has missing dependencies: 'fieldValues' and 'steps'. Either include them or remove the dependency array
const handlePreviousStep = useCallback(() => {
const prevPage = steps[current].prevPage;
prevPage && setCurrent(prevPage);
}, [current]);

Check warning on line 350 in client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx

View workflow job for this annotation

GitHub Actions / React_NX_linting

React Hook useCallback has a missing dependency: 'steps'. Either include it or remove the dependency array
const {
mutate: submitJob,
isPending,
Expand All @@ -368,6 +373,9 @@
setPushKeysSystem(submitResult.execSys);
} else if (isSuccess) {
reset(initialValues);
if (definition.notes.isInteractive) {
setInteractiveModalDetails({ show: true, openedBySubmit: true });
}
}
}, [submitResult]);

Expand Down Expand Up @@ -516,20 +524,22 @@

return (
<>
{submitResult && !submitResult.execSys && (
<Alert
message={
<>
Job submitted successfully. Monitor its progress in{' '}
<NavLink to={'/history'}>Job Status</NavLink>.
</>
}
type="success"
closable
showIcon
style={{ marginBottom: '1rem' }}
/>
)}
{submitResult &&
!submitResult.execSys &&
!definition.notes.isInteractive && (
<Alert
message={
<>
Job submitted successfully. Monitor its progress in{' '}
<NavLink to={'/history'}>Job Status</NavLink>.
</>
}
type="success"
closable
showIcon
style={{ marginBottom: '1rem' }}
/>
)}
{missingAllocation && (
<Alert
message={
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
.session-modal-header {
background-color: #f4f4f4;
h5 {
font-weight: normal;
}
}

.session-modal-body {
display: flex;
flex-direction: column;
margin-bottom: 25px;
min-height: 225px;
& > * {
margin: 0.4rem;
}
Expand All @@ -17,3 +12,7 @@
color: grey;
font-style: italic;
}

.icon {
margin-left: 10px;
}
Original file line number Diff line number Diff line change
@@ -1,41 +1,82 @@
import { Modal } from 'antd';
import React from 'react';
import { PrimaryButton } from '@client/common-components';
import { Modal } from 'antd';
import { PrimaryButton, Icon } from '@client/common-components';
import {
useInteractiveModalContext,
TInteractiveModalContext,
} from '@client/hooks';
import styles from './InteractiveSessionModal.module.css';

export const InteractiveSessionModal: React.FC<{
isOpen: boolean;
interactiveSessionLink: string;
message?: string;
onCancel: VoidFunction;
}> = ({ isOpen, interactiveSessionLink, message, onCancel }) => {
export const InteractiveSessionModal = () => {
const [interactiveModalDetails, setInteractiveModalDetails] =
useInteractiveModalContext() as TInteractiveModalContext;

const { interactiveSessionLink, message, openedBySubmit, show } =
interactiveModalDetails;

return (
<Modal
title={<h2>Open Session</h2>}
width="500px"
open={isOpen}
footer={
<PrimaryButton href={interactiveSessionLink} target="_blank">
Connect
</PrimaryButton>
title={
<h3>
Interactive Session is {interactiveSessionLink ? 'Ready' : 'Queueing'}
</h3>
}
width="650px"
open={show}
footer={null}
onCancel={() =>
setInteractiveModalDetails({
show: false,
})
}
onCancel={onCancel}
>
<div className={styles['session-modal-body']}>
<span>
Click the button below to connect to the interactive session.
</span>
<div style={{ alignSelf: 'center' }}>
<PrimaryButton
href={interactiveSessionLink}
target="_blank"
loading={!interactiveSessionLink}
style={{ width: 150, margin: '25px 0' }}
size="large"
>
Connect
{interactiveSessionLink && (
<Icon
className={`ds-icon-New-Tab ${styles.icon}`}
label="Connect"
/>
)}
</PrimaryButton>
</div>
{openedBySubmit && !interactiveSessionLink && (
<span>
While you wait, you can either:
<ul>
<li>Keep this modal open and wait to connect.</li>
<li>
Close this window and wait for a notification via{' '}
<strong>Job Status</strong>.
</li>
</ul>
</span>
)}
{message && <b>{message}</b>}
<span>To end the job, quit the application within the session.</span>
<span>
Files may take some time to appear in the output location after the
job has ended.
</span>
<span className={styles.url}>
For security purposes, this is the URL that the connect button will
open:
</span>
<span className={styles.url}>{interactiveSessionLink}</span>
{interactiveSessionLink && (
<>
<span>
To end the job, quit the application within the session.
</span>
<span>
Files may take some time to appear in the output location after
the job has ended.
</span>
<span className={styles.url}>
For security purposes, this is the URL that the connect button
will open:
</span>
<span className={styles.url}>{interactiveSessionLink}</span>
</>
)}
</div>
</Modal>
);
Expand Down
30 changes: 14 additions & 16 deletions client/modules/workspace/src/JobsDetailModal/JobsDetailModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export const JobsDetailModalBody: React.FC<{
(isInteractiveJob(jobData) ? (
<JobActionButton
uuid={jobData.uuid}
title="Resubmit Job"
title="Relaunch Job"
operation="resubmitJob"
type="primary"
/>
Expand Down Expand Up @@ -296,21 +296,19 @@ export const JobsDetailModal: React.FC<{ uuid: string }> = ({ uuid }) => {
<Modal
className={`${styles.root} job-history-modal`}
title={
<>
<header>
Job Detail: {uuid}
{jobData && (
<dl className={styles['header-details']}>
<dt>Job UUID: </dt>
<dd>{jobData.uuid}</dd>
<dt>Application: </dt>
<dd>{JSON.parse(jobData.notes).label || jobData.appId}</dd>
<dt>System: </dt>
<dd>{jobData.execSystemId}</dd>
</dl>
)}
</header>
</>
<header>
Job Detail: {uuid}
{jobData && (
<dl className={styles['header-details']}>
<dt>Job UUID: </dt>
<dd>{jobData.uuid}</dd>
<dt>Application: </dt>
<dd>{JSON.parse(jobData.notes).label || jobData.appId}</dd>
<dt>System: </dt>
<dd>{jobData.execSystemId}</dd>
</dl>
)}
</header>
}
width="60%"
open={isModalOpen}
Expand Down
32 changes: 15 additions & 17 deletions client/modules/workspace/src/JobsListing/JobsListing.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useState, useEffect } from 'react';
import React, { useMemo, useEffect } from 'react';
import useWebSocket from 'react-use-websocket';
import { TableProps, Row, Flex, Button as AntButton } from 'antd';
import type { ButtonSize } from 'antd/es/button';
Expand All @@ -13,6 +13,8 @@ import {
TJobPostOperations,
useReadNotifications,
TGetNotificationsResponse,
useInteractiveModalContext,
TInteractiveModalContext,
} from '@client/hooks';
import {
JobsListingTable,
Expand All @@ -26,7 +28,6 @@ import {
isInteractiveJob,
isTerminalState,
} from '../utils';
import { InteractiveSessionModal } from '../InteractiveSessionModal';
import styles from './JobsListing.module.css';
import { formatDateTimeFromValue } from '../utils/timeFormat';
import { JobsReuseInputsButton } from '../JobsReuseInputsButton/JobsReuseInputsButton';
Expand Down Expand Up @@ -59,16 +60,23 @@ export const JobActionButton: React.FC<{

const InteractiveSessionButtons: React.FC<{
uuid: string;
interactiveSessionLink: string;
interactiveSessionLink?: string;
message?: string;
}> = ({ uuid, interactiveSessionLink, message }) => {
const [interactiveModalState, setInteractiveModalState] = useState(false);
const [, setInteractiveModalDetails] =
useInteractiveModalContext() as TInteractiveModalContext;

return (
<>
<SecondaryButton
size="small"
onClick={() => setInteractiveModalState(true)}
onClick={() =>
setInteractiveModalDetails({
show: true,
interactiveSessionLink,
message,
})
}
>
Open
</SecondaryButton>
Expand All @@ -78,12 +86,6 @@ const InteractiveSessionButtons: React.FC<{
title="End"
size="small"
/>
<InteractiveSessionModal
isOpen={interactiveModalState}
interactiveSessionLink={interactiveSessionLink}
message={message}
onCancel={() => setInteractiveModalState(false)}
/>
</>
);
};
Expand Down Expand Up @@ -175,7 +177,7 @@ export const JobsListing: React.FC<Omit<TableProps, 'columns'>> = ({
<JobActionButton
uuid={job.uuid}
operation="resubmitJob"
title="Resubmit"
title="Relaunch"
size="small"
/>
) : (
Expand Down Expand Up @@ -247,9 +249,5 @@ export const JobsListing: React.FC<Omit<TableProps, 'columns'>> = ({
[interactiveSessionNotifs]
);

return (
<>
<JobsListingTable columns={columns} {...tableProps} />
</>
);
return <JobsListingTable columns={columns} {...tableProps} />;
};
Loading
Loading