// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import React from 'react'; import { Grid, Typography, withStyles, Tooltip, IconButton, Checkbox, Chip } from '@material-ui/core'; import { FavoriteStar, PublicFavoriteStar } from '../favorite-star/favorite-star'; import { Resource, ResourceKind, TrashableResource } from 'models/resource'; import { FreezeIcon, ProjectIcon, FilterGroupIcon, CollectionIcon, ProcessIcon, DefaultIcon, ShareIcon, CollectionOldVersionIcon, WorkflowIcon, RemoveIcon, RenameIcon, ActiveIcon, SetupIcon, InactiveIcon, } from 'components/icon/icon'; 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 { ArvadosTheme } from 'common/custom-theme'; import { compose, Dispatch } from 'redux'; import { WorkflowResource } from 'models/workflow'; import { ResourceStatus as WorkflowStatus } from 'views/workflow-panel/workflow-panel-view'; import { getUuidPrefix, openRunProcess } from 'store/workflow-panel/workflow-panel-actions'; import { openSharingDialog } from 'store/sharing-dialog/sharing-dialog-actions'; import { getUserFullname, getUserDisplayName, User, UserResource } from 'models/user'; import { toggleIsAdmin } from 'store/users/users-actions'; import { LinkClass, LinkResource } from 'models/link'; import { navigateTo, navigateToGroupDetails, navigateToUserProfile } from 'store/navigation/navigation-action'; import { withResourceData } from 'views-components/data-explorer/with-resources'; import { CollectionResource } from 'models/collection'; import { IllegalNamingWarning } from 'components/warning/warning'; import { loadResource } from 'store/resources/resources-actions'; import { BuiltinGroups, getBuiltinGroupUuid, GroupClass, GroupResource, isBuiltinGroup } from 'models/group'; import { openRemoveGroupMemberDialog } from 'store/group-details-panel/group-details-panel-actions'; import { setMemberIsHidden } from 'store/group-details-panel/group-details-panel-actions'; import { formatPermissionLevel } from 'views-components/sharing-dialog/permission-select'; import { PermissionLevel } from 'models/permission'; import { openPermissionEditContextMenu } from 'store/context-menu/context-menu-actions'; 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'; const renderName = (dispatch: Dispatch, item: GroupContentsResource) => { const navFunc = ("groupClass" in item && item.groupClass === GroupClass.ROLE ? navigateToGroupDetails : navigateTo); return {renderIcon(item)} dispatch(navFunc(item.uuid))}> {item.kind === ResourceKind.PROJECT || item.kind === ResourceKind.COLLECTION ? : null} {item.name} { item.kind === ResourceKind.PROJECT && } ; }; const FrozenProject = (props: {item: ProjectResource}) => { const [fullUsername, setFullusername] = React.useState(null); const getFullName = React.useCallback(() => { if (props.item.frozenByUuid) { setFullusername(); } }, [props.item, setFullusername]) if (props.item.frozenByUuid) { return Project was frozen by {fullUsername}}> ; } else { return null; } } export const ResourceName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource; })((resource: GroupContentsResource & DispatchProp) => renderName(resource.dispatch, resource)); const renderIcon = (item: GroupContentsResource) => { switch (item.kind) { case ResourceKind.PROJECT: if (item.groupClass === GroupClass.FILTER) { return ; } return ; case ResourceKind.COLLECTION: if (item.uuid === item.currentVersionUuid) { return ; } return ; case ResourceKind.PROCESS: return ; case ResourceKind.WORKFLOW: return ; default: return ; } }; const renderDate = (date?: string) => { return {formatDate(date)}; }; const renderWorkflowName = (item: WorkflowResource) => {renderIcon(item)} {item.name} ; export const ResourceWorkflowName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource; })(renderWorkflowName); const getPublicUuid = (uuidPrefix: string) => { return `${uuidPrefix}-tpzed-anonymouspublic`; }; const resourceShare = (dispatch: Dispatch, uuidPrefix: string, ownerUuid?: string, uuid?: string) => { const isPublic = ownerUuid === getPublicUuid(uuidPrefix); return (
{!isPublic && uuid && dispatch(openSharingDialog(uuid))}> }
); }; export const ResourceShare = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); const uuidPrefix = getUuidPrefix(state); return { uuid: resource ? resource.uuid : '', ownerUuid: resource ? resource.ownerUuid : '', uuidPrefix }; })((props: { ownerUuid?: string, uuidPrefix: string, uuid?: string } & DispatchProp) => resourceShare(props.dispatch, props.uuidPrefix, props.ownerUuid, props.uuid)); // User Resources const renderFirstName = (item: { firstName: string }) => { return {item.firstName}; }; export const ResourceFirstName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { firstName: '' }; })(renderFirstName); const renderLastName = (item: { lastName: string }) => {item.lastName}; export const ResourceLastName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { lastName: '' }; })(renderLastName); const renderFullName = (dispatch: Dispatch, item: { uuid: string, firstName: string, lastName: string }, link?: boolean) => { const displayName = (item.firstName + " " + item.lastName).trim() || item.uuid; return link ? dispatch(navigateToUserProfile(item.uuid))}> {displayName} : {displayName}; } export const UserResourceFullName = connect( (state: RootState, props: { uuid: string, link?: boolean }) => { const resource = getResource(props.uuid)(state.resources); return { item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link }; })((props: { item: { uuid: string, firstName: string, lastName: string }, link?: boolean } & DispatchProp) => renderFullName(props.dispatch, props.item, props.link)); const renderUuid = (item: { uuid: string }) => {item.uuid} {(item.uuid && ) || '-' } ; export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => ( getResource(props.uuid)(state.resources) || { uuid: '' } ))(renderUuid); const renderEmail = (item: { email: string }) => {item.email}; export const ResourceEmail = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { email: '' }; })(renderEmail); enum UserAccountStatus { ACTIVE = 'Active', INACTIVE = 'Inactive', SETUP = 'Setup', UNKNOWN = '' } const renderAccountStatus = (props: { status: UserAccountStatus }) => {(() => { switch (props.status) { case UserAccountStatus.ACTIVE: return ; case UserAccountStatus.SETUP: return ; case UserAccountStatus.INACTIVE: return ; default: return <>; } })()} {props.status} ; const getUserAccountStatus = (state: RootState, props: { uuid: string }) => { const user = getResource(props.uuid)(state.resources); // Get membership links for all users group const allUsersGroupUuid = getBuiltinGroupUuid(state.auth.localCluster, BuiltinGroups.ALL); const permissions = filterResources((resource: LinkResource) => resource.kind === ResourceKind.LINK && resource.linkClass === LinkClass.PERMISSION && resource.headUuid === allUsersGroupUuid && resource.tailUuid === props.uuid )(state.resources); if (user) { return user.isActive ? { status: UserAccountStatus.ACTIVE } : permissions.length > 0 ? { status: UserAccountStatus.SETUP } : { status: UserAccountStatus.INACTIVE }; } else { return { status: UserAccountStatus.UNKNOWN }; } } export const ResourceLinkTailAccountStatus = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); return link && link.tailKind === ResourceKind.USER ? getUserAccountStatus(state, { uuid: link.tailUuid }) : { status: UserAccountStatus.UNKNOWN }; })(renderAccountStatus); export const UserResourceAccountStatus = connect(getUserAccountStatus)(renderAccountStatus); const renderIsHidden = (props: { memberLinkUuid: string, permissionLinkUuid: string, visible: boolean, canManage: boolean, setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void }) => { if (props.memberLinkUuid) { return { e.stopPropagation(); props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.visible); }} />; } else { return ; } } export const ResourceLinkTailIsVisible = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const member = getResource(link?.tailUuid || '')(state.resources); const group = getResource(link?.headUuid || '')(state.resources); const permissions = filterResources((resource: LinkResource) => { return resource.linkClass === LinkClass.PERMISSION && resource.headUuid === link?.tailUuid && resource.tailUuid === group?.uuid && resource.name === PermissionLevel.CAN_READ; })(state.resources); const permissionLinkUuid = permissions.length > 0 ? permissions[0].uuid : ''; const isVisible = link && group && permissions.length > 0; // Consider whether the current user canManage this resurce in addition when it's possible const isBuiltin = isBuiltinGroup(link?.headUuid || ''); return member?.kind === ResourceKind.USER ? { memberLinkUuid: link?.uuid, permissionLinkUuid, visible: isVisible, canManage: !isBuiltin } : { memberLinkUuid: '', permissionLinkUuid: '', visible: false, canManage: false }; }, { setMemberIsHidden } )(renderIsHidden); const renderIsAdmin = (props: { uuid: string, isAdmin: boolean, toggleIsAdmin: (uuid: string) => void }) => { e.stopPropagation(); props.toggleIsAdmin(props.uuid); }} />; export const ResourceIsAdmin = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { isAdmin: false }; }, { toggleIsAdmin } )(renderIsAdmin); const renderUsername = (item: { username: string, uuid: string }) => {item.username || item.uuid}; export const ResourceUsername = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { username: '', uuid: props.uuid }; })(renderUsername); // Virtual machine resource const renderHostname = (item: { hostname: string }) => {item.hostname}; export const VirtualMachineHostname = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { hostname: '' }; })(renderHostname); const renderVirtualMachineLogin = (login: { user: string }) => {login.user} export const VirtualMachineLogin = connect( (state: RootState, props: { linkUuid: string }) => { const permission = getResource(props.linkUuid)(state.resources); const user = getResource(permission?.tailUuid || '')(state.resources); return { user: user?.username || permission?.tailUuid || '' }; })(renderVirtualMachineLogin); // Common methods const renderCommonData = (data: string) => {data}; const renderCommonDate = (date: string) => {formatDate(date)}; export const CommonUuid = withResourceData('uuid', renderCommonData); // Api Client Authorizations export const TokenApiClientId = withResourceData('apiClientId', renderCommonData); export const TokenApiToken = withResourceData('apiToken', renderCommonData); export const TokenCreatedByIpAddress = withResourceData('createdByIpAddress', renderCommonDate); export const TokenDefaultOwnerUuid = withResourceData('defaultOwnerUuid', renderCommonData); export const TokenExpiresAt = withResourceData('expiresAt', renderCommonDate); export const TokenLastUsedAt = withResourceData('lastUsedAt', renderCommonDate); export const TokenLastUsedByIpAddress = withResourceData('lastUsedByIpAddress', renderCommonData); export const TokenScopes = withResourceData('scopes', renderCommonData); export const TokenUserId = withResourceData('userId', renderCommonData); const clusterColors = [ ['#f44336', '#fff'], ['#2196f3', '#fff'], ['#009688', '#fff'], ['#cddc39', '#fff'], ['#ff9800', '#fff'] ]; export const ResourceCluster = (props: { uuid: string }) => { const CLUSTER_ID_LENGTH = 5; const pos = props.uuid.length > CLUSTER_ID_LENGTH ? props.uuid.indexOf('-') : 5; const clusterId = pos >= CLUSTER_ID_LENGTH ? props.uuid.substring(0, pos) : ''; const ci = pos >= CLUSTER_ID_LENGTH ? ((((( (props.uuid.charCodeAt(0) * props.uuid.charCodeAt(1)) + props.uuid.charCodeAt(2)) * props.uuid.charCodeAt(3)) + props.uuid.charCodeAt(4))) % clusterColors.length) : 0; return {clusterId}; }; // Links Resources const renderLinkName = (item: { name: string }) => {item.name || '(none)'}; export const ResourceLinkName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { name: '' }; })(renderLinkName); const renderLinkClass = (item: { linkClass: string }) => {item.linkClass}; export const ResourceLinkClass = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { linkClass: '' }; })(renderLinkClass); const getResourceDisplayName = (resource: Resource): string => { if ((resource as UserResource).kind === ResourceKind.USER && typeof (resource as UserResource).firstName !== 'undefined') { // We can be sure the resource is UserResource return getUserDisplayName(resource as UserResource); } else { return (resource as GroupContentsResource).name; } } const renderResourceLink = (dispatch: Dispatch, item: Resource) => { var displayName = getResourceDisplayName(item); return dispatch(navigateTo(item.uuid))}> {resourceLabel(item.kind, item && item.kind === ResourceKind.GROUP ? (item as GroupResource).groupClass || '' : '')}: {displayName || item.uuid} ; }; export const ResourceLinkTail = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); const tailResource = getResource(resource?.tailUuid || '')(state.resources); return { item: tailResource || { uuid: resource?.tailUuid || '', kind: resource?.tailKind || ResourceKind.NONE } }; })((props: { item: Resource } & DispatchProp) => renderResourceLink(props.dispatch, props.item)); export const ResourceLinkHead = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); const headResource = getResource(resource?.headUuid || '')(state.resources); return { item: headResource || { uuid: resource?.headUuid || '', kind: resource?.headKind || ResourceKind.NONE } }; })((props: { item: Resource } & DispatchProp) => renderResourceLink(props.dispatch, props.item)); export const ResourceLinkUuid = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { uuid: '' }; })(renderUuid); export const ResourceLinkHeadUuid = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const headResource = getResource(link?.headUuid || '')(state.resources); return headResource || { uuid: '' }; })(renderUuid); export const ResourceLinkTailUuid = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const tailResource = getResource(link?.tailUuid || '')(state.resources); return tailResource || { uuid: '' }; })(renderUuid); const renderLinkDelete = (dispatch: Dispatch, item: LinkResource, canManage: boolean) => { if (item.uuid) { return canManage ? dispatch(openRemoveGroupMemberDialog(item.uuid))}> : ; } else { return ; } } export const ResourceLinkDelete = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || ''); return { item: link || { uuid: '', kind: ResourceKind.NONE }, canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin, }; })((props: { item: LinkResource, canManage: boolean } & DispatchProp) => renderLinkDelete(props.dispatch, props.item, props.canManage)); export const ResourceLinkTailEmail = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const resource = getResource(link?.tailUuid || '')(state.resources); return resource || { email: '' }; })(renderEmail); export const ResourceLinkTailUsername = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const resource = getResource(link?.tailUuid || '')(state.resources); return resource || { username: '' }; })(renderUsername); const renderPermissionLevel = (dispatch: Dispatch, link: LinkResource, canManage: boolean) => { return {formatPermissionLevel(link.name as PermissionLevel)} {canManage ? dispatch(openPermissionEditContextMenu(event, link))}> : '' } ; } export const ResourceLinkHeadPermissionLevel = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || ''); return { link: link || { uuid: '', name: '', kind: ResourceKind.NONE }, canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin, }; })((props: { link: LinkResource, canManage: boolean } & DispatchProp) => renderPermissionLevel(props.dispatch, props.link, props.canManage)); export const ResourceLinkTailPermissionLevel = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || ''); return { link: link || { uuid: '', name: '', kind: ResourceKind.NONE }, canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin, }; })((props: { link: LinkResource, canManage: boolean } & DispatchProp) => renderPermissionLevel(props.dispatch, props.link, props.canManage)); const getResourceLinkCanManage = (state: RootState, link: LinkResource) => { const headResource = getResource(link.headUuid)(state.resources); // const tailResource = getResource(link.tailUuid)(state.resources); const userUuid = getUserUuid(state); if (headResource && headResource.kind === ResourceKind.GROUP) { return userUuid ? (headResource as GroupResource).writableBy?.includes(userUuid) : false; } else { // true for now return true; } } // Process Resources const resourceRunProcess = (dispatch: Dispatch, uuid: string) => { return (
{uuid && dispatch(openRunProcess(uuid))}> }
); }; export const ResourceRunProcess = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { uuid: resource ? resource.uuid : '' }; })((props: { uuid: string } & DispatchProp) => resourceRunProcess(props.dispatch, props.uuid)); const renderWorkflowStatus = (uuidPrefix: string, ownerUuid?: string) => { if (ownerUuid === getPublicUuid(uuidPrefix)) { return renderStatus(WorkflowStatus.PUBLIC); } else { return renderStatus(WorkflowStatus.PRIVATE); } }; const renderStatus = (status: string) => {status}; export const ResourceWorkflowStatus = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); const uuidPrefix = getUuidPrefix(state); return { ownerUuid: resource ? resource.ownerUuid : '', uuidPrefix }; })((props: { ownerUuid?: string, uuidPrefix: string }) => renderWorkflowStatus(props.uuidPrefix, props.ownerUuid)); const renderProcessState = (processState: string) => {processState || '-'} export const ResourceProcessState = connect( (state: RootState, props: { uuid: string }) => { const process = getProcess(props.uuid)(state.resources) return { state: process?.container?.state ? process?.container?.state : '' }; })((props: { state: string }) => renderProcessState(props.state)); export const ResourceProcessUuid = 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 })); export const ResourceOutputUuid = connect( (state: RootState, props: { uuid: string }) => { const process = getProcess(props.uuid)(state.resources) const outputUuid = process?.containerRequest.outputUuid return { uuid: outputUuid ? outputUuid : '' }; })((props: { uuid: string }) => renderUuid({ uuid: props.uuid })); export const ResourceLogUuid = connect( (state: RootState, props: { uuid: string }) => { const process = getProcess(props.uuid)(state.resources) const logUuid = process?.containerRequest.logUuid return { uuid: logUuid ? logUuid : '' }; })((props: { uuid: string }) => renderUuid({ uuid: props.uuid })); export const ResourceParentProcess = connect( (state: RootState, props: { uuid: string }) => { const process = getProcess(props.uuid)(state.resources) const parentProcessUuid = process?.containerRequest?.requestingContainerUuid return { parentProcess: parentProcessUuid || '' }; })((props: { parentProcess: string }) => renderUuid({uuid: props.parentProcess})); export const ResourceCreatedAtDate = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { date: resource ? resource.createdAt : '' }; })((props: { date: string }) => renderDate(props.date)); export const ResourceLastModifiedDate = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { date: resource ? resource.modifiedAt : '' }; })((props: { date: string }) => renderDate(props.date)); export const ResourceTrashDate = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { date: resource ? resource.trashAt : '' }; })((props: { date: string }) => renderDate(props.date)); export const ResourceDeleteDate = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { date: resource ? resource.deleteAt : '' }; })((props: { date: string }) => renderDate(props.date)); export const renderFileSize = (fileSize?: number) => {formatFileSize(fileSize)} ; export const ResourceFileSize = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); if (resource && resource.kind !== ResourceKind.COLLECTION) { return { fileSize: '' }; } return { fileSize: resource ? resource.fileSizeTotal : 0 }; })((props: { fileSize?: number }) => renderFileSize(props.fileSize)); const renderOwner = (owner: string) => {owner || '-'} ; export const ResourceOwner = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { owner: resource ? resource.ownerUuid : '' }; })((props: { owner: string }) => renderOwner(props.owner)); export const ResourceOwnerName = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); const ownerNameState = state.ownerName; const ownerName = ownerNameState.find(it => it.uuid === resource!.ownerUuid); return { owner: ownerName ? ownerName!.name : resource!.ownerUuid }; })((props: { owner: string }) => renderOwner(props.owner)); export const ResourceUUID = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { uuid: resource ? resource.uuid : '' }; })((props: { uuid: string }) => renderUuid({uuid: props.uuid})); const renderPortableDataHash = (portableDataHash:string | null) => {portableDataHash ? <>{portableDataHash} : '-' } export const ResourcePortableDataHash = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { portableDataHash: resource ? resource.portableDataHash : '' }; })((props: { portableDataHash: string }) => renderPortableDataHash(props.portableDataHash)); const renderVersion = (version: number) =>{ return {version ?? '-'} } export const ResourceVersion = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { version: resource ? resource.version: '' }; })((props: { version: number }) => renderVersion(props.version)); const renderDescription = (description: string)=>{ const truncatedDescription = description ? description.slice(0, 18) + '...' : '-' return {truncatedDescription}; } const renderFileCount = (fileCount: number) =>{ return {fileCount ?? '-'} } export const ResourceFileCount = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { fileCount: resource ? resource.fileCount: '' }; })((props: { fileCount: number }) => renderFileCount(props.fileCount)); export const ResourceDescription = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(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 userFromID = connect( (state: RootState, props: { uuid: string }) => { let userFullname = ''; const resource = getResource(props.uuid)(state.resources); if (resource) { userFullname = getUserFullname(resource as User) || (resource as GroupContentsResource).name; } return { uuid: props.uuid, userFullname }; }); const ownerFromResourceId = compose( connect((state: RootState, props: { uuid: string }) => { const childResource = getResource(props.uuid)(state.resources); return { uuid: childResource ? (childResource as Resource).ownerUuid : '' }; }), userFromID ); const _resourceWithName = withStyles({}, { withTheme: true }) ((props: { uuid: string, userFullname: string, dispatch: Dispatch, theme: ArvadosTheme }) => { const { uuid, userFullname, dispatch, theme } = props; if (userFullname === '') { dispatch(loadResource(uuid, false)); return {uuid} ; } return {userFullname} ({uuid}) ; }); export const ResourceOwnerWithName = ownerFromResourceId(_resourceWithName); export const ResourceWithName = userFromID(_resourceWithName); export const UserNameFromID = compose(userFromID)( (props: { uuid: string, displayAsText?: string, userFullname: string, dispatch: Dispatch }) => { const { uuid, userFullname, dispatch } = props; if (userFullname === '') { dispatch(loadResource(uuid, false)); } return {userFullname ? userFullname : uuid} ; }); export const ResponsiblePerson = compose( connect( (state: RootState, props: { uuid: string, parentRef: HTMLElement | null }) => { let responsiblePersonName: string = ''; let responsiblePersonUUID: string = ''; let responsiblePersonProperty: string = ''; if (state.auth.config.clusterConfig.Collections.ManagedProperties) { let index = 0; const keys = Object.keys(state.auth.config.clusterConfig.Collections.ManagedProperties); while (!responsiblePersonProperty && keys[index]) { const key = keys[index]; if (state.auth.config.clusterConfig.Collections.ManagedProperties[key].Function === 'original_owner') { responsiblePersonProperty = key; } index++; } } let resource: Resource | undefined = getResource(props.uuid)(state.resources); while (resource && resource.kind !== ResourceKind.USER && responsiblePersonProperty) { responsiblePersonUUID = (resource as CollectionResource).properties[responsiblePersonProperty]; resource = getResource(responsiblePersonUUID)(state.resources); } if (resource && resource.kind === ResourceKind.USER) { responsiblePersonName = getUserFullname(resource as UserResource) || (resource as GroupContentsResource).name; } return { uuid: responsiblePersonUUID, responsiblePersonName, parentRef: props.parentRef }; }), withStyles({}, { withTheme: true })) ((props: { uuid: string | null, responsiblePersonName: string, parentRef: HTMLElement | null, theme: ArvadosTheme }) => { const { uuid, responsiblePersonName, parentRef, theme } = props; if (!uuid && parentRef) { parentRef.style.display = 'none'; return null; } else if (parentRef) { parentRef.style.display = 'block'; } if (!responsiblePersonName) { return {uuid} ; } return {responsiblePersonName} ({uuid}) ; }); const renderType = (type: string, subtype: string) => {resourceLabel(type, subtype)} ; export const ResourceType = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return { type: resource ? resource.kind : '', subtype: resource && resource.kind === ResourceKind.GROUP ? resource.groupClass : '' }; })((props: { type: string, subtype: string }) => renderType(props.type, props.subtype)); export const ResourceStatus = connect((state: RootState, props: { uuid: string }) => { return { resource: getResource(props.uuid)(state.resources) }; })((props: { resource: GroupContentsResource }) => (props.resource && props.resource.kind === ResourceKind.COLLECTION) ? : ); export const CollectionStatus = connect((state: RootState, props: { uuid: string }) => { return { collection: getResource(props.uuid)(state.resources) }; })((props: { collection: CollectionResource }) => (props.collection.uuid !== props.collection.currentVersionUuid) ? version {props.collection.version} : head version ); export const CollectionName = connect((state: RootState, props: { uuid: string, className?: string }) => { return { collection: getResource(props.uuid)(state.resources), uuid: props.uuid, className: props.className, }; })((props: { collection: CollectionResource, uuid: string, className?: string }) => {props.collection?.name || props.uuid} ); export const ProcessStatus = compose( connect((state: RootState, props: { uuid: string }) => { return { process: getProcess(props.uuid)(state.resources) }; }), withStyles({}, { withTheme: true })) ((props: { process?: Process, theme: ArvadosTheme }) => props.process ? : - ); export const ProcessStartDate = connect( (state: RootState, props: { uuid: string }) => { const process = getProcess(props.uuid)(state.resources); return { date: (process && process.container) ? process.container.startedAt : '' }; })((props: { date: string }) => renderDate(props.date)); export const renderRunTime = (time: number) => {formatTime(time, true)} ; interface ContainerRunTimeProps { process: Process; } interface ContainerRunTimeState { runtime: number; } export const ContainerRunTime = connect((state: RootState, props: { uuid: string }) => { return { process: getProcess(props.uuid)(state.resources) }; })(class extends React.Component { private timer: any; constructor(props: ContainerRunTimeProps) { super(props); this.state = { runtime: this.getRuntime() }; } getRuntime() { return this.props.process ? getProcessRuntime(this.props.process) : 0; } updateRuntime() { this.setState({ runtime: this.getRuntime() }); } componentDidMount() { this.timer = setInterval(this.updateRuntime.bind(this), 5000); } componentWillUnmount() { clearInterval(this.timer); } render() { return renderRunTime(this.state.runtime); } });