diff --git a/.drone.env b/.drone.env index 042e7c34d8c..090e1e4b8be 100644 --- a/.drone.env +++ b/.drone.env @@ -1,3 +1,3 @@ # The version of OCIS to use in pipelines that test against OCIS -OCIS_COMMITID=5aeb76f6c8aee574fdd2710f9e883efe0c8166f8 +OCIS_COMMITID=25d6e4efd119049f290683d6d126185368058b4e OCIS_BRANCH=master diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d916791485..ae25e196a24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Summary * Bugfix - Fix location picker breadcrumb url encoding: [#5940](https://github.com/owncloud/web/pull/5940) * Bugfix - Context menu rendering: [#5952](https://github.com/owncloud/web/pull/5952) * Enhancement - Default action order: [#5952](https://github.com/owncloud/web/pull/5952) +* Enhancement - Reduced sidebar width: [#5981](https://github.com/owncloud/web/issues/5981) Details ------- @@ -40,6 +41,14 @@ Details https://github.com/owncloud/web/pull/5952 +* Enhancement - Reduced sidebar width: [#5981](https://github.com/owncloud/web/issues/5981) + + We reduced the sidebar width to give the files list more horizontal room, especially on medium + sized screens. + + https://github.com/owncloud/web/issues/5981 + https://github.com/owncloud/web/pull/5983 + Changelog for ownCloud Web [4.4.0] (2021-10-26) ======================================= The following sections list the changes in ownCloud web 4.4.0 relevant to diff --git a/changelog/unreleased/enhancement-chunks-folder b/changelog/unreleased/enhancement-chunks-folder new file mode 100644 index 00000000000..6dbaeb46603 --- /dev/null +++ b/changelog/unreleased/enhancement-chunks-folder @@ -0,0 +1,5 @@ +Enhancement: Rename `_chunks` folder to `chunks` + +We've renamed the `_chunks` folder to `chunks` in the ownCloud Web build output in order to make it more easily embedable with the Go embed directive. + +https://github.com/owncloud/web/pull/5988 diff --git a/changelog/unreleased/enhancement-files-sidebar-reduced-width b/changelog/unreleased/enhancement-files-sidebar-reduced-width new file mode 100644 index 00000000000..5fd65e855a0 --- /dev/null +++ b/changelog/unreleased/enhancement-files-sidebar-reduced-width @@ -0,0 +1,6 @@ +Enhancement: Reduced sidebar width + +We reduced the sidebar width to give the files list more horizontal room, especially on medium sized screens. + +https://github.com/owncloud/web/issues/5981 +https://github.com/owncloud/web/pull/5983 diff --git a/changelog/unreleased/enhancement-public-link-capabilities b/changelog/unreleased/enhancement-public-link-capabilities new file mode 100644 index 00000000000..18cfb7c069c --- /dev/null +++ b/changelog/unreleased/enhancement-public-link-capabilities @@ -0,0 +1,10 @@ +Enhancement: App provider and archiver on public links + +We made the app provider and archiver services available on public links. As a prerequisite for this we needed to make backend capabilities available on public links, which will +be beneficial for all future extension development. + +https://github.com/owncloud/web/pull/5924 +https://github.com/owncloud/web/issues/5884 +https://github.com/owncloud/ocis/issues/2479 +https://github.com/owncloud/web/issues/2479 +https://github.com/owncloud/web/issues/5901 diff --git a/packages/web-app-external/src/App.vue b/packages/web-app-external/src/App.vue index 01febea6101..4e7c51fb66e 100644 --- a/packages/web-app-external/src/App.vue +++ b/packages/web-app-external/src/App.vue @@ -31,6 +31,24 @@ import { mapGetters } from 'vuex' import ErrorScreen from './components/ErrorScreen.vue' import LoadingScreen from './components/LoadingScreen.vue' +// FIXME: hacky, get rid asap, just a workaround +// same as packages/web-app-files/src/views/PublicFiles.vue +const unauthenticatedUserReady = async (router, store) => { + if (store.getters.userReady) { + return + } + + const publicToken = router.currentRoute.query['public-token'] + const publicLinkPassword = store.getters['Files/publicLinkPassword'] + + await store.dispatch('loadCapabilities', { + publicToken, + ...(publicLinkPassword && { user: 'public', password: publicLinkPassword }) + }) + + store.commit('SET_USER_READY', true) +} + export default { name: 'ExternalApp', @@ -48,6 +66,7 @@ export default { }), computed: { ...mapGetters(['getToken', 'capabilities', 'configuration']), + ...mapGetters('Files', ['publicLinkPassword']), pageTitle() { const translated = this.$gettext('"%{appName}" app page') @@ -69,37 +88,27 @@ export default { } }, async created() { - this.loading = true - - // TODO: Enable externalApp usage on public routes below - // initialize headers() + await unauthenticatedUserReady(this.$router, this.$store) - // if (this.isPublicRoute) { - // // send auth header here if public route - // // if password exists send it via basicauth public:password - - // // headers.append('public-token', 'uUCPJghnVUspjxe') - // // const password = this.publicLinkPassword - - // // if (password) { - // // headers.append( Authorization: 'Basic ' + Buffer.from('public:' + password).toString('base64') } - // // } - // } else { - // - check for token - // - abort if falsy - // - build headers as below - // } + this.loading = true - if (!this.getToken) { - this.loading = false - this.loadingError = true - return + // build headers with respect to the actual auth situation + const { 'public-token': publicToken } = this.$route.query + const publicLinkPassword = this.publicLinkPassword + const accessToken = this.getToken + const headers = { + 'X-Requested-With': 'XMLHttpRequest', + ...(publicToken && { 'public-token': publicToken }), + ...(publicLinkPassword && { + Authorization: + 'Basic ' + Buffer.from(['public', publicLinkPassword].join(':')).toString('base64') + }), + ...(accessToken && { + Authorization: 'Bearer ' + accessToken + }) } - const headers = new Headers() - headers.append('Authorization', 'Bearer ' + this.getToken) - headers.append('X-Requested-With', 'XMLHttpRequest') - + // fetch iframe params for app and file const configUrl = this.configuration.server const appOpenUrl = this.capabilities.files.app_providers[0].open_url.replace('/app', 'app') const url = configUrl + appOpenUrl + '?file_id=' + this.fileId + '&app_name=' + this.appName diff --git a/packages/web-app-external/src/index.js b/packages/web-app-external/src/index.js index 226e3e00eba..6c624169474 100644 --- a/packages/web-app-external/src/index.js +++ b/packages/web-app-external/src/index.js @@ -20,7 +20,8 @@ const routes = [ app: App }, meta: { - title: $gettext('External app') + title: $gettext('External app'), + auth: false } } ] @@ -30,7 +31,7 @@ export default { routes, store, translations, - async ready({ store: runtimeStore }) { - await runtimeStore.dispatch('External/fetchMimeTypes') + userReady({ store }) { + store.dispatch('External/fetchMimeTypes') } } diff --git a/packages/web-app-external/src/store/index.ts b/packages/web-app-external/src/store/index.ts index 65c510679c7..17b663cbcac 100644 --- a/packages/web-app-external/src/store/index.ts +++ b/packages/web-app-external/src/store/index.ts @@ -24,13 +24,18 @@ const actions = { throw new Error('Error fetching app provider MIME types') } - const mimeTypes = await response.json() - commit('SET_MIME_TYPES', mimeTypes['mime-types']) + const { 'mime-types': mimeTypes } = await response.json() + + commit('SET_MIME_TYPES', mimeTypes) } } const getters = { - getMimeTypes: (state: typeof State): { [key: string]: string } => { + mimeTypes: ( + state: typeof State + ): { + [key: string]: string + } => { return state.mimeTypes } } diff --git a/packages/web-app-external/tests/unit/app.spec.js b/packages/web-app-external/tests/unit/app.spec.js index a7f5f4d54d0..3d5543638f4 100644 --- a/packages/web-app-external/tests/unit/app.spec.js +++ b/packages/web-app-external/tests/unit/app.spec.js @@ -18,6 +18,9 @@ const componentStubs = { } const $route = { + query: { + 'public-token': 'a-token' + }, params: { app: 'exampleApp', file_id: '2147491323' @@ -30,6 +33,7 @@ const storeOptions = { configuration: jest.fn(() => ({ server: 'http://example.com/' })), + userReady: () => true, capabilities: jest.fn(() => ({ files: { app_providers: [ @@ -46,7 +50,7 @@ const storeOptions = { External: { namespaced: true, getters: { - getMimeTypes: jest.fn() + mimeTypes: jest.fn() }, actions: { fetchMimeTypes: jest.fn() @@ -84,7 +88,7 @@ describe('The app provider extension', () => { fetchMock.resetMocks() }) - it('should show a loading spinner while loading', () => { + it('should show a loading spinner while loading', async () => { global.fetch = jest.fn(() => setTimeout(() => { Promise.resolve({ @@ -94,19 +98,21 @@ describe('The app provider extension', () => { }, 500) ) const wrapper = createShallowMountWrapper() - + await wrapper.vm.$nextTick() expect(wrapper).toMatchSnapshot() }) it('should show a meaningful message if an error occurs during loading', async () => { fetchMock.mockReject(new Error('fake error message')) const wrapper = createShallowMountWrapper() await wrapper.vm.$nextTick() + await wrapper.vm.$nextTick() expect(wrapper).toMatchSnapshot() }) it('should fail for unauthenticated users', async () => { fetchMock.mockResponseOnce({ status: 401 }) const wrapper = createShallowMountWrapper() await wrapper.vm.$nextTick() + await wrapper.vm.$nextTick() expect(wrapper).toMatchSnapshot() }) it('should be able to load an iFrame via get', async () => { @@ -131,7 +137,6 @@ describe('The app provider extension', () => { json: () => providerSuccessResponsePost }) ) - const wrapper = createShallowMountWrapper() await wrapper.vm.$nextTick() await wrapper.vm.$nextTick() diff --git a/packages/web-app-files/src/App.vue b/packages/web-app-files/src/App.vue index 3e3217d699c..566fb697067 100644 --- a/packages/web-app-files/src/App.vue +++ b/packages/web-app-files/src/App.vue @@ -15,7 +15,7 @@ id="files-sidebar" ref="filesSidebar" tabindex="-1" - class="uk-width-1-1 uk-width-1-2@m uk-width-1-3@xl" + class="uk-width-1-1 uk-width-1-3@m uk-width-1-4@xl" @beforeDestroy="focusSideBar" @mounted="focusSideBar" @fileChanged="focusSideBar" diff --git a/packages/web-app-files/src/components/AppBar/SelectedResources/BatchActions.vue b/packages/web-app-files/src/components/AppBar/SelectedResources/BatchActions.vue index 99d32c08cc2..0a6de30d6cc 100644 --- a/packages/web-app-files/src/components/AppBar/SelectedResources/BatchActions.vue +++ b/packages/web-app-files/src/components/AppBar/SelectedResources/BatchActions.vue @@ -101,7 +101,7 @@ import MixinRoutes from '../../../mixins/routes' import MixinDeleteResources from '../../../mixins/deleteResources' import { cloneStateObject } from '../../../helpers/store' import { canBeMoved } from '../../../helpers/permissions' -import { checkRoute } from '../../../helpers/route' +import { checkRoute, isPublicFilesRoute } from '../../../helpers/route' import { shareStatus } from '../../../helpers/shareStatus' import { triggerShareAction } from '../../../helpers/share/triggerShareAction' import PQueue from 'p-queue' @@ -129,7 +129,7 @@ export default { canDownloadSingleFile() { if ( - !checkRoute(['files-personal', 'files-favorites', 'files-public-list'], this.$route.name) + !checkRoute(['files-personal', 'files-public-list', 'files-favorites'], this.$route.name) ) { return false } @@ -146,7 +146,9 @@ export default { }, canDownloadAsArchive() { - if (!checkRoute(['files-personal', 'files-favorites'], this.$route.name)) { + if ( + !checkRoute(['files-personal', 'files-public-list', 'files-favorites'], this.$route.name) + ) { return false } @@ -363,12 +365,16 @@ export default { await this.downloadFile(this.selectedFiles[0]) return } + await this.downloadAsArchive() }, async downloadAsArchive() { await triggerDownloadAsArchive({ - fileIds: this.selectedFiles.map((r) => r.fileId) + fileIds: this.selectedFiles.map((r) => r.fileId), + ...(isPublicFilesRoute(this.$route) && { + publicToken: this.$route.params.item.split('/')[0] + }) }).catch((e) => { console.error(e) this.showMessage({ diff --git a/packages/web-app-files/src/components/SideBar/Actions/FileActions.vue b/packages/web-app-files/src/components/SideBar/Actions/FileActions.vue index 23e0efbc4ec..db969e59f5f 100644 --- a/packages/web-app-files/src/components/SideBar/Actions/FileActions.vue +++ b/packages/web-app-files/src/components/SideBar/Actions/FileActions.vue @@ -36,6 +36,10 @@ export default { computed: { ...mapGetters('Files', ['highlightedFile', 'currentFolder']), + appList() { + return this.$_fileActions_loadApps(this.highlightedFile) || [] + }, + actions() { return this.$_fileActions_getAllAvailableActions(this.highlightedFile) } diff --git a/packages/web-app-files/src/components/SideBar/FileInfo.vue b/packages/web-app-files/src/components/SideBar/FileInfo.vue index e2c1994cd2d..05fa33a9157 100644 --- a/packages/web-app-files/src/components/SideBar/FileInfo.vue +++ b/packages/web-app-files/src/components/SideBar/FileInfo.vue @@ -1,7 +1,7 @@