From e69fb2678a1dfb5eacf739e93561f03d1e96e070 Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Fri, 26 Jan 2024 12:07:36 +0100 Subject: [PATCH 01/12] feat: extension points, custom components, preferences --- .../enhancement-custom-component-extension | 7 ++ .../unreleased/enhancement-extension-points | 16 +++ .../src/components/AppBar/CreateAndUpload.vue | 2 +- .../src/components/FilesList/QuickActions.vue | 2 +- .../web-app-files/src/views/Favorites.vue | 2 +- .../src/views/spaces/GenericSpace.vue | 2 +- .../src/views/spaces/Projects.vue | 2 +- .../tests/unit/views/Favorites.spec.ts | 2 +- .../unit/views/spaces/GenericSpace.spec.ts | 2 +- .../tests/unit/views/spaces/Projects.spec.ts | 2 +- .../src/components/CustomComponentTarget.vue | 68 ++++++++++++ .../components/FilesList/ContextActions.vue | 2 +- .../src/components/LoadingIndicator.vue | 7 +- .../src/components/SideBar/FileSideBar.vue | 2 +- packages/web-pkg/src/components/index.ts | 1 + .../piniaStores/extensionRegistry.ts | 85 --------------- .../extensionRegistry/extensionPreferences.ts | 62 +++++++++++ .../extensionRegistry/extensionRegistry.ts | 61 +++++++++++ .../piniaStores/extensionRegistry/index.ts | 3 + .../piniaStores/extensionRegistry/types.ts | 72 +++++++++++++ .../Account/ExtensionPreference.vue | 102 ++++++++++++++++++ .../{ => Account}/ThemeSwitcher.vue | 0 packages/web-runtime/src/helpers/navItems.ts | 2 +- .../web-runtime/src/layouts/Application.vue | 46 +++++++- packages/web-runtime/src/pages/account.vue | 35 +++++- .../components/Topbar/ThemeSwitcher.spec.ts | 2 +- .../tests/unit/pages/account.spec.ts | 52 ++++++++- .../src/mocks/useExtensionRegistryMock.ts | 2 + 28 files changed, 531 insertions(+), 112 deletions(-) create mode 100644 changelog/unreleased/enhancement-custom-component-extension create mode 100644 changelog/unreleased/enhancement-extension-points create mode 100644 packages/web-pkg/src/components/CustomComponentTarget.vue delete mode 100644 packages/web-pkg/src/composables/piniaStores/extensionRegistry.ts create mode 100644 packages/web-pkg/src/composables/piniaStores/extensionRegistry/extensionPreferences.ts create mode 100644 packages/web-pkg/src/composables/piniaStores/extensionRegistry/extensionRegistry.ts create mode 100644 packages/web-pkg/src/composables/piniaStores/extensionRegistry/index.ts create mode 100644 packages/web-pkg/src/composables/piniaStores/extensionRegistry/types.ts create mode 100644 packages/web-runtime/src/components/Account/ExtensionPreference.vue rename packages/web-runtime/src/components/{ => Account}/ThemeSwitcher.vue (100%) diff --git a/changelog/unreleased/enhancement-custom-component-extension b/changelog/unreleased/enhancement-custom-component-extension new file mode 100644 index 00000000000..02a6ffa8df2 --- /dev/null +++ b/changelog/unreleased/enhancement-custom-component-extension @@ -0,0 +1,7 @@ +Enhancement: Custom component extension type + +We've introduced a new extension type `customComponent`. This allows to register a custom component via an extension which +can then be rendered in a custom component render target. For the mapping to the render target, an extension point needs to be +registered and a CustomComponentTarget for this extension point needs to be in place in a vue template. + +https://github.com/owncloud/web/pull/10443 diff --git a/changelog/unreleased/enhancement-extension-points b/changelog/unreleased/enhancement-extension-points new file mode 100644 index 00000000000..b552f468823 --- /dev/null +++ b/changelog/unreleased/enhancement-extension-points @@ -0,0 +1,16 @@ +Enhancement: Add extensionPoint concept + +The extension system now allows developers to register extension points. An extension point defines the metadata for the +integration of a certain extension type in a certain context. Examples for extension points are render targets for +custom components, targets for file actions (e.g. the right click context menu, the batch actions, the whitespace context +menu), etc. + +Extensions can now specify that they are only valid for a certain or multiple extension points. This way a file action extension +can e.g. specify to be rendered only in the context menu, but not in the batch actions. Consequently, the extension points +concept is the next iteration of the `scopes` concept. The `scopes` concept will most likely be removed in a future release. + +Extension points can define if users should be able to choose preferences for the extension point. E.g. for the global progress +bar extension point, users can choose which of the available progress bar extensions should be used, since the extension point +only allows one extension to be active. At the moment we persist the user choice in the local storage of the browser. + +https://github.com/owncloud/web/pull/10443 diff --git a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue index 211c93257c6..cb2e2dc69a4 100644 --- a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue +++ b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue @@ -318,7 +318,7 @@ export default defineComponent({ const extensionActions = computed(() => { return [ ...extensionRegistry - .requestExtensions('action', ['upload-menu']) + .requestExtensions('action', { scopes: ['upload-menu'] }) .map((e) => e.action) ].filter((e) => e.isVisible()) }) diff --git a/packages/web-app-files/src/components/FilesList/QuickActions.vue b/packages/web-app-files/src/components/FilesList/QuickActions.vue index 34fbc276710..8cb860691de 100644 --- a/packages/web-app-files/src/components/FilesList/QuickActions.vue +++ b/packages/web-app-files/src/components/FilesList/QuickActions.vue @@ -39,7 +39,7 @@ export default defineComponent({ const filteredActions = computed(() => { return unref(extensionRegistry) - .requestExtensions('action', ['resource.quick-action']) + .requestExtensions('action', { scopes: ['resource.quick-action'] }) .map((e) => e.action) .filter(({ isVisible }) => isVisible({ space: props.space, resources: [props.item] })) }) diff --git a/packages/web-app-files/src/views/Favorites.vue b/packages/web-app-files/src/views/Favorites.vue index 0591b4858bb..fe281213771 100644 --- a/packages/web-app-files/src/views/Favorites.vue +++ b/packages/web-app-files/src/views/Favorites.vue @@ -124,7 +124,7 @@ export default defineComponent({ const viewModes = computed(() => { return [ ...extensionRegistry - .requestExtensions('folderView', ['favorite']) + .requestExtensions('folderView', { scopes: ['favorite'] }) .map((e) => e.folderView) ] }) diff --git a/packages/web-app-files/src/views/spaces/GenericSpace.vue b/packages/web-app-files/src/views/spaces/GenericSpace.vue index 12343012c48..64e8e98d6ae 100644 --- a/packages/web-app-files/src/views/spaces/GenericSpace.vue +++ b/packages/web-app-files/src/views/spaces/GenericSpace.vue @@ -268,7 +268,7 @@ export default defineComponent({ const viewModes = computed(() => { return [ ...extensionRegistry - .requestExtensions('folderView', ['resource']) + .requestExtensions('folderView', { scopes: ['resource'] }) .map((e) => e.folderView) ] }) diff --git a/packages/web-app-files/src/views/spaces/Projects.vue b/packages/web-app-files/src/views/spaces/Projects.vue index a2629eaac81..e59d48c9c3c 100644 --- a/packages/web-app-files/src/views/spaces/Projects.vue +++ b/packages/web-app-files/src/views/spaces/Projects.vue @@ -325,7 +325,7 @@ export default defineComponent({ const viewModes = computed(() => { return [ ...extensionRegistry - .requestExtensions('folderView', ['space']) + .requestExtensions('folderView', { scopes: ['space'] }) .map((e) => e.folderView) ] }) diff --git a/packages/web-app-files/tests/unit/views/Favorites.spec.ts b/packages/web-app-files/tests/unit/views/Favorites.spec.ts index 1e19f0f3001..0ccfadd98fa 100644 --- a/packages/web-app-files/tests/unit/views/Favorites.spec.ts +++ b/packages/web-app-files/tests/unit/views/Favorites.spec.ts @@ -70,7 +70,7 @@ function getMountedWrapper({ mocks = {}, files = [], loading = false } = {}) { vi.mocked(useExtensionRegistry).mockImplementation(() => useExtensionRegistryMock({ - requestExtensions(type: string, scopes: string[]) { + requestExtensions(type: string) { return extensions as ExtensionType[] } }) diff --git a/packages/web-app-files/tests/unit/views/spaces/GenericSpace.spec.ts b/packages/web-app-files/tests/unit/views/spaces/GenericSpace.spec.ts index 0af96969dda..37794813760 100644 --- a/packages/web-app-files/tests/unit/views/spaces/GenericSpace.spec.ts +++ b/packages/web-app-files/tests/unit/views/spaces/GenericSpace.spec.ts @@ -317,7 +317,7 @@ function getMountedWrapper({ vi.mocked(useExtensionRegistry).mockImplementation(() => useExtensionRegistryMock({ - requestExtensions(type: string, scopes: string[]) { + requestExtensions(type: string) { return extensions as ExtensionType[] } }) diff --git a/packages/web-app-files/tests/unit/views/spaces/Projects.spec.ts b/packages/web-app-files/tests/unit/views/spaces/Projects.spec.ts index 41555bf2de2..7648406255a 100644 --- a/packages/web-app-files/tests/unit/views/spaces/Projects.spec.ts +++ b/packages/web-app-files/tests/unit/views/spaces/Projects.spec.ts @@ -115,7 +115,7 @@ function getMountedWrapper({ mocks = {}, spaces = [], abilities = [], stubAppBar vi.mocked(useExtensionRegistry).mockImplementation(() => useExtensionRegistryMock({ - requestExtensions(type: string, scopes: string[]) { + requestExtensions(type: string) { return extensions as ExtensionType[] } }) diff --git a/packages/web-pkg/src/components/CustomComponentTarget.vue b/packages/web-pkg/src/components/CustomComponentTarget.vue new file mode 100644 index 00000000000..4dcf7cbe7f6 --- /dev/null +++ b/packages/web-pkg/src/components/CustomComponentTarget.vue @@ -0,0 +1,68 @@ + + + diff --git a/packages/web-pkg/src/components/FilesList/ContextActions.vue b/packages/web-pkg/src/components/FilesList/ContextActions.vue index 0455c7fda43..ee910b5cf60 100644 --- a/packages/web-pkg/src/components/FilesList/ContextActions.vue +++ b/packages/web-pkg/src/components/FilesList/ContextActions.vue @@ -75,7 +75,7 @@ export default defineComponent({ const extensionRegistry = useExtensionRegistry() const extensionContextActions = computed(() => { return extensionRegistry - .requestExtensions('action', ['resource.context-menu']) + .requestExtensions('action', { scopes: ['resource.context-menu'] }) .map((e) => e.action) }) diff --git a/packages/web-pkg/src/components/LoadingIndicator.vue b/packages/web-pkg/src/components/LoadingIndicator.vue index 297c63974fe..9ad8a207b5c 100644 --- a/packages/web-pkg/src/components/LoadingIndicator.vue +++ b/packages/web-pkg/src/components/LoadingIndicator.vue @@ -1,5 +1,5 @@