Skip to content

Commit

Permalink
Merge branch 'main' into task/WP-708-unit-tests-for-DatafilesToolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanfranklin authored Oct 17, 2024
2 parents 79c73b0 + a330250 commit a114997
Show file tree
Hide file tree
Showing 18 changed files with 229 additions and 105 deletions.
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,14 @@ If you are on a Mac or a Windows machine, the recommended method is to install
Required variables:

- `DJANGO_DEBUG`: should be set to `True` for development
- `DJANGO_SECRET`: should be changed for production
- `DJANGO_SECRET_KEY`: should be changed for production
- `TAS_*`: should be set to enable direct access to `django.contrib.admin`
- `TAPIS_*`: should be set to enable Tapis API integration (authentication, etc.)
- `RT_*`: should be set to enable ticketing

Make a copy of [rabbitmq.sample.env](conf/env_files/rabbitmq.sample.env)
then rename it to `rabbitmq.env`.

Make a copy of [external_resource_secrets.sample.py](designsafe/settings/external_resource_secrets.sample.py)
and rename it to `external_resource_secrets.py`.

3. Configure ngrok

a. Install [ngrok](https://ngrok.com/docs/getting-started/), and create an ngrok account.
Expand Down
2 changes: 2 additions & 0 deletions client/modules/_hooks/src/workspace/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export type TTapisApp = {
queueFilter?: string[];
hideQueue?: boolean;
hideAllocation?: boolean;
hideMaxMinutes?: boolean;
jobLaunchDescription?: string;
};
uuid: string;
deleted: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { useFormContext, useWatch, FieldValues } from 'react-hook-form';
import { z, ZodTypeAny } from 'zod';
import { TField, fieldDisplayOrder } from '../AppsWizard/AppsFormSchema';
import { PrimaryButton } from '@client/common-components';
import { JobSubmitButton } from '../JobSubmitButton/JobSubmitButton';
import styles from './AppsSubmissionDetails.module.css';
import { TTapisApp } from '@client/hooks';

Expand Down Expand Up @@ -255,14 +255,11 @@ export const AppsSubmissionDetails: React.FC<{
style={itemStyle}
className={styles.root}
extra={
<PrimaryButton
htmlType="submit"
<JobSubmitButton
disabled={!isValid}
loading={isSubmitting}
style={{ width: 130 }}
>
{definition.notes.isInteractive ? 'Launch Session' : 'Submit Job'}
</PrimaryButton>
interactive={definition.notes.isInteractive}
/>
}
/>
</Card>
Expand Down
125 changes: 79 additions & 46 deletions client/modules/workspace/src/AppsSubmissionForm/AppsSubmissionForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { NavLink } from 'react-router-dom';
import { Layout, Form, Col, Row, Alert, Button } from 'antd';
import { Layout, Form, Col, Row, Alert, Button, Space } from 'antd';
import { z } from 'zod';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { zodResolver } from '@hookform/resolvers/zod';
import { JobSubmitButton } from '../JobSubmitButton/JobSubmitButton';
import {
useGetAppsSuspense,
useGetJobSuspense,
Expand Down Expand Up @@ -179,12 +180,14 @@ export const AppsSubmissionForm: React.FC = () => {
type FieldNameUnion = keyof typeof fieldValues;

const getSteps = (): TStep => {
const formSteps: TStep = {
configuration: getConfigurationStep(configuration.fields),
...(definition.notes.isInteractive
? {}
: { outputs: getOutputsStep(outputs.fields) }),
};
const formSteps: TStep = {};

if (configuration.fields && Object.keys(configuration.fields).length) {
formSteps.configuration = getConfigurationStep(configuration.fields);
}
if (!definition.notes.isInteractive) {
formSteps.outputs = getOutputsStep(outputs.fields);
}
if (fileInputs.fields && Object.keys(fileInputs.fields).length) {
formSteps.inputs = getInputsStep(fileInputs.fields);
}
Expand Down Expand Up @@ -222,16 +225,16 @@ export const AppsSubmissionForm: React.FC = () => {
outputs: outputs.fields,
});

const initialSteps = useMemo(
() => getSteps(),
[
fileInputs.fields,
parameterSet.fields,
configuration.fields,
outputs.fields,
fields,
]
);
const initialSteps = useMemo(() => {
const steps = getSteps();
return Object.keys(steps).length > 0 ? steps : {};
}, [
fileInputs.fields,
parameterSet.fields,
configuration.fields,
outputs.fields,
fields,
]);

const getInitialCurrentStep = (steps: TStep) => {
if (steps.inputs) return 'inputs';
Expand Down Expand Up @@ -316,23 +319,25 @@ export const AppsSubmissionForm: React.FC = () => {
}

// Note: currently configuration is the only
// step that needs. This can be more generic
// step that needs update. This can be more generic
// in future if the fields shape is same between
// Step and Submission Detail View (mostly related to env vars)
useEffect(() => {
const updatedConfigurationStep = getConfigurationStep(
fields.configuration as { [key: string]: TField }
);
if (configuration.fields && Object.keys(configuration.fields).length) {
const updatedConfigurationStep = getConfigurationStep(
fields.configuration as { [key: string]: TField }
);

const updatedSteps: TStep = {
...steps,
configuration: {
...steps.configuration,
...updatedConfigurationStep,
},
};
const updatedSteps: TStep = {
...steps,
configuration: {
...steps.configuration,
...updatedConfigurationStep,
},
};

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

// next step transition does not block on invalid fields
Expand Down Expand Up @@ -615,23 +620,51 @@ export const AppsSubmissionForm: React.FC = () => {
>
<fieldset disabled={readOnly}>
<Row gutter={[64, 16]} align="top">
<Col span={14}>
<AppsWizard
step={steps[current]}
handlePreviousStep={handlePreviousStep}
handleNextStep={handleNextStep}
/>
</Col>
<Col span={10}>
<AppsSubmissionDetails
schema={schema}
fields={fields}
isSubmitting={isPending}
current={current}
setCurrent={setCurrent}
definition={definition}
/>
</Col>
{Object.keys(steps || {}).length === 0 ? (
<Col style={{ marginTop: '32px', marginLeft: '32px' }}>
<Space direction="vertical" size="large">
<div>
{isSuccess ? (
<span>
Session has been launched. You can view status in{' '}
<strong>Job Status</strong>.
</span>
) : (
definition.notes.jobLaunchDescription ??
'This job is pre-configured. No input is necessary to submit the job.'
)}
</div>
<div>
<JobSubmitButton
loading={isPending}
interactive={definition.notes.isInteractive}
disabled={isPending || isSuccess}
success={isSuccess}
/>
</div>
</Space>
</Col>
) : (
<>
<Col span={14}>
<AppsWizard
step={steps[current]}
handlePreviousStep={handlePreviousStep}
handleNextStep={handleNextStep}
/>
</Col>
<Col span={10}>
<AppsSubmissionDetails
schema={schema}
fields={fields}
isSubmitting={isPending}
current={current}
setCurrent={setCurrent}
definition={definition}
/>
</Col>
</>
)}
</Row>
</fieldset>
</Form>
Expand Down
43 changes: 25 additions & 18 deletions client/modules/workspace/src/AppsWizard/AppsFormSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,13 @@ export const getConfigurationSchema = (
);
}

configurationSchema['maxMinutes'] = getMaxMinutesValidation(
definition,
queue
);
if (!definition.notes.hideMaxMinutes) {
configurationSchema['maxMinutes'] = getMaxMinutesValidation(
definition,
queue
);
}

if (!definition.notes.hideNodeCountAndCoresPerNode) {
configurationSchema['nodeCount'] = getNodeCountValidation(
definition,
Expand Down Expand Up @@ -216,18 +219,20 @@ export const getConfigurationFields = (
};
}

configurationFields['maxMinutes'] = {
description: `The maximum number of minutes you expect this job to run for. Maximum possible is ${getQueueMaxMinutes(
definition,
defaultExecSystem,
queue?.name
)} minutes. After this amount of time your job will end. Shorter run times result in shorter queue wait times.`,
label: 'Maximum Job Runtime (minutes)',
name: 'configuration.maxMinutes',
key: 'configuration.maxMinutes',
required: true,
type: 'number',
};
if (!definition.notes.hideMaxMinutes) {
configurationFields['maxMinutes'] = {
description: `The maximum number of minutes you expect this job to run for. Maximum possible is ${getQueueMaxMinutes(
definition,
defaultExecSystem,
queue?.name
)} minutes. After this amount of time your job will end. Shorter run times result in shorter queue wait times.`,
label: 'Maximum Job Runtime (minutes)',
name: 'configuration.maxMinutes',
key: 'configuration.maxMinutes',
required: true,
type: 'number',
};
}

if (!definition.notes.hideNodeCountAndCoresPerNode) {
configurationFields['nodeCount'] = {
Expand Down Expand Up @@ -509,8 +514,10 @@ const FormSchema = (
: '';
}

appFields.configuration.defaults['maxMinutes'] =
definition.jobAttributes.maxMinutes;
if (!definition.notes.hideMaxMinutes) {
appFields.configuration.defaults['maxMinutes'] =
definition.jobAttributes.maxMinutes;
}

if (!definition.notes.hideNodeCountAndCoresPerNode) {
appFields.configuration.defaults['nodeCount'] =
Expand Down
21 changes: 21 additions & 0 deletions client/modules/workspace/src/JobSubmitButton/JobSubmitButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { PrimaryButton } from '@client/common-components';

export const JobSubmitButton: React.FC<{
loading: boolean;
interactive: boolean | undefined;
disabled?: boolean;
success?: boolean;
}> = ({ loading, interactive, disabled = false, success = false }) => {
return (
<PrimaryButton
disabled={disabled}
htmlType="submit"
loading={loading}
style={{ width: 150 }}
>
{interactive ? 'Launch Session' : 'Submit Job'}
{success && <i className="fa fa-check" style={{ marginLeft: 5 }} />}
</PrimaryButton>
);
};
16 changes: 9 additions & 7 deletions client/modules/workspace/src/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ const Notifications = () => {
const handleNotification = (notification: TJobStatusNotification) => {
switch (notification.event_type) {
case 'interactive_session_ready':
setInteractiveModalDetails({
...interactiveModalDetails,
interactiveSessionLink: notification.action_link,
message: notification.message,
});
if (interactiveModalDetails.show) {
setInteractiveModalDetails({
...interactiveModalDetails,
interactiveSessionLink: notification.action_link,
message: notification.message,
});
}
/* falls through */
case 'job':
queryClient.invalidateQueries({
Expand All @@ -47,7 +49,7 @@ const Notifications = () => {
message: (
<Flex justify="space-between">
{getToastMessage(notification)}
<RightOutlined style={{ marginRight: -5 }} />
<RightOutlined style={{ marginRight: -5, marginLeft: 10 }} />
</Flex>
),
placement: 'bottomLeft',
Expand Down Expand Up @@ -90,7 +92,7 @@ const Notifications = () => {
if (lastMessage !== null) {
handleNotification(JSON.parse(lastMessage.data));
}
}, [lastMessage, handleNotification]);
}, [lastMessage]);

return contextHolder;
};
Expand Down
4 changes: 3 additions & 1 deletion client/src/workspace/layouts/AppsViewLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ export const AppsViewLayout: React.FC = () => {
</Flex>
</Header>
{htmlApp ? (
<div className={styles['overflow']}>
<div
className={`${styles['overflow']} ${styles['html-app-container']}`}
>
{parse(htmlApp.html as string)}
</div>
) : (
Expand Down
6 changes: 6 additions & 0 deletions client/src/workspace/layouts/layout.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
overflow: auto;
}

.html-app-container {
& p {
margin-block: 1em 2em;
}
}

.appDetail-placeholder-message {
display: flex;
justify-content: center;
Expand Down
16 changes: 15 additions & 1 deletion conf/env_files/designsafe.sample.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
###
# Set to "True" to enable Django DEBUG mode.
# Set to `True` to enable React (e.g. the Workspace)
#
RENDER_REACT=True

###
# Set to `True` to enable Django DEBUG mode.
# https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-DEBUG
#
DJANGO_DEBUG=True
Expand Down Expand Up @@ -188,3 +193,12 @@ MONGO_USER=
MONGO_PASS=
MONGO_HOST=
MONGO_DB=

##
# Miscellaneous
#

DATACITE_USER=
DATACITE_PASS=
DATACITE_URL=
DATACITE_SHOULDER=
Loading

0 comments on commit a114997

Please sign in to comment.