[arvados] created: 2.7.0-6100-g2aff408211

git repository hosting git at public.arvados.org
Mon Mar 4 16:39:59 UTC 2024


        at  2aff408211e84a226af6f74cb9338cbaf3fc4645 (commit)


commit 2aff408211e84a226af6f74cb9338cbaf3fc4645
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Mar 4 11:32:45 2024 -0500

    20455: Use noopener everywhere on links and window.open
    
    I removed "noreferrer" as this does something different (it prevents
    passing the "Referer" header when opening the new URL).  It's not
    clear users benefits from suppressing the information that they
    navigated to a link from workbench.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/workbench2/src/components/code-snippet/code-snippet.tsx b/services/workbench2/src/components/code-snippet/code-snippet.tsx
index 209dbc44b5..47d8fe1bf0 100644
--- a/services/workbench2/src/components/code-snippet/code-snippet.tsx
+++ b/services/workbench2/src/components/code-snippet/code-snippet.tsx
@@ -54,8 +54,8 @@ const mapStateToProps = (state: RootState): CodeSnippetAuthProps => ({
 export const CodeSnippet = withStyles(styles)(connect(mapStateToProps)(
     ({ classes, lines, linked, className, apiResponse, dispatch, auth, children, inline }: CodeSnippetProps & CodeSnippetAuthProps & DispatchProp) =>
         <Typography
-        component="div"
-        className={classNames([classes.root, className, inline ? classes.inlineRoot: undefined])}>
+            component="div"
+            className={classNames([classes.root, className, inline ? classes.inlineRoot : undefined])}>
             <Typography className={apiResponse ? classes.space : classNames([className, inline ? classes.inline : undefined])} component="pre">
                 {children}
                 {linked ?
@@ -64,7 +64,7 @@ export const CodeSnippet = withStyles(styles)(connect(mapStateToProps)(
                 }
             </Typography>
         </Typography>
-    ));
+));
 
 const renderLinks = (auth: FederationConfig, dispatch: Dispatch) => (text: string): JSX.Element => {
     // Matches UUIDs & PDHs
@@ -78,18 +78,18 @@ const renderLinks = (auth: FederationConfig, dispatch: Dispatch) => (text: strin
             <React.Fragment key={index}>
                 {part}
                 {links[index] &&
-                <Link onClick={() => {
-                    const url = getNavUrl(links[index], auth)
-                    if (url) {
-                        window.open(`${window.location.origin}${url}`, '_blank');
-                    } else {
-                        dispatch(navigationNotAvailable(links[index]));
-                    }
-                }}
-                    style={ {cursor: 'pointer'} }>
-                    {links[index]}
-                </Link>}
+                    <Link onClick={() => {
+                        const url = getNavUrl(links[index], auth)
+                        if (url) {
+                            window.open(`${window.location.origin}${url}`, '_blank', "noopener");
+                        } else {
+                            dispatch(navigationNotAvailable(links[index]));
+                        }
+                    }}
+                        style={{ cursor: 'pointer' }}>
+                        {links[index]}
+                    </Link>}
             </React.Fragment>
         )}
     </>;
-  };
+};
diff --git a/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx b/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx
index f1e50e0f0b..e58eb89198 100644
--- a/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx
+++ b/services/workbench2/src/components/collection-panel-files/collection-panel-files.tsx
@@ -433,7 +433,7 @@ export const CollectionPanelFiles = withStyles(styles)(
                             getInlineFileUrl(enhancedItem.url, config.keepWebServiceUrl, config.keepWebInlineServiceUrl),
                             true
                         );
-                        window.open(fileUrl, "_blank");
+                        window.open(fileUrl, "_blank", "noopener");
                     }
                 }
 
