Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

add wizard page when submitting job #3430

Merged
merged 11 commits into from
Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const ContainerSizeSection = (props) => {
};

return (
<BasicSection sectionLabel='Resources per instance' sectionTooltip={PROTOCOL_TOOLTIPS.taskRoleContainerSize}>
<BasicSection sectionLabel='Resources' sectionTooltip={PROTOCOL_TOOLTIPS.taskRoleContainerSize}>
<Stack horizontal gap='l1'>
<FormShortSection gap='m'>
<CSpinButton
Expand Down
5 changes: 2 additions & 3 deletions src/webportal/src/app/job-submission/components/form-page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@

import React from 'react';
import {Stack} from 'office-ui-fabric-react';
import {getFormPageSytle, getFormShortSectionStyle} from './form-style';
import {getFormPageSytle} from './form-style';
import PropTypes from 'prop-types';

const {formPageStyle} = getFormPageSytle();
const formShortSectionStyle = getFormShortSectionStyle();

export const FormPage = (props) => {
return (
Expand All @@ -49,7 +48,7 @@ export const FormSection = (props) => {

export const FormShortSection = (props) => {
return (
<Stack {...props} styles={formShortSectionStyle}>
<Stack {...props} styles={{root: {width: '80%'}}}>
{props.children}
</Stack>
);
Expand Down
28 changes: 0 additions & 28 deletions src/webportal/src/app/job-submission/components/form-style.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,34 +113,6 @@ export const getFormBasicSectionStyle = (optional) => {
});
};

export const getFormShortSectionStyle = () => {
return ({
root: {
width: '80%',
},
});
};

export const getImportButtonStyle = () => {
return ({
label: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
width: '100%',
cursor: 'pointer',
fontWeight: FontWeights.semibold,
},
input: {
width: '1px',
height: '1px',
opacity: '.0001',
},
});
};

export const getDockerSectionStyle = () => {
return ({
auth: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/

import React, {useCallback} from 'react';
import {Text, Stack, FontWeights, Link} from 'office-ui-fabric-react';
import PropTypes from 'prop-types';
import {FormTextField} from './form-text-field';
import {FormPage} from './form-page';
Expand Down Expand Up @@ -63,16 +62,6 @@ export const JobInformation = React.memo(({jobInformation, onChange, advanceFlag
return (
<Card>
<FormPage>
<Stack horizontal gap='m' verticalAlign='baseline'>
<Text variant='xLarge' styles={{root: {fontWeight: 'semibold'}}}>
Job submission
</Text>
<Link
target='_blank'
href='https://github.com/microsoft/pai/blob/master/docs/user/job_submission.md'
style={{fontWeight: FontWeights.semibold}}
>{'Learn more >'}</Link>
</Stack>
<FormTextField
sectionLabel={'Job name'}
sectionTooltip={PROTOCOL_TOOLTIPS.jobName}
Expand Down
166 changes: 28 additions & 138 deletions src/webportal/src/app/job-submission/components/submission-section.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,16 @@
import PropTypes from 'prop-types';
import {isNil, debounce, isEqual, isEmpty, cloneDeep} from 'lodash';
import React, {useState, useRef, useEffect, useContext} from 'react';
import MediaQuery from 'react-responsive';
import {
Stack,
DefaultButton,
PrimaryButton,
Text,
getTheme,
Label,
StackItem,
Toggle,
} from 'office-ui-fabric-react';

import {getImportButtonStyle} from './form-style';
import {JobProtocol} from '../models/job-protocol';
import {JobBasicInfo} from '../models/job-basic-info';
import {JobTaskRole} from '../models/job-task-role';
Expand All @@ -51,35 +48,13 @@ import {
isValidUpdatedTensorBoardExtras,
} from '../utils/utils';
import Context from './context';
import {BasicSection} from './basic-section';
import {FormShortSection} from './form-page';

const JOB_PROTOCOL_SCHEMA_URL =
'https://github.com/microsoft/pai/blob/master/docs/pai-job-protocol.yaml';

const user = cookies.get('user');
const {palette, spacing} = getTheme();
const importButtonStyle = getImportButtonStyle();

const _exportFile = (data, filename, type) => {
let file = new Blob([data], {type: type});
if (window.navigator.msSaveOrOpenBlob) {
// IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
} else {
// Others
let a = document.createElement('a');
let url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
};
const {palette} = getTheme();

const VALIDATION_ERROR_MESSAGE_ID = 'Submission Section';

Expand All @@ -94,11 +69,12 @@ export const SubmissionSection = (props) => {
advanceFlag,
onToggleAdvanceFlag,
jobData,
initJobProtocol,
jobProtocol,
setJobProtocol,
setWizardStatus,
} = props;
const [isEditorOpen, setEditorOpen] = useState(false);

const [jobProtocol, setjobProtocol] = useState(new JobProtocol(initJobProtocol));
const [protocolYaml, setProtocolYaml] = useState('');
const [validationMsg, setValidationMsg] = useState('');

Expand All @@ -108,7 +84,7 @@ export const SubmissionSection = (props) => {

const _protocolAndErrorUpdate = (protocol) => {
if (!isEqual(jobProtocol, protocol)) {
setjobProtocol(protocol);
setJobProtocol(protocol);
}
const newValidationMessage = JobProtocol.validateFromObject(protocol);
if (newValidationMessage !== validationMsg) {
Expand Down Expand Up @@ -155,7 +131,7 @@ export const SubmissionSection = (props) => {
return;
}

setjobProtocol(updatedJob);
setJobProtocol(updatedJob);
if (onChange === undefined) {
return;
}
Expand Down Expand Up @@ -192,38 +168,6 @@ export const SubmissionSection = (props) => {
monaco.current.editor.setTheme('vs');
};

const _exportYaml = async (event) => {
event.preventDefault();
const protocol = cloneDeep(jobProtocol);
try {
await populateProtocolWithDataCli(user, protocol, jobData);
_exportFile(
protocol.toYaml(),
(protocol.name || 'job') + '.yaml',
'text/yaml',
);
} catch (err) {
alert(err);
}
};

const _importFile = (event) => {
event.preventDefault();
const files = event.target.files;
if (!files || !files[0]) {
return;
}
const fileReader = new FileReader();
fileReader.addEventListener('load', () => {
const text = String(fileReader.result);
try {
_updatedComponent(text);
} catch (err) {
alert(err.message);
}
});
fileReader.readAsText(files[0]);
};

const _onYamlTextChange = (text) => {
setProtocolYaml(text);
Expand All @@ -244,84 +188,28 @@ export const SubmissionSection = (props) => {
}
};


const widthBreakpoint = 1550;

return (
<Card>
{/* large - align with task role card (simulate the top section taskrole-sidebar layout) */}
<MediaQuery minWidth={widthBreakpoint}>
<Stack horizontal horizontalAlign='space-between'>
<DefaultButton text='Back' onClick={() => {
setWizardStatus('wizard');
}}/>
<Stack horizontal gap='l1'>
<StackItem grow styles={{root: {minWidth: 600, flexBasis: 0}}}>
<BasicSection>
<Stack horizontal gap='l1'>
<FormShortSection>
<Stack horizontal horizontalAlign='space-between'>
<Stack horizontal gap='s1'>
<PrimaryButton onClick={_submitJob} disabled={!isEmpty(errorMessages)}>
Submit
</PrimaryButton>
<DefaultButton
onClick={_openEditor}
>
Edit YAML
</DefaultButton>
</Stack>
<Stack horizontal gap='s1'>
<DefaultButton onClick={_exportYaml}>Export</DefaultButton>
<DefaultButton>
<Label styles={{root: importButtonStyle.label}}>
{'Import'}
<input
type='file'
style={importButtonStyle.input}
accept='.yml,.yaml'
onChange={_importFile}
/>
</Label>
</DefaultButton>
</Stack>
</Stack>
</FormShortSection>
<Stack horizontal verticalAlign='center' gap='s1'>
<div>Advanced</div>
<Toggle
styles={{root: {margin: 0}}}
checked={advanceFlag}
onChange={onToggleAdvanceFlag}
/>
</Stack>
<FormShortSection>
<Stack horizontal horizontalAlign='space-between'>
<Stack horizontal gap='s1'>
<PrimaryButton onClick={_submitJob} disabled={!isEmpty(errorMessages)}>
Submit
</PrimaryButton>
<DefaultButton
onClick={_openEditor}
>
Edit YAML
</DefaultButton>
</Stack>
</BasicSection>
</StackItem>
<div style={{width: 550}}></div>
</Stack>
</MediaQuery>
{/* small screen - center */}
<MediaQuery maxWidth={widthBreakpoint - 1}>
<Stack horizontal gap='s1' horizontalAlign='center'>
<PrimaryButton onClick={_submitJob} disabled={!isEmpty(errorMessages)}>
Submit
</PrimaryButton>
<DefaultButton
onClick={_openEditor}
styles={{root: {marginRight: spacing.l2}}}
>
Edit YAML
</DefaultButton>
<DefaultButton onClick={_exportYaml}>Export</DefaultButton>
<DefaultButton>
<Label styles={{root: importButtonStyle.label}}>
{'Import'}
<input
type='file'
style={importButtonStyle.input}
accept='.yml,.yaml'
onChange={_importFile}
/>
</Label>
</DefaultButton>
<Stack horizontal padding='0 0 0 s1' verticalAlign='center' gap='s1'>
</Stack>
</FormShortSection>
<Stack horizontal verticalAlign='center' gap='s1'>
<div>Advanced</div>
<Toggle
styles={{root: {margin: 0}}}
Expand All @@ -330,7 +218,7 @@ export const SubmissionSection = (props) => {
/>
</Stack>
</Stack>
</MediaQuery>
</Stack>
<MonacoPanel
isOpen={isEditorOpen}
onDismiss={_closeEditor}
Expand Down Expand Up @@ -373,5 +261,7 @@ SubmissionSection.propTypes = {
advanceFlag: PropTypes.bool,
onToggleAdvanceFlag: PropTypes.func,
jobData: PropTypes.object,
initJobProtocol: PropTypes.object,
jobProtocol: PropTypes.object,
setJobProtocol: PropTypes.func,
setWizardStatus: PropTypes.func,
};
Loading