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

Commit

Permalink
resolve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
sunqinzheng committed Apr 26, 2019
2 parents 0ead44c + b232486 commit 3d6bb70
Show file tree
Hide file tree
Showing 118 changed files with 4,527 additions and 1,201 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ matrix:
- npm run coveralls

- language: node_js
node_js: node
node_js: lts/dubnium
env: NODE_ENV=test
before_install:
- cd src/rest-server
Expand All @@ -117,7 +117,7 @@ matrix:
- npm test

- language: node_js
node_js: node
node_js: lts/dubnium
before_install:
- cd src/webportal
install:
Expand All @@ -139,7 +139,7 @@ matrix:
script: yarn build

- language: node_js
node_js: node
node_js: lts/dubnium
before_install: cd contrib/submit-protocol
install: yarn --frozen-lockfiles
script: yarn build
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Refer to [here](docs/user/troubleshooting_job.md) for more information about tro

* [Manage cluster with paictl](docs/paictl/paictl-manual.md)
* [Monitoring](./docs/webportal/README.md)
* [Upgrade](./docs/upgrade/upgrade_to_v0.11.md)
* [Upgrade](./docs/upgrade/upgrade_to_v0.12.md)

## Reference

Expand Down
2 changes: 1 addition & 1 deletion README_zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Web 界面和 Job 日志有助于分析错误,OpenPAI 也支持通过 SSH 登

* [使用 paictl 管理集群](docs/paictl/paictl-manual.md)
* [监测](./docs/webportal/README.md)
* [升级](./docs/upgrade/upgrade_to_v0.11.md)
* [升级](./docs/upgrade/upgrade_to_v0.12.md)

## 参考手册

Expand Down
198 changes: 198 additions & 0 deletions contrib/submit-protocol/src/App/MarketplaceForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import React from "react";
import {
Callout, DefaultButton, Dropdown, DropdownMenuItemType,
Fabric, IDropdownOption, Stack, TextField,
mergeStyleSets,
} from "office-ui-fabric-react";

type MarketplaceUriType = (null | "GitHub");

interface IProtocolItem {
name: string;
uri: string;
}

interface IMarketplaceProps {
defaultURI: string;
defaultURIType: MarketplaceUriType;
onSelectProtocol: ((text: string) => void);
disabled: boolean;
}

interface IMarketplaceState {
uri: string;
uriType: MarketplaceUriType;
protocolOptions: IDropdownOption[];
uriConfigCallout: boolean;
}

const styles = mergeStyleSets({
dropdown: {
width: 240,
},
textfiled: {
width: 480,
},
});

const defaultProtocolOptions: IDropdownOption[] = [
{ key: "None", text: "None" },
{ key: "jobsDivider", text: "-", itemType: DropdownMenuItemType.Divider },
{ key: "jobsHeader", text: "Protocol Jobs", itemType: DropdownMenuItemType.Header },
];

export default class MarketplaceForm extends React.Component<IMarketplaceProps, IMarketplaceState> {
public static defaultProps: Partial<IMarketplaceProps> = {
defaultURI: "https://api.github.com/repos/Microsoft/pai/contents/marketplace-v2",
defaultURIType: "GitHub",
disabled: false,
};

public state = {
uri: this.props.defaultURI,
uriType: this.props.defaultURIType,
protocolOptions: defaultProtocolOptions,
uriConfigCallout: false,
};

private uriConfigCalloutBtn = React.createRef<HTMLDivElement>();

public componentDidMount() {
this.setProtocolOptions();
}

public render() {
return (
<Fabric>
<Stack gap={5} horizontal={true} verticalAlign="center">
<Stack>
<Dropdown
className={styles.dropdown}
placeholder="Select a protocol config file"
options={this.state.protocolOptions}
onChange={this.selectProtocol}
disabled={this.props.disabled}
/>
</Stack>
<Stack maxWidth="5px">
<div ref={this.uriConfigCalloutBtn}>
<DefaultButton
onClick={this.toggleConfigCallout}
iconProps={{iconName: "ConfigurationSolid"}}
text="URI"
disabled={this.props.disabled}
/>
</div>
<Callout
role="alertdialog"
target={this.uriConfigCalloutBtn.current}
onDismiss={this.closeConfigCallout}
setInitialFocus={true}
hidden={!this.state.uriConfigCallout}
>
<Stack padding={20}>
<TextField
className={styles.textfiled}
label="Marketplace URI"
prefix={this.state.uriType || undefined}
value={this.state.uri}
onChange={this.setMarketplaceURI}
onBlur={this.setProtocolOptions}
/>
</Stack>
</Callout>
</Stack>
</Stack>
</Fabric>
);
}

private toggleConfigCallout = () => {
this.setState({uriConfigCallout: !this.state.uriConfigCallout});
}

private closeConfigCallout = () => {
this.setState({uriConfigCallout: false});
}

private setMarketplaceURI = (event: React.FormEvent<HTMLElement>, uri?: string) => {
if (uri !== undefined) {
this.setState({
uri,
uriType: "GitHub",
});
}
}

private setProtocolOptions = async () => {
const protocolList = await this.getProtocolList(this.state.uri, this.state.uriType);
if (protocolList) {
const protocolOptions: IDropdownOption[] = [... defaultProtocolOptions];
for (const protocolItem of protocolList) {
protocolOptions.push({
key: protocolItem.name,
text: protocolItem.name,
data: protocolItem.uri,
});
}
this.setState({ protocolOptions });
}
}

private selectProtocol = async (event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption) => {
if (option !== undefined) {
if (option.data !== undefined) {
try {
const res = await fetch(option.data);
const data = await res.text();
this.props.onSelectProtocol(data);
} catch (err) {
alert(`Cannot get ${option.data}`);
}
}
}
}

private getProtocolList = async (uri: string, uriType: MarketplaceUriType) => {
if (uriType === "GitHub") {
try {
const res = await fetch(uri);
const data = await res.json();
if (Array.isArray(data)) {
const protocolList: IProtocolItem[] = [];
for (const item of data) {
if (item.type === "file") {
protocolList.push({
name: item.name,
uri: item.download_url,
});
}
}
return protocolList;
} else {
alert(`Cannot get ${uri}`);
}
} catch (err) {
alert(err.message);
}
}
return null;
}
}
99 changes: 63 additions & 36 deletions contrib/submit-protocol/src/App/ProtocolForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import update from "immutability-helper";
import yaml from "yaml";

