16672: Adds 'copy to clipboard' feature.
authorLucas Di Pentima <lucas.dipentima@curii.com>
Tue, 22 Mar 2022 14:19:26 +0000 (11:19 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Fri, 25 Mar 2022 20:59:23 +0000 (17:59 -0300)
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

src/views/process-panel/process-log-card.tsx
src/views/process-panel/process-panel-root.tsx
src/views/process-panel/process-panel.tsx

index 56ac4d92738110dd49325a2b6ed92b4f8fb5efff..ac409ec1873a25db7d039f5c779b665fcca09545 100644 (file)
@@ -19,6 +19,7 @@ import { ArvadosTheme } from 'common/custom-theme';
 import {
     CloseIcon,
     CollectionIcon,
+    CopyIcon,
     LogIcon,
     MaximizeIcon,
     TextDecreaseIcon,
@@ -34,6 +35,7 @@ import {
 import { ProcessLogCodeSnippet } from 'views/process-panel/process-log-code-snippet';
 import { DefaultView } from 'components/default-view/default-view';
 import { CodeSnippetDataProps } from 'components/code-snippet/code-snippet';
+import CopyToClipboard from 'react-copy-to-clipboard';
 
 type CssRules = 'card' | 'content' | 'title' | 'iconHeader' | 'header' | 'root' | 'logViewer' | 'logViewerContainer';
 
@@ -77,6 +79,7 @@ export interface ProcessLogsCardDataProps {
 export interface ProcessLogsCardActionProps {
     onLogFilterChange: (filter: FilterOption) => void;
     navigateToLog: (uuid: string) => void;
+    onCopy: (text: string) => void;
 }
 
 type ProcessLogsCardProps = ProcessLogsCardDataProps
@@ -86,7 +89,8 @@ type ProcessLogsCardProps = ProcessLogsCardDataProps
     & MPVPanelProps;
 
 export const ProcessLogsCard = withStyles(styles)(
-    ({ classes, process, filters, selectedFilter, lines, onLogFilterChange, navigateToLog,
+    ({ classes, process, filters, selectedFilter, lines,
+        onLogFilterChange, navigateToLog, onCopy,
         doHidePanel, doMaximizePanel, panelMaximized, panelName }: ProcessLogsCardProps) => {
         const [wordWrapToggle, setWordWrapToggle] = useState<boolean>(true);
         const [fontSize, setFontSize] = useState<number>(3);
@@ -116,6 +120,15 @@ export const ProcessLogsCard = withStyles(styles)(
                                 </IconButton>
                             </Tooltip>
                         </Grid>
+                        <Grid item>
+                            <Tooltip title="Copy to clipboard" disableFocusListener>
+                                <IconButton>
+                                    <CopyToClipboard text={lines.join()} onCopy={() => onCopy("Log copied to clipboard")}>
+                                        <CopyIcon />
+                                    </CopyToClipboard>
+                                </IconButton>
+                            </Tooltip>
+                        </Grid>
                         <Grid item>
                             <Tooltip title="Toggle word wrapping" disableFocusListener>
                                 <IconButton onClick={() => setWordWrapToggle(!wordWrapToggle)}>
index 862dbd68aba3b18b312b975b3a94806a57eccab1..3e695a2fb4fafbc428905208866579e3cbb2d6b3 100644 (file)
@@ -42,6 +42,7 @@ export interface ProcessPanelRootActionProps {
     cancelProcess: (uuid: string) => void;
     onLogFilterChange: (filter: FilterOption) => void;
     navigateToLog: (uuid: string) => void;
+    onLogCopyToClipboard: (uuid: string) => void;
 }
 
 export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps & WithStyles<CssRules>;
@@ -72,6 +73,7 @@ export const ProcessPanelRoot = withStyles(styles)(
             </MPVPanelContent>
             <MPVPanelContent forwardProps xs maxHeight='50%'>
                 <ProcessLogsCard
+                    onCopy={props.onLogCopyToClipboard}
                     process={process}
                     lines={getProcessPanelLogs(processLogsPanel)}
                     selectedFilter={{
index 6dd02c9b5c64c5025ef299cdd78d3ed885d7f3f9..e04602925798fb9c624bdb30e5d750d028fb6375 100644 (file)
@@ -25,6 +25,7 @@ import {
 import { openProcessInputDialog } from 'store/processes/process-input-actions';
 import { cancelRunningWorkflow } from 'store/processes/processes-actions';
 import { navigateToLogCollection, setProcessLogsPanelFilter } from 'store/process-logs-panel/process-logs-panel-actions';
+import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
 
 const mapStateToProps = ({ router, resources, processPanel, processLogsPanel }: RootState): ProcessPanelRootDataProps => {
     const uuid = getProcessPanelCurrentUuid(router) || '';
@@ -38,6 +39,13 @@ const mapStateToProps = ({ router, resources, processPanel, processLogsPanel }:
 };
 
 const mapDispatchToProps = (dispatch: Dispatch): ProcessPanelRootActionProps => ({
+    onLogCopyToClipboard: (message: string) => {
+        dispatch<any>(snackbarActions.OPEN_SNACKBAR({
+            message,
+            hideDuration: 2000,
+            kind: SnackbarKind.SUCCESS,
+        }));
+    },
     onContextMenu: (event, process) => {
         dispatch<any>(openProcessContextMenu(event, process));
     },