|
| 1 | +<!-- |
| 2 | + - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors |
| 3 | + - SPDX-License-Identifier: AGPL-3.0-or-later |
| 4 | +--> |
| 5 | + |
| 6 | +<template> |
| 7 | + <NcSettingsSection :name="t('richdocuments', 'Nextcloud Office')" |
| 8 | + :description="t('richdocuments', 'Personal Settings for Nextcloud Office')" |
| 9 | + :limit-width="true"> |
| 10 | + <!-- Template folder selection --> |
| 11 | + <div class="template-folder-settings"> |
| 12 | + <div class="template-input-wrapper"> |
| 13 | + <NcTextField v-model="templateFolder" |
| 14 | + :label="t('richdocuments', 'Select a template directory')" |
| 15 | + :disabled="true" /> |
| 16 | + </div> |
| 17 | + <NcButton id="templateSelectButton" |
| 18 | + type="secondary" |
| 19 | + @click="onTemplateSelectButtonClick"> |
| 20 | + <span class="icon-folder" |
| 21 | + :title="t('richdocuments', 'Select a personal template folder')" |
| 22 | + data-toggle="tooltip" /> |
| 23 | + </NcButton> |
| 24 | + <NcButton id="templateResetButton" |
| 25 | + type="secondary" |
| 26 | + :title="t('richdocuments', 'Remove personal template folder')" |
| 27 | + @click="resetTemplate"> |
| 28 | + <DeleteIcon :size="20" /> |
| 29 | + </NcButton> |
| 30 | + </div> |
| 31 | + <p> |
| 32 | + <em> |
| 33 | + {{ t('richdocuments', 'Templates inside of this directory will be added to the template selector of Nextcloud Office.') }} |
| 34 | + </em> |
| 35 | + </p> |
| 36 | + |
| 37 | + <!-- Zotero --> |
| 38 | + <div class="zotero-section"> |
| 39 | + <p><strong>{{ t('richdocuments', 'Zotero') }}</strong></p> |
| 40 | + <template v-if="hasZoteroSupport"> |
| 41 | + <div class="input-wrapper"> |
| 42 | + <div class="zotero-inline"> |
| 43 | + <div class="zotero-input-wrapper"> |
| 44 | + <NcTextField id="zoteroAPIKeyField" |
| 45 | + :value="zoteroAPIKey" |
| 46 | + :label="t('richdocuments', 'Enter Zotero API Key')" |
| 47 | + @update:value="setZoteroAPIKey" /> |
| 48 | + </div> |
| 49 | + <NcButton id="zoteroAPIKeySave" |
| 50 | + type="secondary" |
| 51 | + @click="saveZoteroAPIKey"> |
| 52 | + {{ t('richdocuments', 'Save') }} |
| 53 | + </NcButton> |
| 54 | + <NcButton id="zoteroAPIKeyRemove" |
| 55 | + type="secondary" |
| 56 | + :title="t('richdocuments', 'Remove Zotero API Key')" |
| 57 | + @click="resetZoteroAPI"> |
| 58 | + <DeleteIcon :size="20" /> |
| 59 | + </NcButton> |
| 60 | + </div> |
| 61 | + <p> |
| 62 | + <em> |
| 63 | + {{ t('richdocuments', 'To use Zotero specify your API key here. You can create your API key in your') }} |
| 64 | + <a href="https://www.zotero.org/settings/keys" target="_blank"> |
| 65 | + {{ t('richdocuments', 'Zotero account API settings.') }} |
| 66 | + </a> |
| 67 | + </em> |
| 68 | + </p> |
| 69 | + </div> |
| 70 | + </template> |
| 71 | + <p v-else> |
| 72 | + <em> |
| 73 | + {{ t('richdocuments', 'This instance does not support Zotero, because the feature is missing or disabled. Please contact the administration.') }} |
| 74 | + </em> |
| 75 | + </p> |
| 76 | + </div> |
| 77 | + |
| 78 | + <!-- Document signing --> |
| 79 | + <div class="docsign-section"> |
| 80 | + <p class="doc_sign_head"> |
| 81 | + <strong>{{ t('richdocuments', 'Document signing') }}</strong> |
| 82 | + </p> |
| 83 | + <template v-if="hasDocumentSigningSupport"> |
| 84 | + <div class="input-wrapper"> |
| 85 | + <!-- Document Signing Cert --> |
| 86 | + <DocSigningField v-model="documentSigningCert" |
| 87 | + :label="t('richdocuments', 'Enter document signing cert (in PEM format)')" |
| 88 | + @save="val => setDocumentSigningCert(val)" |
| 89 | + @remove="() => setDocumentSigningCert('')" /> |
| 90 | + <!-- Document Signing Key --> |
| 91 | + <DocSigningField v-model="documentSigningKey" |
| 92 | + :label="t('richdocuments', 'Enter document signing key')" |
| 93 | + @save="val => setDocumentSigningKey(val)" |
| 94 | + @remove="() => setDocumentSigningKey('')" /> |
| 95 | + <!-- Document Signing CA --> |
| 96 | + <DocSigningField v-model="documentSigningCa" |
| 97 | + :label="t('richdocuments', 'Enter document signing CA chain')" |
| 98 | + @save="val => setDocumentSigningCa(val)" |
| 99 | + @remove="() => setDocumentSigningCa('')" /> |
| 100 | + <p> |
| 101 | + <em> |
| 102 | + {{ t('richdocuments', 'To use document signing, specify your signing certificate, key and CA chain here.') }} |
| 103 | + </em> |
| 104 | + </p> |
| 105 | + </div> |
| 106 | + </template> |
| 107 | + <p v-else> |
| 108 | + <em> |
| 109 | + {{ t('richdocuments', 'This instance does not support document signing, because the feature is missing or disabled. Please contact the administrator.') }} |
| 110 | + </em> |
| 111 | + </p> |
| 112 | + </div> |
| 113 | + </NcSettingsSection> |
| 114 | +</template> |
| 115 | + |
| 116 | +<script> |
| 117 | +import { generateFilePath } from '@nextcloud/router' |
| 118 | +import { showError, showSuccess } from '@nextcloud/dialogs' |
| 119 | +import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js' |
| 120 | +import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' |
| 121 | +import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' |
| 122 | +import DocSigningField from './DocSigningField.vue' |
| 123 | +import DeleteIcon from 'vue-material-design-icons/Delete.vue' |
| 124 | +import axios from '@nextcloud/axios' |
| 125 | +
|
| 126 | +export default { |
| 127 | + name: 'PersonalSettings', |
| 128 | + components: { |
| 129 | + NcSettingsSection, |
| 130 | + NcTextField, |
| 131 | + NcButton, |
| 132 | + DocSigningField, |
| 133 | + DeleteIcon, |
| 134 | + }, |
| 135 | + props: { |
| 136 | + initial: { |
| 137 | + type: Object, |
| 138 | + required: true, |
| 139 | + }, |
| 140 | + }, |
| 141 | + data() { |
| 142 | + return { |
| 143 | + templateFolder: this.initial.templateFolder || '', |
| 144 | + hasZoteroSupport: this.initial.hasZoteroSupport || false, |
| 145 | + zoteroAPIKey: this.initial.zoteroAPIKey || '', |
| 146 | + hasDocumentSigningSupport: this.initial.hasDocumentSigningSupport || false, |
| 147 | + documentSigningCert: this.initial.documentSigningCert || '', |
| 148 | + documentSigningKey: this.initial.documentSigningKey || '', |
| 149 | + documentSigningCa: this.initial.documentSigningCa || '', |
| 150 | + } |
| 151 | + }, |
| 152 | + methods: { |
| 153 | + setZoteroAPIKey(newVal) { |
| 154 | + this.zoteroAPIKey = newVal |
| 155 | + }, |
| 156 | + async onTemplateSelectButtonClick() { |
| 157 | + OC.dialogs.filepicker( |
| 158 | + this.t('richdocuments', 'Select a personal template folder'), |
| 159 | + async (datapath) => { |
| 160 | + const success = await this.updateSetting({ templateFolder: datapath }) |
| 161 | + if (success) { |
| 162 | + this.templateFolder = datapath |
| 163 | + } |
| 164 | + }, |
| 165 | + false, |
| 166 | + 'httpd/unix-directory', |
| 167 | + true, |
| 168 | + OC.dialogs.FILEPICKER_TYPE_CHOOSE, |
| 169 | + ) |
| 170 | + }, |
| 171 | + async resetTemplate() { |
| 172 | + const success = await this.updateSetting({ templateFolder: '' }) |
| 173 | + if (success) { |
| 174 | + this.templateFolder = '' |
| 175 | + } |
| 176 | + }, |
| 177 | + async saveZoteroAPIKey() { |
| 178 | + await this.updateSetting({ zoteroAPIKeyInput: this.zoteroAPIKey }) |
| 179 | + }, |
| 180 | + async resetZoteroAPI() { |
| 181 | + const success = await this.updateSetting({ zoteroAPIKeyInput: '' }) |
| 182 | + if (success) { |
| 183 | + this.zoteroAPIKey = '' |
| 184 | + } |
| 185 | + }, |
| 186 | + async setDocumentSigningCert(val) { |
| 187 | + const success = await this.updateSetting({ documentSigningCertInput: val }) |
| 188 | + if (success) { |
| 189 | + this.documentSigningCert = val |
| 190 | + } |
| 191 | + }, |
| 192 | + async setDocumentSigningKey(val) { |
| 193 | + const success = await this.updateSetting({ documentSigningKeyInput: val }) |
| 194 | + if (success) { |
| 195 | + this.documentSigningKey = val |
| 196 | + } |
| 197 | + }, |
| 198 | + async setDocumentSigningCa(val) { |
| 199 | + const success = await this.updateSetting({ documentSigningCaInput: val }) |
| 200 | + if (success) { |
| 201 | + this.documentSigningCa = val |
| 202 | + } |
| 203 | + }, |
| 204 | + async updateSetting(settings) { |
| 205 | + try { |
| 206 | + const response = await axios.post( |
| 207 | + generateFilePath('richdocuments', 'ajax', 'personal.php'), |
| 208 | + settings, |
| 209 | + ) |
| 210 | +
|
| 211 | + if (response.data.status === 'success') { |
| 212 | + showSuccess(this.t('richdocuments', 'Settings saved successfully.')) |
| 213 | + return true |
| 214 | + } else { |
| 215 | + showError(response.data.data.message || this.t('richdocuments', 'Failed to save settings.')) |
| 216 | + return false |
| 217 | + } |
| 218 | + } catch (error) { |
| 219 | + console.error('Error updating settings:', error) |
| 220 | + showError(this.t('richdocuments', 'Unexpected error occurred.')) |
| 221 | + return false |
| 222 | + } |
| 223 | + }, |
| 224 | + }, |
| 225 | +} |
| 226 | +</script> |
| 227 | + |
| 228 | +<style scoped> |
| 229 | +.template-folder-settings { |
| 230 | + display: flex; |
| 231 | + align-items: center; |
| 232 | + gap: 1rem; |
| 233 | + margin-bottom: 2rem; |
| 234 | +} |
| 235 | +
|
| 236 | +.template-input-wrapper { |
| 237 | + width: 300px; |
| 238 | + flex-shrink: 0; |
| 239 | +} |
| 240 | +
|
| 241 | +.input-wrapper { |
| 242 | + display: flex; |
| 243 | + flex-direction: column; |
| 244 | + gap: 1rem; |
| 245 | +} |
| 246 | +
|
| 247 | +.zotero-section p { |
| 248 | + margin-top: 5px !important; |
| 249 | +} |
| 250 | +
|
| 251 | +.zotero-inline { |
| 252 | + display: flex; |
| 253 | + align-items: center; |
| 254 | + gap: 1rem; |
| 255 | +} |
| 256 | +
|
| 257 | +.doc_sign_head { |
| 258 | + padding-top: 10px; |
| 259 | + padding-bottom: 5px; |
| 260 | +} |
| 261 | +
|
| 262 | +.msg { |
| 263 | + display: inline-block; |
| 264 | + margin-bottom: 1rem; |
| 265 | + color: var(--color-warning); |
| 266 | +} |
| 267 | +
|
| 268 | +.icon-folder::before { |
| 269 | + content: "\1F4C1"; |
| 270 | +} |
| 271 | +</style> |
0 commit comments