Merge branch '16116-collection-rename-fix'
authorLucas Di Pentima <lucas@di-pentima.com.ar>
Wed, 5 Feb 2020 21:13:56 +0000 (18:13 -0300)
committerLucas Di Pentima <lucas@di-pentima.com.ar>
Wed, 5 Feb 2020 21:13:56 +0000 (18:13 -0300)
Closes #16116

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas@di-pentima.com.ar>

src/common/config.ts
src/components/warning/warning.tsx
src/store/users/users-actions.ts
src/validators/validators.tsx
src/views-components/context-menu/action-sets/user-action-set.ts
src/views-components/dialog-forms/setup-shell-account-dialog.tsx
src/views/virtual-machine-panel/virtual-machine-user-panel.tsx

index f44dc1680935596b14d3923b04b13b199e3abe84..23faaf91adbe7c75a16b566edc3538add8d6d5f6 100644 (file)
@@ -41,6 +41,9 @@ export interface ClusterConfigJSON {
         },
         WebDAVDownload: {
             ExternalURL: string
+        },
+        WebShell: {
+            ExternalURL: string
         }
     };
     Workbench: {
@@ -49,6 +52,7 @@ export interface ClusterConfigJSON {
         FileViewersConfigURL: string;
         WelcomePageHTML: string;
         InactivePageHTML: string;
+        SSHHelpPageHTML: string;
         SiteName: string;
     };
     Login: {
@@ -155,6 +159,7 @@ export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): Clust
         Websocket: { ExternalURL: "" },
         WebDAV: { ExternalURL: "" },
         WebDAVDownload: { ExternalURL: "" },
+        WebShell: { ExternalURL: "" },
     },
     Workbench: {
         ArvadosDocsite: "",
@@ -162,6 +167,7 @@ export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): Clust
         FileViewersConfigURL: "",
         WelcomePageHTML: "",
         InactivePageHTML: "",
+        SSHHelpPageHTML: "",
         SiteName: "",
     },
     Login: {
index bd3303616d7e41a9b7f618ec6742df558c8cc159..95e495d72a038db1b48a66d9f06738028803899f 100644 (file)
@@ -16,11 +16,12 @@ interface WarningComponentProps {
 }
 
 export const WarningComponent = ({ text, rules, message }: WarningComponentProps) =>
-    rules.find(aRule => text.match(aRule) !== null)
-        ? message
-            ? <Tooltip title={message}><ErrorIcon /></Tooltip>
-            : <ErrorIcon />
-        : null;
+    !text ? <Tooltip title={"No name"}><ErrorIcon /></Tooltip>
+        : (rules.find(aRule => text.match(aRule) !== null)
+            ? message
+                ? <Tooltip title={message}><ErrorIcon /></Tooltip>
+                : <ErrorIcon />
+            : null);
 
 interface IllegalNamingWarningProps {
     name: string;
index f6287260d67e816603ea9ef47ad139932ca0118d..7b12fe75633ec403a8978bb15c9ece5bc9012cce 100644 (file)
@@ -27,6 +27,12 @@ export interface UserCreateFormDialogData {
     groupVirtualMachine: string;
 }
 
+export interface SetupShellAccountFormDialogData {
+    email: string;
+    virtualMachineName: string;
+    groupVirtualMachine: string;
+}
+
 export const openUserAttributes = (uuid: string) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const { resources } = getState();
@@ -94,6 +100,23 @@ export const createUser = (user: UserCreateFormDialogData) =>
         }
     };
 
+
+export const setupUserVM = (setupData: SetupShellAccountFormDialogData) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(startSubmit(USER_CREATE_FORM_NAME));
+        try {
+            // TODO: make correct API call
+            // const setupResult = await services.userService.setup({ ...setupData });
+            dispatch(dialogActions.CLOSE_DIALOG({ id: SETUP_SHELL_ACCOUNT_DIALOG }));
+            dispatch(reset(SETUP_SHELL_ACCOUNT_DIALOG));
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: "User has been added to VM.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+            dispatch<any>(loadUsersPanel());
+            dispatch(userBindedActions.REQUEST_ITEMS());
+        } catch (e) {
+            return;
+        }
+    };
+
 export const openUserPanel = () =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const user = getState().auth.user;
