[arvados] created: 2.7.0-6359-g0a39d337a1

git repository hosting git at public.arvados.org
Sat Apr 6 03:08:18 UTC 2024


        at  0a39d337a1c58d7cbdd51b2f852b84eebc1c68ef (commit)


commit 0a39d337a1c58d7cbdd51b2f852b84eebc1c68ef
Author: Stephen Smith <stephen at curii.com>
Date:   Fri Apr 5 23:05:57 2024 -0400

    21651: Update io card unit tests for virtual list
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

diff --git a/services/workbench2/src/views/process-panel/process-io-card.test.tsx b/services/workbench2/src/views/process-panel/process-io-card.test.tsx
index ff1ec24de1..c0feead398 100644
--- a/services/workbench2/src/views/process-panel/process-io-card.test.tsx
+++ b/services/workbench2/src/views/process-panel/process-io-card.test.tsx
@@ -11,7 +11,7 @@ import Adapter from "enzyme-adapter-react-16";
 import { Provider } from 'react-redux';
 import { ProcessIOCard, ProcessIOCardType } from './process-io-card';
 import { DefaultView } from "components/default-view/default-view";
-import { DefaultCodeSnippet } from "components/default-code-snippet/default-code-snippet";
+import { DefaultVirtualCodeSnippet } from "components/default-code-snippet/default-virtual-code-snippet";
 import { ProcessOutputCollectionFiles } from './process-output-collection-files';
 import { MemoryRouter } from 'react-router-dom';
 
@@ -111,7 +111,7 @@ describe('renderers', () => {
             // then
             expect(panel.find(CircularProgress).exists()).toBeFalsy();
             expect(panel.find(Tab).length).toBe(1);
-            expect(panel.find(DefaultCodeSnippet).text()).toContain(JSON.stringify(raw, null, 2));
+            expect(panel.find(DefaultVirtualCodeSnippet).text()).toContain(JSON.stringify(raw, null, 2).replace(/\n/g, ''));
         });
 
         it('shows main process with params', () => {

commit 015668c71b0d0a88fefab6783d3199472df95eb2
Author: Stephen Smith <stephen at curii.com>
Date:   Fri Apr 5 19:57:31 2024 -0400

    21651: Change io panel json tab to virtual list, fix layout issues
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

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 25bcb19e78..d9e7b87c92 100644
--- a/services/workbench2/src/views/process-panel/process-io-card.tsx
+++ b/services/workbench2/src/views/process-panel/process-io-card.tsx
@@ -65,7 +65,7 @@ import { ProcessOutputCollectionFiles } from "./process-output-collection-files"
 import { Process } from "store/processes/process";
 import { navigateTo } from "store/navigation/navigation-action";
 import classNames from "classnames";
-import { DefaultCodeSnippet } from "components/default-code-snippet/default-code-snippet";
+import { DefaultVirtualCodeSnippet } from "components/default-code-snippet/default-virtual-code-snippet";
 import { KEEP_URL_REGEX } from "models/resource";
 import { FixedSizeList } from 'react-window';
 import AutoSizer from "react-virtualized-auto-sizer";
@@ -82,6 +82,7 @@ type CssRules =
     | "paramTableRoot"
     | "paramTableCellText"
     | "mountsTableRoot"
+    | "jsonWrapper"
     | "keepLink"
     | "collectionLink"
     | "secondaryVal"
@@ -122,7 +123,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         color: theme.customs.colors.greyD,
         fontSize: "1.875rem",
     },
-    // Applies to each tab's content
+    // Applies to table tab's content
     tableWrapper: {
         height: "auto",
         maxHeight: `calc(100% - ${theme.spacing.unit * 6}px)`,
@@ -206,6 +207,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
             paddingRight: "25px",
         },
     },
+    // JSON tab wrapper
+    jsonWrapper: {
+        height: `calc(100% - ${theme.spacing.unit * 6}px)`,
+    },
     keepLink: {
         color: theme.palette.primary.main,
         textDecoration: "none",
@@ -418,7 +423,7 @@ export const ProcessIOCard = withStyles(styles)(
                                             </div>
                                         )}
                                         {(mainProcTabState === 1 || !hasParams) && (
-                                            <div className={classes.tableWrapper}>
+                                            <div className={classes.jsonWrapper}>
                                                 <ProcessIORaw data={raw} />
                                             </div>
                                         )}
