mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
server: allow updating project name (#7149)
This PR adds name in updateProject API to allow renaming 'name' field with description from both API and UI level. Fixes: #7107 Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> Co-authored-by: Rahul Agarwal <rahul.agarwal@shapeblue.com> Co-authored-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
2ac1b7e959
commit
0ed4950896
@ -78,9 +78,9 @@ public interface ProjectService {
|
||||
|
||||
Project findByNameAndDomainId(String name, long domainId);
|
||||
|
||||
Project updateProject(long id, String displayText, String newOwnerName) throws ResourceAllocationException;
|
||||
Project updateProject(long id, String name, String displayText, String newOwnerName) throws ResourceAllocationException;
|
||||
|
||||
Project updateProject(long id, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
|
||||
Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
|
||||
|
||||
boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType);
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.api.response.UserResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.event.EventTypes;
|
||||
@ -35,7 +36,6 @@ import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.projects.Project;
|
||||
import com.cloud.projects.ProjectAccount;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@APICommand(name = "updateProject", description = "Updates a project", responseObject = ProjectResponse.class, since = "3.0.0",
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
@ -67,6 +67,9 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
|
||||
"to promote or demote the user/account based on the roleType (Regular or Admin) provided. Defaults to true")
|
||||
private Boolean swapOwner;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the project", since = "4.19.0")
|
||||
private String name;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -87,6 +90,10 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ProjectAccount.Role getRoleType(String role) {
|
||||
String type = role.substring(0, 1).toUpperCase() + role.substring(1).toLowerCase();
|
||||
if (!EnumUtils.isValidEnum(ProjectAccount.Role.class, type)) {
|
||||
@ -136,9 +143,9 @@ public class UpdateProjectCmd extends BaseAsyncCmd {
|
||||
|
||||
Project project = null;
|
||||
if (isSwapOwner()) {
|
||||
project = _projectService.updateProject(getId(), getDisplayText(), getAccountName());
|
||||
project = _projectService.updateProject(getId(), getName(), getDisplayText(), getAccountName());
|
||||
} else {
|
||||
project = _projectService.updateProject(getId(), getDisplayText(), getAccountName(), getUserId(), getAccountRole());
|
||||
project = _projectService.updateProject(getId(), getName(), getDisplayText(), getAccountName(), getUserId(), getAccountRole());
|
||||
}
|
||||
if (project != null) {
|
||||
ProjectResponse response = _responseGenerator.createProjectResponse(project);
|
||||
|
||||
@ -18,9 +18,11 @@ package com.cloud.projects;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -33,26 +35,20 @@ import javax.inject.Inject;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
import org.apache.cloudstack.acl.ProjectRole;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.acl.dao.ProjectRoleDao;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
import org.apache.cloudstack.framework.config.Configurable;
|
||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
import org.apache.cloudstack.framework.messagebus.MessageBus;
|
||||
import org.apache.cloudstack.framework.messagebus.PublishScope;
|
||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||
import org.apache.cloudstack.utils.mailing.MailAddress;
|
||||
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
|
||||
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -72,11 +68,19 @@ import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.projects.Project.State;
|
||||
import com.cloud.projects.ProjectAccount.Role;
|
||||
import com.cloud.projects.dao.ProjectAccountDao;
|
||||
import com.cloud.projects.dao.ProjectDao;
|
||||
import com.cloud.projects.dao.ProjectInvitationDao;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.tags.dao.ResourceTagDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
@ -95,14 +99,10 @@ import com.cloud.utils.db.TransactionCallbackNoReturn;
|
||||
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
|
||||
import com.cloud.utils.db.TransactionStatus;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
import org.apache.cloudstack.framework.config.Configurable;
|
||||
import org.apache.cloudstack.utils.mailing.MailAddress;
|
||||
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
|
||||
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Component
|
||||
public class ProjectManagerImpl extends ManagerBase implements ProjectManager, Configurable {
|
||||
@ -650,7 +650,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
|
||||
@Override
|
||||
@DB
|
||||
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
|
||||
public Project updateProject(final long projectId, final String displayText, final String newOwnerName) throws ResourceAllocationException {
|
||||
public Project updateProject(final long projectId, String name, final String displayText, final String newOwnerName) throws ResourceAllocationException {
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
//check that the project exists
|
||||
@ -666,10 +666,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
|
||||
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
|
||||
@Override
|
||||
public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
|
||||
if (displayText != null) {
|
||||
project.setDisplayText(displayText);
|
||||
_projectDao.update(projectId, project);
|
||||
}
|
||||
updateProjectNameAndDisplayText(project, name, displayText);
|
||||
|
||||
if (newOwnerName != null) {
|
||||
//check that the new owner exists
|
||||
@ -717,7 +714,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
|
||||
@Override
|
||||
@DB
|
||||
@ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
|
||||
public Project updateProject(final long projectId, final String displayText, final String newOwnerName, Long userId,
|
||||
public Project updateProject(final long projectId, String name, final String displayText, final String newOwnerName, Long userId,
|
||||
Role newRole) throws ResourceAllocationException {
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
@ -737,10 +734,8 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
|
||||
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
|
||||
@Override
|
||||
public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
|
||||
if (displayText != null) {
|
||||
project.setDisplayText(displayText);
|
||||
_projectDao.update(projectId, project);
|
||||
}
|
||||
updateProjectNameAndDisplayText(project, name, displayText);
|
||||
|
||||
if (newOwnerName != null) {
|
||||
//check that the new owner exists
|
||||
Account updatedAcc = _accountMgr.getActiveAccountByName(newOwnerName, project.getDomainId());
|
||||
@ -1443,4 +1438,17 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager, C
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey<?>[] {ProjectSmtpEnabledSecurityProtocols, ProjectSmtpUseStartTLS};
|
||||
}
|
||||
|
||||
protected void updateProjectNameAndDisplayText(final ProjectVO project, String name, String displayText) {
|
||||
if (name == null && displayText == null){
|
||||
return;
|
||||
}
|
||||
if (name != null) {
|
||||
project.setName(name);
|
||||
}
|
||||
if (displayText != null) {
|
||||
project.setDisplayText(displayText);
|
||||
}
|
||||
_projectDao.update(project.getId(), project);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,12 +85,12 @@ public class MockProjectManagerImpl extends ManagerBase implements ProjectManage
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project updateProject(long id, String displayText, String newOwnerName) throws ResourceAllocationException {
|
||||
public Project updateProject(long id, String name, String displayText, String newOwnerName) throws ResourceAllocationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project updateProject(long id, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException {
|
||||
public Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.projects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.cloud.projects.dao.ProjectDao;
|
||||
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ProjectManagerImplTest {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
ProjectManagerImpl projectManager;
|
||||
|
||||
@Mock
|
||||
ProjectDao projectDao;
|
||||
|
||||
List<ProjectVO> updateProjects;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
updateProjects = new ArrayList<>();
|
||||
Mockito.when(projectDao.update(Mockito.anyLong(), Mockito.any(ProjectVO.class))).thenAnswer((Answer<Boolean>) invocation -> {
|
||||
ProjectVO project = (ProjectVO)invocation.getArguments()[1];
|
||||
updateProjects.add(project);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void runUpdateProjectNameAndDisplayTextTest(boolean nonNullName, boolean nonNullDisplayText) {
|
||||
ProjectVO projectVO = new ProjectVO();
|
||||
String newName = nonNullName ? "NewName" : null;
|
||||
String newDisplayText = nonNullDisplayText ? "NewDisplayText" : null;
|
||||
projectManager.updateProjectNameAndDisplayText(projectVO, newName, newDisplayText);
|
||||
if (!nonNullName && !nonNullDisplayText) {
|
||||
Assert.assertTrue(updateProjects.isEmpty());
|
||||
} else {
|
||||
Assert.assertFalse(updateProjects.isEmpty());
|
||||
Assert.assertEquals(1, updateProjects.size());
|
||||
ProjectVO updatedProject = updateProjects.get(0);
|
||||
Assert.assertNotNull(updatedProject);
|
||||
if (nonNullName) {
|
||||
Assert.assertEquals(newName, updatedProject.getName());
|
||||
}
|
||||
if (nonNullDisplayText) {
|
||||
Assert.assertEquals(newDisplayText, updatedProject.getDisplayText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProjectNameAndDisplayTextNoUpdate() {
|
||||
runUpdateProjectNameAndDisplayTextTest(false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProjectNameAndDisplayTextUpdateName() {
|
||||
runUpdateProjectNameAndDisplayTextTest(true, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProjectNameAndDisplayTextUpdateDisplayText() {
|
||||
runUpdateProjectNameAndDisplayTextTest(false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateProjectNameAndDisplayTextUpdateNameDisplayText() {
|
||||
runUpdateProjectNameAndDisplayTextTest(true, true);
|
||||
}
|
||||
}
|
||||
@ -1821,49 +1821,20 @@ class TestProjectSuspendActivate(cloudstackTestCase):
|
||||
)
|
||||
return
|
||||
|
||||
class TestProjectWithEmptyDisplayText(cloudstackTestCase):
|
||||
|
||||
class TestProjectWithNameDisplayTextAction(cloudstackTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.testClient = super(
|
||||
TestProjectWithEmptyDisplayText,
|
||||
TestProjectWithNameDisplayTextAction,
|
||||
cls).getClsTestClient()
|
||||
cls.api_client = cls.testClient.getApiClient()
|
||||
|
||||
cls.services = Services().services
|
||||
# Get Zone
|
||||
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
cls.domain = get_domain(cls.api_client)
|
||||
cls.services['mode'] = cls.zone.networktype
|
||||
cls.template = get_test_template(
|
||||
cls.api_client,
|
||||
cls.zone.id,
|
||||
cls.hypervisor
|
||||
)
|
||||
cls._cleanup = []
|
||||
cls.isGlobalSettingInvalid = False
|
||||
configs = Configurations.list(
|
||||
cls.api_client,
|
||||
name='project.invite.required'
|
||||
)
|
||||
|
||||
if (configs[0].value).lower() != 'false':
|
||||
cls.isGlobalSettingInvalid = True
|
||||
return
|
||||
|
||||
# Create account, service offering, disk offering etc.
|
||||
cls.disk_offering = DiskOffering.create(
|
||||
cls.api_client,
|
||||
cls.services["disk_offering"]
|
||||
)
|
||||
cls._cleanup.append(cls.disk_offering)
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.api_client,
|
||||
cls.services["service_offering"],
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.service_offering)
|
||||
cls.account = Account.create(
|
||||
cls.api_client,
|
||||
cls.services["account"],
|
||||
@ -1871,40 +1842,19 @@ class TestProjectWithEmptyDisplayText(cloudstackTestCase):
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.account)
|
||||
cls.user = Account.create(
|
||||
cls.api_client,
|
||||
cls.services["account"],
|
||||
admin=True,
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.user)
|
||||
|
||||
# Create project as a domain admin
|
||||
cls.project = Project.create(
|
||||
cls.api_client,
|
||||
cls.services["project"],
|
||||
account=cls.account.name,
|
||||
domainid=cls.account.domainid
|
||||
)
|
||||
cls._cleanup.append(cls.project)
|
||||
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestProjectWithEmptyDisplayText, cls).tearDownClass()
|
||||
super(TestProjectWithNameDisplayTextAction, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.dbclient = self.testClient.getDbConnection()
|
||||
self.cleanup = []
|
||||
|
||||
if self.isGlobalSettingInvalid:
|
||||
self.skipTest("'project.invite.required' should be set to false")
|
||||
return
|
||||
|
||||
def tearDown(self):
|
||||
super(TestProjectWithEmptyDisplayText, self).tearDown()
|
||||
super(TestProjectWithNameDisplayTextAction, self).tearDown()
|
||||
|
||||
@attr(
|
||||
tags=[
|
||||
@ -1919,20 +1869,17 @@ class TestProjectWithEmptyDisplayText(cloudstackTestCase):
|
||||
""" create Project with Empty DisplayText
|
||||
"""
|
||||
# Validate the following
|
||||
# 1. Create a project.
|
||||
# 2. Give empty displayText
|
||||
# 3. Verify displayText takes content of Project name.
|
||||
# 1. Create a project while giving empty displayText
|
||||
# 2. Verify displayText takes content of Project name.
|
||||
|
||||
self.services["project"]["displaytext"] = ""
|
||||
|
||||
# Create project as a domain admin
|
||||
project = Project.create(
|
||||
self.apiclient,
|
||||
self.services["project"],
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
|
||||
self.cleanup.append(project)
|
||||
|
||||
self.assertEqual(
|
||||
@ -1940,5 +1887,49 @@ class TestProjectWithEmptyDisplayText(cloudstackTestCase):
|
||||
project.name,
|
||||
"displayText does not matches project name"
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
@attr(
|
||||
tags=[
|
||||
"advanced",
|
||||
"basic",
|
||||
"sg",
|
||||
"eip",
|
||||
"advancedns",
|
||||
"simulator"],
|
||||
required_hardware="false")
|
||||
def test_12_update_project_name_display_text(self):
|
||||
""" Create Project and update its name
|
||||
"""
|
||||
# Validate the following
|
||||
# 1. Create a project
|
||||
# 2. Update project name and display text
|
||||
# 2. Verify name and display text for the project are updated
|
||||
|
||||
project = Project.create(
|
||||
self.apiclient,
|
||||
self.services["project"],
|
||||
account=self.account.name,
|
||||
domainid=self.account.domainid
|
||||
)
|
||||
self.cleanup.append(project)
|
||||
|
||||
new_name = "NewName"
|
||||
new_display_text = "NewDisplayText"
|
||||
project.update(self.apiclient, name=new_name, displaytext=new_display_text)
|
||||
updated_project = Project.list(
|
||||
self.apiclient,
|
||||
id=project.id,
|
||||
listall=True
|
||||
)[0]
|
||||
self.assertEqual(
|
||||
updated_project.name,
|
||||
new_name,
|
||||
"Project name not updated"
|
||||
)
|
||||
self.assertEqual(
|
||||
updated_project.displaytext,
|
||||
new_display_text,
|
||||
"Project displaytext not updated"
|
||||
)
|
||||
return
|
||||
|
||||
@ -101,7 +101,7 @@ export default {
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit.project.details',
|
||||
dataView: true,
|
||||
args: ['displaytext'],
|
||||
args: ['name', 'displaytext'],
|
||||
show: (record, store) => {
|
||||
return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user