Skip to content

Commit

Permalink
Update styles for VEP submissions list, and add confirmation dialog f…
Browse files Browse the repository at this point in the history
…or submission deletion (#1158)

- Updated styles for VEP submissions in the list such that they can shrink gracefully to smaller screen widths
- In the list of VEP submissions, only show the submission id if it has been issued by the server,
   rather than temporarily assigned on the client (i.e. only if submission has a permanent server-side submission status)
- Removed the top grey bar in VEP species selector view
- Updated scrolling of VEP submissions list page (only the main content of the view, under the grey top bar,
  should be scrollable)
- Added deletion confirmation dialog
  • Loading branch information
azangru authored Aug 5, 2024
1 parent f090f3a commit 70d0287
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 45 deletions.
6 changes: 6 additions & 0 deletions src/content/app/tools/vep/VepPageContent.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@
grid-template-rows: auto max-content 1fr;
height: 100%;
}

.speciesSelectorGrid {
display: grid;
grid-template-rows: auto 1fr; /* No grey bar at the top of the species selector */
height: 100%;
}
19 changes: 18 additions & 1 deletion src/content/app/tools/vep/VepPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ import { NotFoundErrorScreen } from 'src/shared/components/error-screen';
import styles from './VepPageContent.module.css';

const VepPageContent = () => {
return (
<Routes>
<Route path="species-selector" element={<SpeciesSelectorWrapper />} />
<Route path="*" element={<MainWrapper />} />
</Routes>
);
};

const SpeciesSelectorWrapper = () => {
return (
<div className={styles.speciesSelectorGrid}>
<VepAppBar />
<VepSpeciesSelector />
</div>
);
};

