Skip to content

Commit

Permalink
Merge pull request #9818 from LukasHirt/feat/mode-config
Browse files Browse the repository at this point in the history
feat: introduce mode config option
  • Loading branch information
JammingBen authored Oct 18, 2023
2 parents 1f889eb + 0b75bb5 commit 411fc98
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 13 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/enhancement-add-mode-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add `mode` config option

We've added a new config option called `mode`. This option can be set via config.json in the options object or query parameter.
This config option asserts different modes of the UI. Currently, it will be used in the embed mode to hide certain parts of the UI.

https://github.com/owncloud/web/pull/9818
https://github.com/owncloud/web/issues/9768
1 change: 1 addition & 0 deletions packages/web-pkg/src/composables/embedMode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useEmbedMode'
10 changes: 10 additions & 0 deletions packages/web-pkg/src/composables/embedMode/useEmbedMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { computed } from 'vue'
import { useStore } from '../store'

export const useEmbedMode = () => {
const store = useStore()

const isEnabled = computed<boolean>(() => store.getters.configuration.options.mode === 'embed')

return { isEnabled }
}
1 change: 1 addition & 0 deletions packages/web-pkg/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from './spaces'
export * from './store'
export * from './upload'
export * from './viewMode'
export * from './embedMode'
1 change: 1 addition & 0 deletions packages/web-pkg/src/configuration/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface OptionsConfiguration {
openLinksWithDefaultApp?: boolean
tokenStorageLocal?: boolean
disabledExtensions?: string[]
mode?: string
}