diff --git a/services/workbench2/src/components/details-attribute/details-attribute.tsx b/services/workbench2/src/components/details-attribute/details-attribute.tsx
index d965b60f5b..5130db56d1 100644
--- a/services/workbench2/src/components/details-attribute/details-attribute.tsx
+++ b/services/workbench2/src/components/details-attribute/details-attribute.tsx
@@ -96,10 +96,10 @@ export const DetailsAttribute = connect(mapStateToProps)(withStyles(styles)(
                 if (linkUrl[0] === '/') {
                     valueNode = <Link to={linkUrl} className={classes.link}>{uuid}</Link>;
                 } else {
-                    valueNode = <a href={linkUrl} className={classes.link} target='_blank' rel="noopener noreferrer">{uuid}</a>;
+                    valueNode = <a href={linkUrl} className={classes.link} target='_blank' rel="noopener">{uuid}</a>;
                 }
             } else if (link) {
-                valueNode = <a href={link} className={classes.link} target='_blank' rel="noopener noreferrer">{value}</a>;
+                valueNode = <a href={link} className={classes.link} target='_blank' rel="noopener">{value}</a>;
             } else {
                 valueNode = value;
             }
diff --git a/services/workbench2/src/store/open-in-new-tab/open-in-new-tab.actions.ts b/services/workbench2/src/store/open-in-new-tab/open-in-new-tab.actions.ts
index 83055e32fc..28da3cf95a 100644
--- a/services/workbench2/src/store/open-in-new-tab/open-in-new-tab.actions.ts
+++ b/services/workbench2/src/store/open-in-new-tab/open-in-new-tab.actions.ts
@@ -12,9 +12,9 @@ export const openInNewTabAction = (resource: any) => (dispatch: Dispatch, getSta
     const url = getNavUrl(resource.uuid, getState().auth);
 
     if (url[0] === "/") {
-        window.open(`${window.location.origin}${url}`, "_blank");
+        window.open(`${window.location.origin}${url}`, "_blank", "noopener");
     } else if (url.length) {
-        window.open(url, "_blank");
+        window.open(url, "_blank", "noopener");
     }
 };
 
diff --git a/services/workbench2/src/views-components/context-menu/actions/file-viewer-action.tsx b/services/workbench2/src/views-components/context-menu/actions/file-viewer-action.tsx
index 5d98ab6e13..0a77876bac 100644
--- a/services/workbench2/src/views-components/context-menu/actions/file-viewer-action.tsx
+++ b/services/workbench2/src/views-components/context-menu/actions/file-viewer-action.tsx
@@ -12,7 +12,7 @@ export const FileViewerAction = (props: any) => {
             style={{ textDecoration: 'none' }}
             href={props.href}
             target="_blank"
-            rel="noopener noreferrer"
+            rel="noopener"
             onClick={props.onClick}>
             <ListItem button>
                 <ListItemIcon>
@@ -20,7 +20,7 @@ export const FileViewerAction = (props: any) => {
                 </ListItemIcon>
                 <ListItemText>
                     Open in new tab
-                    </ListItemText>
+                </ListItemText>
             </ListItem>
         </a>
         : null;
diff --git a/services/workbench2/src/views-components/context-menu/actions/file-viewer-actions.tsx b/services/workbench2/src/views-components/context-menu/actions/file-viewer-actions.tsx
index 6d713d5559..6eebda2469 100644
--- a/services/workbench2/src/views-components/context-menu/actions/file-viewer-actions.tsx
+++ b/services/workbench2/src/views-components/context-menu/actions/file-viewer-actions.tsx
@@ -63,6 +63,7 @@ export const FileViewerActions = connect(mapStateToProps)(
                     style={{ textDecoration: 'none' }}
                     href={fillViewerUrl(fileUrl, viewer)}
                     onClick={onClick}
+                    rel="noopener"
                     target='_blank'>
                     <ListItemIcon>
                         {
diff --git a/services/workbench2/src/views-components/main-app-bar/help-menu.tsx b/services/workbench2/src/views-components/main-app-bar/help-menu.tsx
index af76e4f127..1ce2fa1f0f 100644
--- a/services/workbench2/src/views-components/main-app-bar/help-menu.tsx
+++ b/services/workbench2/src/views-components/main-app-bar/help-menu.tsx
@@ -72,7 +72,7 @@ export const HelpMenu = compose(
                 {
                     links.map(link =>
                         <MenuItem key={link.title}>
-                            <a href={link.link} target="_blank" rel="noopener noreferrer" className={classes.link}>
+                            <a href={link.link} target="_blank" rel="noopener" className={classes.link}>
                                 <ImportContactsIcon className={classes.icon} />
                                 <Typography className={classes.linkTitle}>{link.title}</Typography>
                             </a>
diff --git a/services/workbench2/src/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog.tsx b/services/workbench2/src/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog.tsx
index 854f3f4f68..7df99300f7 100644
--- a/services/workbench2/src/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog.tsx
+++ b/services/workbench2/src/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog.tsx
@@ -54,8 +54,8 @@ export const RepositoriesSampleGitDialog = compose(
                         lines={[snippetText(props.data.uuidPrefix)]} />
                     <Typography variant='body1' className={props.classes.spacing}>
                         See also:
-                        <div><a href="https://doc.arvados.org/user/getting_started/ssh-access-unix.html" className={props.classes.link} target="_blank" rel="noopener noreferrer">SSH access</a></div>
-                        <div><a href="https://doc.arvados.org/user/tutorials/tutorial-firstscript.html" className={props.classes.link} target="_blank" rel="noopener noreferrer">Writing a Crunch Script</a></div>
+                        <div><a href="https://doc.arvados.org/user/getting_started/ssh-access-unix.html" className={props.classes.link} target="_blank" rel="noopener">SSH access</a></div>
+                        <div><a href="https://doc.arvados.org/user/tutorials/tutorial-firstscript.html" className={props.classes.link} target="_blank" rel="noopener">Writing a Crunch Script</a></div>
                     </Typography>
                 </DialogContent>
                 <DialogActions>
@@ -64,7 +64,7 @@ export const RepositoriesSampleGitDialog = compose(
                         color='primary'
                         onClick={props.closeDialog}>
                         Close
-                </Button>
+                    </Button>
                 </DialogActions>
             </Dialog>
     );
diff --git a/services/workbench2/src/views-components/sharing-dialog/sharing-urls-component.tsx b/services/workbench2/src/views-components/sharing-dialog/sharing-urls-component.tsx
index 5facb2e381..c17fadd5f0 100644
--- a/services/workbench2/src/views-components/sharing-dialog/sharing-urls-component.tsx
+++ b/services/workbench2/src/views-components/sharing-dialog/sharing-urls-component.tsx
@@ -72,7 +72,7 @@ export const SharingURLsComponent = withStyles(styles)((props: SharingURLsCompon
 
                 return <Grid container alignItems='center' key={token.uuid} className={props.classes.sharingUrlRow}>
                     <Grid item>
-                        <Link className={props.classes.sharingUrlText} href={url} target='_blank'>
+                        <Link className={props.classes.sharingUrlText} href={url} target='_blank' rel="noopener">
                             {urlLabel}
                         </Link>
                     </Grid>
diff --git a/services/workbench2/src/views-components/token-dialog/token-dialog.tsx b/services/workbench2/src/views-components/token-dialog/token-dialog.tsx
index b9d195f587..e6f3ed582c 100644
--- a/services/workbench2/src/views-components/token-dialog/token-dialog.tsx
+++ b/services/workbench2/src/views-components/token-dialog/token-dialog.tsx
@@ -110,7 +110,7 @@ unset ARVADOS_API_HOST_INSECURE`
                     The Arvados API token is a secret key that enables the Arvados SDKs to access Arvados with the proper permissions.
                     <Typography component='span'>
                         For more information see
-                        <a href='http://doc.arvados.org/user/reference/api-tokens.html' target='blank' className={classes.link}>
+                        <a href='http://doc.arvados.org/user/reference/api-tokens.html' target='blank' rel="noopener" className={classes.link}>
                             Getting an API token.
                         </a>
                     </Typography>
@@ -119,7 +119,7 @@ unset ARVADOS_API_HOST_INSECURE`
                 <DetailsAttributeComponent label='API Host' value={data.apiHost} copyValue={data.apiHost} onCopy={this.onCopy} />
                 <DetailsAttributeComponent label='API Token' value={data.token} copyValue={data.token} onCopy={this.onCopy} />
                 <DetailsAttributeComponent label='Token expiration' value={tokenExpiration} />
-                { this.props.canCreateNewTokens && <Button
+                {this.props.canCreateNewTokens && <Button
                     onClick={() => this.onGetNewToken()}
                     color="primary"
                     size="small"
@@ -127,7 +127,7 @@ unset ARVADOS_API_HOST_INSECURE`
                     className={classes.actionButton}
                 >
                     GET NEW TOKEN
-                </Button> }
+                </Button>}
 
                 <Typography paragraph={true}>
                     Paste the following lines at a shell prompt to set up the necessary environment for Arvados SDKs to authenticate to your account.
@@ -145,7 +145,7 @@ unset ARVADOS_API_HOST_INSECURE`
                 </CopyToClipboard>
                 <Typography>
                     Arvados
-                            <a href='http://doc.arvados.org/user/reference/api-tokens.html' target='blank' className={classes.link}>virtual machines</a>
+                    <a href='http://doc.arvados.org/user/reference/api-tokens.html' target='blank' rel="noopener" className={classes.link}>virtual machines</a>
                     do this for you automatically. This setup is needed only when you use the API remotely (e.g., from your own workstation).
                 </Typography>
             </DialogContent>
@@ -160,4 +160,3 @@ export const TokenDialog =
     withStyles(styles)(
         connect(getTokenDialogData)(
             withDialog(TOKEN_DIALOG_NAME)(TokenDialogComponent)));
-
diff --git a/services/workbench2/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx b/services/workbench2/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx
index a32044a711..5aab053d8e 100644
--- a/services/workbench2/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx
+++ b/services/workbench2/src/views-components/webdav-s3-dialog/webdav-s3-dialog.tsx
@@ -170,7 +170,7 @@ export const WebDavS3InfoDialog = compose(
 
                     <DetailsAttribute
                         label='Internet address'
-                        value={<a href={winDav.toString()} target="_blank" rel="noopener noreferrer">{winDav.toString()}</a>}
+                        value={<a href={winDav.toString()} target="_blank" rel="noopener">{winDav.toString()}</a>}
                         copyValue={winDav.toString()} />
 
                     <DetailsAttribute
@@ -202,7 +202,7 @@ export const WebDavS3InfoDialog = compose(
                 <TabPanel index={0} value={activeTab}>
                     <DetailsAttribute
                         label='Server'
-                        value={<a href={cyberDavStr} target="_blank" rel="noopener noreferrer">{cyberDavStr}</a>}
+                        value={<a href={cyberDavStr} target="_blank" rel="noopener">{cyberDavStr}</a>}
                         copyValue={cyberDavStr} />
 
                     <DetailsAttribute
diff --git a/services/workbench2/src/views/process-panel/process-io-card.tsx b/services/workbench2/src/views/process-panel/process-io-card.tsx
index da4d150a29..5716340edc 100644
--- a/services/workbench2/src/views/process-panel/process-io-card.tsx
+++ b/services/workbench2/src/views/process-panel/process-io-card.tsx
@@ -854,7 +854,7 @@ const KeepUrlPath = withStyles(styles)(({ auth, res, pdh, classes }: KeepUrlProp
                 className={classes.keepLink}
                 href={keepUrlPathNav}
                 target="_blank"
-                rel="noopener noreferrer"
+                rel="noopener"
             >
                 {keepUrlPath || "/"}
             </a>
@@ -934,6 +934,7 @@ const fileToProcessIOValue = (file: File, secondary: boolean, auth: AuthState, p
                 <MuiLink
                     href={file.location}
                     target="_blank"
+                    rel="noopener"
                 >
                     {file.location}
                 </MuiLink>
diff --git a/services/workbench2/src/views/process-panel/process-log-code-snippet.tsx b/services/workbench2/src/views/process-panel/process-log-code-snippet.tsx
index 50d343d622..77857822a4 100644
--- a/services/workbench2/src/views/process-panel/process-log-code-snippet.tsx
+++ b/services/workbench2/src/views/process-panel/process-log-code-snippet.tsx
@@ -33,7 +33,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         },
     },
     logText: {
-        padding: `0 ${theme.spacing.unit*0.5}px`,
+        padding: `0 ${theme.spacing.unit * 0.5}px`,
     },
     wordWrap: {
         whiteSpace: 'pre-wrap',
@@ -73,21 +73,21 @@ const renderLinks = (fontSize: number, auth: FederationConfig, dispatch: Dispatc
     }
     return <Typography style={{ fontSize: fontSize }}>
         {text.split(REGEX).map((part, index) =>
-        <React.Fragment key={index}>
-            {part}
-            {links[index] &&
-            <Link onClick={() => {
-                const url = getNavUrl(links[index], auth)
-                if (url) {
-                    window.open(`${window.location.origin}${url}`, '_blank');
-                } else {
-                    dispatch(navigationNotAvailable(links[index]));
-                }
-            }}
-                style={ {cursor: 'pointer'} }>
-                {links[index]}
-            </Link>}
-        </React.Fragment>
+            <React.Fragment key={index}>
+                {part}
+                {links[index] &&
+                    <Link onClick={() => {
+                        const url = getNavUrl(links[index], auth)
+                        if (url) {
+                            window.open(`${window.location.origin}${url}`, '_blank', "noopener");
+                        } else {
+                            dispatch(navigationNotAvailable(links[index]));
+                        }
+                    }}
+                        style={{ cursor: 'pointer' }}>
+                        {links[index]}
+                    </Link>}
+            </React.Fragment>
         )}
     </Typography>;
 };
@@ -97,7 +97,7 @@ const mapStateToProps = (state: RootState): ProcessLogCodeSnippetAuthProps => ({
 });
 
 export const ProcessLogCodeSnippet = withStyles(styles)(connect(mapStateToProps)(
-    ({classes, lines, fontSize, auth, dispatch, wordWrap}: ProcessLogCodeSnippetProps & WithStyles<CssRules> & ProcessLogCodeSnippetAuthProps & DispatchProp) => {
+    ({ classes, lines, fontSize, auth, dispatch, wordWrap }: ProcessLogCodeSnippetProps & WithStyles<CssRules> & ProcessLogCodeSnippetAuthProps & DispatchProp) => {
         const [followMode, setFollowMode] = useState<boolean>(true);
         const scrollRef = useRef<HTMLDivElement>(null);
 
@@ -112,18 +112,18 @@ export const ProcessLogCodeSnippet = withStyles(styles)(connect(mapStateToProps)
             <div ref={scrollRef} className={classes.root}
                 onScroll={(e) => {
                     const elem = e.target as HTMLDivElement;
-                    if (elem.scrollTop + (elem.clientHeight*1.1) >= elem.scrollHeight) {
+                    if (elem.scrollTop + (elem.clientHeight * 1.1) >= elem.scrollHeight) {
                         setFollowMode(true);
                     } else {
                         setFollowMode(false);
                     }
                 }}>
-                { lines.map((line: string, index: number) =>
-                <Typography key={index} component="pre"
-                    className={classNames(classes.logText, wordWrap ? classes.wordWrap : undefined)}>
-                    {renderLinks(fontSize, auth, dispatch)(line)}
-                </Typography>
-                ) }
+                {lines.map((line: string, index: number) =>
+                    <Typography key={index} component="pre"
+                        className={classNames(classes.logText, wordWrap ? classes.wordWrap : undefined)}>
+                        {renderLinks(fontSize, auth, dispatch)(line)}
+                    </Typography>
+                )}
             </div>
         </MuiThemeProvider>
     }));
diff --git a/services/workbench2/src/views/ssh-key-panel/ssh-key-panel-root.tsx b/services/workbench2/src/views/ssh-key-panel/ssh-key-panel-root.tsx
index 8a266d00c6..344352adc7 100644
--- a/services/workbench2/src/views/ssh-key-panel/ssh-key-panel-root.tsx
+++ b/services/workbench2/src/views/ssh-key-panel/ssh-key-panel-root.tsx
@@ -12,8 +12,8 @@ type CssRules = 'root' | 'link' | 'buttonContainer' | 'table' | 'tableRow' | 'ke
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     root: {
-       width: '100%',
-       overflow: 'auto'
+        width: '100%',
+        overflow: 'auto'
     },
     link: {
         color: theme.palette.primary.main,
@@ -55,16 +55,16 @@ export const SshKeyPanelRoot = withStyles(styles)(
             <CardContent>
                 <Grid container direction="row">
                     <Grid item xs={8}>
-                        { !hasKeys && <Typography  paragraph={true} >
+                        {!hasKeys && <Typography paragraph={true} >
                             You have not yet set up an SSH public key for use with Arvados.
                             <a href='https://doc.arvados.org/user/getting_started/ssh-access-unix.html'
-                                target='blank' className={classes.link}>
+                                target='blank' rel="noopener" className={classes.link}>
                                 Learn more.
                             </a>
                         </Typography>}
-                        { !hasKeys && <Typography  paragraph={true}>
+                        {!hasKeys && <Typography paragraph={true}>
                             When you have an SSH key you would like to use, add it using button below.
-                        </Typography> }
+                        </Typography>}
                     </Grid>
                     <Grid item xs={4} className={classes.buttonContainer}>
                         <Button onClick={openSshKeyCreateDialog} color="primary" variant="contained">
@@ -113,4 +113,4 @@ export const SshKeyPanelRoot = withStyles(styles)(
                 </Grid>
             </CardContent>
         </Card>
-    );
+);
diff --git a/services/workbench2/src/views/virtual-machine-panel/virtual-machine-user-panel.tsx b/services/workbench2/src/views/virtual-machine-panel/virtual-machine-user-panel.tsx
index 56c92805e2..36d432f95a 100644
--- a/services/workbench2/src/views/virtual-machine-panel/virtual-machine-user-panel.tsx
+++ b/services/workbench2/src/views/virtual-machine-panel/virtual-machine-user-panel.tsx
@@ -174,7 +174,7 @@ const CardContentWithVirtualMachines = (props: VirtualMachineProps) =>
                         {virtualMachineSendRequest(props)}
                     </div>
                     <div className={props.classes.icon}>
-                        <a href="https://doc.arvados.org/user/getting_started/vm-login-with-webshell.html" target="_blank" rel="noopener noreferrer" className={props.classes.linkIcon}>
+                        <a href="https://doc.arvados.org/user/getting_started/vm-login-with-webshell.html" target="_blank" rel="noopener" className={props.classes.linkIcon}>
                             <Tooltip title="Access VM using webshell">
                                 <HelpIcon />
                             </Tooltip>
@@ -219,7 +219,7 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                         const command = `ssh ${username}@${it.hostname}${props.hostSuffix}`;
                         let tokenParam = "";
                         if (props.tokenLocation === SESSION_STORAGE || props.tokenLocation === EXTRA_TOKEN) {
-                          tokenParam = `&token=${encodeURIComponent(props.token)}`;
+                            tokenParam = `&token=${encodeURIComponent(props.token)}`;
                         }
                         const loginHref = `/webshell/?host=${encodeURIComponent(props.webshellUrl + '/' + it.hostname)}&timeout=${props.idleTimeout}&login=${encodeURIComponent(username)}${tokenParam}`;
                         return <TableRow key={lk.uuid}>
@@ -228,11 +228,11 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                             <TableCell>
                                 <Grid container spacing={8} className={props.classes.chipsRoot}>
                                     {
-                                    (lk.properties.groups || []).map((group, i) => (
-                                        <Grid item key={i}>
-                                            <Chip label={group} />
-                                        </Grid>
-                                    ))
+                                        (lk.properties.groups || []).map((group, i) => (
+                                            <Grid item key={i}>
+                                                <Chip label={group} />
+                                            </Grid>
+                                        ))
                                     }
                                 </Grid>
                             </TableCell>
@@ -253,8 +253,8 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                                     size="small"
                                     href={loginHref}
                                     target="_blank"
-                                    rel="noopener noreferrer">
-                                        Log in as {username}
+                                    rel="noopener">
+                                    Log in as {username}
                                 </Button>
                             </TableCell>
                         </TableRow>;

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list