Merge branch '19715-preserve-url-autologout' into main. Closes #19715
[arvados.git] / src / views-components / data-explorer / renderers.tsx
index c01e3918a7c7d2534438b02092e935cde415b276..d274157c48e2b1cd22804179fa33954c4b8fb361 100644 (file)
@@ -30,13 +30,13 @@ import {
     SetupIcon,
     InactiveIcon,
 } from 'components/icon/icon';
-import { formatDate, formatFileSize, formatTime, formatObjectProperties} from 'common/formatters';
+import { formatDate, formatFileSize, formatTime } from 'common/formatters';
 import { resourceLabel } from 'common/labels';
 import { connect, DispatchProp } from 'react-redux';
 import { RootState } from 'store/store';
 import { getResource, filterResources } from 'store/resources/resources';
 import { GroupContentsResource } from 'services/groups-service/groups-service';
-import { getProcess, Process, getProcessStatus, getProcessStatusColor, getProcessRuntime } from 'store/processes/process';
+import { getProcess, Process, getProcessStatus, getProcessStatusStyles, getProcessRuntime } from 'store/processes/process';
 import { ArvadosTheme } from 'common/custom-theme';
 import { compose, Dispatch } from 'redux';
 import { WorkflowResource } from 'models/workflow';
@@ -61,9 +61,10 @@ import { getUserUuid } from 'common/getuser';
 import { VirtualMachinesResource } from 'models/virtual-machines';
 import { CopyToClipboardSnackbar } from 'components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar';
 import { ProjectResource } from 'models/project';
+import { ProcessResource } from 'models/process';
 
-const renderName = (dispatch: Dispatch, item: GroupContentsResource) => {
 
+const renderName = (dispatch: Dispatch, item: GroupContentsResource) => {
     const navFunc = ("groupClass" in item && item.groupClass === GroupClass.ROLE ? navigateToGroupDetails : navigateTo);
     return <Grid container alignItems="center" wrap="nowrap" spacing={16}>
         <Grid item>
@@ -89,6 +90,7 @@ const renderName = (dispatch: Dispatch, item: GroupContentsResource) => {
     </Grid>;
 };
 
+
 const FrozenProject = (props: {item: ProjectResource}) => {
     const [fullUsername, setFullusername] = React.useState<any>(null);
     const getFullName = React.useCallback(() => {
@@ -113,6 +115,7 @@ export const ResourceName = connect(
         return resource;
     })((resource: GroupContentsResource & DispatchProp<any>) => renderName(resource.dispatch, resource));
 
+    
 const renderIcon = (item: GroupContentsResource) => {
     switch (item.kind) {
         case ResourceKind.PROJECT:
@@ -227,7 +230,12 @@ export const UserResourceFullName = connect(
 const renderUuid = (item: { uuid: string }) =>
     <Typography data-cy="uuid" noWrap>
         {item.uuid}
-        <CopyToClipboardSnackbar value={item.uuid} />
+        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-' }
+    </Typography>;
+
+const renderUuidCopyIcon = (item: { uuid: string }) =>
+    <Typography data-cy="uuid" noWrap>
+        {(item.uuid && <CopyToClipboardSnackbar value={item.uuid} />) || '-' }
     </Typography>;
 
 export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => (
@@ -446,7 +454,7 @@ export const ResourceCluster = (props: { uuid: string }) => {
 
 // Links Resources
 const renderLinkName = (item: { name: string }) =>
-    <Typography noWrap>{item.name || '(none)'}</Typography>;
+    <Typography noWrap>{item.name || '-'}</Typography>;
 
 export const ResourceLinkName = connect(
     (state: RootState, props: { uuid: string }) => {
@@ -664,7 +672,59 @@ export const ResourceWorkflowStatus = connect(
         };
     })((props: { ownerUuid?: string, uuidPrefix: string }) => renderWorkflowStatus(props.uuidPrefix, props.ownerUuid));
 
-export const ResourceCreatedAtDate = connect(
+export const ResourceContainerUuid = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const process = getProcess(props.uuid)(state.resources)
+        return { uuid: process?.container?.uuid ? process?.container?.uuid : '' };
+    })((props: { uuid: string }) => renderUuid({ uuid: props.uuid }));
+
+enum ColumnSelection {
+    OUTPUT_UUID = 'outputUuid',
+    LOG_UUID = 'logUuid'
+}
+
+const renderUuidLinkWithCopyIcon = (dispatch: Dispatch, item: ProcessResource, column: string) => {
+    const selectedColumnUuid = item[column]
+    return <Grid container alignItems="center" wrap="nowrap" >
+        <Grid item>
+            {selectedColumnUuid ? 
+                <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} noWrap 
+                    onClick={() => dispatch<any>(navigateTo(selectedColumnUuid))}>
+                    {selectedColumnUuid} 
+                </Typography> 
+            : '-' }
+        </Grid>
+        <Grid item>
+            {selectedColumnUuid && renderUuidCopyIcon({ uuid: selectedColumnUuid })}
+        </Grid>
+    </Grid>;
+};
+
+export const ResourceOutputUuid = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource<ProcessResource>(props.uuid)(state.resources);
+        return resource;
+    })((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.OUTPUT_UUID));
+
+export const ResourceLogUuid = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource<ProcessResource>(props.uuid)(state.resources);
+        return resource;
+    })((process: ProcessResource & DispatchProp<any>) => renderUuidLinkWithCopyIcon(process.dispatch, process, ColumnSelection.LOG_UUID));
+
+export const ResourceParentProcess = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const process = getProcess(props.uuid)(state.resources)
+        return { parentProcess: process?.containerRequest?.requestingContainerUuid || '' };
+    })((props: { parentProcess: string }) => renderUuid({uuid: props.parentProcess}));
+
+export const ResourceModifiedByUserUuid = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const process = getProcess(props.uuid)(state.resources)
+        return { userUuid: process?.containerRequest?.modifiedByUserUuid || '' };
+    })((props: { userUuid: string }) => renderUuid({uuid: props.userUuid}));
+
+    export const ResourceCreatedAtDate = connect(
     (state: RootState, props: { uuid: string }) => {
         const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
         return { date: resource ? resource.createdAt : '' };
@@ -706,7 +766,7 @@ export const ResourceFileSize = connect(
 
 const renderOwner = (owner: string) =>
     <Typography noWrap>
-        {owner}
+        {owner || '-'}
     </Typography>;
 
 export const ResourceOwner = connect(
@@ -729,20 +789,6 @@ export const ResourceUUID = connect(
         return { uuid: resource ? resource.uuid : '' };
     })((props: { uuid: string }) => renderUuid({uuid: props.uuid}));
 
-const renderMetadata = (metadata:any) => {
-    return <>{formatObjectProperties(metadata).map((property, i)=>
-        <Typography key={i} noWrap>{property[0]}: {property[1]}</Typography>
-    )}</>
-}
-
-export const ResourceMetadata = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
-        const metadata = resource && Object.keys(resource.properties).length ? resource.properties : {}
-        if(resource && resource.portableDataHash) metadata['Portable Data Hash'] = resource.portableDataHash
-        return { properties: metadata };
-    })((props: { properties: string }) => renderMetadata(props.properties));
-
 const renderVersion = (version: number) =>{
     return <Typography>{version ?? '-'}</Typography>
 }
@@ -752,21 +798,29 @@ export const ResourceVersion = connect(
         const resource = getResource<CollectionResource>(props.uuid)(state.resources);
         return { version: resource ? resource.version: '' };
     })((props: { version: number }) => renderVersion(props.version));