import monacoStyles from "./monaco.scss";
import MarketplaceForm from "./MarketplaceForm";

const MonacoEditor = lazy(() => import("react-monaco-editor"));
const styles = mergeStyleSets({
Expand Down Expand Up @@ -133,10 +134,11 @@ interface IProtocolProps {
api: string;
user: string;
token: string;
source ?: {
source?: {
jobName: string;
user: string;
};
pluginId?: string;
}

interface IProtocolState {
Expand Down Expand Up @@ -235,6 +237,10 @@ export default class ProtocolForm extends React.Component<IProtocolProps, IProto
<Stack gap={10} horizontal={true} verticalAlign="baseline">
{render!(props)}
<Label>Select from marketplace</Label>
<MarketplaceForm
onSelectProtocol={this.onSelectProtocol}
disabled={props ? !props.checked : false}
/>
</Stack>
);
},
Expand Down Expand Up @@ -313,30 +319,36 @@ export default class ProtocolForm extends React.Component<IProtocolProps, IProto
);
}

private fetchConfig = () => {
private fetchConfig = async () => {
const source = this.props.source;
if (source && source.jobName && source.user) {
fetch(
`${this.props.api}/api/v1/user/${source.user}/jobs/${source.jobName}/config`,
).then((res) => {
return res.json();
}).then((body) => {
const protocol = yaml.parse(body);
this.setState(
{ protocol },
() => this.setJobName(
null as any,
`${source.jobName}_clone_${Math.random().toString(36).slice(2, 10)}`,
),
const pluginId = this.props.pluginId;
if (source && source.jobName && source.user && pluginId) {
try {
const res = await fetch(
`${this.props.api}/api/v1/user/${source.user}/jobs/${source.jobName}/config`,
);
}).catch((err) => {
const body = await res.json();
const protocol = yaml.parse(body);
if (protocol.extras.submitFrom !== pluginId) {
throw new Error(`Unknown plugin id ${protocol.extras.submitFrom}`);
}
protocol.name = this.getCloneJobName(source.jobName);
this.setState({
jobName: protocol.name,
protocol,
protocolYAML: yaml.stringify(protocol),
});
} catch (err) {
alert(err.message);
}).finally(() => {
this.setState({ loading: false });
});
} else {
this.setState({ loading: false });
}
}
this.setState({ loading: false });
}

private getCloneJobName = (jobName: string) => {
const originalName = jobName.replace(/_clone_([a-z0-9]{8,})$/, "");
const randomHash = Math.random().toString(36).slice(2, 10);
return `${originalName}_clone_${randomHash}`;
}

private setJobName = (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, jobName?: string) => {
Expand All @@ -352,6 +364,19 @@ export default class ProtocolForm extends React.Component<IProtocolProps, IProto
}
}

private onSelectProtocol = (text: string) => {
try {
const protocol = yaml.parse(text);
this.setState({
jobName: protocol.name || "",
protocol,
protocolYAML: text,
});
} catch (err) {
alert(err.message);
}
}

private importFile = (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault();
const files = event.target.files;
Expand Down Expand Up @@ -474,28 +499,30 @@ export default class ProtocolForm extends React.Component<IProtocolProps, IProto
});
}

private submitProtocol = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
private submitProtocol = async (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
event.preventDefault();
if (this.state.protocolYAML == null) {
if (!this.state.protocolYAML) {
return;
}
fetch(`${this.props.api}/api/v2/jobs`, {
body: this.state.protocolYAML,
headers: {
"Authorization": `Bearer ${this.props.token}`,
"Content-Type": "text/yaml",
},
method: "POST",
}).then((res) => {
return res.json();
}).then((body) => {
if (Number(body.status) >= 400) {
const protocol = yaml.parse(this.state.protocolYAML);
protocol.extras = { submitFrom: this.props.pluginId };
try {
const res = await fetch(`${this.props.api}/api/v2/jobs`, {
body: yaml.stringify(protocol),
headers: {
"Authorization": `Bearer ${this.props.token}`,
"Content-Type": "text/yaml",
},
method: "POST",
});
const body = await res.json();
if (Number(res.status) >= 400) {
alert(body.message);
} else {
window.location.href = `/job-detail.html?username=${this.props.user}&jobName=${this.state.jobName}`;
}
}).catch((err) => {
} catch (err) {
alert(err.message);
});
}
}
}
Loading

0 comments on commit 3d6bb70

Please sign in to comment.