export interface OAuth2Configuration {
Expand Down
28 changes: 18 additions & 10 deletions packages/web-runtime/src/components/Topbar/TopBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
:aria-label="$gettext('Top bar')"
>
<div class="oc-topbar-left oc-flex oc-flex-middle oc-flex-start">
<applications-menu v-if="appMenuItems.length" :applications-list="appMenuItems" />
<applications-menu
v-if="appMenuItems.length && !isEmbedModeEnabled"
:applications-list="appMenuItems"
/>
<router-link
ref="navigationSidebarLogo"
v-oc-tooltip="$gettext('Back to home')"
Expand All @@ -21,14 +24,16 @@
<div class="oc-topbar-right oc-flex oc-flex-middle">
<portal-target name="app.runtime.header.right" multiple />
</div>
<portal to="app.runtime.header.right" :order="50">
<theme-switcher v-if="darkThemeAvailable" />
<feedback-link v-if="isFeedbackLinkEnabled" v-bind="feedbackLinkOptions" />
</portal>
<portal to="app.runtime.header.right" :order="100">
<notifications v-if="isNotificationBellEnabled" />
<user-menu :applications-list="userMenuItems" />
</portal>
<template v-if="!isEmbedModeEnabled">
<portal to="app.runtime.header.right" :order="50">
<theme-switcher v-if="darkThemeAvailable" />
<feedback-link v-if="isFeedbackLinkEnabled" v-bind="feedbackLinkOptions" />
</portal>
<portal to="app.runtime.header.right" :order="100">
<notifications v-if="isNotificationBellEnabled" />
<user-menu :applications-list="userMenuItems" />
</portal>
</template>
<portal-target name="app.runtime.header.left" @change="updateLeftPortal" />
</header>
</template>
Expand All @@ -43,6 +48,7 @@ import FeedbackLink from './FeedbackLink.vue'
import ThemeSwitcher from './ThemeSwitcher.vue'
import {
useCapabilityNotifications,
useEmbedMode,
useRouter,
useStore,
useUserContext
Expand Down Expand Up @@ -71,6 +77,7 @@ export default {
const isUserContext = useUserContext({ store })
const language = useGettext()
const router = useRouter()
const { isEnabled: isEmbedModeEnabled } = useEmbedMode()
const logoWidth = ref('150px')
const isNotificationBellEnabled = computed(() => {
Expand Down Expand Up @@ -169,7 +176,8 @@ export default {
isNotificationBellEnabled,
userMenuItems,
appMenuItems,
logoWidth
logoWidth,
isEmbedModeEnabled
}
},
computed: {
Expand Down
6 changes: 6 additions & 0 deletions packages/web-runtime/src/container/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import { merge } from 'lodash-es'
import { AppConfigObject } from '@ownclouders/web-pkg'
import { MESSAGE_TYPE } from '@ownclouders/web-client/src/sse'
import { getQueryParam } from '../helpers/url'

/**
* fetch runtime configuration, this step is optional, all later steps can use a static
Expand All @@ -49,6 +50,11 @@ export const announceConfiguration = async (path: string): Promise<RuntimeConfig
const rawConfig = (await request.json().catch((error) => {
throw new Error(`config could not be parsed. ${error}`)
})) as RawConfig

if (!rawConfig.options?.mode) {
rawConfig.options = { ...rawConfig.options, mode: getQueryParam('mode') ?? 'web' }
}

configurationManager.initialize(rawConfig)
// TODO: we might want to get rid of exposing the raw config. needs more refactoring though.
return rawConfig
Expand Down
5 changes: 5 additions & 0 deletions packages/web-runtime/src/helpers/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const getQueryParam = (paramName: string): string | null => {
const searchParams = new URLSearchParams(window.location.search)

return searchParams.get(paramName)
}
26 changes: 24 additions & 2 deletions packages/web-runtime/tests/unit/components/Topbar/TopBar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,30 @@ describe('Top Bar component', () => {
expect(wrapper.find('notifications-stub').exists()).toBeFalsy()
})
})
it.each(['applications-menu', 'theme-switcher', 'feedback-link', 'notifications', 'user-menu'])(
'should hide %s when mode is "embed"',
(componentName) => {
const { wrapper } = getWrapper({
configuration: { options: { disableFeedbackLink: false, mode: 'embed' } }
})
expect(wrapper.find(`${componentName}-stub`).exists()).toBeFalsy()
}
)
it.each(['applications-menu', 'theme-switcher', 'feedback-link', 'notifications', 'user-menu'])(
'should not hide %s when mode is not "embed"',
(componentName) => {
const { wrapper } = getWrapper({
configuration: { options: { disableFeedbackLink: false, mode: 'web' } },
capabilities: {
notifications: { 'ocs-endpoints': ['list', 'get', 'delete'] }
}
})
expect(wrapper.find(`${componentName}-stub`).exists()).toBeTruthy()
}
)
})

const getWrapper = ({ capabilities = {}, isUserContextReady = true } = {}) => {
const getWrapper = ({ capabilities = {}, isUserContextReady = true, configuration = {} } = {}) => {
const mocks = { ...defaultComponentMocks() }
const storeOptions = {
...defaultStoreMockOptions,
Expand All @@ -62,7 +83,8 @@ const getWrapper = ({ capabilities = {}, isUserContextReady = true } = {}) => {
logo: {
topbar: 'example-logo.svg'
}
}
},
...configuration
}))
storeOptions.getters.user.mockImplementation(() => ({ id: 'einstein' }))
storeOptions.modules.runtime.modules.auth.getters.isUserContextReady.mockReturnValue(
Expand Down
46 changes: 45 additions & 1 deletion packages/web-runtime/tests/unit/container/bootstrap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { mock, mockDeep } from 'jest-mock-extended'
import { createApp, defineComponent, App } from 'vue'
import { createStore } from 'vuex'
import { ConfigurationManager } from '@ownclouders/web-pkg'
import fetchMock from 'jest-fetch-mock'
import {
initializeApplications,
announceApplicationsReady,
announceCustomScripts,
announceCustomStyles
announceCustomStyles,
announceConfiguration
} from '../../../src/container/bootstrap'
import { buildApplication } from '../../../src/container/application'
import { defaultStoreMockOptions } from 'web-test-helpers/src'
Expand Down Expand Up @@ -114,3 +116,45 @@ describe('announceCustomStyles', () => {
expect(elements.length).toBeFalsy()
})
})

describe('announceConfiguration', () => {
afterEach(() => {
jest.clearAllMocks()
})

it('should set "web" as the default mode when none is set', async () => {
fetchMock.mockResponseOnce('{}')
const config = await announceConfiguration('/config.json')
expect(config.options.mode).toStrictEqual('web')
})

it('should use the mode that is defined in config.json', async () => {
fetchMock.mockResponseOnce('{ "options": { "mode": "config-mode" } }')
const config = await announceConfiguration('/config.json')
expect(config.options.mode).toStrictEqual('config-mode')
})

it('should use the mode that is defined in URL query when config.json does not set it', async () => {
Object.defineProperty(window, 'location', {
value: {
search: '?mode=query-mode'
},
writable: true
})
fetchMock.mockResponseOnce('{}')
const config = await announceConfiguration('/config.json')
expect(config.options.mode).toStrictEqual('query-mode')
})

it('should not use the mode that is defined in URL query when config.json sets one', async () => {
Object.defineProperty(window, 'location', {
value: {
search: '?mode=query-mode'
},
writable: true
})
fetchMock.mockResponseOnce('{ "options": { "mode": "config-mode" } }')
const config = await announceConfiguration('/config.json')
expect(config.options.mode).toStrictEqual('config-mode')
})
})

0 comments on commit 411fc98

Please sign in to comment.