index 605d051c789388f34a21c0b1c3df89a6cb890f69..d9eca97f4c2a85b54a424497f3bce836e1380112 100644 (file)
@@ -38,3 +38,5 @@ export const SSH_KEY_NAME_VALIDATION = [require, maxLength(255)];
 export const SITE_MANAGER_REMOTE_HOST_VALIDATION = [require, isRemoteHost, maxLength(255)];
 
 export const MY_ACCOUNT_VALIDATION = [require];
+
+export const CHOOSE_VM_VALIDATION = [require];
index d2b97d15525755f6d66260ff6b78bdf7f9d3400e..2582800e5b7ed73dbef42577b7655e1f44d2c0e8 100644 (file)
@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
-import { AdvancedIcon, ProjectIcon, AttributesIcon, UserPanelIcon } from "~/components/icon/icon";
+import { AdvancedIcon, ProjectIcon, AttributesIcon } from "~/components/icon/icon";
 import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab';
-import { openUserAttributes, openUserProjects, openUserManagement } from "~/store/users/users-actions";
+import { openUserAttributes, openUserProjects } from "~/store/users/users-actions";
 
 export const userActionSet: ContextMenuActionSet = [[{
     name: "Attributes",
@@ -25,10 +25,13 @@ export const userActionSet: ContextMenuActionSet = [[{
     execute: (dispatch, { uuid }) => {
         dispatch<any>(openAdvancedTabDialog(uuid));
     }
-}, {
+}, /*
+    // Neither of the buttons on this dialog work correctly (bugs #16114 and #16124) so hide it for now.
+    {
     name: "Manage",
     icon: UserPanelIcon,
     execute: (dispatch, { uuid }) => {
         dispatch<any>(openUserManagement(uuid));
     }
-}]];
+} */
+]];
index c53f53c2ad90346572ff53cdf7ccd7a975238218..7e8a657ac032e70e7c9884e1578667d2d5e889b4 100644 (file)
@@ -8,24 +8,18 @@ import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
 import { FormDialog } from '~/components/form-dialog/form-dialog';
 import { TextField } from '~/components/text-field/text-field';
 import { VirtualMachinesResource } from '~/models/virtual-machines';
-import { USER_LENGTH_VALIDATION } from '~/validators/validators';
+import { USER_LENGTH_VALIDATION, CHOOSE_VM_VALIDATION } from '~/validators/validators';
 import { InputLabel } from '@material-ui/core';
 import { NativeSelectField } from '~/components/select-field/select-field';
-import { SETUP_SHELL_ACCOUNT_DIALOG, createUser } from '~/store/users/users-actions';
+import { SetupShellAccountFormDialogData, SETUP_SHELL_ACCOUNT_DIALOG, setupUserVM } from '~/store/users/users-actions';
 import { UserResource } from '~/models/user';
 
-interface SetupShellAccountFormDialogData {
-    email: string;
-    virtualMachineName: string;
-    groupVirtualMachine: string;
-}
-
 export const SetupShellAccountDialog = compose(
     withDialog(SETUP_SHELL_ACCOUNT_DIALOG),
     reduxForm<SetupShellAccountFormDialogData>({
         form: SETUP_SHELL_ACCOUNT_DIALOG,
         onSubmit: (data, dispatch) => {
-            dispatch(createUser(data));
+            dispatch(setupUserVM(data));
         }
     })
 )(
@@ -68,7 +62,7 @@ const UserVirtualMachineField = ({ data }: VirtualMachinesProps) =>
         <Field
             name='virtualMachine'
             component={NativeSelectField}
-            validate={USER_LENGTH_VALIDATION}
+            validate={CHOOSE_VM_VALIDATION}
             items={getVirtualMachinesList(data.items)} />
     </div>;
 
@@ -80,7 +74,7 @@ const UserGroupsVirtualMachineField = () =>
         label="Groups for virtual machine (comma separated list)" />;
 
 const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) =>
-    virtualMachines.map(it => ({ key: it.hostname, value: it.hostname }));
+    [{ key: "", value: "" }].concat(virtualMachines.map(it => ({ key: it.hostname, value: it.hostname })));
 
 type SetupShellAccountDialogComponentProps = WithDialogProps<{}> & InjectedFormProps<SetupShellAccountFormDialogData>;
 
@@ -90,6 +84,3 @@ const SetupShellAccountFormFields = (props: SetupShellAccountDialogComponentProp
         <UserVirtualMachineField data={props.data as DataProps} />
         <UserGroupsVirtualMachineField />
     </>;
-
-
-
index 291041b3b984cbf4ddf3951b99c1931043f5335c..a641ec63cd8b8c2a687e6fb68755ad7f2ecb17e2 100644 (file)
@@ -7,14 +7,11 @@ import { connect } from 'react-redux';
 import { Grid, Typography, Button, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip } from '@material-ui/core';
 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
 import { ArvadosTheme } from '~/common/custom-theme';
-import { DefaultCodeSnippet } from '~/components/default-code-snippet/default-code-snippet';
-import { Link } from 'react-router-dom';
 import { compose, Dispatch } from 'redux';
 import { saveRequestedDate, loadVirtualMachinesUserData } from '~/store/virtual-machines/virtual-machines-actions';
 import { RootState } from '~/store/store';
 import { ListResults } from '~/services/common-service/common-service';
 import { HelpIcon } from '~/components/icon/icon';
-import { Routes } from '~/routes/routes';
 
 type CssRules = 'button' | 'codeSnippet' | 'link' | 'linkIcon' | 'rightAlign' | 'cardWithoutMachines' | 'icon';
 
@@ -61,6 +58,8 @@ const mapStateToProps = (state: RootState) => {
     return {
         requestedDate: state.virtualMachines.date,
         userUuid: state.auth.user!.uuid,
+        helpText: state.auth.config.clusterConfig.Workbench.SSHHelpPageHTML,
+        webShell: state.auth.config.clusterConfig.Services.WebShell.ExternalURL,
         ...state.virtualMachines
     };
 };
@@ -75,6 +74,8 @@ interface VirtualMachinesPanelDataProps {
     virtualMachines: ListResults<any>;
     userUuid: string;
     links: ListResults<any>;
+    helpText: string;
+    webShell: string;
 }
 
 interface VirtualMachinesPanelActionProps {
@@ -161,7 +162,7 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                 <TableCell>Host name</TableCell>
                 <TableCell>Login name</TableCell>
                 <TableCell>Command line</TableCell>
-                <TableCell>Web shell</TableCell>
+                {props.webShell !== "" && <TableCell>Web shell</TableCell>}
             </TableRow>
         </TableHead>
         <TableBody>
@@ -169,12 +170,12 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                 <TableRow key={index}>
                     <TableCell>{it.hostname}</TableCell>
                     <TableCell>{getUsername(props.links, props.userUuid)}</TableCell>
-                    <TableCell>ssh {getUsername(props.links, props.userUuid)}@{it.hostname}.arvados</TableCell>
-                    <TableCell>
-                        <a href={`https://workbench.c97qk.arvadosapi.com${it.href}/webshell/${getUsername(props.links, props.userUuid)}`} target="_blank" className={props.classes.link}>
+                    <TableCell>ssh {getUsername(props.links, props.userUuid)}@{it.hostname}</TableCell>
+                    {props.webShell !== "" && <TableCell>
+                        <a href={`${props.webShell}${it.href}/webshell/${getUsername(props.links, props.userUuid)}`} target="_blank" className={props.classes.link}>
                             Log in as {getUsername(props.links, props.userUuid)}
                         </a>
-                    </TableCell>
+                    </TableCell>}
                 </TableRow>
             )}
         </TableBody>
@@ -188,17 +189,9 @@ const CardSSHSection = (props: VirtualMachineProps) =>
     <Grid item xs={12}>
         <Card>
             <CardContent>
-                <Typography variant='body1'>
-                    In order to access virtual machines using SSH, <Link to={Routes.SSH_KEYS_USER} className={props.classes.link}>add an SSH key to your account</Link> and add a section like this to your SSH configuration file ( ~/.ssh/config):
+                <Typography>
+                    <div dangerouslySetInnerHTML={{ __html: props.helpText }} style={{ margin: "1em" }} />
                 </Typography>
-                <DefaultCodeSnippet
-                    className={props.classes.codeSnippet}
-                    lines={[textSSH]} />
             </CardContent>
         </Card>
     </Grid>;
-
-const textSSH = `Host *.arvados
-    TCPKeepAlive yes
-    ServerAliveInterval 60
-    ProxyCommand ssh -p2222 turnout@switchyard.api.ardev.roche.com -x -a $SSH_PROXY_FLAGS %h`;
\ No newline at end of file