diff --git a/client/src/components/runs/logs/Log.js b/client/src/components/runs/logs/Log.js index ad10cb609e..91b3ff7ec2 100644 --- a/client/src/components/runs/logs/Log.js +++ b/client/src/components/runs/logs/Log.js @@ -43,7 +43,7 @@ import pipelineRunFSBrowserCache from '../../../models/pipelines/PipelineRunFSBr import PipelineRunCommit from '../../../models/pipelines/PipelineRunCommit'; import pipelines from '../../../models/pipelines/Pipelines'; import Roles from '../../../models/user/Roles'; -import PipelineRunUpdateSids from '../../../models/pipelines/PipelineRunUpdateSids'; +import PipelineRunUpdateSids, {AccessTypes} from '../../../models/pipelines/PipelineRunUpdateSids'; import { stopRun, canCommitRun, @@ -73,7 +73,7 @@ import LoadingView from '../../special/LoadingView'; import AWSRegionTag from '../../special/AWSRegionTag'; import DataStorageList from '../controls/data-storage-list'; import CommitRunDialog from './forms/CommitRunDialog'; -import ShareWithForm from './forms/ShareWithForm'; +import ShareWithForm, {ROLE_ALL, shouldCombineRoles} from './forms/ShareWithForm'; import DockerImageLink from './DockerImageLink'; import {getResumeFailureReason} from '../utilities/map-resume-failure-reason'; import RunTags from '../run-tags'; @@ -308,6 +308,15 @@ class Logs extends localization.LocalizedReactComponent { return false; } + get combineRolesIntoAllRoles () { + const {run} = this.state; + const {runSids = []} = run || {}; + return { + ssh: shouldCombineRoles(runSids, ROLE_ALL.includedRoles, AccessTypes.ssh), + endpoint: shouldCombineRoles(runSids, ROLE_ALL.includedRoles, AccessTypes.endpoint) + }; + } + exportLog = async () => { const {runId} = this.props; try { @@ -1670,8 +1679,24 @@ class Logs extends localization.LocalizedReactComponent { roleModel.isOwner(run) ) { let shareList = 'Not shared (click to configure)'; - if ((runSids || []).length > 0) { - shareList = (runSids || []) + const { + ssh: combineSshRoles, + endpoint: combineEndpointRoles + } = this.combineRolesIntoAllRoles; + const filteredRunSids = combineSshRoles || combineEndpointRoles + ? [ROLE_ALL, ...runSids] + .filter(({name, accessType}) => { + if ( + (combineSshRoles && accessType === AccessTypes.ssh) || + (combineEndpointRoles && accessType === AccessTypes.endpoint) + ) { + return !ROLE_ALL.includedRoles.includes(name); + } + return true; + }) + : runSids; + if (filteredRunSids.length > 0) { + shareList = filteredRunSids .map((s, index, array) => { return ( s)} pending={this.state.operationInProgress} onSave={this.operationWrapper(this.saveShareSids)} - onClose={this.closeShareDialog} /> + onClose={this.closeShareDialog} + runSharing + /> !!sids + .find((role) => !role.isPrincipal && + role.accessType === accessType && + role.name === roleName + ) + ); +}; + @observer export default class ShareWithForm extends React.Component { static propTypes = { @@ -49,7 +68,8 @@ export default class ShareWithForm extends React.Component { onClose: PropTypes.func, visible: PropTypes.bool, roles: PropTypes.array, - pending: PropTypes.bool + pending: PropTypes.bool, + runSharing: PropTypes.bool }; state = { @@ -65,6 +85,15 @@ export default class ShareWithForm extends React.Component { operationInProgress: false }; + get combineRolesIntoAllRoles () { + const {sids} = this.state; + const {runSharing} = this.props; + return { + ssh: runSharing && shouldCombineRoles(sids, ROLE_ALL.includedRoles, AccessTypes.ssh), + endpoint: runSharing && shouldCombineRoles(sids, ROLE_ALL.includedRoles, AccessTypes.endpoint) + }; + } + operationWrapper = (operation) => (...props) => { this.setState({ operationInProgress: true @@ -142,15 +171,16 @@ export default class ShareWithForm extends React.Component { ) : []; if (this.groupFind && !this.groupFind.pending && !this.groupFind.error) { - return [ - ...new Set( - [ - ...roles, - ...(this.groupFind.value || []).map(g => g)] - ) - ].sort((u1, u2) => sortByOverlap(u1, u2, query)); + const set = [...new Set([ + ...(this.props.runSharing ? [ROLE_ALL.name] : []), + ...roles, + ...(this.groupFind.value || []).map(g => g) + ])]; + return set + .sort((u1, u2) => sortByOverlap(u1, u2, query)); } - return [...roles].sort((u1, u2) => sortByOverlap(u1, u2, query)); + return [...roles] + .sort((u1, u2) => sortByOverlap(u1, u2, query)); }; openFindUserDialog = () => { @@ -164,7 +194,7 @@ export default class ShareWithForm extends React.Component { onSelectUser = async () => { const {userSearchString} = this.state; const selectedUser = userSearchString ? userSearchString.trim() : null; - await this.grantPermission(selectedUser, true); + this.grantPermission(selectedUser, true); this.closeFindUserDialog(); }; @@ -182,11 +212,15 @@ export default class ShareWithForm extends React.Component { const [role] = this.props.roles .filter(r => !r.predefined && this.splitRoleName(r.name) === selectedGroup); const roleName = role ? role.name : selectedGroup; - await this.grantPermission(roleName, false); + if (roleName === ROLE_ALL.name) { + ROLE_ALL.includedRoles.forEach(role => this.grantPermission(role, false)); + } else { + this.grantPermission(roleName, false); + } this.closeFindGroupDialog(); }; - grantPermission = async (name, isPrincipal) => { + grantPermission = (name, isPrincipal) => { if (name) { const sids = this.state.sids; const [sidItem] = sids.filter(s => { @@ -207,17 +241,15 @@ export default class ShareWithForm extends React.Component { removeUserOrGroupClicked = (item) => async (event) => { event.stopPropagation(); - const sids = this.state.sids; - const [sidItem] = sids.filter(s => { - return s.isPrincipal === item.isPrincipal && s.name.toLowerCase() === item.name.toLowerCase(); - }); - if (sidItem) { - const index = sids.indexOf(sidItem); - if (index >= 0) { - sids.splice(index, 1); - this.setState({sids}); + const {sids} = this.state; + const filterSids = ({name, isPrincipal}) => { + if (item.name === ROLE_ALL.name) { + return !ROLE_ALL.includedRoles.includes(name); } - } + return !(name.toLowerCase() === item.name.toLowerCase() && + isPrincipal === item.isPrincipal); + }; + this.setState({sids: sids.filter(filterSids)}); }; renderUserName = (user) => { @@ -326,9 +358,31 @@ export default class ShareWithForm extends React.Component { ); - const data = this.state.sids.map((p, index) => { + let data = this.state.sids.map((p, index) => { return {...p, id: index}; }); + const { + ssh: combineSshRoles, + endpoint: combineEndpointRoles + } = this.combineRolesIntoAllRoles; + if (combineSshRoles || combineEndpointRoles) { + data = [ + ...data, + { + ...ROLE_ALL, + key: ROLE_ALL.name, + id: data.length + } + ].filter(({name, accessType}) => { + if ( + (combineSshRoles && accessType === AccessTypes.ssh) || + (combineEndpointRoles && accessType === AccessTypes.endpoint) + ) { + return !ROLE_ALL.includedRoles.includes(name); + } + return true; + }); + } return (