diff --git a/changelog/unreleased/enhancement-enable-rename-groups b/changelog/unreleased/enhancement-enable-rename-groups
new file mode 100644
index 00000000000..ce79f2abbf1
--- /dev/null
+++ b/changelog/unreleased/enhancement-enable-rename-groups
@@ -0,0 +1,6 @@
+Enhancement: Enable rename groups
+
+Groups can now be renamed via the admin-settings.
+
+https://github.com/owncloud/web/pull/8715
+https://github.com/owncloud/web/issues/8714
diff --git a/packages/web-app-admin-settings/src/components/Groups/ContextActions.vue b/packages/web-app-admin-settings/src/components/Groups/ContextActions.vue
index de1e316ef4f..c346e777707 100644
--- a/packages/web-app-admin-settings/src/components/Groups/ContextActions.vue
+++ b/packages/web-app-admin-settings/src/components/Groups/ContextActions.vue
@@ -9,7 +9,7 @@ import { useActionsShowDetails } from '../../../../web-pkg/src/composables/actio
import { computed, defineComponent, PropType, unref } from 'vue'
import ContextActionMenu from 'web-pkg/src/components/ContextActions/ContextActionMenu.vue'
import { GroupActionOptions } from 'web-pkg/src/composables/actions'
-import { useGroupActionsDelete } from '../../composables/actions/groups/useGroupActionsDelete'
+import { useGroupActionsEdit, useGroupActionsDelete } from '../../composables/actions/groups'
import { useStore } from 'web-pkg/src/composables'
export default defineComponent({
@@ -25,9 +25,12 @@ export default defineComponent({
const store = useStore()
const { actions: showDetailsActions } = useActionsShowDetails()
const { actions: deleteActions } = useGroupActionsDelete({ store })
+ const { actions: editActions } = useGroupActionsEdit()
const menuItemsPrimaryActions = computed(() =>
- [...unref(deleteActions)].filter((item) => item.isEnabled(props.actionOptions))
+ [...unref(editActions), ...unref(deleteActions)].filter((item) =>
+ item.isEnabled(props.actionOptions)
+ )
)
const menuItemsSidebar = computed(() =>
diff --git a/packages/web-app-admin-settings/src/components/Groups/CreateGroupModal.vue b/packages/web-app-admin-settings/src/components/Groups/CreateGroupModal.vue
index a787f99c67d..2fb6b82dc88 100644
--- a/packages/web-app-admin-settings/src/components/Groups/CreateGroupModal.vue
+++ b/packages/web-app-admin-settings/src/components/Groups/CreateGroupModal.vue
@@ -26,32 +26,28 @@
+
diff --git a/packages/web-app-admin-settings/src/composables/actions/groups/index.ts b/packages/web-app-admin-settings/src/composables/actions/groups/index.ts
index b8647746c40..307a19f2241 100644
--- a/packages/web-app-admin-settings/src/composables/actions/groups/index.ts
+++ b/packages/web-app-admin-settings/src/composables/actions/groups/index.ts
@@ -1 +1,2 @@
export * from './useGroupActionsDelete'
+export * from './useGroupActionsEdit'
diff --git a/packages/web-app-admin-settings/src/composables/actions/groups/useGroupActionsEdit.ts b/packages/web-app-admin-settings/src/composables/actions/groups/useGroupActionsEdit.ts
new file mode 100644
index 00000000000..976cb1777a0
--- /dev/null
+++ b/packages/web-app-admin-settings/src/composables/actions/groups/useGroupActionsEdit.ts
@@ -0,0 +1,27 @@
+import { eventBus } from 'web-pkg'
+import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar'
+import { useGettext } from 'vue3-gettext'
+import { computed } from 'vue'
+import { GroupAction } from 'web-pkg/src/composables/actions'
+
+export const useGroupActionsEdit = () => {
+ const { $gettext } = useGettext()
+
+ const actions = computed((): GroupAction[] => [
+ {
+ name: 'edit',
+ icon: 'pencil',
+ label: () => $gettext('Edit'),
+ handler: () => eventBus.publish(SideBarEventTopics.openWithPanel, 'EditPanel'),
+ isEnabled: ({ resources }) => {
+ return resources.length > 0
+ },
+ componentType: 'button',
+ class: 'oc-groups-actions-edit-trigger'
+ }
+ ])
+
+ return {
+ actions
+ }
+}
diff --git a/packages/web-app-admin-settings/src/views/Groups.vue b/packages/web-app-admin-settings/src/views/Groups.vue
index 21035a4ade4..69ae4b1d5b5 100644
--- a/packages/web-app-admin-settings/src/views/Groups.vue
+++ b/packages/web-app-admin-settings/src/views/Groups.vue
@@ -63,7 +63,6 @@
@@ -186,10 +185,11 @@ export default defineComponent({
title: this.$gettext('Edit group'),
component: EditPanel,
default: false,
- enabled: false // this.selectedGroups.length === 1
- /**
- * Editing groups is currently not supported by backend
- */
+ enabled: this.selectedGroups.length === 1,
+ componentAttrs: {
+ group: this.selectedGroups.length === 1 ? this.selectedGroups[0] : null,
+ onConfirm: this.editGroup
+ }
}
].filter((p) => p.enabled)
}
@@ -238,12 +238,20 @@ export default defineComponent({
try {
const client = this.clientService.graphAuthenticated
await client.groups.editGroup(editGroup.id, editGroup)
- const group = this.groups.find((group) => group.id === editGroup.id)
- Object.assign(group, editGroup)
+ const { data: updatedGroup } = await client.groups.getGroup(editGroup.id)
+ const groupIndex = this.groups.findIndex((group) => group.id === editGroup.id)
+ this.groups[groupIndex] = updatedGroup
+ const selectedGroupIndex = this.selectedGroups.findIndex(
+ (group) => group.id === updatedGroup.id
+ )
+ if (selectedGroupIndex >= 0) {
+ // FIXME: why do we need to update selectedUsers?
+ this.selectedGroups[selectedGroupIndex] = updatedGroup
+ }
- this.showMessage({
- title: this.$gettext('Group was edited successfully')
- })
+ eventBus.publish('sidebar.entity.saved')
+
+ return updatedGroup
} catch (error) {
console.error(error)
this.showMessage({
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/ContextActions.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Groups/ContextActions.spec.ts
index 4bf0bc2f5cf..5b9b6611c6e 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Groups/ContextActions.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/ContextActions.spec.ts
@@ -7,7 +7,10 @@ import {
import { mock } from 'jest-mock-extended'
import { Resource } from 'web-client/src/helpers'
import ContextActions from '../../../../src/components/Groups/ContextActions.vue'
-import { useGroupActionsDelete } from 'web-app-admin-settings/src/composables/actions'
+import {
+ useGroupActionsDelete,
+ useGroupActionsEdit
+} from 'web-app-admin-settings/src/composables/actions'
import { computed } from 'vue'
import { Action } from 'web-pkg/src/composables/actions'
@@ -25,6 +28,12 @@ jest.mock('web-app-admin-settings/src/composables/actions/groups/useGroupActions
)
)
+jest.mock('web-app-admin-settings/src/composables/actions/groups/useGroupActionsEdit', () =>
+ createMockActionComposables(
+ jest.requireActual('web-app-admin-settings/src/composables/actions/groups/useGroupActionsEdit')
+ )
+)
+
const selectors = {
actionMenuItemStub: 'action-menu-item-stub'
}
@@ -37,10 +46,13 @@ describe('ContextActions', () => {
})
it('render enabled actions', () => {
- const enabledComposables = [useGroupActionsDelete]
+ const enabledComposables = [useGroupActionsDelete, useGroupActionsEdit]
jest.mocked(useGroupActionsDelete).mockImplementation(() => ({
actions: computed(() => [mock({ isEnabled: () => true })])
}))
+ jest.mocked(useGroupActionsEdit).mockImplementation(() => ({
+ actions: computed(() => [mock({ isEnabled: () => true })])
+ }))
const { wrapper } = getWrapper()
expect(wrapper.findAll(selectors.actionMenuItemStub).length).toBe(enabledComposables.length)
})
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/CreateGroupModal.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Groups/CreateGroupModal.spec.ts
index 3057eebb4d7..6e5d1e9d65c 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Groups/CreateGroupModal.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/CreateGroupModal.spec.ts
@@ -1,5 +1,14 @@
import CreateGroupModal from '../../../../src/components/Groups/CreateGroupModal.vue'
-import { defaultPlugins, shallowMount } from 'web-test-helpers'
+import {
+ createStore,
+ defaultComponentMocks,
+ defaultPlugins,
+ defaultStoreMockOptions,
+ mockAxiosReject,
+ shallowMount
+} from 'web-test-helpers'
+import { mock } from 'jest-mock-extended'
+import { AxiosResponse } from 'axios'
describe('CreateGroupModal', () => {
describe('computed method "isFormInvalid"', () => {
@@ -8,48 +17,56 @@ describe('CreateGroupModal', () => {
wrapper.vm.formData.displayName.valid = false
expect(wrapper.vm.isFormInvalid).toBeTruthy()
})
- })
- it('should be false if no data set is invalid', () => {
- const { wrapper } = getWrapper()
- Object.keys(wrapper.vm.formData).forEach((key) => {
- wrapper.vm.formData[key].valid = true
+ it('should be false if no data set is invalid', () => {
+ const { wrapper } = getWrapper()
+ Object.keys(wrapper.vm.formData).forEach((key) => {
+ wrapper.vm.formData[key].valid = true
+ })
+ expect(wrapper.vm.isFormInvalid).toBeFalsy()
})
- expect(wrapper.vm.isFormInvalid).toBeFalsy()
})
-
describe('method "validateDisplayName"', () => {
- it('should be false when displayName is empty', () => {
+ it('should be false when displayName is empty', async () => {
const { wrapper } = getWrapper()
wrapper.vm.group.displayName = ''
- expect(wrapper.vm.validateDisplayName()).toBeFalsy()
+ expect(await wrapper.vm.validateDisplayName()).toBeFalsy()
})
- it('should be false when displayName is already existing', () => {
- const { wrapper } = getWrapper()
+ it('should be false when displayName is already existing', async () => {
+ const { wrapper, mocks } = getWrapper()
+ const graphMock = mocks.$clientService.graphAuthenticated
wrapper.vm.group.displayName = 'admins'
- expect(wrapper.vm.validateDisplayName()).toBeFalsy()
+ const getGroupSub = graphMock.groups.getGroup.mockResolvedValue(
+ mock({ data: { displayName: 'admins' } })
+ )
+ expect(await wrapper.vm.validateDisplayName()).toBeFalsy()
+ expect(getGroupSub).toHaveBeenCalled()
})
- it('should be true when displayName is valid', () => {
- const { wrapper } = getWrapper()
+ it('should be true when displayName is valid', async () => {
+ const { wrapper, mocks } = getWrapper()
+ const graphMock = mocks.$clientService.graphAuthenticated
+ const getGroupSub = graphMock.groups.getGroup.mockRejectedValue(() => mockAxiosReject())
wrapper.vm.group.displayName = 'users'
- expect(wrapper.vm.validateDisplayName()).toBeTruthy()
+ expect(await wrapper.vm.validateDisplayName()).toBeTruthy()
+ expect(getGroupSub).toHaveBeenCalled()
})
})
})
function getWrapper() {
+ const mocks = defaultComponentMocks()
+ const storeOptions = defaultStoreMockOptions
+ const store = createStore(storeOptions)
+
return {
+ mocks,
wrapper: shallowMount(CreateGroupModal, {
props: {
cancel: jest.fn(),
- confirm: jest.fn(),
- existingGroups: [
- {
- displayName: 'admins'
- }
- ]
+ confirm: jest.fn()
},
global: {
- plugins: [...defaultPlugins()]
+ mocks,
+ plugins: [...defaultPlugins(), store]
}
})
}
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/DetailsPanel.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/DetailsPanel.spec.ts
index bc3c4e6c698..492266cbf78 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/DetailsPanel.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/DetailsPanel.spec.ts
@@ -4,8 +4,10 @@ import { defaultPlugins, mount } from 'web-test-helpers'
describe('DetailsPanel', () => {
describe('computed method "group"', () => {
it('should be set if only one group is given', () => {
- const { wrapper } = getWrapper({ propsData: { groups: [{ displayName: 'group' }] } })
- expect(wrapper.vm.group).toEqual({ displayName: 'group' })
+ const { wrapper } = getWrapper({
+ propsData: { groups: [{ displayName: 'group', members: [] }] }
+ })
+ expect(wrapper.vm.group).toEqual({ displayName: 'group', members: [] })
})
it('should not be set if no groups are given', () => {
const { wrapper } = getWrapper({
@@ -15,7 +17,12 @@ describe('DetailsPanel', () => {
})
it('should not be set if multiple groups are given', () => {
const { wrapper } = getWrapper({
- propsData: { groups: [{ displayName: 'group1' }, { displayName: 'group2' }] }
+ propsData: {
+ groups: [
+ { displayName: 'group1', members: [] },
+ { displayName: 'group2', members: [] }
+ ]
+ }
})
expect(wrapper.vm.group).toEqual(null)
})
@@ -29,7 +36,9 @@ describe('DetailsPanel', () => {
expect(wrapper.vm.noGroups).toBeTruthy()
})
it('should be false if groups are given', () => {
- const { wrapper } = getWrapper({ propsData: { groups: [{ displayName: 'group' }] } })
+ const { wrapper } = getWrapper({
+ propsData: { groups: [{ displayName: 'group', members: [] }] }
+ })
expect(wrapper.vm.noGroups).toBeFalsy()
})
})
@@ -40,12 +49,14 @@ describe('DetailsPanel', () => {
expect(wrapper.vm.multipleGroups).toBeFalsy()
})
it('should be false if one group is given', () => {
- const { wrapper } = getWrapper({ propsData: { groups: [{ displayName: 'group' }] } })
+ const { wrapper } = getWrapper({
+ propsData: { groups: [{ displayName: 'group', members: [] }] }
+ })
expect(wrapper.vm.multipleGroups).toBeFalsy()
})
it('should be true if multiple groups are given', () => {
const { wrapper } = getWrapper({
- propsData: { groups: [{ displayName: 'group1' }, { displayName: 'group2' }] }
+ propsData: { groups: [{ displayName: 'group1' }, { displayName: 'group2', members: [] }] }
})
expect(wrapper.vm.multipleGroups).toBeTruthy()
})
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/EditPanel.spec.ts b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/EditPanel.spec.ts
index 0b1b3286a5a..922d86a21df 100644
--- a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/EditPanel.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/EditPanel.spec.ts
@@ -1,24 +1,29 @@
import EditPanel from '../../../../../src/components/Groups/SideBar/EditPanel.vue'
-import { defaultPlugins, mount } from 'web-test-helpers'
+import {
+ createStore,
+ defaultComponentMocks,
+ defaultPlugins,
+ defaultStoreMockOptions,
+ mockAxiosReject,
+ mount
+} from 'web-test-helpers'
+import { mock } from 'jest-mock-extended'
+import { AxiosResponse } from 'axios'
describe('EditPanel', () => {
+ it('renders all available inputs', () => {
+ const { wrapper } = getWrapper()
+ expect(wrapper.html()).toMatchSnapshot()
+ })
describe('method "revertChanges"', () => {
it('should revert changes on property editGroup', () => {
- const { wrapper } = getWrapper({
- propsData: {
- groups: [{ displayName: 'group' }]
- }
- })
- wrapper.vm.editGroup = { displayName: 'my group' }
+ const { wrapper } = getWrapper()
+ wrapper.vm.editGroup.dispayName = 'users'
wrapper.vm.revertChanges()
- expect(wrapper.vm.editGroup).toEqual({ displayName: 'group' })
+ expect(wrapper.vm.editGroup.displayName).toEqual('group')
})
it('should revert changes on property formData', () => {
- const { wrapper } = getWrapper({
- propsData: {
- groups: [{ displayName: 'group' }]
- }
- })
+ const { wrapper } = getWrapper()
wrapper.vm.formData.displayName.valid = false
wrapper.vm.formData.displayName.errorMessage = 'error'
wrapper.vm.revertChanges()
@@ -28,17 +33,28 @@ describe('EditPanel', () => {
})
describe('method "validateDisplayName"', () => {
- it('should return true if displayName is valid', () => {
- const { wrapper } = getWrapper()
- wrapper.vm.editGroup.displayName = 'jan'
- expect(wrapper.vm.validateDisplayName()).toBeTruthy()
- expect(wrapper.vm.formData.displayName.valid).toBeTruthy()
+ it('should return true if displayName is valid', async () => {
+ const { wrapper, mocks } = getWrapper()
+ wrapper.vm.editGroup.displayName = 'users'
+ const graphMock = mocks.$clientService.graphAuthenticated
+ const getGroupStub = graphMock.groups.getGroup.mockRejectedValue(() => mockAxiosReject())
+ expect(await wrapper.vm.validateDisplayName()).toBeTruthy()
+ expect(getGroupStub).toHaveBeenCalled()
})
- it('should return false if displayName is not valid', () => {
+ it('should return false if displayName is empty', async () => {
const { wrapper } = getWrapper()
wrapper.vm.editGroup.displayName = ''
- expect(wrapper.vm.validateDisplayName()).toBeFalsy()
- expect(wrapper.vm.formData.displayName.valid).toBeFalsy()
+ expect(await wrapper.vm.validateDisplayName()).toBeFalsy()
+ })
+ it('should return false if displayName is already existing', async () => {
+ const { wrapper, mocks } = getWrapper()
+ wrapper.vm.editGroup.displayName = 'users'
+ const graphMock = mocks.$clientService.graphAuthenticated
+ const getGroupStub = graphMock.groups.getGroup.mockResolvedValue(
+ mock({ data: { displayName: 'group' } })
+ )
+ expect(await wrapper.vm.validateDisplayName()).toBeFalsy()
+ expect(getGroupStub).toHaveBeenCalled()
})
})
@@ -56,15 +72,20 @@ describe('EditPanel', () => {
})
})
-function getWrapper({ propsData = {} } = {}) {
+function getWrapper() {
+ const mocks = defaultComponentMocks()
+ const storeOptions = defaultStoreMockOptions
+ const store = createStore(storeOptions)
+
return {
+ mocks,
wrapper: mount(EditPanel, {
props: {
- groups: [{ displayName: 'group' }],
- ...propsData
+ group: { displayName: 'group', members: [] }
},
global: {
- plugins: [...defaultPlugins()],
+ mocks,
+ plugins: [...defaultPlugins(), store],
stubs: {
'oc-text-input': true,
'avatar-image': true,
diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/EditPanel.spec.ts.snap b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/EditPanel.spec.ts.snap
new file mode 100644
index 00000000000..94449e982f0
--- /dev/null
+++ b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/EditPanel.spec.ts.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EditPanel renders all available inputs 1`] = `
+
+`;
diff --git a/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts b/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
index e3b165ada12..bf21ae4d9da 100644
--- a/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
+++ b/packages/web-app-admin-settings/tests/unit/views/Groups.spec.ts
@@ -1,7 +1,7 @@
import Groups from '../../../src/views/Groups.vue'
import { mockAxiosResolve, mockAxiosReject } from 'web-test-helpers/src/mocks'
import { mockDeep } from 'jest-mock-extended'
-import { ClientService } from 'web-pkg/src'
+import { ClientService, eventBus } from 'web-pkg/src'
import {
createStore,
defaultComponentMocks,
@@ -14,7 +14,7 @@ const selectors = { batchActionsStub: 'batch-actions-stub' }
const getClientServiceMock = () => {
const clientService = mockDeep()
clientService.graphAuthenticated.groups.listGroups.mockImplementation(() =>
- mockAxiosResolve({ value: [{ id: '1' }] })
+ mockAxiosResolve({ value: [{ id: '1', name: 'users' }] })
)
return clientService
}
@@ -49,12 +49,27 @@ describe('Groups view', () => {
})
describe('method "editGroup"', () => {
- it('should show message on success', async () => {
- const { wrapper } = getWrapper()
- const showMessageStub = jest.spyOn(wrapper.vm, 'showMessage')
- await wrapper.vm.editGroup({ id: '1', displayName: 'Super group' })
+ it('should emit event on success', async () => {
+ const clientService = getClientServiceMock()
+ clientService.graphAuthenticated.groups.editGroup.mockImplementation(() => mockAxiosResolve())
+ clientService.graphAuthenticated.groups.getGroup.mockImplementation(() =>
+ mockAxiosResolve({ id: '1', displayName: 'administrators' })
+ )
+ const { wrapper } = getWrapper({ clientService })
- expect(showMessageStub).toHaveBeenCalled()
+ const editGroup = {
+ id: '1',
+ name: 'administrators'
+ }
+
+ const busStub = jest.spyOn(eventBus, 'publish')
+ await wrapper.vm.loadResourcesTask.last
+
+ const updatedGroup = await wrapper.vm.editGroup(editGroup)
+
+ expect(updatedGroup.id).toEqual('1')
+ expect(updatedGroup.displayName).toEqual('administrators')
+ expect(busStub).toHaveBeenCalled()
})
it('should show message on error', async () => {
@@ -70,11 +85,7 @@ describe('Groups view', () => {
})
describe('computed method "sideBarAvailablePanels"', () => {
- /**
- * As soon as edit panel will be available in group management, please un-skip it.
- */
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('should contain EditPanel when one group is selected', () => {
+ it('should contain EditPanel when one group is selected', () => {
const { wrapper } = getWrapper()
wrapper.vm.selectedGroups = [{ id: '1' }]
expect(
diff --git a/packages/web-client/src/graph.ts b/packages/web-client/src/graph.ts
index 90a11267eb8..c622cc95066 100644
--- a/packages/web-client/src/graph.ts
+++ b/packages/web-client/src/graph.ts
@@ -148,7 +148,8 @@ export const graph = (baseURI: string, axiosClient: AxiosInstance): Graph => {
groups: {
createGroup: (group: Group) => groupsApiFactory.createGroup(group),
editGroup: (groupId: string, group: Group) => groupApiFactory.updateGroup(groupId, group),
- getGroup: (groupId: string) => groupApiFactory.getGroup(groupId),
+ getGroup: (groupId: string) =>
+ groupApiFactory.getGroup(groupId, new Set([]), new Set(['members'])),
deleteGroup: (groupId: string) => groupApiFactory.deleteGroup(groupId),
listGroups: (orderBy?: any) =>
groupsApiFactory.listGroups(
diff --git a/tests/e2e/cucumber/features/smoke/admin-settings/groups.ocis.feature b/tests/e2e/cucumber/features/smoke/admin-settings/groups.ocis.feature
index 6afa5f7d7f1..42689ea3dbe 100644
--- a/tests/e2e/cucumber/features/smoke/admin-settings/groups.ocis.feature
+++ b/tests/e2e/cucumber/features/smoke/admin-settings/groups.ocis.feature
@@ -39,3 +39,17 @@ Feature: groups management
| security |
| finance |
And "Admin" logs out
+
+ Scenario: edit groups
+ Given "Admin" creates following user using API
+ | id |
+ | Alice |
+ Given "Admin" creates following groups using API
+ | id |
+ | sales |
+ When "Admin" logs in
+ And "Admin" opens the "admin-settings" app
+ And "Admin" navigates to the groups management page
+ When "Admin" changes displayName to "a renamed group" for group "sales" using the sidebar panel
+ And "Admin" logs out
+
diff --git a/tests/e2e/cucumber/steps/ui/adminSettings.ts b/tests/e2e/cucumber/steps/ui/adminSettings.ts
index 502b57852fd..14ea6db813c 100644
--- a/tests/e2e/cucumber/steps/ui/adminSettings.ts
+++ b/tests/e2e/cucumber/steps/ui/adminSettings.ts
@@ -428,6 +428,27 @@ When(
}
)
+When(
+ /^"([^"]*)" changes (displayName) to "([^"]*)" for group "([^"]*)" using the sidebar panel$/,
+ async function (
+ this: World,
+ stepUser: string,
+ attribute: string,
+ value: string,
+ user: string
+ ): Promise {
+ const { page } = this.actorsEnvironment.getActor({ key: stepUser })
+ const groupsObject = new objects.applicationAdminSettings.Groups({ page })
+
+ await groupsObject.changeGroup({
+ key: user,
+ attribute: attribute,
+ value: value,
+ action: 'context-menu'
+ })
+ }
+)
+
Then(
/^"([^"]*)" (should see|should not see) the following group(?:s)?$/,
async function (
diff --git a/tests/e2e/support/objects/app-admin-settings/groups/actions.ts b/tests/e2e/support/objects/app-admin-settings/groups/actions.ts
index e4609c058c3..eb7804c5421 100644
--- a/tests/e2e/support/objects/app-admin-settings/groups/actions.ts
+++ b/tests/e2e/support/objects/app-admin-settings/groups/actions.ts
@@ -1,14 +1,22 @@
import { Page } from 'playwright'
import util from 'util'
+import { selectUser } from '../users/actions'
const newGroupBtn = '.admin-settings-app-bar-actions'
const createGroupInput = '#create-group-input-display-name'
const actionConfirmButton = '.oc-modal-body-actions-confirm'
+const editActionBtnContextMenu = '.context-menu .oc-groups-actions-edit-trigger'
+const editActionBtnQuickActions =
+ '[data-item-id="%s"] .oc-table-data-cell-actions .groups-table-btn-edit'
const groupTrSelector = 'tr'
const groupIdSelector = `[data-item-id="%s"] .groups-table-btn-action-dropdown`
const groupCheckboxSelector = `[data-item-id="%s"]:not(.oc-table-highlighted) input[type=checkbox]`
const deleteBtnContextMenu = '.context-menu .oc-groups-actions-delete-trigger'
const deleteBtnBatchAction = '#oc-appbar-batch-actions'
+const editPanel = '.sidebar-panel__body-EditPanel:visible'
+const closeEditPanel = '.sidebar-panel__header .header__close'
+const userInput = '#%s-input'
+const compareDialogConfirm = '.compare-save-dialog-confirm-btn'
export const createGroup = async (args: { page: Page; key: string }): Promise => {
const { page, key } = args
@@ -89,3 +97,45 @@ export const deleteGrouprUsingBatchAction = async (args: {
await Promise.all([...checkResponses, page.locator(actionConfirmButton).click()])
}
+
+export const changeGroup = async (args: {
+ page: Page
+ uuid: string
+ attribute: string
+ value: string
+}): Promise => {
+ const { page, attribute, value, uuid } = args
+ await page.locator(util.format(userInput, attribute)).fill(value)
+
+ await Promise.all([
+ page.waitForResponse(
+ (resp) =>
+ resp.url().endsWith(encodeURIComponent(uuid)) &&
+ resp.status() === 204 &&
+ resp.request().method() === 'PATCH'
+ ),
+ await page.locator(compareDialogConfirm).click()
+ ])
+}
+export const openEditPanel = async (args: {
+ page: Page
+ uuid: string
+ action: string
+}): Promise => {
+ const { page, uuid, action } = args
+ if (await page.locator(editPanel).count()) {
+ await page.locator(closeEditPanel).click()
+ }
+ switch (action) {
+ case 'context-menu':
+ await page.locator(util.format(groupIdSelector, uuid)).click()
+ await page.locator(editActionBtnContextMenu).click()
+ break
+ case 'quick-action':
+ await selectUser({ page, uuid })
+ await page.locator(util.format(editActionBtnQuickActions, uuid)).click()
+ break
+ default:
+ throw new Error(`${action} not implemented`)
+ }
+}
diff --git a/tests/e2e/support/objects/app-admin-settings/groups/index.ts b/tests/e2e/support/objects/app-admin-settings/groups/index.ts
index 578a6b26e80..152962c39f2 100644
--- a/tests/e2e/support/objects/app-admin-settings/groups/index.ts
+++ b/tests/e2e/support/objects/app-admin-settings/groups/index.ts
@@ -2,10 +2,12 @@ import { Page } from 'playwright'
import { UsersEnvironment } from '../../../environment'
import {
createGroup,
+ openEditPanel,
getDisplayedGroups,
selectGroup,
deleteGroupUsingContextMenu,
- deleteGrouprUsingBatchAction
+ deleteGrouprUsingBatchAction,
+ changeGroup
} from './actions'
export class Groups {
@@ -33,4 +35,24 @@ export class Groups {
async deleteGroupUsingContextMenu({ key }: { key: string }): Promise {
await deleteGroupUsingContextMenu({ page: this.#page, uuid: this.getUUID({ key }) })
}
+
+ async changeGroup({
+ key,
+ attribute,
+ value,
+ action
+ }: {
+ key: string
+ attribute: string
+ value: string
+ action: string
+ }): Promise {
+ const uuid = this.getUUID({ key })
+ await openEditPanel({ page: this.#page, uuid, action })
+ await changeGroup({ uuid, attribute: attribute, value: value, page: this.#page })
+ }
+
+ async openEditPanel({ key, action }: { key: string; action: string }): Promise {
+ await openEditPanel({ page: this.#page, uuid: this.getUUID({ key }), action })
+ }
}