From 904c3c409678a7ed4c2ab522f35197aca3065cf7 Mon Sep 17 00:00:00 2001 From: Elizabeth Danzberger Date: Wed, 9 Oct 2024 17:31:05 -0400 Subject: [PATCH] refactor: move template settings to vue component Signed-off-by: Elizabeth Danzberger --- css/admin.scss | 84 +------ lib/Service/InitialStateService.php | 9 + lib/Settings/Admin.php | 8 +- src/admin.js | 118 ---------- src/components/AdminSettings.vue | 15 +- .../AdminSettings/GlobalTemplates.vue | 212 ++++++++++++++++++ templates/admin.php | 47 +--- 7 files changed, 234 insertions(+), 259 deletions(-) create mode 100644 src/components/AdminSettings/GlobalTemplates.vue diff --git a/css/admin.scss b/css/admin.scss index 0d2a579709..3222da918e 100644 --- a/css/admin.scss +++ b/css/admin.scss @@ -21,14 +21,7 @@ margin-top: -4px; width: 300px !important; } -} - -input#zoteroAPIKeyField { - width: 300px; -} -#richdocuments, -#richdocuments-templates { // inline buttons on section headers > h2 { display: inline-flex; @@ -55,77 +48,6 @@ input#zoteroAPIKeyField { } } -#richdocuments-templates { - > input { - // feedback for keyboard navigation - &:hover, - &:focus, - &:active { - + h2 .icon-add, - + h2 .icon-loading-small { - opacity: 0.7; - } - + #emptycontent label { - color: var(--color-text-light); - } - } - } - ul:not(.hidden) { - display: flex; - flex-wrap: wrap; - li { - $size: 150px; - $sizeY: math.div($size, 210) * 297; - $space: 10px; - border-radius: var(--border-radius); - border: 1px solid var(--color-border); - margin: $space; - position: relative; - figure { - display: flex; - flex-direction: column; - width: $size; - margin: $space; - img, .templatePlaceholder { - width: $size; - height: $sizeY; - background-color: var(--color-background-dark); - } - figcaption { - margin-top: $space; - } - } - .delete-cover, - .delete-template { - width: $size; - height: $sizeY; - top: 0; - left: 0; - position: absolute; - margin: $space; - opacity: 0; - transition: opacity 250ms ease-in-out; - z-index: 3; - line-height: $sizeY; - text-align: center; - font-size: 20px; - background-size: 24px; - // text is set as bg - color: var(--color-background-darker); - } - .delete-cover { - // bg is set as color - background-color: var(--color-text-lighter); - z-index: 2; - } - &:hover .delete-template, - .delete-template:focus, - .delete-template.icon-loading { - opacity: 1; - + .delete-cover { - opacity: 0.5; - } - } - } - } -} +input#zoteroAPIKeyField { + width: 300px; +} \ No newline at end of file diff --git a/lib/Service/InitialStateService.php b/lib/Service/InitialStateService.php index 8e2550204b..9a8be2f469 100644 --- a/lib/Service/InitialStateService.php +++ b/lib/Service/InitialStateService.php @@ -11,6 +11,7 @@ use OCA\Richdocuments\AppConfig; use OCA\Richdocuments\AppInfo\Application; use OCA\Richdocuments\Db\Wopi; +use OCA\Richdocuments\TemplateManager; use OCP\AppFramework\Services\IInitialState; use OCP\Defaults; use OCP\IConfig; @@ -22,6 +23,7 @@ class InitialStateService { public function __construct( private IInitialState $initialState, private AppConfig $appConfig, + private TemplateManager $templateManager, private CapabilitiesService $capabilitiesService, private IURLGenerator $urlGenerator, private Defaults $themingDefaults, @@ -56,6 +58,13 @@ public function provideDocument(Wopi $wopi, array $params): void { $this->provideOptions(); } + public function provideAdminSettings(): void { + $this->initialState->provideInitialState('adminSettings', [ + 'templatesAvailable' => $this->capabilitiesService->hasTemplateSource(), + 'templates' => $this->templateManager->getSystemFormatted(), + ]); + } + public function prepareParams(array $params): array { $defaults = [ 'instanceId' => $this->config->getSystemValue('instanceid'), diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index 9c99946772..100ef6eddd 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -30,6 +30,8 @@ public function __construct( public function getForm(): TemplateResponse { $this->initialStateService->provideCapabilities(); + $this->initialStateService->provideAdminSettings(); + return new TemplateResponse( 'richdocuments', 'admin', @@ -45,8 +47,6 @@ public function getForm(): TemplateResponse { 'external_apps' => $this->config->getAppValue('richdocuments', 'external_apps'), 'canonical_webroot' => $this->config->getAppValue('richdocuments', 'canonical_webroot'), 'disable_certificate_verification' => $this->config->getAppValue('richdocuments', 'disable_certificate_verification', '') === 'yes', - 'templates' => $this->manager->getSystemFormatted(), - 'templatesAvailable' => $this->capabilitiesService->hasTemplateSource(), 'settings' => $this->appConfig->getAppSettings(), 'demo_servers' => $this->demoService->fetchDemoServers(), 'web_server' => strtolower($_SERVER['SERVER_SOFTWARE']), @@ -59,11 +59,11 @@ public function getForm(): TemplateResponse { ); } - public function getSection() { + public function getSection(): string { return 'richdocuments'; } - public function getPriority() { + public function getPriority(): int { return 0; } } diff --git a/src/admin.js b/src/admin.js index 0b716f4333..1bea381dba 100644 --- a/src/admin.js +++ b/src/admin.js @@ -4,8 +4,6 @@ */ import './init-shared.js' import Vue from 'vue' -import axios from '@nextcloud/axios' -import { generateUrl } from '@nextcloud/router' import AdminSettings from './components/AdminSettings.vue' import '../css/admin.scss' @@ -29,119 +27,3 @@ const element = document.getElementById('admin-vue') new Vue({ render: h => h(AdminSettings, { props: { initial: JSON.parse(element.dataset.initial) } }), }).$mount('#admin-vue') - -/** - * Append a new template to the dom - * - * @param {object} data the template data from the template controller response - */ -function appendTemplateFromData(data) { - const template = document.querySelector('.template-model').cloneNode(true) - template.className = '' - template.dataset.filename = data.name - template.querySelector('img').src = data.preview - template.querySelector('figcaption').textContent = data.name - template.querySelector('.delete-template').href = data.delete - - document.querySelector('#richdocuments-templates > ul').appendChild(template) - template.querySelector('.delete-template').addEventListener('click', deleteTemplate) -} - -/** - * Delete template event handler - * - * @param {Event} event the button click event - */ -function deleteTemplate(event) { - event.preventDefault() - const emptyElmt = document.querySelector('#richdocuments-templates #emptycontent') - const tplListElmt = document.querySelector('#richdocuments-templates > ul') - const elmt = event.target - - // ensure no request is in progress - if (elmt.className.indexOf('loading') === -1 && elmt.textContent === '') { - const remote = event.target.href - elmt.classList.add('icon-loading') - elmt.classList.remove('icon-delete') - - // send request - axios.delete(remote) - .then(function() { - // remove template - elmt.parentElement.remove() - // is list empty? Only the default template is left - if (tplListElmt.querySelectorAll('li').length === 1) { - tplListElmt.classList.add('hidden') - emptyElmt.classList.remove('hidden') - } - }) - .catch(function(e) { - // failure, show warning - elmt.textContent = t('richdocuments', 'Error') - elmt.classList.remove('icon-loading') - setTimeout(function() { - elmt.classList.add('icon-delete') - elmt.textContent = '' - }, 2000) - }) - } -} - -/** - * Init the upload manager and the delete template handler - */ -function initTemplateManager() { - const inputElmt = document.querySelector('#add-template') - const buttonElmt = document.querySelector('.icon-add') - const deleteElmts = document.querySelectorAll('.delete-template') - const emptyElmt = document.querySelector('#richdocuments-templates #emptycontent') - const tplListElmt = document.querySelector('#richdocuments-templates > ul') - - deleteElmts.forEach(function(elmt) { - elmt.addEventListener('click', deleteTemplate) - }) - - // fileupload plugin - $('#richdocuments-templates').fileupload({ - dataType: 'json', - url: generateUrl('apps/richdocuments/template'), - type: 'POST', - - add(e, data) { - // submit on file selection - data.submit() - inputElmt.disabled = true - buttonElmt.className = 'icon-loading-small' - }, - - submit(e, data) { - data.formData = _.extend(data.formData || {}, { - requesttoken: OC.requestToken, - }) - }, - - success(e) { - document.querySelector(`[data-filename="${e.data.name}"]`)?.remove() - inputElmt.disabled = false - buttonElmt.className = 'icon-add' - // add template to dom - appendTemplateFromData(e.data) - tplListElmt.classList.remove('hidden') - emptyElmt.classList.add('hidden') - }, - - fail(e, data) { - // failure, show warning - buttonElmt.className = 'icon-add' - buttonElmt.textContent = t('richdocuments', 'An error occurred') + ': ' + data.jqXHR.responseJSON.data.message - setTimeout(function() { - inputElmt.disabled = false - buttonElmt.textContent = '' - }, 2000) - }, - }) -} - -document.addEventListener('DOMContentLoaded', () => { - initTemplateManager() -}) diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue index 4ca5e687e1..e2b30eccce 100644 --- a/src/components/AdminSettings.vue +++ b/src/components/AdminSettings.vue @@ -390,6 +390,8 @@