+    
+const renderPortableDataHash = (portableDataHash:string | null) => 
+    <Typography noWrap>
+        {portableDataHash ? <>{portableDataHash}
+        <CopyToClipboardSnackbar value={portableDataHash} /></> : '-' }
+    </Typography>
+    
+export const ResourcePortableDataHash = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+        return { portableDataHash: resource ? resource.portableDataHash : '' };    
+    })((props: { portableDataHash: string }) => renderPortableDataHash(props.portableDataHash));
+
 
-const renderDescription = (description: string)=>{
-    const truncatedDescription = description ? description.slice(0, 18) + '...' : '-'
-    return <Typography title={description}>{truncatedDescription}</Typography>;
+const renderFileCount = (fileCount: number) =>{
+    return <Typography>{fileCount ?? '-'}</Typography>
 }
 
-export const ResourceDescription = connect(
+export const ResourceFileCount = connect(
     (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
-        //testing---------------
-        const containerRequestDescription = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
-        if (resource && !resource.description && resource.kind === ResourceKind.PROCESS) resource.description = containerRequestDescription
-        //testing---------------
-        return { description: resource ? resource.description : '' };
-    })((props: { description: string }) => renderDescription(props.description));
+        const resource = getResource<CollectionResource>(props.uuid)(state.resources);
+        return { fileCount: resource ? resource.fileCount: '' };
+    })((props: { fileCount: number }) => renderFileCount(props.fileCount));
 
 const userFromID =
     connect(
@@ -790,11 +844,14 @@ const ownerFromResourceId =
         userFromID
     );
 
+
+
+
+
 const _resourceWithName =
     withStyles({}, { withTheme: true })
         ((props: { uuid: string, userFullname: string, dispatch: Dispatch, theme: ArvadosTheme }) => {
             const { uuid, userFullname, dispatch, theme } = props;
-
             if (userFullname === '') {
                 dispatch<any>(loadResource(uuid, false));
                 return <Typography style={{ color: theme.palette.primary.main }} inline noWrap>
@@ -811,6 +868,8 @@ export const ResourceOwnerWithName = ownerFromResourceId(_resourceWithName);
 
 export const ResourceWithName = userFromID(_resourceWithName);
 
+
+
 export const UserNameFromID =
     compose(userFromID)(
         (props: { uuid: string, displayAsText?: string, userFullname: string, dispatch: Dispatch }) => {
@@ -928,15 +987,14 @@ export const ProcessStatus = compose(
                 style={{
                     height: props.theme.spacing.unit * 3,
                     width: props.theme.spacing.unit * 12,
-                    backgroundColor: getProcessStatusColor(
+                    ...getProcessStatusStyles(
                         getProcessStatus(props.process), props.theme),
-                    color: props.theme.palette.common.white,
                     fontSize: '0.875rem',
                     borderRadius: props.theme.spacing.unit * 0.625,
                 }}
             />
             : <Typography>-</Typography>
-    );
+        );
 
 export const ProcessStartDate = connect(
     (state: RootState, props: { uuid: string }) => {
@@ -984,6 +1042,6 @@ export const ContainerRunTime = connect((state: RootState, props: { uuid: string
     }
 
     render() {
-        return renderRunTime(this.state.runtime);
+        return this.props.process ? renderRunTime(this.state.runtime) : <Typography>-</Typography>;
     }
 });