f7cloud_client/apps/whiteboard/js/whiteboard-settings.mjs.map
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

1 line
13 KiB
Plaintext

{"version":3,"file":"whiteboard-settings.mjs","sources":["../src/components/AdminSettings.vue","../src/admin.ts"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div>\n\t\t<NcSettingsSection :name=\"t('whiteboard', 'Real-time collaboration server')\">\n\t\t\t<NcNoteCard v-if=\"!loading && setupCheck !== null\" :type=\"setupCheck.severity\">\n\t\t\t\t{{ setupCheck.description }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcNoteCard v-else-if=\"!loading && validConnection === true\" type=\"success\">\n\t\t\t\t{{ t('whiteboard', 'WebSocket server for real-time collaboration is configured and connected.') }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcNoteCard v-else-if=\"!loading && validConnection === false\" type=\"error\">\n\t\t\t\t{{ t('whiteboard', 'Failed to verify the connection:') }} {{ connectionError }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcNoteCard v-else type=\"info\" :text=\"t('whiteboard', 'Verifying connection…')\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon />\n\t\t\t\t</template>\n\t\t\t</NcNoteCard>\n\n\t\t\t<p>\n\t\t\t\t{{ t('whiteboard', 'The WebSocket server handles real-time collaboration sessions between users. Basic whiteboard functionality works without it, but real-time collaboration requires this server to be running and accessible from users\\' browsers.') }}\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<a href=\"https://github.com/nextcloud/whiteboard?tab=readme-ov-file#websocket-server-for-real-time-collaboration\"\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\tclass=\"external\">{{ t('whiteboard', 'See the documentation on how to install and configure the WebSocket server.') }}</a>\n\t\t\t</p>\n\t\t\t<form @submit.prevent=\"submit\">\n\t\t\t\t<p>\n\t\t\t\t\t<NcTextField :label=\"t('whiteboard', 'WebSocket server URL')\"\n\t\t\t\t\t\t:value.sync=\"serverUrl\"\n\t\t\t\t\t\t:helper-text=\"t('whiteboard', 'URL where the WebSocket server for real-time collaboration is running. Must be accessible from users\\' browsers.')\" />\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\t<NcTextField :label=\"t('whiteboard', 'Shared secret')\"\n\t\t\t\t\t\t:value.sync=\"secret\"\n\t\t\t\t\t\t:helper-text=\"t('whiteboard', 'JWT secret key shared between Nextcloud and the WebSocket server for secure authentication.')\" />\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\t<NcButton type=\"submit\"\n\t\t\t\t\t\t:disabled=\"!serverUrl || loading\"\n\t\t\t\t\t\t@click.prevent=\"submit\">\n\t\t\t\t\t\t{{ t('whiteboard', 'Save settings') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</p>\n\t\t\t</form>\n\t\t</NcSettingsSection>\n\t\t<NcSettingsSection :name=\"t('whiteboard', 'Advanced settings')\">\n\t\t\t<p>\n\t\t\t\t<NcTextField :label=\"t('whiteboard', 'Max image size (MB)')\"\n\t\t\t\t\t:value.sync=\"maxFileSize\"\n\t\t\t\t\t:helper-text=\"maxFileSizeHelperText\"\n\t\t\t\t\t@blur=\"saveMaxFileSize\" />\n\t\t\t</p>\n\t\t\t<p v-if=\"wsLimitHelperText\" class=\"settings-help\">\n\t\t\t\t{{ wsLimitHelperText }}\n\t\t\t</p>\n\t\t\t<NcNoteCard v-if=\"maxFileSizeNotice\" :type=\"maxFileSizeNotice.type\">\n\t\t\t\t{{ maxFileSizeNotice.message }}\n\t\t\t</NcNoteCard>\n\t\t</NcSettingsSection>\n\t</div>\n</template>\n<script>\nimport axios from '@nextcloud/axios'\nimport { io } from 'socket.io-client'\nimport NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'\nimport NcButton from '@nextcloud/vue/dist/Components/NcButton.js'\nimport NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'\nimport NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'\nimport NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js'\nimport { loadState } from '@nextcloud/initial-state'\nimport { generateUrl } from '@nextcloud/router'\nimport { t } from '@nextcloud/l10n'\nimport { showError } from '@nextcloud/dialogs'\n\nexport default {\n\tname: 'AdminSettings',\n\tcomponents: {\n\t\tNcTextField,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t\tNcSettingsSection,\n\t},\n\tdata() {\n\t\treturn {\n\t\t\tserverUrl: loadState('whiteboard', 'url', ''),\n\t\t\tsecret: loadState('whiteboard', 'secret', ''),\n\t\t\tmaxFileSize: loadState('whiteboard', 'maxFileSize', 10),\n\t\t\twsMaxUploadFileSizeBytes: null,\n\t\t\tvalidConnection: undefined,\n\t\t\tconnectionError: undefined,\n\t\t\tloadingSettings: false,\n\t\t\tloadingSocket: false,\n\t\t\tsetupCheck: null,\n\t\t}\n\t},\n\tcomputed: {\n\t\tloading() {\n\t\t\treturn this.loadingSettings || this.loadingSocket\n\t\t},\n\t\twsLimitMb() {\n\t\t\tif (!this.wsMaxUploadFileSizeBytes) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.wsMaxUploadFileSizeBytes / 1e6\n\t\t},\n\t\tmaxFileSizeHelperText() {\n\t\t\treturn t('whiteboard', 'Per image added to the board (original file size).')\n\t\t},\n\t\twsLimitHelperText() {\n\t\t\tif (this.wsLimitMb) {\n\t\t\t\treturn t('whiteboard', 'WebSocket payload cap: {limit} MB (MAX_UPLOAD_FILE_SIZE on collaboration server).', { limit: this.wsLimitMb.toFixed(1) })\n\t\t\t}\n\t\t\tif (this.serverUrl) {\n\t\t\t\treturn t('whiteboard', 'WebSocket payload cap set by MAX_UPLOAD_FILE_SIZE on the collaboration server.')\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\t\tmaxFileSizeNotice() {\n\t\t\tconst maxFileSize = Number(this.maxFileSize)\n\t\t\tif (!Number.isFinite(maxFileSize) || maxFileSize <= 0) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\tmessage: t('whiteboard', 'Enter a positive number of MB.'),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.wsMaxUploadFileSizeBytes) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tif (this.wsLimitMb && maxFileSize > this.wsLimitMb) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\tmessage: t('whiteboard', 'Exceeds WebSocket payload limit ({limit} MB). Images may not sync.', { limit: this.wsLimitMb.toFixed(1) }),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null\n\t\t},\n\t},\n\tmounted() {\n\t\tthis.callSettings({\n\t\t\tserverUrl: this.serverUrl,\n\t\t})\n\t\tthis.verifyConnection({ jwt: loadState('whiteboard', 'jwt', '') })\n\t\tthis.fetchWebsocketLimits()\n\t},\n\tmethods: {\n\t\tasync submit() {\n\t\t\tconst data = await this.callSettings({\n\t\t\t\tserverUrl: this.serverUrl,\n\t\t\t\tsecret: this.secret,\n\t\t\t\tmaxFileSize: this.maxFileSize,\n\t\t\t})\n\t\t\tawait this.verifyConnection(data)\n\t\t\tawait this.fetchWebsocketLimits()\n\t\t},\n\t\tasync saveMaxFileSize() {\n\t\t\tconst maxFileSize = Number(this.maxFileSize)\n\t\t\tif (!Number.isFinite(maxFileSize) || maxFileSize <= 0) {\n\t\t\t\tshowError(t('whiteboard', 'Max image size must be a positive number.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.wsLimitMb && maxFileSize > this.wsLimitMb) {\n\t\t\t\tshowError(t('whiteboard', 'Max image size exceeds the WebSocket payload limit ({limit} MB).', { limit: this.wsLimitMb.toFixed(1) }))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.callSettings({\n\t\t\t\tmaxFileSize: this.maxFileSize,\n\t\t\t})\n\t\t},\n\t\tasync callSettings(updateValues = {}) {\n\t\t\tthis.loadingSettings = true\n\t\t\tconst { data } = await axios.post(generateUrl('/apps/whiteboard/settings'), updateValues)\n\t\t\tif (data.check) {\n\t\t\t\tthis.setupCheck = data.check.severity !== 'success' ? data.check : null\n\t\t\t}\n\t\t\tthis.loadingSettings = false\n\t\t\treturn data\n\t\t},\n\t\tasync fetchWebsocketLimits() {\n\t\t\tif (!this.serverUrl) {\n\t\t\t\tthis.wsMaxUploadFileSizeBytes = null\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlet statusUrl\n\t\t\ttry {\n\t\t\t\tconst url = new URL(this.serverUrl)\n\t\t\t\tconst pathPrefix = url.pathname.replace(/\\/$/, '')\n\t\t\t\tconst protocol = url.protocol === 'wss:' ? 'https:' : url.protocol === 'ws:' ? 'http:' : url.protocol\n\t\t\t\tstatusUrl = `${protocol}//${url.host}${pathPrefix}/status`\n\t\t\t} catch (error) {\n\t\t\t\tthis.wsMaxUploadFileSizeBytes = null\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(statusUrl, { method: 'GET', mode: 'cors', credentials: 'omit' })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`Status ${response.status}`)\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tthis.wsMaxUploadFileSizeBytes = data?.config?.maxUploadFileSizeBytes ?? null\n\t\t\t} catch (error) {\n\t\t\t\tthis.wsMaxUploadFileSizeBytes = null\n\t\t\t}\n\t\t},\n\t\tasync verifyConnection(data) {\n\t\t\tif (!data.jwt) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst url = new URL(this.serverUrl)\n\t\t\tconst path = url.pathname.replace(/\\/$/, '') + '/socket.io'\n\n\t\t\tthis.loadingSocket = true\n\t\t\tconst socket = io(url.origin, {\n\t\t\t\tpath,\n\t\t\t\twithCredentials: true,\n\t\t\t\tauth: {\n\t\t\t\t\tsecret: data.jwt,\n\t\t\t\t},\n\t\t\t\ttransports: ['websocket'],\n\t\t\t\ttimeout: 5000,\n\t\t\t})\n\t\t\tsocket.on('connect', () => {\n\t\t\t\tthis.validConnection = true\n\t\t\t\tthis.connectionError = undefined\n\t\t\t\tthis.loadingSocket = false\n\t\t\t})\n\t\t\tsocket.on('connect_error', (error) => {\n\t\t\t\tthis.validConnection = error.message === 'Connection verified'\n\t\t\t\tthis.connectionError = this.validConnection === false ? error.message : undefined\n\t\t\t\tsocket.close()\n\t\t\t\tthis.loadingSocket = false\n\t\t\t})\n\t\t\tsocket.connect()\n\t\t},\n\t\tt,\n\t},\n}\n</script>\n<style scoped>\n.section {\n\tmax-width: 700px;\n}\n\np {\n\tmargin-bottom: calc(var(--default-grid-baseline) * 4);\n}\n\n.settings-help {\n\tmargin-top: calc(var(--default-grid-baseline) * -3);\n\tmargin-bottom: calc(var(--default-grid-baseline) * 4);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.875rem;\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport Vue from 'vue'\nimport { t, n } from '@nextcloud/l10n'\n\nimport AdminSettings from './components/AdminSettings.vue'\n\nVue.prototype.t = t\nVue.prototype.n = n\n\n/* eslint-disable-next-line no-new */\nnew Vue({\n\trender: h => h(AdminSettings, {}),\n}).$mount('#admin-vue')\n"],"names":["_sfc_main","NcTextField","NcButton","NcLoadingIcon","NcNoteCard","NcSettingsSection","loadState","t","maxFileSize","data","showError","updateValues","axios","generateUrl","statusUrl","url","pathPrefix","response","path","socket","io","error","Vue","n","h","AdminSettings"],"mappings":"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"}