From f0dd02b5f1f6485e49af3865a9a632b6a20f6224 Mon Sep 17 00:00:00 2001 From: JanAckermann Date: Thu, 17 Mar 2022 10:00:41 +0100 Subject: [PATCH 01/14] Fix single space page title, add trash space title --- .../src/views/spaces/Project.vue | 4 +-- .../src/views/spaces/Trashbin.vue | 32 ++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) 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..baac6866248 100644 --- a/packages/web-app-files/src/views/spaces/Trashbin.vue +++ b/packages/web-app-files/src/views/spaces/Trashbin.vue @@ -2,8 +2,38 @@ From cbf5ad1a3f2a06811b63e185dda55cb463450af8 Mon Sep 17 00:00:00 2001 From: JanAckermann Date: Thu, 17 Mar 2022 12:34:01 +0100 Subject: [PATCH 02/14] Redesign trash bin breadcrumbs --- .../src/components/AppBar/AppBar.vue | 33 +++++++++++++---- .../components/FilesList/ContextActions.vue | 7 +++- .../src/mixins/spaces/actions/navigate.js | 37 +++++++++++++++++++ 3 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 packages/web-app-files/src/mixins/spaces/actions/navigate.js 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/mixins/spaces/actions/navigate.js b/packages/web-app-files/src/mixins/spaces/actions/navigate.js new file mode 100644 index 00000000000..c97649888ca --- /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({ resources }) { + this.$router.push( + createLocationSpaces('files-spaces-project', { + params: { + storageId: this.$route.params.storageId + } + }) + ) + } + } +} From bc311bdc08f8f00460475f0de17536c3e68cd573 Mon Sep 17 00:00:00 2001 From: JanAckermann Date: Thu, 17 Mar 2022 14:01:26 +0100 Subject: [PATCH 03/14] Rename trashbin component && remove duplicate test --- .../components/{Trashbin.vue => TrashBin.vue} | 2 +- packages/web-app-files/src/views/Trashbin.vue | 6 +- .../src/views/spaces/Trashbin.vue | 6 +- .../{Trashbin.spec.js => TrashBin.spec.js} | 4 +- ...bin.spec.js.snap => TrashBin.spec.js.snap} | 0 .../tests/unit/views/Trashbin.spec.js | 203 ------------------ 6 files changed, 9 insertions(+), 212 deletions(-) rename packages/web-app-files/src/components/{Trashbin.vue => TrashBin.vue} (99%) rename packages/web-app-files/tests/unit/components/{Trashbin.spec.js => TrashBin.spec.js} (98%) rename packages/web-app-files/tests/unit/components/__snapshots__/{Trashbin.spec.js.snap => TrashBin.spec.js.snap} (100%) delete mode 100644 packages/web-app-files/tests/unit/views/Trashbin.spec.js 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/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/Trashbin.vue b/packages/web-app-files/src/views/spaces/Trashbin.vue index baac6866248..1757174cefc 100644 --- a/packages/web-app-files/src/views/spaces/Trashbin.vue +++ b/packages/web-app-files/src/views/spaces/Trashbin.vue @@ -1,7 +1,7 @@ - + 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 + } + }) +} From 2b7457e5a09ddf7a6d5b9a234ccfcfd0fcd944af Mon Sep 17 00:00:00 2001 From: JanAckermann Date: Mon, 21 Mar 2022 11:37:20 +0100 Subject: [PATCH 14/14] React on code review --- .../unit/components/AppBar/AppBar.spec.js | 148 ++++++++++-------- 1 file changed, 81 insertions(+), 67 deletions(-) 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 ea7ecfb3964..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 @@ -136,87 +136,101 @@ describe('AppBar component', () => { }) describe('computed showContextActions', () => { - it('should be false if isTrashPersonalActive is true', () => { - const store = createStore({ selected: [], currentFolder }) - const route = { - ...createLocationTrash('files-trash-personal', { - params: { - storageId: '1' + 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: {} } - }), - meta: {} - } - const wrapper = getShallowWrapper(route, store, { isTrashPersonalActive: true }) - expect(wrapper.vm.showContextActions).toBeFalsy() - }) - it('should be true if isSpacesProjectLocation is true and item is given', () => { - const store = createStore({ selected: [], currentFolder }) - const route = { - ...createLocationTrash('files-trash-personal', { - params: { - storageId: '1', - item: 'New folder' + + 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: {} } - }), - meta: {} - } - const wrapper = getShallowWrapper(route, store, { - isSpacesProjectLocation: true + const wrapper = getShallowWrapper(route, store, { + isPersonalLocation: true + }) + expect(wrapper.vm.showContextActions).toBeFalsy() + }) }) - expect(wrapper.vm.showContextActions).toBeTruthy() }) - it('should be false if isSpacesProjectLocation is true but no item is given', () => { - const store = createStore({ selected: [], currentFolder }) - const route = { - ...createLocationTrash('files-trash-personal', { - params: { - storageId: '1' + 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: {} } - }), - meta: {} - } - const wrapper = getShallowWrapper(route, store, { - isSpacesProjectLocation: true + const wrapper = getShallowWrapper(route, store, { + isSpacesProjectLocation: true + }) + expect(wrapper.vm.showContextActions).toBeTruthy() + }) }) - expect(wrapper.vm.showContextActions).toBeFalsy() - }) - it('should be true if isPersonalLocation is true and item is given', () => { - const store = createStore({ selected: [], currentFolder }) - const route = { - ...createLocationSpaces('files-spaces-personal-home', { - params: { - storageId: '1', - item: 'New folder' + 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: {} } - }), - meta: {} - } - const wrapper = getShallowWrapper(route, store, { - isPersonalLocation: true + const wrapper = getShallowWrapper(route, store, { + isSpacesProjectLocation: true + }) + expect(wrapper.vm.showContextActions).toBeFalsy() + }) }) - expect(wrapper.vm.showContextActions).toBeTruthy() }) - it('should be false if isPersonalLocation is true but no item is given', () => { - const store = createStore({ selected: [], currentFolder }) - const route = { - ...createLocationSpaces('files-spaces-personal-home', { - params: { - storageId: '1' - } - }), - meta: {} - } - - const wrapper = getShallowWrapper(route, store, { - isPersonalLocation: true + 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() }) - expect(wrapper.vm.showContextActions).toBeFalsy() }) }) @@ -251,7 +265,7 @@ describe('AppBar component', () => { }) describe('computed breadcrumbs', () => { - it('should contain to two items if isTrashPersonalActive is true', () => { + it('should contain two items if isTrashPersonalActive is true', () => { const store = createStore({ selected: [], currentFolder }) const route = { ...createLocationTrash('files-trash-personal', { @@ -266,7 +280,7 @@ describe('AppBar component', () => { expect(wrapper.vm.breadcrumbs.length).toEqual(2) }) - it('should contain to two items if isTrashSpacesProjectActive is true', () => { + it('should contain two items if isTrashSpacesProjectActive is true', () => { const store = createStore({ selected: [], currentFolder }) const route = { ...createLocationTrash('files-trash-spaces-project', {