From 5baff0a88f9fb1caaf91c1e94fb87cffe19d6e5c Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 1 Jul 2019 17:10:43 +0800 Subject: [PATCH 1/3] data instruction --- .../components/data/custom-storage.jsx | 8 +-- .../components/data/data-component.jsx | 62 ++++++++++++------- .../components/data/mount-tree-view.jsx | 2 +- .../components/data/team-storage.jsx | 9 +-- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/webportal/src/app/job-submission/components/data/custom-storage.jsx b/src/webportal/src/app/job-submission/components/data/custom-storage.jsx index 78bd520425..ffbccd9ce6 100644 --- a/src/webportal/src/app/job-submission/components/data/custom-storage.jsx +++ b/src/webportal/src/app/job-submission/components/data/custom-storage.jsx @@ -1,19 +1,19 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {FontClassNames, FontWeights} from 'office-ui-fabric-react'; +import {FontClassNames, FontWeights, getTheme} from 'office-ui-fabric-react'; import c from 'classnames'; import {AddDataSource} from './add-data-source'; import {MountList} from './custom-mount-list'; import {InputData} from '../../models/data/input-data'; -import t from '../../../../app/components/tachyons.scss'; +const {spacing} = getTheme(); export const CustomStorage = ({dataList, setDataList, setDataError}) => { return (
Customized Storage
diff --git a/src/webportal/src/app/job-submission/components/data/data-component.jsx b/src/webportal/src/app/job-submission/components/data/data-component.jsx index 30e8056513..391cd3cf58 100644 --- a/src/webportal/src/app/job-submission/components/data/data-component.jsx +++ b/src/webportal/src/app/job-submission/components/data/data-component.jsx @@ -1,5 +1,6 @@ import React, {useCallback, useReducer, useEffect, useState} from 'react'; import PropTypes from 'prop-types'; +import {Stack} from 'office-ui-fabric-react'; import {TeamStorage} from './team-storage'; import {CustomStorage} from './custom-storage'; @@ -15,9 +16,10 @@ import { fetchStorageServer, } from '../../utils/conn'; import config from '../../../config/webportal.config'; +import {JobData} from '../../models/data/job-data'; +import {Hint} from '../sidebar/hint'; const host = getHostNameFromUrl(config.restServerUri); -import {JobData} from '../../models/data/job-data'; function reducer(state, action) { let jobData; @@ -50,7 +52,10 @@ export const DataComponent = React.memo((props) => { const {onChange} = props; const [teamConfigs, setTeamConfigs] = useState(); const [defaultTeamConfigs, setDefaultTeamConfigs] = useState(); - const [dataError, setDataError] = useState({customContainerPathError: false, customDataSourceError: false}); + const [dataError, setDataError] = useState({ + customContainerPathError: false, + customDataSourceError: false, + }); const [jobData, dispatch] = useReducer( reducer, new JobData(hdfsClient, [], null), @@ -134,30 +139,39 @@ export const DataComponent = React.memo((props) => { title='Data' selected={props.selected} onSelect={props.onSelect} - error={dataError.customContainerPathError || dataError.customDataSourceError} + error={ + dataError.customContainerPathError || dataError.customDataSourceError + } > - {teamConfigs && ( - + + The data configured here will be mounted or copied into job + container. You could use them with {'Container Path'}{' '} + value below. + + {teamConfigs && ( + + )} + - )} - - + + ); diff --git a/src/webportal/src/app/job-submission/components/data/mount-tree-view.jsx b/src/webportal/src/app/job-submission/components/data/mount-tree-view.jsx index 33dc1ff933..b504d4cb6e 100644 --- a/src/webportal/src/app/job-submission/components/data/mount-tree-view.jsx +++ b/src/webportal/src/app/job-submission/components/data/mount-tree-view.jsx @@ -133,7 +133,7 @@ export const MountTreeView = ({dataList}) => { return (
-
Preview Mounted Files
+
Preview Container Paths
diff --git a/src/webportal/src/app/job-submission/components/data/team-storage.jsx b/src/webportal/src/app/job-submission/components/data/team-storage.jsx index 98e8485ec7..e8b1ad4075 100644 --- a/src/webportal/src/app/job-submission/components/data/team-storage.jsx +++ b/src/webportal/src/app/job-submission/components/data/team-storage.jsx @@ -24,14 +24,15 @@ */ import React, {useEffect, useState} from 'react'; -import {Stack, Checkbox, FontClassNames, FontWeights} from 'office-ui-fabric-react'; +import {Stack, Checkbox, FontClassNames, FontWeights, getTheme} from 'office-ui-fabric-react'; import c from 'classnames'; import PropTypes from 'prop-types'; import {cloneDeep} from 'lodash'; import {MountDirectories} from '../../models/data/mount-directories'; import {TeamMountList} from './team-mount-list'; -import t from '../../../../app/components/tachyons.scss'; + +const {spacing} = getTheme(); export const TeamStorage = ({ teamConfigs, @@ -92,8 +93,8 @@ export const TeamStorage = ({ return (
Team Share Storage
From 123206795cedd434a35985ea851ab250c6ab5529 Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 1 Jul 2019 17:20:34 +0800 Subject: [PATCH 2/3] parameter instruction --- .../components/sidebar/parameters.jsx | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/webportal/src/app/job-submission/components/sidebar/parameters.jsx b/src/webportal/src/app/job-submission/components/sidebar/parameters.jsx index b43836f435..4586a62c3c 100644 --- a/src/webportal/src/app/job-submission/components/sidebar/parameters.jsx +++ b/src/webportal/src/app/job-submission/components/sidebar/parameters.jsx @@ -30,31 +30,35 @@ import {Hint} from './hint'; import {SidebarCard} from './sidebar-card'; import {KeyValueList} from '../controls/key-value-list'; -export const Parameters = React.memo(({parameters, onChange, selected, onSelect}) => { - const [error, setError] = useState(false); - return ( - - - - You could reference these parameters in command by {'<% $parameters.paramKey %>'} - -
- -
-
-
- ); -}); +export const Parameters = React.memo( + ({parameters, onChange, selected, onSelect}) => { + const [error, setError] = useState(false); + return ( + + + + You could reference these parameters in command by{' '} + {'<% $parameters.paramKey %>'}. For sensitive data, please refer to {'Secrets'}{' '} + section. For default reserved parameters, please refer to {'PAI Environment Variables'}{' '} section. + +
+ +
+
+
+ ); + }, +); Parameters.propTypes = { parameters: PropTypes.array.isRequired, From 540a5d3780246780da806733fc6e9801e8d975dc Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 1 Jul 2019 19:39:41 +0800 Subject: [PATCH 3/3] stack adjust --- .../components/submission-section.jsx | 167 ++++++++++------- .../src/app/job-submission/job-submission.jsx | 175 +++++++++--------- 2 files changed, 187 insertions(+), 155 deletions(-) diff --git a/src/webportal/src/app/job-submission/components/submission-section.jsx b/src/webportal/src/app/job-submission/components/submission-section.jsx index 11b12a785f..1400c4f1ca 100644 --- a/src/webportal/src/app/job-submission/components/submission-section.jsx +++ b/src/webportal/src/app/job-submission/components/submission-section.jsx @@ -24,7 +24,16 @@ */ import React, {useState, useRef, useEffect, useContext} from 'react'; -import {Stack, DefaultButton, PrimaryButton, Text, getTheme, Label, StackItem, Toggle} from 'office-ui-fabric-react'; +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'; @@ -44,17 +53,20 @@ import Context from './context'; import PropTypes from 'prop-types'; import {isNil, debounce, isEqual, isEmpty} from 'lodash'; -const JOB_PROTOCOL_SCHEMA_URL = 'https://github.com/microsoft/pai/blob/master/docs/pai-job-protocol.yaml'; +const JOB_PROTOCOL_SCHEMA_URL = + 'https://github.com/microsoft/pai/blob/master/docs/pai-job-protocol.yaml'; const user = cookies.get('user'); -const {palette} = getTheme(); +const {palette, spacing} = getTheme(); const importButtonStyle = getImportButtonStyle(); const _exportFile = (data, filename, type) => { let file = new Blob([data], {type: type}); - if (window.navigator.msSaveOrOpenBlob) { // IE10+ + if (window.navigator.msSaveOrOpenBlob) { + // IE10+ window.navigator.msSaveOrOpenBlob(file, filename); - } else { // Others + } else { + // Others let a = document.createElement('a'); let url = URL.createObjectURL(file); a.href = url; @@ -103,7 +115,12 @@ export const SubmissionSection = (props) => { }; useEffect(() => { - const protocol = jobProtocol.getUpdatedProtocol(jobInformation, jobTaskRoles, parameters, secrets); + const protocol = jobProtocol.getUpdatedProtocol( + jobInformation, + jobTaskRoles, + parameters, + secrets, + ); _protocolAndErrorUpdate(protocol); }, [jobInformation, jobTaskRoles, parameters, secrets, jobProtocol]); @@ -111,7 +128,12 @@ export const SubmissionSection = (props) => { event.preventDefault(); setEditorOpen(true); - const protocol = jobProtocol.getUpdatedProtocol(jobInformation, jobTaskRoles, parameters, secrets); + const protocol = jobProtocol.getUpdatedProtocol( + jobInformation, + jobTaskRoles, + parameters, + secrets, + ); _protocolAndErrorUpdate(protocol); try { await populateProtocolWithDataCli(user, protocol, jobData); @@ -141,7 +163,12 @@ export const SubmissionSection = (props) => { ] = getJobComponentsFormConfig(updatedJob); pruneComponents(updatedJobInformation, updatedSecrets, {vcNames}); - onChange(updatedJobInformation, updatedTaskRoles, updatedParameters, updatedSecrets); + onChange( + updatedJobInformation, + updatedTaskRoles, + updatedParameters, + updatedSecrets, + ); }; const _closeEditor = () => { @@ -157,7 +184,11 @@ export const SubmissionSection = (props) => { const protocol = new JobProtocol(jobProtocol); try { await populateProtocolWithDataCli(user, protocol, jobData); - _exportFile(jobProtocol.toYaml(), (jobInformation.name || 'job') + '.yaml', 'text/yaml'); + _exportFile( + jobProtocol.toYaml(), + (jobInformation.name || 'job') + '.yaml', + 'text/yaml', + ); } catch (err) { alert(err); } @@ -202,71 +233,65 @@ export const SubmissionSection = (props) => { return ( - - - - Submit - Edit YAML - - - - Export - - - - -
Advanced
- + + Submit + + + Edit YAML + + Export + +
+ + + +
Advanced
+
- - - - {String(validationMsg)} - - - - - (window.open(JOB_PROTOCOL_SCHEMA_URL)) - } - > - Protocol Schema - - -
- } - monacoRef={monaco} - monacoProps={{ - language: 'yaml', - options: {wordWrap: 'on', readOnly: false}, - value: protocolYaml, - onChange: debounce(_onYamlTextChange, 100), - }} - />
+ + + + {String(validationMsg)} + + + + window.open(JOB_PROTOCOL_SCHEMA_URL)} + > + Protocol Schema + + + + } + monacoRef={monaco} + monacoProps={{ + language: 'yaml', + options: {wordWrap: 'on', readOnly: false}, + value: protocolYaml, + onChange: debounce(_onYamlTextChange, 100), + }} + />
); }; diff --git a/src/webportal/src/app/job-submission/job-submission.jsx b/src/webportal/src/app/job-submission/job-submission.jsx index 9992ea2ae4..edb5287f8f 100644 --- a/src/webportal/src/app/job-submission/job-submission.jsx +++ b/src/webportal/src/app/job-submission/job-submission.jsx @@ -69,7 +69,9 @@ const SIDEBAR_ENVVAR = 'envvar'; const SIDEBAR_DATA = 'data'; const JobSubmission = () => { - const [jobTaskRoles, setJobTaskRolesState] = useState([new JobTaskRole({name: 'Task_role_1'})]); + const [jobTaskRoles, setJobTaskRolesState] = useState([ + new JobTaskRole({name: 'Task_role_1'}), + ]); const [parameters, setParametersState] = useState([{key: '', value: ''}]); const [secrets, setSecretsState] = useState([{key: '', value: ''}]); const [jobInformation, setJobInformation] = useState( @@ -120,7 +122,9 @@ const JobSubmission = () => { useEffect(() => { const taskRolesManager = new TaskRolesManager(jobTaskRoles); - const isUpdated = taskRolesManager.populateTaskRolesWithUpdatedSecret(secrets); + const isUpdated = taskRolesManager.populateTaskRolesWithUpdatedSecret( + secrets, + ); if (isUpdated) { taskRolesManager.populateTaskRolesDockerInfo(); setJobTaskRoles(jobTaskRoles); @@ -183,11 +187,14 @@ const JobSubmission = () => { [setErrorMessages], ); - const contextValue = useMemo(() => ({ - vcNames, - errorMessages, - setErrorMessage, - }), [vcNames, errorMessages, setErrorMessage]); + const contextValue = useMemo( + () => ({ + vcNames, + errorMessages, + setErrorMessage, + }), + [vcNames, errorMessages, setErrorMessage], + ); useEffect(() => { listVirtualClusters() @@ -206,11 +213,9 @@ const JobSubmission = () => { if (user && jobName) { fetchJobConfig(user, jobName) .then((jobConfig) => { - const [ - jobInfo, - taskRoles, - parameters, - ] = getJobComponentsFormConfig(jobConfig); + const [jobInfo, taskRoles, parameters] = getJobComponentsFormConfig( + jobConfig, + ); setJobTaskRoles(taskRoles); setParameters(parameters); setJobInformation(jobInfo); @@ -227,7 +232,7 @@ const JobSubmission = () => { const selectParam = useCallback(() => onSelect(SIDEBAR_PARAM), [onSelect]); const selectSecret = useCallback(() => onSelect(SIDEBAR_SECRET), [onSelect]); - const selectEnv= useCallback(() => onSelect(SIDEBAR_ENVVAR), [onSelect]); + const selectEnv = useCallback(() => onSelect(SIDEBAR_ENVVAR), [onSelect]); const selectData = useCallback(() => onSelect(SIDEBAR_DATA), [onSelect]); if (loading) { @@ -237,77 +242,79 @@ const JobSubmission = () => { return ( - - {/* left column */} - - - - - { - setJobInformation(updatedJobInfo); - setJobTaskRoles(updatedTaskRoles); - setParameters(updatedParameters); - setSecrets(updatedSecrets); - }} - /> - - - {/* right column */} - - - - - - - - + + + {/* left column */} + + + + + + + {/* right column */} + + + + + + + + + + { + setJobInformation(updatedJobInfo); + setJobTaskRoles(updatedTaskRoles); + setParameters(updatedParameters); + setSecrets(updatedSecrets); + }} + />