const MainWrapper = () => {
return (
<div className={styles.grid}>
<VepAppBar />
Expand All @@ -40,7 +58,6 @@ const Main = () => {
return (
<Routes>
<Route index={true} element={<VepForm />} />
<Route path="species-selector" element={<VepSpeciesSelector />} />
<Route
path="unviewed-submissions"
element={<div>List of unviewed submissions</div>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ for ListedVepSubmission, and for the VEP results

.container {
display: grid;
grid-template-columns: [title] 300px [submission-id] 200px [rerun] auto [submission-date] auto [controls] 1fr; /* the grid will need updating */
grid-template-columns: [title] minmax(auto, 300px) [submission-id] 200px [rerun] auto [submission-date] auto [controls] 1fr; /* the grid will need updating */
align-items: center;
column-gap: var(--standard-gutter);
padding-left: var(--standard-gutter);
Expand Down Expand Up @@ -54,3 +54,19 @@ for ListedVepSubmission, and for the VEP results
font-size: 12px;
font-weight: var(--font-weight-light);
}

.deletionConfirmationContainer {
display: flex;
justify-content: right;
padding-bottom: 12px;
}

.deletionConfirmation {
display: flex;
align-items: center;
column-gap: var(--standard-gutter);
}

.deletionConfirmationMessage {
color: var(--color-red);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { useState } from 'react';
import classNames from 'classnames';
import noop from 'lodash/noop';

Expand All @@ -23,13 +24,17 @@ import { getFormattedDateTime } from 'src/shared/helpers/formatters/dateFormatte

import { deleteSubmission } from 'src/content/app/tools/vep/state/vep-submissions/vepSubmissionsSlice';

import {
serverSideSubmissionStatuses,
type VepSubmission
} from 'src/content/app/tools/vep/types/vepSubmission';

import { PrimaryButton } from 'src/shared/components/button/Button';
import TextButton from 'src/shared/components/text-button/TextButton';
import ButtonLink from 'src/shared/components/button-link/ButtonLink';
import DeleteButton from 'src/shared/components/delete-button/DeleteButton';
import DownloadButton from 'src/shared/components/download-button/DownloadButton';

import type { VepSubmission } from 'src/content/app/tools/vep/types/vepSubmission';

import styles from './VepSubmissionHeader.module.css';

type Props = {
Expand All @@ -42,47 +47,101 @@ type Props = {

const VepSubmissionHeader = (props: Props) => {
const { submission } = props;
const [isDeleting, setIsDeleting] = useState(false);
const submissionTime = submission.submittedAt
? getFormattedDateTime(new Date(submission.submittedAt))
: null;

const toggleDeletionConfirmation = () => {
setIsDeleting(!isDeleting);
};

return (
<div className={styles.container}>
<div className={styles.light}>Vep analysis</div>
<div className={styles.submissionId}>
<span className={classNames(styles.labelLeft, styles.smallLight)}>
Submission
</span>
{submission.id}
<>
<div className={styles.container}>
<div className={styles.light}>Vep analysis</div>
<div className={styles.submissionId}>
{hasServerSideSubmissionId(submission) && (
<>
<span className={classNames(styles.labelLeft, styles.smallLight)}>
Submission
</span>
{submission.id}
</>
)}
</div>
<div className={styles.rerun}>
<TextButton onClick={noop}>Edit/rerun</TextButton>
</div>
<div className={styles.submissionDate}>
{submissionTime} <span className={styles.timezone}>GMT</span>
</div>
<ControlButtons
{...props}
isDeleting={isDeleting}
onDelete={toggleDeletionConfirmation}
/>
</div>
<div className={styles.rerun}>
<TextButton onClick={noop}>Edit/rerun</TextButton>
</div>
<div className={styles.submissionDate}>
{submissionTime} <span className={styles.timezone}>GMT</span>
</div>
<ControlButtons {...props} />
</div>
{isDeleting && (
<div className={styles.deletionConfirmationContainer}>
<DeletionConfirmation
{...props}
onCancel={toggleDeletionConfirmation}
/>
</div>
)}
</>
);
};

const ControlButtons = (props: Props) => {
const { submission } = props;
const dispatch = useAppDispatch();
const hasServerSideSubmissionId = (submission: { status: string }) => {
// Only submissions with a server-side status will have an id assigned by the server
// (temporary client-side ids aren't helpful for users; so there's no point in displaying those)
return (serverSideSubmissionStatuses as readonly string[]).includes(
submission.status
);
};

const ControlButtons = (
props: Props & {
isDeleting: boolean;
onDelete: () => void;
}
) => {
const { submission, isDeleting, onDelete } = props;

const canGetResults = submission.status === 'SUCCEEDED';

return (
<div className={styles.controls}>
<DeleteButton onClick={onDelete} disabled={isDeleting} />
<DownloadButton onClick={noop} disabled={isDeleting || !canGetResults} />
<ButtonLink isDisabled={isDeleting || !canGetResults} to="/">
Results
</ButtonLink>
</div>
);
};

const DeletionConfirmation = (
props: Props & {
onCancel: () => void;
}
) => {
const { submission, onCancel } = props;
const dispatch = useAppDispatch();

const onDelete = () => {
dispatch(deleteSubmission({ submissionId: submission.id }));
};

return (
<div className={styles.controls}>
<DeleteButton onClick={onDelete} />
<DownloadButton onClick={noop} disabled={!canGetResults} />
<ButtonLink isDisabled={!canGetResults} to="/">
Results
</ButtonLink>
<div className={styles.deletionConfirmation}>
<span className={styles.deletionConfirmationMessage}>
Delete this submisison?
</span>
<PrimaryButton onClick={onDelete}>Delete</PrimaryButton>
<TextButton onClick={onCancel}>Do not delete</TextButton>
</div>
);
};
Expand Down
27 changes: 17 additions & 10 deletions src/content/app/tools/vep/types/vepSubmission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,29 @@ import type { CommittedItem } from 'src/content/app/species-selector/types/commi

export type VepSelectedSpecies = Omit<CommittedItem, 'isEnabled'>;

type ClientSideSubmissionStatus =
| 'NOT_SUBMITTED' // initial status of a submission while it is being prepared by the user
| 'SUBMITTING' // during the time between user clicking the submit button, and the submission being accepted by the backend
| 'UNSUCCESSFUL_SUBMISSION'; // some unspecified (most likely network timeout) error happened during submission
export const clientSideSubmissionStatuses = [
'NOT_SUBMITTED', // initial status of a submission while it is being prepared by the user
'SUBMITTING', // during the time between user clicking the submit button, and the submission being accepted by the backend
'UNSUCCESSFUL_SUBMISSION' // some unspecified (most likely network timeout) error happened during submission
] as const;

/**
* Note: Seqera also has an UNKNOWN status, which it explains as "an indeterminate status";
* but we don't know either when it can occur or what to do with it. Currently the expectation is
* that if it ever occurs, tools api will report this submission as failed.
*/
type ServerSideSubmissionStatus =
| 'SUBMITTED' // Pending execution
| 'RUNNING'
| 'SUCCEEDED'
| 'FAILED' // Executed, but at least one task failed with a terminate error strategy
| 'CANCELLED'; // Stopped manually during execution
export const serverSideSubmissionStatuses = [
'SUBMITTED', // Pending execution
'RUNNING',
'SUCCEEDED',
'FAILED', // Executed, but at least one task failed with a terminate error strategy
'CANCELLED' // Stopped manually during execution
] as const;

export type ClientSideSubmissionStatus =
(typeof clientSideSubmissionStatuses)[number];
export type ServerSideSubmissionStatus =
(typeof serverSideSubmissionStatuses)[number];

export type SubmissionStatus =
| ClientSideSubmissionStatus
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
.container {
/* This container takes full width of the page and enables scrolling,
with the scrollbar at the right edge of the window */
.scrollContainer {
height: 100%;
overflow-y: auto;
}

/* This container ensures the maximum width of the content */
.container {
padding-left: var(--double-standard-gutter);
padding-right: var(--standard-gutter);
padding-top: 20px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ const VepSubmissions = () => {
const unviewedVepSubmissions = useAppSelector(getUnviewedVepSubmissions);

return (
<div className={styles.container}>
{unviewedVepSubmissions.map((submission) => (
<ListedVepSubmission key={submission.id} submission={submission} />
))}
<div className={styles.scrollContainer}>
<div className={styles.container}>
{unviewedVepSubmissions.map((submission) => (
<ListedVepSubmission key={submission.id} submission={submission} />
))}
</div>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

.head {
display: grid;
grid-template-columns: [title] 300px 1fr; /* the grid will need updating */
grid-template-columns: [title] 300px 1fr;
padding-left: var(--standard-gutter);
padding-bottom: 12px;
}
Expand All @@ -31,7 +31,7 @@
}

.bodyAccepted:has(.submissionName) {
grid-template-columns: [species-name] 300px [input-summary] 292px [submission-name] 1fr [status] auto;
grid-template-columns: [species-name] 300px [input-summary] minmax(20%, 292px) [submission-name] minmax(200px, 1fr) [status] auto;
}

.spinner {
Expand All @@ -55,6 +55,7 @@

.inputSummary {
grid-column: input-summary;
word-wrap: break-word;
}

.submissionName {
Expand Down

0 comments on commit 70d0287

Please sign in to comment.