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

[webportal] Update storage API using JS SDK #4660

Merged
merged 8 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions src/webportal/.yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--install.ignore-engines true
1 change: 1 addition & 0 deletions src/webportal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"dependencies": {
"@hapi/joi": "~15.1.0",
"@loadable/component": "^5.10.3",
"@microsoft/openpai-js-sdk": "^0.1.1",
"@svgr/webpack": "^4.3.3",
"@webcomponents/custom-elements": "^1.2.1",
"admin-lte": "~2.4.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Stack } from 'office-ui-fabric-react';
Expand All @@ -15,11 +18,7 @@ import {
getStoragePlugin,
} from '../../utils/utils';
import { MountDirectories } from '../../models/data/mount-directories';
import {
listUserStorageConfigs,
fetchStorageConfigs,
fetchStorageServers,
} from '../../utils/conn';
import { listUserStorageConfigs, fetchStorageDetails } from '../../utils/conn';
import config from '../../../config/webportal.config';
import { JobData } from '../../models/data/job-data';
import { Hint } from '../sidebar/hint';
Expand Down Expand Up @@ -119,29 +118,9 @@ export const DataComponent = React.memo(props => {
const initialize = async () => {
try {
const userConfigNames = await listUserStorageConfigs(user);
const storageConfigs = await fetchStorageConfigs(userConfigNames);
let serverNames = new Set();
for (const config of storageConfigs) {
if (config.mountInfos === undefined) continue;
for (const mountInfo of config.mountInfos) {
serverNames = serverNames.add(mountInfo.server);
}
}

const rawStorageServers = await fetchStorageServers([...serverNames]);
const storageServers = [];
for (const rawServer of rawStorageServers) {
const server = {
spn: rawServer.spn,
type: rawServer.type,
...rawServer.data,
extension: rawServer.extension,
};
storageServers.push(server);
}
const storageDetails = await fetchStorageDetails(userConfigNames);
setTeamStorageConfig({
storageServers: storageServers,
storageConfigs: storageConfigs,
storageDetails: storageDetails,
});
} catch {}
};
Expand All @@ -154,15 +133,15 @@ export const DataComponent = React.memo(props => {

const selectedTeamStorageConfigs = getValidStorageConfigs(
extras,
teamStorageConfig.storageConfigs,
teamStorageConfig.storageDetails,
);

const user = cookies.get('user');
const mountDirectories = new MountDirectories(
user,
props.jobName,
selectedTeamStorageConfigs,
teamStorageConfig.storageServers,
teamStorageConfig.storageDetails,
);

setJobData(jobData => {
Expand Down Expand Up @@ -231,7 +210,7 @@ export const DataComponent = React.memo(props => {
</Hint>
{!isEmpty(teamStorageConfig) && (
<TeamStorage
teamStorageConfigs={teamStorageConfig.storageConfigs}
teamStorageConfigs={teamStorageConfig.storageDetails}
mountDirs={jobData.mountDirs}
onMountDirChange={onMountDirChange}
/>
Expand Down
104 changes: 35 additions & 69 deletions src/webportal/src/app/job-submission/components/data/team-detail.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
// 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.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React from 'react';
import {
Expand All @@ -31,31 +17,21 @@ import PropTypes from 'prop-types';
import c from 'classnames';
import t from '../../../components/tachyons.scss';
import { get } from 'lodash';
export default function TeamDetail({
isOpen = false,
config,
servers = [],
hide,
}) {
export default function TeamDetail({ isOpen = false, config, hide }) {
const handleCancel = () => {
hide();
};

const usedServers = servers.filter(server => {
const mountInfo = config.mountInfos.find(
info => info.server === server.spn,
);
return mountInfo !== undefined;
});

const columes = [
{
key: 'containerPath',
name: 'Path',
headerClassName: FontClassNames.semibold,
minWidth: 120,
onRender: item => {
return <div className={FontClassNames.small}>{item.mountPoint}</div>;
return (
<div className={FontClassNames.small}>{`/mnt/${item.name}`}</div>
);
},
},
{
Expand All @@ -64,13 +40,10 @@ export default function TeamDetail({
headerClassName: FontClassNames.semibold,
minWidth: 80,
onRender: item => {
const serverInfo = usedServers.find(
server => server.spn === item.server,
);
if (serverInfo === undefined) {
if (item === undefined) {
return <div className={FontClassNames.small}>{'Invalid Server'}</div>;
} else {
return <div className={FontClassNames.small}>{serverInfo.type}</div>;
return <div className={FontClassNames.small}>{item.type}</div>;
}
},
},
Expand All @@ -80,13 +53,10 @@ export default function TeamDetail({
headerClassName: FontClassNames.semibold,
minWidth: 400,
onRender: item => {
const serverInfo = usedServers.find(
server => server.spn === item.server,
);
if (serverInfo === undefined) {
if (item === undefined) {
return <div className={FontClassNames.small}>{'Invalid Server'}</div>;
} else {
return SERVER_PATH[serverInfo.type](serverInfo, item);
return SERVER_PATH[item.type](item);
}
},
},
Expand Down Expand Up @@ -156,17 +126,13 @@ export default function TeamDetail({
before use. Different server types require different upload methods.
</div>
<div>
{usedServers.map(server => {
return (
<div
key={server.spn}
className={c(FontClassNames.small, t.ml4)}
style={{ marginTop: '12px' }}
>
{NAS_TIPS[server.type]}
</div>
);
})}
<div
key={config.name}
className={c(FontClassNames.small, t.ml4)}
style={{ marginTop: '12px' }}
>
{NAS_TIPS[config.type]}
</div>
</div>
<div
className={c(t.mt5)}
Expand Down Expand Up @@ -195,7 +161,7 @@ export default function TeamDetail({
columns={columes}
disableSelectionZone
selectionMode={SelectionMode.none}
items={config.mountInfos}
items={[config]}
layoutMode={DetailsListLayoutMode.fixedColumns}
compact
/>
Expand Down Expand Up @@ -270,7 +236,7 @@ export const NAS_TIPS = {
</div>
</div>
),
azurefile: (
azureFile: (
<div>
<div style={{ fontWeight: FontWeights.semibold }}>AzureFile</div>
<span>Download </span>
Expand All @@ -288,7 +254,7 @@ export const NAS_TIPS = {
</span>
</div>
),
azureblob: (
azureBlob: (
<div>
<div style={{ fontWeight: FontWeights.semibold }}>AzureBlob</div>
<span>Download </span>
Expand Down Expand Up @@ -331,34 +297,34 @@ export const NAS_TIPS = {
};

export const SERVER_PATH = {
nfs: (server, mountInfo) => (
nfs: storage => (
<div className={FontClassNames.semibold}>
<b>{`${server.address}:${server.rootPath}`}</b>
{`/${mountInfo.path}`}
<b>{`${storage.data.server}:${storage.data.path}`}</b>
{storage.share === false ? '/$' + '{PAI_USER_NAME}' : '/'}
</div>
),
samba: (server, mountInfo) => (
samba: storage => (
<div className={FontClassNames.semibold}>
<b>{`${server.address}/${server.rootPath}`}</b>
{server.rootPath.length === 0 ? '' : '/' + mountInfo.path}
<b>{`${storage.data.server}:${storage.data.path}`}</b>
{storage.share === false ? '/$' + '{PAI_USER_NAME}' : '/'}
</div>
),
azurefile: (server, mountInfo) => (
azureFile: storage => (
<div className={FontClassNames.semibold}>
<b>{`${server.dataStore}/${server.fileShare}`}</b>
{`/${mountInfo.path}`}
<b>{`${storage.data.accountName}.file.core.windows.net/${storage.data.shareName}`}</b>
{storage.data.path || '/'}
</div>
),
azureblob: (server, mountInfo) => (
azureBlob: storage => (
<div className={FontClassNames.semibold}>
<b>{`${server.dataStore}/${server.containerName}`}</b>
{`/${mountInfo.path}`}
<b>{`${storage.data.accountName}.blob.core.windows.net/${storage.data.containerName}`}</b>
{storage.data.path || '/'}
</div>
),
hdfs: (server, mountInfo) => (
hdfs: storage => (
<div className={FontClassNames.semibold}>
<b>{`${server.namenode}:${server.port}`}</b>
{`/${mountInfo.path}`}
<b>{`${storage.data.namenode}:${storage.data.port}`}</b>
{storage.data.path || '/'}
</div>
),
};
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
/* !
* 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.
*/
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useLayoutEffect, useState, useCallback, useMemo } from 'react';

Expand Down Expand Up @@ -71,15 +49,6 @@ export const TeamStorage = ({
});
}, [mountDirs]);

const mountPoints = useMemo(() => {
if (isNil(mountDirs) || isNil(mountDirs.selectedConfigs)) {
return [];
}
return mountDirs.selectedConfigs.flatMap(ele =>
ele.mountInfos.map(mountInfo => mountInfo.mountPoint),
);
}, [mountDirs]);

const [teamDetail, setTeamDetail] = useState({ isOpen: false });

const openTeamDetail = useCallback(config => {
Expand Down Expand Up @@ -132,14 +101,6 @@ export const TeamStorage = ({
isChecked &&
!selectedConfigNames.includes(item.name)
) {
for (const mountInfo of item.mountInfos) {
if (mountPoints.includes(mountInfo.mountPoint)) {
alert(
`Mount point error! More than one mount point ${mountInfo.mountPoint}!`,
);
return;
}
}
newSelectedConfigNames = cloneDeep(selectedConfigNames);
newSelectedConfigNames.push(item.name);
}
Expand All @@ -157,9 +118,7 @@ export const TeamStorage = ({
onRender: item => {
return (
<div className={FontClassNames.medium}>
{item.mountInfos.map((mountInfo, infoId) => {
return <div key={item.name + infoId}>{mountInfo.mountPoint}</div>;
})}
<div key={item.name}>{`/mnt/${item.name}`}</div>
</div>
);
},
Expand All @@ -172,9 +131,7 @@ export const TeamStorage = ({
onRender: item => {
return (
<div className={FontClassNames.medium}>
{item.mountInfos.map((mountInfo, infoId) => {
return <div key={item.name + 'per' + infoId}>RW</div>;
})}
<div key={item.name + 'per'}>RW</div>
</div>
);
},
Expand Down
Loading