diff --git a/package-lock.json b/package-lock.json index 25f4d09d43b..d48aa48d929 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", + "@jest/globals": "^29.7.0", "@nextcloud/babel-config": "^1.2.0", "@nextcloud/browserslist-config": "^3.0.1", "@nextcloud/eslint-config": "^8.4.1", diff --git a/package.json b/package.json index 94a4a239f8b..f793beed31c 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", + "@jest/globals": "^29.7.0", "@nextcloud/babel-config": "^1.2.0", "@nextcloud/browserslist-config": "^3.0.1", "@nextcloud/eslint-config": "^8.4.1", diff --git a/src/components/SettingsDialog/SettingsDialog.vue b/src/components/SettingsDialog/SettingsDialog.vue index 1b9b1d300a3..387fb6c7974 100644 --- a/src/components/SettingsDialog/SettingsDialog.vue +++ b/src/components/SettingsDialog/SettingsDialog.vue @@ -7,8 +7,16 @@ + + + + + @@ -188,6 +196,7 @@ import MediaDevicesPreview from './MediaDevicesPreview.vue' import { PRIVACY } from '../../constants.js' import BrowserStorage from '../../services/BrowserStorage.js' import { getTalkConfig } from '../../services/CapabilitiesManager.ts' +import { useCustomSettings } from '../../services/SettingsAPI.ts' import { useSettingsStore } from '../../stores/settings.js' const isBackgroundBlurred = loadState('spreed', 'force_enable_blur_filter', '') @@ -207,11 +216,13 @@ export default { setup() { const settingsStore = useSettingsStore() + const { customSettingsSections } = useCustomSettings() return { settingsStore, supportTypingStatus, isBackgroundBlurred, + customSettingsSections, } }, diff --git a/src/main.js b/src/main.js index 9c74e5000c5..c1c21917c8b 100644 --- a/src/main.js +++ b/src/main.js @@ -18,6 +18,7 @@ import App from './App.vue' import './init.js' import router from './router/router.js' +import { SettingsAPI } from './services/SettingsAPI.ts' import store from './store/index.js' // Leaflet icon patch @@ -81,7 +82,7 @@ const Sidebar = function() { if (!sidebarShown) { this.state.file = '' } - } + }, ) } @@ -153,5 +154,6 @@ if (!window.OCA.Talk) { window.OCA.Talk = {} } OCA.Talk.instance = instance +OCA.Talk.Settings = SettingsAPI export default instance diff --git a/src/services/SettingsAPI.ts b/src/services/SettingsAPI.ts new file mode 100644 index 00000000000..0d80d90a5a4 --- /dev/null +++ b/src/services/SettingsAPI.ts @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { readonly, shallowReactive } from 'vue' + +import { emit } from '@nextcloud/event-bus' + +type TalkSettingsSection = { + /** + * Section internal ID + */ + id: string + /** + * Section visible name + */ + name: string + /** + * WebComponent's (custom element's) tag name to render as the section content + */ + element: string +} + +const customSettingsSections: TalkSettingsSection[] = shallowReactive([]) + +/** + * Register a custom settings section + * @param section - Settings section + */ +function registerSection(section: TalkSettingsSection) { + customSettingsSections.push(section) +} + +/** + * Unregister a custom settings section + * @param id - Section ID + */ +function unregisterSection(id: string) { + const index = customSettingsSections.findIndex((section) => section.id === id) + if (index !== -1) { + customSettingsSections.splice(index, 1) + } +} + +/** + * Open settings dialog + */ +function open() { + emit('show-settings', undefined) +} + +export const SettingsAPI = { + open, + registerSection, + unregisterSection, +} + +/** + * Composable to use custom settings in Talk + */ +export function useCustomSettings() { + return { + customSettingsSections: readonly(customSettingsSections), + } +} diff --git a/src/services/__tests__/SettingsAPI.spec.js b/src/services/__tests__/SettingsAPI.spec.js new file mode 100644 index 00000000000..57aa2b5ed1e --- /dev/null +++ b/src/services/__tests__/SettingsAPI.spec.js @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +import { jest, describe, it, expect } from '@jest/globals' + +import { emit } from '@nextcloud/event-bus' + +import { SettingsAPI, useCustomSettings } from '../SettingsAPI.ts' + +jest.mock('@nextcloud/event-bus') + +describe('SettingsAPI', () => { + it('should have open method to open settings', () => { + expect(SettingsAPI.open).toBeDefined() + SettingsAPI.open() + // Currently, a global event is used to open the settings + expect(emit).toHaveBeenCalledWith('show-settings', undefined) + }) + + it('should have registerSection method to register settings sections', () => { + const { customSettingsSections } = useCustomSettings() + expect(customSettingsSections).toEqual([]) + expect(SettingsAPI.registerSection).toBeDefined() + SettingsAPI.registerSection({ + id: 'test', + name: 'Test', + element: 'test-element', + }) + SettingsAPI.registerSection({ + id: 'test2', + name: 'Test 2', + element: 'test-element-two', + }) + expect(customSettingsSections).toEqual([{ + id: 'test', + name: 'Test', + element: 'test-element', + }, { + id: 'test2', + name: 'Test 2', + element: 'test-element-two', + }]) + }) + + it('should have unregisterSection method to unregister settings sections', () => { + const { customSettingsSections } = useCustomSettings() + expect(customSettingsSections).toEqual([{ + id: 'test', + name: 'Test', + element: 'test-element', + }, { + id: 'test2', + name: 'Test 2', + element: 'test-element-two', + }]) + expect(SettingsAPI.unregisterSection).toBeDefined() + SettingsAPI.unregisterSection('test') + expect(customSettingsSections).toEqual([{ + id: 'test2', + name: 'Test 2', + element: 'test-element-two', + }]) + }) +})