From abeac41f6a402268bfaf48ca71311aae322db31c Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Fri, 21 Jun 2024 13:41:26 +0200 Subject: [PATCH 01/21] Add open action for editors --- .../web-app-search/src/portals/SearchBar.vue | 15 ++++- .../components/AppTemplates/AppWrapper.vue | 10 ++- .../src/components/Modals/FilePickerModal.vue | 66 +++++++++++++++++++ .../web-pkg/src/components/Modals/index.ts | 1 + .../src/composables/actions/files/index.ts | 1 + .../files/useFileActionsOpenWithApp.ts | 66 +++++++++++++++++++ 6 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 packages/web-pkg/src/components/Modals/FilePickerModal.vue create mode 100644 packages/web-pkg/src/composables/actions/files/useFileActionsOpenWithApp.ts diff --git a/packages/web-app-search/src/portals/SearchBar.vue b/packages/web-app-search/src/portals/SearchBar.vue index 957bb00ef6b..d56299de548 100644 --- a/packages/web-app-search/src/portals/SearchBar.vue +++ b/packages/web-app-search/src/portals/SearchBar.vue @@ -109,7 +109,8 @@ import { queryItemAsString, useAuthStore, useCapabilityStore, - useResourcesStore + useResourcesStore, + useEmbedMode } from '@ownclouders/web-pkg' import Mark from 'mark.js' import { storeToRefs } from 'pinia' @@ -139,6 +140,8 @@ export default defineComponent({ const resourcesStore = useResourcesStore() const { currentFolder } = storeToRefs(resourcesStore) + const { isEnabled: isEmbedEnabled } = useEmbedMode() + const locationFilterId = ref(SearchLocationFilterConstants.allFiles) const optionsDropRef = ref(null) const activePreviewIndex = ref(null) @@ -328,7 +331,8 @@ export default defineComponent({ search, showPreview, updateTerm, - getSearchResultLocation + getSearchResultLocation, + isEmbedEnabled } }, @@ -350,7 +354,12 @@ export default defineComponent({ * since we are not able to provide search in the public link yet. * Enable as soon this feature is available. */ - return this.availableProviders.length && this.userContextReady && !this.publicLinkContextReady + return ( + this.availableProviders.length && + this.userContextReady && + !this.publicLinkContextReady && + !this.isEmbedEnabled + ) }, displayProviders() { /** diff --git a/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue b/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue index adbbd17632f..b28e69cfd7c 100644 --- a/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue +++ b/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue @@ -87,6 +87,7 @@ import { import { DavPermission } from '@ownclouders/web-client/webdav' import { HttpError } from '@ownclouders/web-client' import { dirname } from 'path' +import { useFileActionsOpenWithApp } from '../../composables/actions/files/useFileActionsOpenWithApp' export default defineComponent({ name: 'AppWrapper', @@ -135,6 +136,11 @@ export default defineComponent({ const configStore = useConfigStore() const resourcesStore = useResourcesStore() + console.log(resourcesStore) + + const { actions: openWithAppActions } = useFileActionsOpenWithApp({ + appId: props.applicationId + }) const { actions: createQuickLinkActions } = useFileActionsCopyQuickLink() const { actions: downloadFileActions } = useFileActionsDownloadFile() const { actions: showDetailsActions } = useFileActionsShowDetails() @@ -459,7 +465,9 @@ export default defineComponent({ }) const menuItemsContext = computed(() => { - return [...unref(fileActionsSave)].filter((item) => item.isVisible(unref(actionOptions))) + return [...unref(openWithAppActions), ...unref(fileActionsSave)].filter((item) => + item.isVisible(unref(actionOptions)) + ) }) const menuItemsShare = computed(() => { return [...unref(showSharesActions), ...unref(createQuickLinkActions)].filter((item) => diff --git a/packages/web-pkg/src/components/Modals/FilePickerModal.vue b/packages/web-pkg/src/components/Modals/FilePickerModal.vue new file mode 100644 index 00000000000..e35101f481f --- /dev/null +++ b/packages/web-pkg/src/components/Modals/FilePickerModal.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/packages/web-pkg/src/components/Modals/index.ts b/packages/web-pkg/src/components/Modals/index.ts index a658ada401b..ab3922b7dcf 100644 --- a/packages/web-pkg/src/components/Modals/index.ts +++ b/packages/web-pkg/src/components/Modals/index.ts @@ -1,3 +1,4 @@ export { default as ResourceConflictModal } from './ResourceConflictModal.vue' export { default as SpaceMoveInfoModal } from './SpaceMoveInfoModal.vue' export { default as EmojiPickerModal } from './EmojiPickerModal.vue' +export { default as FilePickerModal } from './FilePickerModal.vue' diff --git a/packages/web-pkg/src/composables/actions/files/index.ts b/packages/web-pkg/src/composables/actions/files/index.ts index 7bbde527210..b001e44e7ab 100644 --- a/packages/web-pkg/src/composables/actions/files/index.ts +++ b/packages/web-pkg/src/composables/actions/files/index.ts @@ -25,3 +25,4 @@ export * from './useFileActionsCreateNewFile' export * from './useFileActionsCreateNewShortcut' export * from './useFileActionsOpenShortcut' export * from './useFileActionsCreateLink' +export * from './useFileActionsOpenWithApp' diff --git a/packages/web-pkg/src/composables/actions/files/useFileActionsOpenWithApp.ts b/packages/web-pkg/src/composables/actions/files/useFileActionsOpenWithApp.ts new file mode 100644 index 00000000000..328b499ecf7 --- /dev/null +++ b/packages/web-pkg/src/composables/actions/files/useFileActionsOpenWithApp.ts @@ -0,0 +1,66 @@ +import { FileAction, FileActionOptions } from '../types' +import { useIsFilesAppActive, useIsSearchActive } from '../helpers' +import { computed, unref } from 'vue' +import { useGettext } from 'vue3-gettext' +import { useEmbedMode } from '../../embedMode' +import { useAppsStore, useModals } from '../../piniaStores' +import { storeToRefs } from 'pinia' +import FilePickerModal from '../../../components/Modals/FilePickerModal.vue' +import { useFolderLink } from '../../folderLink' + +export const useFileActionsOpenWithApp = ({ appId }: { appId: string }) => { + const { $gettext } = useGettext() + const isFilesAppActive = useIsFilesAppActive() + const isSearchActive = useIsSearchActive() + const { isEnabled: isEmbedModeEnabled } = useEmbedMode() + const { dispatchModal } = useModals() + const appsStore = useAppsStore() + const { apps } = storeToRefs(appsStore) + const { getParentFolderLink } = useFolderLink() + + const handler = ({ space, resources }: FileActionOptions) => { + const app = unref(apps)[appId] + const parentFolderLink = getParentFolderLink(resources[0]) + + dispatchModal({ + elementClass: 'open-with-app-modal', + title: $gettext('Open file with %{app}', { app: app.name }), + hideConfirmButton: true, + customComponent: FilePickerModal, + customComponentAttrs: () => ({ + app, + parentFolderLink + }), + focusTrapInitial: false + }) + } + + const actions = computed((): FileAction[] => [ + { + name: 'open-with-app', + icon: 'folder-open', + handler, + label: () => { + return $gettext('Open') + }, + isVisible: ({ resources }) => { + if (!unref(isFilesAppActive) && !unref(isSearchActive) && unref(isEmbedModeEnabled)) { + return false + } + if (resources.length !== 1) { + return false + } + if (resources[0].isFolder) { + return false + } + return resources[0].canDownload() + }, + componentType: 'button', + class: 'oc-files-actions-open-with-app-trigger' + } + ]) + + return { + actions + } +} From 288b818c4ca98aa623b128aceba1562530a28092 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Fri, 21 Jun 2024 14:10:17 +0200 Subject: [PATCH 02/21] Disable preview search in embed mode --- packages/web-app-files/src/extensions.ts | 4 ++- .../web-app-files/src/search/sdk/index.ts | 11 +++++-- .../web-app-files/src/search/sdk/preview.ts | 17 ++++++++-- .../web-app-search/src/portals/SearchBar.vue | 33 +++++++++---------- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/packages/web-app-files/src/extensions.ts b/packages/web-app-files/src/extensions.ts index de58705d2bd..09a4e35bb99 100644 --- a/packages/web-app-files/src/extensions.ts +++ b/packages/web-app-files/src/extensions.ts @@ -1,6 +1,7 @@ import { Extension, useCapabilityStore, + useConfigStore, useFileActionsCopyQuickLink, useFileActionsShowShares, useRouter, @@ -14,6 +15,7 @@ import { quickActionsExtensionPoint } from './extensionPoints' export const extensions = () => { const capabilityStore = useCapabilityStore() + const configStore = useConfigStore() const router = useRouter() const { search: searchFunction } = useSearch() @@ -30,7 +32,7 @@ export const extensions = () => { id: 'com.github.owncloud.web.files.search', extensionPointIds: ['app.search.provider'], type: 'search', - searchProvider: new SDKSearch(capabilityStore, router, searchFunction) + searchProvider: new SDKSearch(capabilityStore, router, searchFunction, configStore) }, { id: 'com.github.owncloud.web.files.quick-action.collaborator', diff --git a/packages/web-app-files/src/search/sdk/index.ts b/packages/web-app-files/src/search/sdk/index.ts index 77ea0465564..8c34b1266d0 100644 --- a/packages/web-app-files/src/search/sdk/index.ts +++ b/packages/web-app-files/src/search/sdk/index.ts @@ -3,6 +3,7 @@ import List from './list' import { Router } from 'vue-router' import { CapabilityStore, + ConfigStore, SearchFunction, SearchList, SearchPreview, @@ -19,11 +20,17 @@ export default class Provider implements SearchProvider { public readonly previewSearch: SearchPreview public readonly listSearch: SearchList private readonly capabilityStore: CapabilityStore + private readonly configStore: ConfigStore - constructor(capabilityStore: CapabilityStore, router: Router, searchFunction: SearchFunction) { + constructor( + capabilityStore: CapabilityStore, + router: Router, + searchFunction: SearchFunction, + configStore: ConfigStore + ) { this.id = 'files.sdk' this.displayName = $gettext('Files') - this.previewSearch = new Preview(router, searchFunction) + this.previewSearch = new Preview(router, searchFunction, configStore) this.listSearch = new List(searchFunction) this.capabilityStore = capabilityStore } diff --git a/packages/web-app-files/src/search/sdk/preview.ts b/packages/web-app-files/src/search/sdk/preview.ts index 14b2f1816c9..eeb19e6c746 100644 --- a/packages/web-app-files/src/search/sdk/preview.ts +++ b/packages/web-app-files/src/search/sdk/preview.ts @@ -1,4 +1,10 @@ -import { SearchFunction, SearchPreview, SearchResult } from '@ownclouders/web-pkg' +import { + CapabilityStore, + ConfigStore, + SearchFunction, + SearchPreview, + SearchResult +} from '@ownclouders/web-pkg' import { Component, unref } from 'vue' import { Router } from 'vue-router' import { ResourcePreview } from '@ownclouders/web-pkg' @@ -9,11 +15,13 @@ export default class Preview implements SearchPreview { public readonly component: Component private readonly router: Router private readonly searchFunction: SearchFunction + private readonly configStore: ConfigStore - constructor(router: Router, searchFunction: SearchFunction) { + constructor(router: Router, searchFunction: SearchFunction, configStore: ConfigStore) { this.component = ResourcePreview this.router = router this.searchFunction = searchFunction + this.configStore = configStore } public search(term: string): Promise { @@ -21,6 +29,9 @@ export default class Preview implements SearchPreview { } public get available(): boolean { - return unref(this.router.currentRoute).name !== 'search-provider-list' + return ( + unref(this.router.currentRoute).name !== 'search-provider-list' && + !this.configStore.options.embed?.enabled + ) } } diff --git a/packages/web-app-search/src/portals/SearchBar.vue b/packages/web-app-search/src/portals/SearchBar.vue index d56299de548..2323e6b5eab 100644 --- a/packages/web-app-search/src/portals/SearchBar.vue +++ b/packages/web-app-search/src/portals/SearchBar.vue @@ -47,6 +47,7 @@ { + return unref(availableProviders).some( + (provider) => provider?.previewSearch?.available === true + ) + }) + return { userContextReady, publicLinkContextReady, @@ -332,7 +336,7 @@ export default defineComponent({ showPreview, updateTerm, getSearchResultLocation, - isEmbedEnabled + showDrop } }, @@ -354,12 +358,7 @@ export default defineComponent({ * since we are not able to provide search in the public link yet. * Enable as soon this feature is available. */ - return ( - this.availableProviders.length && - this.userContextReady && - !this.publicLinkContextReady && - !this.isEmbedEnabled - ) + return this.availableProviders.length && this.userContextReady && !this.publicLinkContextReady }, displayProviders() { /** @@ -515,7 +514,7 @@ export default defineComponent({ this.showCancelButton = false }, hideOptionsDrop() { - this.optionsDrop.hide() + this.optionsDrop?.hide() } } }) From ab31326fb5d38c88f49e1a6af40685981464c277 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Fri, 21 Jun 2024 14:22:05 +0200 Subject: [PATCH 03/21] Make file picking functional --- .../web-app-files/src/search/sdk/index.ts | 1 - .../web-app-files/src/search/sdk/preview.ts | 10 +-- .../tests/unit/search/sdk.spec.ts | 7 +- .../components/AppTemplates/AppWrapper.vue | 2 - .../components/FilesList/ResourceTable.vue | 24 ++++--- .../src/components/FilesList/ResourceTile.vue | 22 +++---- .../components/FilesList/ResourceTiles.vue | 37 ++++++++++- .../src/components/Modals/FilePickerModal.vue | 64 +++++++++++++++++-- .../files/useFileActionsOpenWithApp.ts | 22 ++----- .../__snapshots__/ResourceTile.spec.ts.snap | 4 +- 10 files changed, 131 insertions(+), 62 deletions(-) diff --git a/packages/web-app-files/src/search/sdk/index.ts b/packages/web-app-files/src/search/sdk/index.ts index 8c34b1266d0..0d21decd567 100644 --- a/packages/web-app-files/src/search/sdk/index.ts +++ b/packages/web-app-files/src/search/sdk/index.ts @@ -20,7 +20,6 @@ export default class Provider implements SearchProvider { public readonly previewSearch: SearchPreview public readonly listSearch: SearchList private readonly capabilityStore: CapabilityStore - private readonly configStore: ConfigStore constructor( capabilityStore: CapabilityStore, diff --git a/packages/web-app-files/src/search/sdk/preview.ts b/packages/web-app-files/src/search/sdk/preview.ts index eeb19e6c746..9a46b77279a 100644 --- a/packages/web-app-files/src/search/sdk/preview.ts +++ b/packages/web-app-files/src/search/sdk/preview.ts @@ -1,10 +1,4 @@ -import { - CapabilityStore, - ConfigStore, - SearchFunction, - SearchPreview, - SearchResult -} from '@ownclouders/web-pkg' +import { ConfigStore, SearchFunction, SearchPreview, SearchResult } from '@ownclouders/web-pkg' import { Component, unref } from 'vue' import { Router } from 'vue-router' import { ResourcePreview } from '@ownclouders/web-pkg' @@ -31,7 +25,7 @@ export default class Preview implements SearchPreview { public get available(): boolean { return ( unref(this.router.currentRoute).name !== 'search-provider-list' && - !this.configStore.options.embed?.enabled + !this.configStore.options?.embed?.enabled ) } } diff --git a/packages/web-app-files/tests/unit/search/sdk.spec.ts b/packages/web-app-files/tests/unit/search/sdk.spec.ts index fb04b43500b..21ace33f519 100644 --- a/packages/web-app-files/tests/unit/search/sdk.spec.ts +++ b/packages/web-app-files/tests/unit/search/sdk.spec.ts @@ -3,7 +3,7 @@ import { RouteLocation, Router } from 'vue-router' import { mock } from 'vitest-mock-extended' import { ref } from 'vue' import { createTestingPinia } from 'web-test-helpers/src' -import { useCapabilityStore } from '@ownclouders/web-pkg' +import { ConfigStore, useCapabilityStore } from '@ownclouders/web-pkg' const getStore = (reports: string[] = []) => { createTestingPinia({ @@ -14,7 +14,7 @@ const getStore = (reports: string[] = []) => { describe('SDKProvider', () => { it('is only available if announced via capabilities', () => { - const search = new SDKSearch(getStore(), mock(), vi.fn()) + const search = new SDKSearch(getStore(), mock(), vi.fn(), mock()) expect(search.available).toBe(false) }) @@ -30,7 +30,8 @@ describe('SDKProvider', () => { mock({ currentRoute: ref(mock({ name: v.route })) }), - vi.fn() + vi.fn(), + mock() ) expect(!!search.previewSearch.available).toBe(!!v.available) diff --git a/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue b/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue index b28e69cfd7c..7f3487f9aa2 100644 --- a/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue +++ b/packages/web-pkg/src/components/AppTemplates/AppWrapper.vue @@ -136,8 +136,6 @@ export default defineComponent({ const configStore = useConfigStore() const resourcesStore = useResourcesStore() - console.log(resourcesStore) - const { actions: openWithAppActions } = useFileActionsOpenWithApp({ appId: props.applicationId }) diff --git a/packages/web-pkg/src/components/FilesList/ResourceTable.vue b/packages/web-pkg/src/components/FilesList/ResourceTable.vue index 4b394131c4c..6078c044000 100644 --- a/packages/web-pkg/src/components/FilesList/ResourceTable.vue +++ b/packages/web-pkg/src/components/FilesList/ResourceTable.vue @@ -508,6 +508,7 @@ export default defineComponent({ const { isLocationPicker, isFilePicker, + postMessage, isEnabled: isEmbedModeEnabled, extensions: embedModeExtensions } = useEmbedMode() @@ -540,13 +541,12 @@ export default defineComponent({ const getTagToolTip = (text: string) => (text.length > 7 ? text : '') const isResourceDisabled = (resource: Resource) => { - if ( - unref(isEmbedModeEnabled) && - unref(embedModeExtensions)?.length && - !unref(embedModeExtensions).includes(resource.extension) && - !resource.isFolder - ) { - return true + if (unref(isEmbedModeEnabled) && unref(embedModeExtensions)?.length) { + return ( + !unref(embedModeExtensions).includes(resource.extension) && + !unref(embedModeExtensions).includes(resource.mimeType) && + !resource.isFolder + ) } return resource.processing === true } @@ -587,6 +587,7 @@ export default defineComponent({ space: ref(props.space), targetRouteCallback: computed(() => props.targetRouteCallback) }), + postMessage, isFilePicker, isLocationPicker, isEmbedModeEnabled, @@ -988,6 +989,13 @@ export default defineComponent({ */ const resource = data[0] + if (this.isEmbedModeEnabled && this.isFilePicker) { + return this.postMessage( + 'owncloud-embed:file-pick', + JSON.parse(JSON.stringify(resource)) + ) + } + if (this.isResourceDisabled(resource)) { return } @@ -1054,7 +1062,7 @@ export default defineComponent({ return false } - if (this.isEmbedModeEnabled && !resource.isFolder) { + if (this.isEmbedModeEnabled && !this.isFilePicker && !resource.isFolder) { return false } diff --git a/packages/web-pkg/src/components/FilesList/ResourceTile.vue b/packages/web-pkg/src/components/FilesList/ResourceTile.vue index 2d732e9667e..8106c9dbd4a 100644 --- a/packages/web-pkg/src/components/FilesList/ResourceTile.vue +++ b/packages/web-pkg/src/components/FilesList/ResourceTile.vue @@ -4,8 +4,8 @@ :data-item-id="resource.id" :class="{ 'oc-tile-card-selected': isResourceSelected, - 'oc-tile-card-disabled': resource.processing, - 'state-trashed': resourceDisabled + 'oc-tile-card-disabled': isResourceDisabled && !isProjectSpaceResource(resource), + 'state-trashed': isResourceDisabled && isProjectSpaceResource(resource) }" @contextmenu="$emit('contextmenu', $event)" > @@ -21,7 +21,7 @@ @@ -85,7 +85,7 @@ import { computed, defineComponent, PropType } from 'vue' import ResourceIcon from './ResourceIcon.vue' import ResourceListItem from './ResourceListItem.vue' import ResourceLink from './ResourceLink.vue' -import { Resource } from '@ownclouders/web-client' +import { isProjectSpaceResource, Resource } from '@ownclouders/web-client' import { useGettext } from 'vue3-gettext' import { isSpaceResource } from '@ownclouders/web-client' import { isResourceTxtFileAlmostEmpty } from '../../helpers' @@ -115,6 +115,11 @@ export default defineComponent({ required: false, default: true }, + isResourceDisabled: { + type: Boolean, + required: false, + default: false + }, isExtensionDisplayed: { type: Boolean, default: true @@ -158,11 +163,6 @@ export default defineComponent({ } return null }) - - const resourceDisabled = computed(() => { - return isSpaceResource(props.resource) && props.resource.disabled === true - }) - const resourceDescription = computed(() => { if (isSpaceResource(props.resource)) { return props.resource.description @@ -178,11 +178,11 @@ export default defineComponent({ statusIconAttrs, showStatusIcon, tooltipLabelIcon, - resourceDisabled, resourceDescription, shouldDisplayThumbnails } - } + }, + methods: { isProjectSpaceResource } }) diff --git a/packages/web-pkg/src/components/FilesList/ResourceTiles.vue b/packages/web-pkg/src/components/FilesList/ResourceTiles.vue index d2b03658fe0..75709445d0e 100644 --- a/packages/web-pkg/src/components/FilesList/ResourceTiles.vue +++ b/packages/web-pkg/src/components/FilesList/ResourceTiles.vue @@ -46,6 +46,7 @@ :resource-route="getRoute(resource)" :is-resource-selected="isResourceSelected(resource)" :is-resource-clickable="isResourceClickable(resource)" + :is-resource-disabled="isResourceDisabled(resource)" :is-extension-displayed="areFileExtensionsShown" :resource-icon-size="resourceIconSize" :draggable="dragDrop" @@ -221,7 +222,13 @@ export default defineComponent({ const { $gettext } = useGettext() const resourcesStore = useResourcesStore() const { emit } = context - const { isEnabled: isEmbedModeEnabled, isLocationPicker, isFilePicker } = useEmbedMode() + const { + isEnabled: isEmbedModeEnabled, + extensions: embedModeExtensions, + isLocationPicker, + isFilePicker, + postMessage + } = useEmbedMode() const viewSizeMax = useViewSizeMax() const viewSizeCurrent = computed(() => { return Math.min(unref(viewSizeMax), props.viewSize) @@ -268,6 +275,13 @@ export default defineComponent({ } const emitTileClick = (resource: Resource) => { + if (unref(isEmbedModeEnabled) && unref(isFilePicker)) { + return postMessage( + 'owncloud-embed:file-pick', + JSON.parse(JSON.stringify(resource)) + ) + } + if (isSpaceResource(resource) && resource.disabled) { showMessage({ title: $gettext('Disabled spaces cannot be entered'), @@ -297,7 +311,23 @@ export default defineComponent({ } const isResourceClickable = (resource: Resource) => { - return !(unref(isEmbedModeEnabled) && !resource.isFolder) + return !(unref(isEmbedModeEnabled) && !unref(isFilePicker) && !resource.isFolder) + } + + const isResourceDisabled = (resource: Resource) => { + if (unref(isEmbedModeEnabled) && unref(embedModeExtensions)?.length) { + return ( + !unref(embedModeExtensions).includes(resource.extension) && + !unref(embedModeExtensions).includes(resource.mimeType) && + !resource.isFolder + ) + } + + if (isSpaceResource(resource) && resource.disabled) { + return true + } + + return resource.processing === true } const emitSelect = (selectedIds: string[]) => { @@ -525,7 +555,8 @@ export default defineComponent({ ghostTilesCount, getIndicators, isFilePicker, - isLocationPicker + isLocationPicker, + isResourceDisabled } }, data() { diff --git a/packages/web-pkg/src/components/Modals/FilePickerModal.vue b/packages/web-pkg/src/components/Modals/FilePickerModal.vue index e35101f481f..57f65443d45 100644 --- a/packages/web-pkg/src/components/Modals/FilePickerModal.vue +++ b/packages/web-pkg/src/components/Modals/FilePickerModal.vue @@ -3,17 +3,26 @@ ``` +## File picker + +The File Picker mode in ownCloud Web is designed for embedding an interface that allows users to pick a single file. +This mode can be configured to restrict the file types that users can select. To enable the File Picker mode, you need +to include the embed-target=file query parameter in the iframe URL. Furthermore, you can specify allowed file types +using the embed-file-types parameter. The file types can be specified using file extensions, MIME types, or a +combination of both. If the embed-file-types parameter is not provided, all file types will be selectable by default. + +### Example + +```html + + + + +``` + ## Delegate authentication If you already have a valid `access_token` that can be used to call the API from within the Embed mode and do not want to force the user to authenticate again, you can delegate the authentication. Delegating authentication will disable internal login form in ownCloud Web and will instead use events to obtain the token and update it. From a1a2199eba40561ad266b6c03085bc9473aa6ac5 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Sat, 22 Jun 2024 23:15:45 +0200 Subject: [PATCH 07/21] fix iframe title --- packages/web-pkg/src/components/Modals/FilePickerModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-pkg/src/components/Modals/FilePickerModal.vue b/packages/web-pkg/src/components/Modals/FilePickerModal.vue index 52192a0a947..5dac93d5c08 100644 --- a/packages/web-pkg/src/components/Modals/FilePickerModal.vue +++ b/packages/web-pkg/src/components/Modals/FilePickerModal.vue @@ -44,7 +44,7 @@ export default defineComponent({ e.extension ? e.extension : e.mimeType ) - const iframeTitle = themeStore.currentTheme.name + const iframeTitle = themeStore.currentTheme.common?.name const iframeUrl = new URL(parentFolderRoute.href, window.location.origin) iframeUrl.searchParams.append('embed', 'true') iframeUrl.searchParams.append('embed-target', 'file') From b14fbe2034039ac5581f541eef36f876ae1ff0e1 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Sun, 23 Jun 2024 12:18:38 +0200 Subject: [PATCH 08/21] fix operator --- docs/embed-mode/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/embed-mode/_index.md b/docs/embed-mode/_index.md index d91e978c875..27511139fa1 100644 --- a/docs/embed-mode/_index.md +++ b/docs/embed-mode/_index.md @@ -94,7 +94,7 @@ combination of both. If the embed-file-types parameter is not provided, all file ```html - + From f366ef3813b2912c33cb8d8afdd7eecea8174662 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Tue, 2 Jul 2024 18:11:50 +0200 Subject: [PATCH 18/21] Simplify if statement --- packages/web-pkg/src/components/FilesList/ResourceTiles.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/web-pkg/src/components/FilesList/ResourceTiles.vue b/packages/web-pkg/src/components/FilesList/ResourceTiles.vue index cc0ba836c6c..a81b9d094b7 100644 --- a/packages/web-pkg/src/components/FilesList/ResourceTiles.vue +++ b/packages/web-pkg/src/components/FilesList/ResourceTiles.vue @@ -311,7 +311,11 @@ export default defineComponent({ } const isResourceClickable = (resource: Resource) => { - return !(unref(isEmbedModeEnabled) && !unref(isFilePicker) && !resource.isFolder) + if (unref(isEmbedModeEnabled) && !unref(isFilePicker) && !resource.isFolder) { + return false + } + + return true } const isResourceDisabled = (resource: Resource) => { From 008d33084f04efd8f11e0cfd98d8aee2b2d26835 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Tue, 2 Jul 2024 18:16:58 +0200 Subject: [PATCH 19/21] Make linter happy --- .../tests/unit/components/Modals/FilePickerModal.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-pkg/tests/unit/components/Modals/FilePickerModal.spec.ts b/packages/web-pkg/tests/unit/components/Modals/FilePickerModal.spec.ts index 021de77ff1a..286b866eda6 100644 --- a/packages/web-pkg/tests/unit/components/Modals/FilePickerModal.spec.ts +++ b/packages/web-pkg/tests/unit/components/Modals/FilePickerModal.spec.ts @@ -39,7 +39,7 @@ describe('FilePickerModal', () => { }) }) -function getWrapper({ props = {} }: { props?: PartialComponentProps } = {}) { +function getWrapper() { const mocks = defaultComponentMocks() return { From 3a08a84f537e2048d1e97077e207c8eb84a6d030 Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Thu, 4 Jul 2024 10:01:36 +0200 Subject: [PATCH 20/21] Adjust code style --- packages/web-pkg/src/components/Modals/FilePickerModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-pkg/src/components/Modals/FilePickerModal.vue b/packages/web-pkg/src/components/Modals/FilePickerModal.vue index f551ca7f8f5..2dd380b1255 100644 --- a/packages/web-pkg/src/components/Modals/FilePickerModal.vue +++ b/packages/web-pkg/src/components/Modals/FilePickerModal.vue @@ -34,7 +34,7 @@ export default defineComponent({ app: { type: Object as PropType, required: true }, parentFolderLink: { type: Object as PropType, required: true } }, - setup: function (props) { + setup(props) { const isLoading = ref(true) const router = useRouter() const { removeModal } = useModals() From 91d7a61ed4081c9f67b1e9534b0a9be7539f540d Mon Sep 17 00:00:00 2001 From: Jan Ackermann Date: Thu, 4 Jul 2024 10:05:25 +0200 Subject: [PATCH 21/21] add changelog item --- .../unreleased/enhancement-open-file-directly-from-app | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog/unreleased/enhancement-open-file-directly-from-app diff --git a/changelog/unreleased/enhancement-open-file-directly-from-app b/changelog/unreleased/enhancement-open-file-directly-from-app new file mode 100644 index 00000000000..007beb7ab2b --- /dev/null +++ b/changelog/unreleased/enhancement-open-file-directly-from-app @@ -0,0 +1,7 @@ +Enhancement: Open file directly from app + +We've added an 'Open' item to the drop down menu in the app top bar, +so the user can open a different file directly from the opened app. + +https://github.com/owncloud/web/pull/11085 +https://github.com/owncloud/web/issues/11013