+ + @@ -406,6 +408,7 @@ import SettingsSelectGroup from './SettingsSelectGroup.vue' import SettingsExternalApps from './SettingsExternalApps.vue' import SettingsInputFile from './SettingsInputFile.vue' import SettingsFontList from './SettingsFontList.vue' +import GlobalTemplates from './AdminSettings/GlobalTemplates.vue' import '@nextcloud/dialogs/style.css' import { getCallbackBaseUrl } from '../helpers/url.js' @@ -435,6 +438,7 @@ export default { SettingsExternalApps, SettingsInputFile, SettingsFontList, + GlobalTemplates, NcModal, NcNoteCard, }, @@ -533,9 +537,6 @@ export default { else this.serverError = Object.values(getCapabilities().collabora).length > 0 ? SERVER_STATE_OK : SERVER_STATE_CONNECTION_ERROR } }, - isSetup() { - this.toggleTemplateSettings() - }, }, beforeMount() { for (const key in this.initial.settings) { @@ -581,7 +582,6 @@ export default { } this.checkIfDemoServerIsActive() this.checkSettings() - this.toggleTemplateSettings() }, methods: { async checkSettings() { @@ -815,13 +815,6 @@ export default { this.settings.fonts.splice(index, 1) } }, - toggleTemplateSettings() { - if (this.isSetup) { - document.getElementById('richdocuments-templates').classList.remove('hidden') - } else { - document.getElementById('richdocuments-templates').classList.add('hidden') - } - }, }, } diff --git a/src/components/AdminSettings/GlobalTemplates.vue b/src/components/AdminSettings/GlobalTemplates.vue new file mode 100644 index 0000000000..2b4002497d --- /dev/null +++ b/src/components/AdminSettings/GlobalTemplates.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/templates/admin.php b/templates/admin.php index a5dca9c522..4c27962b7a 100644 --- a/templates/admin.php +++ b/templates/admin.php @@ -4,51 +4,8 @@ * SPDX-FileCopyrightText: 2014-2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-or-later */ -script('richdocuments', 'richdocuments-admin'); -script('files', 'jquery.fileupload'); +\OCP\Util::addScript('richdocuments', 'richdocuments-admin'); /** @var array $_ */ ?> -
- - - - - +
\ No newline at end of file