@@ -505,7 +510,7 @@ export const ProcessIOCard = withStyles(styles)(
                                                 </>
                                             )}
                                             {isRawLoaded && (subProcTabState === 1 || (!hasInputMounts && !hasOutputCollecton)) && (
-                                                <div className={classes.tableWrapper}>
+                                                <div className={classes.jsonWrapper}>
                                                     <ProcessIORaw data={raw} />
                                                 </div>
                                             )}
@@ -650,9 +655,9 @@ interface ProcessIORawDataProps {
 }
 
 const ProcessIORaw = withStyles(styles)(({ data }: ProcessIORawDataProps) => (
-    <Paper elevation={0} style={{minWidth: "100%"}}>
-        <DefaultCodeSnippet
-            lines={[JSON.stringify(data, null, 2)]}
+    <Paper elevation={0} style={{minWidth: "100%", height: "100%"}}>
+        <DefaultVirtualCodeSnippet
+            lines={JSON.stringify(data, null, 2).split('\n')}
             linked
         />
     </Paper>

commit ff1759078071c52b857afdbe64713ebf0833fae4
Author: Stephen Smith <stephen at curii.com>
Date:   Fri Apr 5 19:21:19 2024 -0400

    21651: Create CopyResultToClipboard to format cmd for clipboard using callback
    
    Performs formatting on large text only when clicked
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

diff --git a/services/workbench2/src/components/copy-to-clipboard/copy-result-to-clipboard.ts b/services/workbench2/src/components/copy-to-clipboard/copy-result-to-clipboard.ts
new file mode 100644
index 0000000000..129002b247
--- /dev/null
+++ b/services/workbench2/src/components/copy-to-clipboard/copy-result-to-clipboard.ts
@@ -0,0 +1,63 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { ReactElementLike } from 'prop-types';
+import copy from 'copy-to-clipboard';
+
+interface CopyToClipboardProps {
+  getText: (() => string);
+  children: ReactElementLike;
+  onCopy?(text: string, result: boolean): void;
+  options?: {
+    debug?: boolean;
+    message?: string;
+    format?: string; // MIME type
+  };
+}
+
+export default class CopyResultToClipboard extends React.PureComponent<CopyToClipboardProps> {
+  static defaultProps = {
+    onCopy: undefined,
+    options: undefined
+  };
+
+  onClick = event => {
+    const {
+      getText,
+      onCopy,
+      children,
+      options
+    } = this.props;
+
+    const elem = React.Children.only(children);
+
+    const text = getText();
+
+    const result = copy(text, options);
+
+    if (onCopy) {
+      onCopy(text, result);
+    }
+
+    // Bypass onClick if it was present
+    if (elem && elem.props && typeof elem.props.onClick === 'function') {
+      elem.props.onClick(event);
+    }
+  };
+
+
+  render() {
+    const {
+      getText: _getText,
+      onCopy: _onCopy,
+      options: _options,
+      children,
+      ...props
+    } = this.props;
+    const elem = React.Children.only(children);
+
+    return React.cloneElement(elem, {...props, onClick: this.onClick});
+  }
+}
diff --git a/services/workbench2/src/views/process-panel/process-cmd-card.tsx b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
index 488b8d7fb4..6cef09b4a8 100644
--- a/services/workbench2/src/views/process-panel/process-cmd-card.tsx
+++ b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
@@ -21,7 +21,7 @@ import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 import { DefaultVirtualCodeSnippet } from 'components/default-code-snippet/default-virtual-code-snippet';
 import { Process } from 'store/processes/process';
 import shellescape from 'shell-escape';
-import CopyToClipboard from 'react-copy-to-clipboard';
+import CopyResultToClipboard from 'components/copy-to-clipboard/copy-result-to-clipboard';
 
 type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader';
 
@@ -83,6 +83,12 @@ export const ProcessCmdCard = withStyles(styles)(
       return `${indent}${line}${lineBreak}`;
     };
 
+    const formatClipboardText = (command: string[]) => (): string => (
+      command.map((v) =>
+        shellescape([v]) // Escape each arg separately
+      ).join(' ')
+    );
+
     return (
       <Card className={classes.card}>
         <CardHeader
@@ -102,12 +108,12 @@ export const ProcessCmdCard = withStyles(styles)(
               <Grid item>
                 <Tooltip title="Copy link to clipboard" disableFocusListener>
                   <IconButton>
-                    <CopyToClipboard
-                      text={" "}
+                    <CopyResultToClipboard
+                      getText={formatClipboardText(process.containerRequest.command)}
                       onCopy={() => onCopy("Command copied to clipboard")}
                     >
                       <CopyIcon />
-                    </CopyToClipboard>
+                    </CopyResultToClipboard>
                   </IconButton>
                 </Tooltip>
               </Grid>

commit 2bbea832f0a7a16e70b85b2e2ad9ca4637a80118
Author: Stephen Smith <stephen at curii.com>
Date:   Fri Apr 5 21:46:29 2024 -0400

    21651: Add line formatter to VirtualCodeSnippet to do cmd card line processing
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

diff --git a/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx b/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx
index bc43d5d9f2..09db2c0426 100644
--- a/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx
+++ b/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx
@@ -32,7 +32,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 
 export interface CodeSnippetDataProps {
     lines: string[];
-    lineTransformer?: (line: string) => string;
+    lineFormatter?: (lines: string[], index: number) => string;
     className?: string;
     apiResponse?: boolean;
     linked?: boolean;
@@ -49,10 +49,11 @@ const mapStateToProps = (state: RootState): CodeSnippetAuthProps => ({
 });
 
 export const VirtualCodeSnippet = withStyles(styles)(connect(mapStateToProps)(
-    ({ classes, lines, linked, className, apiResponse, dispatch, auth }: CodeSnippetProps & CodeSnippetAuthProps & DispatchProp) => {
-        const RenderRow = ({index, style}) => (
-            <span style={style}>{linked ? renderLinks(auth, dispatch)(lines[index]) : lines[index]}</span>
-        );
+    ({ classes, lines, lineFormatter, linked, className, apiResponse, dispatch, auth }: CodeSnippetProps & CodeSnippetAuthProps & DispatchProp) => {
+        const RenderRow = ({index, style}) => {
+            const lineContents = lineFormatter ? lineFormatter(lines, index) : lines[index];
+            return <span style={style}>{linked ? renderLinks(auth, dispatch)(lineContents) : lineContents}</span>
+        };
 
         return <Typography
             component="div"
diff --git a/services/workbench2/src/views/process-panel/process-cmd-card.tsx b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
index d7b47653e6..488b8d7fb4 100644
--- a/services/workbench2/src/views/process-panel/process-cmd-card.tsx
+++ b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
@@ -71,18 +71,17 @@ export const ProcessCmdCard = withStyles(styles)(
     classes,
     doHidePanel,
   }: ProcessCmdCardProps) => {
-    const command = process.containerRequest.command.map((v) =>
-      shellescape([v]) // Escape each arg separately
-    );
 
-    let formattedCommand = [...command];
-    formattedCommand.forEach((item, i, arr) => {
+    const formatLine = (lines: string[], index: number): string => {
+      // Escape each arg separately
+      let line = shellescape([lines[index]])
       // Indent lines after the first
-      const indent = i > 0 ? '  ' : '';
-      // Escape newlines on every non-last arg when there are multiple lines
-      const lineBreak = arr.length > 1 && i < arr.length - 1 ? ' \\' : '';
-      arr[i] = `${indent}${item}${lineBreak}`;
-    });
+      const indent = index > 0 ? '  ' : '';
+      // Add backslash "escaped linebreak"
+      const lineBreak = lines.length > 1 && index < lines.length - 1 ? ' \\' : '';
+
+      return `${indent}${line}${lineBreak}`;
+    };
 
     return (
       <Card className={classes.card}>
@@ -104,7 +103,7 @@ export const ProcessCmdCard = withStyles(styles)(
                 <Tooltip title="Copy link to clipboard" disableFocusListener>
                   <IconButton>
                     <CopyToClipboard
-                      text={command.join(" ")}
+                      text={" "}
                       onCopy={() => onCopy("Command copied to clipboard")}
                     >
                       <CopyIcon />
@@ -128,7 +127,11 @@ export const ProcessCmdCard = withStyles(styles)(
           }
         />
         <CardContent className={classes.content}>
-          <DefaultVirtualCodeSnippet lines={formattedCommand} linked />
+          <DefaultVirtualCodeSnippet
+            lines={process.containerRequest.command}
+            lineFormatter={formatLine}
+            linked
+          />
         </CardContent>
       </Card>
     );

commit a9a011ed1f1daec47a9bc306f13ff91a63954e42
Author: Stephen Smith <stephen at curii.com>
Date:   Fri Apr 5 17:43:16 2024 -0400

    21651: Add virtual code snippet, implement in cmd card
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen 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 47d8fe1bf0..3be1e4fc71 100644
--- a/services/workbench2/src/components/code-snippet/code-snippet.tsx
+++ b/services/workbench2/src/components/code-snippet/code-snippet.tsx
@@ -66,7 +66,7 @@ export const CodeSnippet = withStyles(styles)(connect(mapStateToProps)(
         </Typography>
 ));
 
-const renderLinks = (auth: FederationConfig, dispatch: Dispatch) => (text: string): JSX.Element => {
+export const renderLinks = (auth: FederationConfig, dispatch: Dispatch) => (text: string): JSX.Element => {
     // Matches UUIDs & PDHs
     const REGEX = /[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}|[0-9a-f]{32}\+\d+/g;
     const links = text.match(REGEX);
diff --git a/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx b/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx
new file mode 100644
index 0000000000..bc43d5d9f2
--- /dev/null
+++ b/services/workbench2/src/components/code-snippet/virtual-code-snippet.tsx
@@ -0,0 +1,75 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { StyleRulesCallback, WithStyles, Typography, withStyles } from '@material-ui/core';
+import { ArvadosTheme } from 'common/custom-theme';
+import classNames from 'classnames';
+import { connect, DispatchProp } from 'react-redux';
+import { RootState } from 'store/store';
+import { FederationConfig } from 'routes/routes';
+import { renderLinks } from './code-snippet';
+import { FixedSizeList } from 'react-window';
+import AutoSizer from "react-virtualized-auto-sizer";
+
+type CssRules = 'root' | 'space' | 'content' ;
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    root: {
+        boxSizing: 'border-box',
+        height: '100%',
+        padding: theme.spacing.unit,
+    },
+    space: {
+        marginLeft: '15px',
+    },
+    content: {
+        maxHeight: '100%',
+        height: '100vh',
+    },
+});
+
+export interface CodeSnippetDataProps {
+    lines: string[];
+    lineTransformer?: (line: string) => string;
+    className?: string;
+    apiResponse?: boolean;
+    linked?: boolean;
+}
+
+interface CodeSnippetAuthProps {
+    auth: FederationConfig;
+}
+
+type CodeSnippetProps = CodeSnippetDataProps & WithStyles<CssRules>;
+
+const mapStateToProps = (state: RootState): CodeSnippetAuthProps => ({
+    auth: state.auth,
+});
+
+export const VirtualCodeSnippet = withStyles(styles)(connect(mapStateToProps)(
+    ({ classes, lines, linked, className, apiResponse, dispatch, auth }: CodeSnippetProps & CodeSnippetAuthProps & DispatchProp) => {
+        const RenderRow = ({index, style}) => (
+            <span style={style}>{linked ? renderLinks(auth, dispatch)(lines[index]) : lines[index]}</span>
+        );
+
+        return <Typography
+            component="div"
+            className={classNames([classes.root, className])}>
+            <Typography className={classNames(classes.content, apiResponse ? classes.space : className)} component="pre">
+                <AutoSizer>
+                    {({ height, width }) =>
+                        <FixedSizeList
+                            height={height}
+                            width={width}
+                            itemSize={21}
+                            itemCount={lines.length}
+                        >
+                            {RenderRow}
+                        </FixedSizeList>
+                    }
+                </AutoSizer>
+            </Typography>
+        </Typography>;
+}));
diff --git a/services/workbench2/src/components/default-code-snippet/default-virtual-code-snippet.tsx b/services/workbench2/src/components/default-code-snippet/default-virtual-code-snippet.tsx
new file mode 100644
index 0000000000..581f0f4acc
--- /dev/null
+++ b/services/workbench2/src/components/default-code-snippet/default-virtual-code-snippet.tsx
@@ -0,0 +1,31 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
+import { VirtualCodeSnippet, CodeSnippetDataProps } from 'components/code-snippet/virtual-code-snippet';
+import grey from '@material-ui/core/colors/grey';
+import { themeOptions } from 'common/custom-theme';
+
+const theme = createMuiTheme(Object.assign({}, themeOptions, {
+    overrides: {
+        MuiTypography: {
+            body1: {
+                color: grey["900"]
+            },
+            root: {
+                backgroundColor: grey["200"]
+            }
+        }
+    },
+    typography: {
+        fontFamily: 'monospace',
+        useNextVariants: true,
+    }
+}));
+
+export const DefaultVirtualCodeSnippet = (props: CodeSnippetDataProps) =>
+    <MuiThemeProvider theme={theme}>
+        <VirtualCodeSnippet {...props} />
+    </MuiThemeProvider>;
diff --git a/services/workbench2/src/views/process-panel/process-cmd-card.tsx b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
index 478b0bc56f..d7b47653e6 100644
--- a/services/workbench2/src/views/process-panel/process-cmd-card.tsx
+++ b/services/workbench2/src/views/process-panel/process-cmd-card.tsx
@@ -18,7 +18,7 @@ import {
 import { ArvadosTheme } from 'common/custom-theme';
 import { CloseIcon, CommandIcon, CopyIcon } from 'components/icon/icon';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
-import { DefaultCodeSnippet } from 'components/default-code-snippet/default-code-snippet';
+import { DefaultVirtualCodeSnippet } from 'components/default-code-snippet/default-virtual-code-snippet';
 import { Process } from 'store/processes/process';
 import shellescape from 'shell-escape';
 import CopyToClipboard from 'react-copy-to-clipboard';
@@ -31,7 +31,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     },
     header: {
         paddingTop: theme.spacing.unit,
-        paddingBottom: theme.spacing.unit,
+        paddingBottom: 0,
     },
     iconHeader: {
         fontSize: '1.875rem',
@@ -42,8 +42,9 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         paddingTop: theme.spacing.unit * 0.5
     },
     content: {
+        height: `calc(100% - ${theme.spacing.unit * 6}px)`,
         padding: theme.spacing.unit * 1.0,
-        paddingTop: theme.spacing.unit * 0.5,
+        paddingTop: 0,
         '&:last-child': {
             paddingBottom: theme.spacing.unit * 1,
         }
@@ -52,7 +53,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         overflow: 'hidden',
         paddingTop: theme.spacing.unit * 0.5,
         color: theme.customs.colors.greyD,
-        fontSize: '1.875rem'  
+        fontSize: '1.875rem'
     },
 });
 
@@ -127,7 +128,7 @@ export const ProcessCmdCard = withStyles(styles)(
           }
         />
         <CardContent className={classes.content}>
-          <DefaultCodeSnippet lines={formattedCommand} linked />
+          <DefaultVirtualCodeSnippet lines={formattedCommand} linked />
         </CardContent>
       </Card>
     );
diff --git a/services/workbench2/src/views/process-panel/process-panel-root.tsx b/services/workbench2/src/views/process-panel/process-panel-root.tsx
index 2a9b3882e8..21f38b0938 100644
--- a/services/workbench2/src/views/process-panel/process-panel-root.tsx
+++ b/services/workbench2/src/views/process-panel/process-panel-root.tsx
@@ -198,6 +198,7 @@ export const ProcessPanelRoot = withStyles(styles)(
                 <MPVPanelContent
                     forwardProps
                     xs="auto"
+                    maxHeight={"50%"}
                     data-cy="process-cmd">
                     <ProcessCmdCard
                         onCopy={props.onCopyToClipboard}

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list