diff --git a/changelog/unreleased/enhancement-trash-bin-breadcrumbs b/changelog/unreleased/enhancement-trash-bin-breadcrumbs new file mode 100644 index 00000000000..8388d7373ab --- /dev/null +++ b/changelog/unreleased/enhancement-trash-bin-breadcrumbs @@ -0,0 +1,9 @@ +Enhancement: Trash bin breadcrumbs + +We've improved the trash bin in general: +* Add a breadcrumb for personal trash bin +* Improve the breadcrumb for spaces trash bin, also add 'Navigate to space' action to context menu +* Fix wrong page title in spaces trash bin + +https://github.com/owncloud/web/pull/6609 + diff --git a/packages/web-app-files/src/components/AppBar/AppBar.vue b/packages/web-app-files/src/components/AppBar/AppBar.vue index 71abe73b9ef..30f2dfd5e78 100644 --- a/packages/web-app-files/src/components/AppBar/AppBar.vue +++ b/packages/web-app-files/src/components/AppBar/AppBar.vue @@ -22,7 +22,7 @@ :items="breadcrumbs" > @@ -95,6 +95,7 @@ export default { isPublicLocation: useActiveLocation(isLocationPublicActive, 'files-public-files'), isSpacesProjectsLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-projects'), isSpacesProjectLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-project'), + isTrashPersonalActive: useActiveLocation(isLocationTrashActive, 'files-trash-personal'), isTrashSpacesProjectActive: useActiveLocation( isLocationTrashActive, 'files-trash-spaces-project' @@ -119,7 +120,7 @@ export default { ...mapState('Files', ['areHiddenFilesShown']), showContextActions() { - if (this.isTrashSpacesProjectActive) { + if (this.isTrashPersonalActive) { return false } if (this.isSpacesProjectLocation) { @@ -128,6 +129,12 @@ export default { return this.currentFolder && this.breadcrumbs.length > 1 }, + contextActionItems() { + if (this.isTrashSpacesProjectActive) { + return [] + } + return [this.currentFolder] + }, currentPath() { const path = this.$route.params.item || '' if (path.endsWith('/')) { @@ -176,24 +183,34 @@ export default { this.isPersonalLocation || this.isSpacesProjectsLocation || this.isSpacesProjectLocation || + this.isTrashPersonalActive || this.isTrashSpacesProjectActive ) ) { return [] } - if (this.isTrashSpacesProjectActive) { + if (this.isTrashPersonalActive) { return [ { - text: this.$gettext('Spaces'), - to: '/files/spaces/projects' + text: this.$gettext('Deleted files'), + to: '/files/trash' }, { - text: this.$route.params.storageId, - to: `/files/spaces/projects/${this.$route.params.storageId}` + text: this.$gettext('Personal'), + onClick: () => bus.publish('app.files.list.load') + } + ] + } + + if (this.isTrashSpacesProjectActive) { + return [ + { + text: this.$gettext('Deleted files'), + to: '/files/trash' }, { - text: this.$gettext('Deleted Files'), + text: this.$route.params.storageId, onClick: () => bus.publish('app.files.list.load') } ] diff --git a/packages/web-app-files/src/components/FilesList/ContextActions.vue b/packages/web-app-files/src/components/FilesList/ContextActions.vue index fa43d33f521..1e28893e703 100644 --- a/packages/web-app-files/src/components/FilesList/ContextActions.vue +++ b/packages/web-app-files/src/components/FilesList/ContextActions.vue @@ -41,6 +41,7 @@ import ShowDetails from '../../mixins/actions/showDetails' import ShowShares from '../../mixins/actions/showShares' import SetSpaceImage from '../../mixins/spaces/actions/setImage' import SetSpaceReadme from '../../mixins/spaces/actions/setReadme' +import SpaceNavigate from '../../mixins/spaces/actions/navigate' export default { name: 'ContextActions', @@ -64,7 +65,8 @@ export default { ShowDetails, ShowShares, SetSpaceImage, - SetSpaceReadme + SetSpaceReadme, + SpaceNavigate ], props: { @@ -165,7 +167,8 @@ export default { ...this.$_acceptShare_items, ...this.$_declineShare_items, ...this.$_setSpaceImage_items, - ...this.$_setSpaceReadme_items + ...this.$_setSpaceReadme_items, + ...this.$_navigate_space_items ].filter((item) => item.isEnabled(this.filterParams)) }, diff --git a/packages/web-app-files/src/components/Trashbin.vue b/packages/web-app-files/src/components/TrashBin.vue similarity index 99% rename from packages/web-app-files/src/components/Trashbin.vue rename to packages/web-app-files/src/components/TrashBin.vue index 11fa15ac363..1572b6e13e2 100644 --- a/packages/web-app-files/src/components/Trashbin.vue +++ b/packages/web-app-files/src/components/TrashBin.vue @@ -62,7 +62,7 @@ import { useResourcesViewDefaults } from '../composables' import { bus } from 'web-pkg/src/instance' export default { - name: 'Trashbin', + name: 'TrashBin', components: { ResourceTable, ListLoader, NoContentMessage, ListInfo, Pagination, ContextActions }, diff --git a/packages/web-app-files/src/helpers/resources.js b/packages/web-app-files/src/helpers/resources.js index ab2e3d6fbc1..62f66f02b5a 100644 --- a/packages/web-app-files/src/helpers/resources.js +++ b/packages/web-app-files/src/helpers/resources.js @@ -543,7 +543,22 @@ export function buildDeletedResource(resource) { indicators: [], canUpload: () => false, canDownload: () => false, - canBeDeleted: () => true, + canBeDeleted: () => { + /** FIXME: once https://github.com/owncloud/ocis/issues/3339 gets implemented, + * we want to add a check if the permission is set. + * We might to be careful and do an early return true if DavProperty.Permissions is not set + * as oc10 does not support it. + **/ + return true + }, + canBeRestored: function () { + /** FIXME: once https://github.com/owncloud/ocis/issues/3339 gets implemented, + * we want to add a check if the permission is set. + * We might to be careful and do an early return true if DavProperty.Permissions is not set + * as oc10 does not support it. + **/ + return true + }, canRename: () => false, canShare: () => false, canCreate: () => false, diff --git a/packages/web-app-files/src/mixins/actions/restore.js b/packages/web-app-files/src/mixins/actions/restore.js index 28c7f9d3061..8727d86e353 100644 --- a/packages/web-app-files/src/mixins/actions/restore.js +++ b/packages/web-app-files/src/mixins/actions/restore.js @@ -26,6 +26,10 @@ export default { ) { return false } + if (!resources.every((r) => r.canBeRestored())) { + return false + } + return resources.length > 0 }, componentType: 'oc-button', diff --git a/packages/web-app-files/src/mixins/spaces/actions/navigate.js b/packages/web-app-files/src/mixins/spaces/actions/navigate.js new file mode 100644 index 00000000000..34188b871a8 --- /dev/null +++ b/packages/web-app-files/src/mixins/spaces/actions/navigate.js @@ -0,0 +1,37 @@ +import { createLocationSpaces, isLocationTrashActive } from '../../../router' + +export default { + computed: { + $_navigate_space_items() { + return [ + { + name: 'navigate', + icon: 'layout-grid', + label: () => { + return this.$gettext('Navigate to space') + }, + handler: this.$_navigate_space_trigger, + isEnabled: ({ resources }) => { + if (resources.length) { + return false + } + return isLocationTrashActive(this.$router, 'files-trash-spaces-project') + }, + componentType: 'oc-button', + class: 'oc-files-actions-navigate-trigger' + } + ] + } + }, + methods: { + $_navigate_space_trigger() { + this.$router.push( + createLocationSpaces('files-spaces-project', { + params: { + storageId: this.$router.currentRoute.params.storageId + } + }) + ) + } + } +} diff --git a/packages/web-app-files/src/views/Trashbin.vue b/packages/web-app-files/src/views/Trashbin.vue index 2ab9482f50b..c990e021a0a 100644 --- a/packages/web-app-files/src/views/Trashbin.vue +++ b/packages/web-app-files/src/views/Trashbin.vue @@ -1,9 +1,9 @@ - + diff --git a/packages/web-app-files/src/views/spaces/Project.vue b/packages/web-app-files/src/views/spaces/Project.vue index 6c47e7fbd98..41a084551bc 100644 --- a/packages/web-app-files/src/views/spaces/Project.vue +++ b/packages/web-app-files/src/views/spaces/Project.vue @@ -238,7 +238,7 @@ export default { 'totalFilesCount', 'totalFilesSize' ]), - ...mapGetters(['user', 'getToken']), + ...mapGetters(['user', 'getToken', 'configuration']), selected: { get() { @@ -360,7 +360,7 @@ export default { async mounted() { await this.loadResourcesTask.perform(this, false, this.$route.params.item || '') - document.title = `${this.space.name} - ${this.$route.meta.title}` + document.title = `${this.$route.meta.title} - ${this.space.name} - ${this.configuration.currentTheme.general.name}` this.$route.params.name = this.space.name const loadSpaceEventToken = bus.subscribe('app.files.list.load', (path) => { diff --git a/packages/web-app-files/src/views/spaces/Trashbin.vue b/packages/web-app-files/src/views/spaces/Trashbin.vue index aa2b5c74dc6..0709839d210 100644 --- a/packages/web-app-files/src/views/spaces/Trashbin.vue +++ b/packages/web-app-files/src/views/spaces/Trashbin.vue @@ -1,9 +1,44 @@ - + diff --git a/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js b/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js index fb63f2a3571..8572d9c8c06 100644 --- a/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js +++ b/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js @@ -8,7 +8,8 @@ import { createLocationCommon, createLocationPublic, createLocationShares, - createLocationSpaces + createLocationSpaces, + createLocationTrash } from '../../../../src/router' const localVue = createLocalVue() @@ -134,6 +135,167 @@ describe('AppBar component', () => { }) }) + describe('computed showContextActions', () => { + describe('if isPersonalLocation is true', () => { + describe('and item is selected', () => { + it('should be true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationSpaces('files-spaces-personal-home', { + params: { + storageId: '1', + item: 'New folder' + } + }), + meta: {} + } + + const wrapper = getShallowWrapper(route, store, { + isPersonalLocation: true + }) + expect(wrapper.vm.showContextActions).toBeTruthy() + }) + }) + describe('and no item is selected', () => { + it('should be false', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationSpaces('files-spaces-personal-home', { + params: { + storageId: '1' + } + }), + meta: {} + } + + const wrapper = getShallowWrapper(route, store, { + isPersonalLocation: true + }) + expect(wrapper.vm.showContextActions).toBeFalsy() + }) + }) + }) + + describe('if isSpacesProjectLocation is true', () => { + describe('and item is selected', () => { + it('should be true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1', + item: 'New folder' + } + }), + meta: {} + } + + const wrapper = getShallowWrapper(route, store, { + isSpacesProjectLocation: true + }) + expect(wrapper.vm.showContextActions).toBeTruthy() + }) + }) + + describe('and no item is selected', () => { + it('should be false', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1' + } + }), + meta: {} + } + + const wrapper = getShallowWrapper(route, store, { + isSpacesProjectLocation: true + }) + expect(wrapper.vm.showContextActions).toBeFalsy() + }) + }) + }) + + describe('if isTrashPersonalActive is true', () => { + it('should be false', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1' + } + }), + meta: {} + } + const wrapper = getShallowWrapper(route, store, { isTrashPersonalActive: true }) + expect(wrapper.vm.showContextActions).toBeFalsy() + }) + }) + }) + + describe('computed contextActionItems', () => { + it('should be empty if isTrashSpacesProjectActive is true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1' + } + }), + meta: {} + } + const wrapper = getShallowWrapper(route, store, { isTrashSpacesProjectActive: true }) + expect(wrapper.vm.contextActionItems).toEqual([]) + }) + + it('should not be empty if isTrashPersonalActive is true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1' + } + }), + meta: {} + } + const wrapper = getShallowWrapper(route, store, { isTrashPersonalActive: true }) + expect(wrapper.vm.contextActionItems).toEqual([wrapper.vm.currentFolder]) + }) + }) + + describe('computed breadcrumbs', () => { + it('should contain two items if isTrashPersonalActive is true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-personal', { + params: { + storageId: '1' + } + }), + meta: {} + } + const wrapper = getShallowWrapper(route, store, { isTrashSpacesProjectActive: true }) + expect(wrapper.vm.breadcrumbs[0].to).toEqual('/files/trash') + expect(wrapper.vm.breadcrumbs.length).toEqual(2) + }) + + it('should contain two items if isTrashSpacesProjectActive is true', () => { + const store = createStore({ selected: [], currentFolder }) + const route = { + ...createLocationTrash('files-trash-spaces-project', { + params: { + storageId: '1' + } + }), + meta: {} + } + const wrapper = getShallowWrapper(route, store, { isTrashSpacesProjectActive: true }) + expect(wrapper.vm.breadcrumbs[0].to).toEqual('/files/trash') + expect(wrapper.vm.breadcrumbs.length).toEqual(2) + }) + }) + describe.each([favoritesLocation.name, sharesWithOthersLocation.name, sharesWithMeLocation.name])( '%s page', (page) => { @@ -184,7 +346,7 @@ describe('AppBar component', () => { ) }) -function getShallowWrapper(route = {}, store = {}) { +function getShallowWrapper(route = {}, store = {}, mocks = {}) { return shallowMount(AppBar, { localVue, mocks: { @@ -196,7 +358,8 @@ function getShallowWrapper(route = {}, store = {}) { } }, publicPage: jest.fn(() => false), - isIE11: jest.fn(() => false) + isIE11: jest.fn(() => false), + ...mocks }, store }) diff --git a/packages/web-app-files/tests/unit/components/Trashbin.spec.js b/packages/web-app-files/tests/unit/components/TrashBin.spec.js similarity index 98% rename from packages/web-app-files/tests/unit/components/Trashbin.spec.js rename to packages/web-app-files/tests/unit/components/TrashBin.spec.js index dc5a84ea535..da871bd466f 100644 --- a/packages/web-app-files/tests/unit/components/Trashbin.spec.js +++ b/packages/web-app-files/tests/unit/components/TrashBin.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils' -import Trashbin from '@files/src/components/Trashbin.vue' +import TrashBin from '@files/src/components/TrashBin.vue' import { getStore, localVue, createFile } from '@files/tests/unit/components/components.setup.js' const stubs = { @@ -176,7 +176,7 @@ describe('Trashbin component', () => { paginationPages = 12, paginationPage = 21 } = {}) { - const component = { ...Trashbin, created: jest.fn() } + const component = { ...TrashBin, created: jest.fn() } const store = createStore({ totalFilesCount: { files: paginatedResources.length, folders: 0 }, selectedFiles diff --git a/packages/web-app-files/tests/unit/components/__snapshots__/Trashbin.spec.js.snap b/packages/web-app-files/tests/unit/components/__snapshots__/TrashBin.spec.js.snap similarity index 100% rename from packages/web-app-files/tests/unit/components/__snapshots__/Trashbin.spec.js.snap rename to packages/web-app-files/tests/unit/components/__snapshots__/TrashBin.spec.js.snap diff --git a/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js b/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js index 4ff703ac89d..f151f770cb4 100644 --- a/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js +++ b/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js @@ -22,9 +22,17 @@ describe('restore', () => { const wrapper = getWrapper() expect(wrapper.vm.$_restore_items[0].isEnabled({ resources: [] })).toBe(false) }) - it('should be true when resource is given', () => { + it('should be true when permission is sufficient', () => { const wrapper = getWrapper() - expect(wrapper.vm.$_restore_items[0].isEnabled({ resources: [{}] })).toBe(true) + expect( + wrapper.vm.$_restore_items[0].isEnabled({ resources: [{ canBeRestored: () => true }] }) + ).toBe(true) + }) + it('should be false when permission is not sufficient', () => { + const wrapper = getWrapper() + expect( + wrapper.vm.$_restore_items[0].isEnabled({ resources: [{ canBeRestored: () => false }] }) + ).toBe(false) }) it('should be false when location is invalid', () => { const wrapper = getWrapper({ invalidLocation: true }) diff --git a/packages/web-app-files/tests/unit/mixins/spaces/navigate.spec.js b/packages/web-app-files/tests/unit/mixins/spaces/navigate.spec.js new file mode 100644 index 00000000000..93eebb68c27 --- /dev/null +++ b/packages/web-app-files/tests/unit/mixins/spaces/navigate.spec.js @@ -0,0 +1,86 @@ +import Vuex from 'vuex' +import { createStore } from 'vuex-extensions' +import { mount, createLocalVue } from '@vue/test-utils' +import Navigate from '@files/src/mixins/spaces/actions/navigate.js' +import { createLocationSpaces, createLocationTrash } from '../../../../src/router' + +const localVue = createLocalVue() +localVue.use(Vuex) + +const Component = { + render() {}, + mixins: [Navigate] +} + +describe('navigate', () => { + afterEach(() => jest.clearAllMocks()) + + describe('isEnabled property', () => { + it('should be true when no resource given', () => { + const wrapper = getWrapper() + expect(wrapper.vm.$_navigate_space_items[0].isEnabled({ resources: [] })).toBe(true) + }) + it('should be false when resource is given', () => { + const wrapper = getWrapper() + expect(wrapper.vm.$_navigate_space_items[0].isEnabled({ resources: [{}] })).toBe(false) + }) + it('should be false when location is invalid', () => { + const wrapper = getWrapper({ invalidLocation: true }) + expect(wrapper.vm.$_navigate_space_items[0].isEnabled({ resources: [] })).toBe(false) + }) + }) + + describe('method "$_navigate_space_trigger"', () => { + it('should trigger route change', async () => { + const wrapper = getWrapper() + await wrapper.vm.$_navigate_space_trigger() + + expect(wrapper.vm.$router.push).toHaveBeenCalledWith( + createLocationSpaces('files-spaces-project', { + params: { + storageId: wrapper.vm.$router.currentRoute.params.storageId + } + }) + ) + }) + }) +}) + +function getWrapper({ invalidLocation = false } = {}) { + return mount(Component, { + localVue, + mocks: { + $router: { + currentRoute: invalidLocation + ? createLocationTrash('files-trash-personal') + : createLocationTrash('files-trash-spaces-project', { params: { storageId: '1' } }), + resolve: (r) => { + return { href: r.name } + }, + push: jest.fn() + }, + $gettext: jest.fn() + }, + store: createStore(Vuex.Store, { + actions: { + createModal: jest.fn(), + hideModal: jest.fn(), + showMessage: jest.fn() + }, + getters: { + configuration: () => ({ + server: 'https://example.com' + }), + getToken: () => 'token' + }, + modules: { + Files: { + namespaced: true, + mutations: { + REMOVE_FILE: jest.fn() + } + } + } + }) + }) +} diff --git a/packages/web-app-files/tests/unit/views/Trashbin.spec.js b/packages/web-app-files/tests/unit/views/Trashbin.spec.js deleted file mode 100644 index 1797f5fbae5..00000000000 --- a/packages/web-app-files/tests/unit/views/Trashbin.spec.js +++ /dev/null @@ -1,203 +0,0 @@ -import { mount } from '@vue/test-utils' -import Trashbin from '@files/src/components/Trashbin.vue' -import { getStore, localVue, createFile } from '@files/tests/unit/views/views.setup.js' - -const stubs = { - 'list-loader': true, - 'no-content-message': true, - 'resource-table': true, - 'context-actions': true, - pagination: true, - 'list-info': true, - 'router-link': true -} - -const listLoaderStub = 'list-loader-stub' -const noContentStub = 'no-content-message-stub' -const filesTableStub = 'resource-table-stub' -const filesTableSelector = '#files-trashbin-table' -const contextActionsStub = 'context-actions-stub' -const listInfoStub = 'list-info-stub' -const paginationStub = 'pagination-stub' - -describe('Trashbin component', () => { - it('should show the list loader when the view is still loading', () => { - const wrapper = getMountedWrapper({ loading: true }) - - expect(wrapper.find(listLoaderStub).exists()).toBeTruthy() - expect(wrapper.find(noContentStub).exists()).toBeFalsy() - expect(wrapper.find(filesTableStub).exists()).toBeFalsy() - }) - - describe('when the view is not loading anymore', () => { - it('should show the no content message component if the paginated resources is empty', () => { - const wrapper = getMountedWrapper() - - expect(wrapper.find(listLoaderStub).exists()).toBeFalsy() - expect(wrapper.find(filesTableStub).exists()).toBeFalsy() - expect(wrapper.find(noContentStub).exists()).toBeTruthy() - }) - - describe('when length of the paginated resources is greater than zero', () => { - const resourceList = [ - createFile({ id: '1234' }), - createFile({ id: '5896' }), - createFile({ id: '9856' }) - ] - const wrapper = getMountedWrapper({ - paginatedResources: resourceList - }) - - it('should not show the no content message component', () => { - expect(wrapper.find(noContentStub).exists()).toBeFalsy() - }) - - it('should load the resource table with correct props', () => { - stubs['resource-table'] = false - const wrapper = getMountedWrapper({ - paginatedResources: resourceList - }) - const filesTable = wrapper.find(filesTableSelector) - - expect(filesTable.exists()).toBeTruthy() - expect(filesTable).toMatchSnapshot() - - stubs['resource-table'] = true - }) - - describe('context menu', () => { - let wrapper - const selectedResources = [resourceList[0], resourceList[1]] - const notSelectedResources = [resourceList[2]] - beforeEach(() => { - stubs['resource-table'] = false - - wrapper = getMountedWrapper({ - selectedFiles: selectedResources, - paginatedResources: resourceList, - paginationPage: 1, - paginationPages: 2 - }) - }) - afterEach(() => { - stubs['resource-table'] = true - }) - it('should show the context actions for every selected resource', () => { - selectedResources.forEach((selectedResource) => { - const fileRow = wrapper.find(`[data-item-id="${selectedResource.id}"]`) - const contextMenu = fileRow.find(contextActionsStub) - expect(contextMenu.exists()).toBeTruthy() - expect(contextMenu.props().items).toMatchObject(selectedResources) - }) - }) - it('should not show the context actions for a resource that is not selected', () => { - notSelectedResources.forEach((notSelectedResource) => { - const fileRow = wrapper.find(`[data-item-id="${notSelectedResource.id}"]`) - const contextMenu = fileRow.find(contextActionsStub) - expect(contextMenu.exists()).toBeFalsy() - }) - }) - }) - - describe('pagination', () => { - it('should be visible if the paginated pages is greater than zero', () => { - stubs['resource-table'] = false - const wrapper = getMountedWrapper({ - paginatedResources: resourceList, - paginationPages: 2, - paginationPage: 1 - }) - - const pagination = wrapper.find(paginationStub) - - expect(pagination.exists()).toBeTruthy() - expect(pagination.props()).toMatchObject({ - pages: 2, - currentPage: 1 - }) - stubs['resource-table'] = true - }) - }) - - describe('list info', () => { - it('should be present if the paginated resources list is not empty', () => { - stubs['resource-table'] = false - - const wrapper = getMountedWrapper({ - paginatedResources: resourceList, - paginationPage: 1, - paginationPages: 2 - }) - - const listInfo = wrapper.find(listInfoStub) - expect(listInfo.exists()).toBeTruthy() - expect(listInfo.props()).toMatchObject({ - files: 3, - folders: 0 - }) - stubs['resource-table'] = true - }) - }) - }) - }) - - function mountOptions({ store, loading, paginatedResources, paginationPages, paginationPage }) { - const $route = { params: { page: 1 } } - const $router = { - afterEach: jest.fn(), - currentRoute: { - query: {} - } - } - return { - localVue, - store: store, - stubs, - mocks: { - $route, - $router - }, - setup: () => ({ - loadResourcesTask: { - isRunning: loading, - perform: jest.fn() - }, - paginatedResources: paginatedResources, - paginationPages: paginationPages, - paginationPage: paginationPage - }) - } - } - - function getMountedWrapper({ - selectedFiles = [], - loading = false, - paginatedResources = [], - paginationPages = 12, - paginationPage = 21 - } = {}) { - const component = { ...Trashbin, created: jest.fn() } - const store = createStore({ - totalFilesCount: { files: paginatedResources.length, folders: 0 }, - selectedFiles - }) - return mount( - component, - mountOptions({ - store, - loading, - paginatedResources, - paginationPages, - paginationPage - }) - ) - } - - function createStore({ totalFilesCount, highlightedFile, selectedFiles } = {}) { - return getStore({ - highlightedFile, - totalFilesCount, - selectedFiles - }) - } -}) diff --git a/packages/web-app-files/tests/unit/views/__snapshots__/Trashbin.spec.js.snap b/packages/web-app-files/tests/unit/views/__snapshots__/Trashbin.spec.js.snap deleted file mode 100644 index 4655f395437..00000000000 --- a/packages/web-app-files/tests/unit/views/__snapshots__/Trashbin.spec.js.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Trashbin component when the view is not loading anymore when length of the paginated resources is greater than zero should load the resource table with correct props 1`] = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
Name Status - - Actions - -
-
-
file-name-1234 - -
- file-path -
-
-
-
-
-
-
-
-
-
file-name-5896 - -
- file-path -
-
-
-
-
-
-
-
-
-
file-name-9856 - -
- file-path -
-
-
-
-
-
-
-
-`; diff --git a/packages/web-app-files/tests/unit/views/spaces/Trashbin.spec.js b/packages/web-app-files/tests/unit/views/spaces/Trashbin.spec.js new file mode 100644 index 00000000000..4001d7510b7 --- /dev/null +++ b/packages/web-app-files/tests/unit/views/spaces/Trashbin.spec.js @@ -0,0 +1,70 @@ +import Vuex from 'vuex' +import { mount, createLocalVue } from '@vue/test-utils' +import Trashbin from '@files/src/views/spaces/Trashbin.vue' +import { createStore } from 'vuex-extensions' +import { createLocationTrash } from '../../../../src/router' +import { waitFor } from '@testing-library/dom' + +const localVue = createLocalVue() +localVue.use(Vuex) + +afterEach(() => jest.clearAllMocks()) + +describe('Trashbin', () => { + describe('method "mounted"', () => { + it('should change document title', async () => { + const wrapper = getWrapper() + expect(wrapper.vm.loadResourcesTask.perform).toBeCalled() + await waitFor(() => expect(document.title).toBe('Deleted files - Space - ownCloud')) + }) + }) +}) + +function getWrapper() { + return mount(Trashbin, { + localVue, + mocks: { + $router: { + currentRoute: { + ...createLocationTrash('files-trash-spaces-project'), + meta: { + title: 'Deleted files' + } + }, + resolve: (r) => { + return { href: r.name } + } + }, + loadResourcesTask: { + isRunning: false, + perform: jest.fn() + }, + space: { + name: 'Space' + }, + $gettext: jest.fn(), + document: { + title: '' + } + }, + store: createStore(Vuex.Store, { + actions: { + showMessage: jest.fn() + }, + getters: { + configuration: () => ({ + server: 'https://example.com', + currentTheme: { + general: { + name: 'ownCloud' + } + } + }), + getToken: () => 'token' + } + }), + stubs: { + 'trash-bin': true + } + }) +} diff --git a/packages/web-pkg/src/constants/dav.ts b/packages/web-pkg/src/constants/dav.ts index 1199618b60e..197382fdfd5 100644 --- a/packages/web-pkg/src/constants/dav.ts +++ b/packages/web-pkg/src/constants/dav.ts @@ -75,6 +75,7 @@ export abstract class DavProperties { DavProperty.ResourceType, DavProperty.TrashbinOriginalLocation, DavProperty.TrashbinOriginalFilename, - DavProperty.TrashbinDeletedDate + DavProperty.TrashbinDeletedDate, + DavProperty.Permissions ] }