Options.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <script setup>
  2. import SettingTabs from '@/layouts/SettingTabs.vue'
  3. import userService from '@/services/userService'
  4. import appSettingService from '@/services/appSettingService'
  5. import { useUserStore } from '@/stores/user'
  6. import { useGroups } from '@/stores/groups'
  7. import { useAppSettingsStore } from '@/stores/appSettings'
  8. import { useNotifyStore } from '@/stores/notify'
  9. import VersionChecker from '@/components/VersionChecker.vue'
  10. const $2fauth = inject('2fauth')
  11. const user = useUserStore()
  12. const groups = useGroups()
  13. const notify = useNotifyStore()
  14. const appSettings = useAppSettingsStore()
  15. const returnTo = useStorage($2fauth.prefix + 'returnTo', 'accounts')
  16. const layouts = [
  17. { text: 'settings.forms.grid', value: 'grid', icon: 'th' },
  18. { text: 'settings.forms.list', value: 'list', icon: 'list' },
  19. ]
  20. const themes = [
  21. { text: 'settings.forms.light', value: 'light', icon: 'sun' },
  22. { text: 'settings.forms.dark', value: 'dark', icon: 'moon' },
  23. { text: 'settings.forms.automatic', value: 'system', icon: 'desktop' },
  24. ]
  25. const passwordFormats = [
  26. { text: '12 34 56', value: 2, legend: 'settings.forms.pair', title: 'settings.forms.pair_legend' },
  27. { text: '123 456', value: 3, legend: 'settings.forms.trio', title: 'settings.forms.trio_legend' },
  28. { text: '1234 5678', value: 0.5, legend: 'settings.forms.half', title: 'settings.forms.half_legend' },
  29. ]
  30. const kickUserAfters = [
  31. { text: 'settings.forms.never', value: 0 },
  32. { text: 'settings.forms.on_otp_copy', value: -1 },
  33. { text: 'settings.forms.1_minutes', value: 1 },
  34. { text: 'settings.forms.5_minutes', value: 5 },
  35. { text: 'settings.forms.10_minutes', value: 10 },
  36. { text: 'settings.forms.15_minutes', value: 15 },
  37. { text: 'settings.forms.30_minutes', value: 30 },
  38. { text: 'settings.forms.1_hour', value: 60 },
  39. { text: 'settings.forms.1_day', value: 1440 },
  40. ]
  41. const groupsList = ref([
  42. { text: 'groups.no_group', value: 0 },
  43. { text: 'groups.active_group', value: -1 },
  44. ])
  45. const captureModes = [
  46. { text: 'settings.forms.livescan', value: 'livescan' },
  47. { text: 'settings.forms.upload', value: 'upload' },
  48. { text: 'settings.forms.advanced_form', value: 'advancedForm' },
  49. ]
  50. const getOtpTriggers = [
  51. { text: 'settings.forms.otp_generation_on_request', value: true, legend: 'settings.forms.otp_generation_on_request_legend', title: 'settings.forms.otp_generation_on_request_title' },
  52. { text: 'settings.forms.otp_generation_on_home', value: false, legend: 'settings.forms.otp_generation_on_home_legend', title: 'settings.forms.otp_generation_on_home_title' },
  53. ]
  54. const langs = computed(() => {
  55. let locales = [{
  56. text: 'languages.browser_preference',
  57. value: 'browser'
  58. }];
  59. for (const locale of $2fauth.langs) {
  60. locales.push({
  61. text: 'languages.' + locale,
  62. value: locale
  63. })
  64. }
  65. return locales
  66. })
  67. onMounted(() => {
  68. groups.items.forEach((group) => {
  69. if( group.id > 0 ) {
  70. groupsList.value.push({
  71. text: group.name,
  72. value: group.id
  73. })
  74. }
  75. })
  76. })
  77. /**
  78. * Saves a preference on the backend
  79. * @param {string} preference
  80. * @param {any} value
  81. */
  82. function savePreference(preference, value) {
  83. userService.updatePreference(preference, value).then(response => {
  84. useNotifyStore().success({ type: 'is-success', text: trans('settings.forms.setting_saved') })
  85. if(preference === 'lang' && getActiveLanguage() !== value) {
  86. user.applyLanguage()
  87. }
  88. else if(preference === 'theme') {
  89. user.applyTheme()
  90. }
  91. })
  92. }
  93. /**
  94. * Saves a setting on the backend
  95. * @param {string} preference
  96. * @param {any} value
  97. */
  98. function saveSetting(setting, value) {
  99. appSettingService.update(setting, value).then(response => {
  100. useNotifyStore().success({ type: 'is-success', text: trans('settings.forms.setting_saved') })
  101. })
  102. }
  103. onBeforeRouteLeave((to) => {
  104. if (! to.name.startsWith('settings.')) {
  105. notify.clear()
  106. }
  107. })
  108. </script>
  109. <template>
  110. <div>
  111. <SettingTabs activeTab="settings.options" />
  112. <div class="options-tabs">
  113. <FormWrapper>
  114. <form>
  115. <!-- <input type="hidden" name="isReady" id="isReady" :value="isReady" /> -->
  116. <!-- user preferences -->
  117. <div class="block">
  118. <h4 class="title is-4 has-text-grey-light">{{ $t('settings.general') }}</h4>
  119. <!-- Language -->
  120. <FormSelect v-model="user.preferences.lang" @update:model-value="val => savePreference('lang', val)" :options="langs" fieldName="lang" label="settings.forms.language.label" help="settings.forms.language.help" />
  121. <div class="field help">
  122. {{ $t('settings.forms.some_translation_are_missing') }}
  123. <a class="ml-2" href="https://crowdin.com/project/2fauth">
  124. {{ $t('settings.forms.help_translate_2fauth') }}
  125. <FontAwesomeIcon :icon="['fas', 'external-link-alt']" />
  126. </a>
  127. </div>
  128. <!-- display mode -->
  129. <FormToggle v-model="user.preferences.displayMode" @update:model-value="val => savePreference('displayMode', val)" :choices="layouts" fieldName="displayMode" label="settings.forms.display_mode.label" help="settings.forms.display_mode.help"/>
  130. <!-- theme -->
  131. <FormToggle v-model="user.preferences.theme" @update:model-value="val => savePreference('theme', val)" :choices="themes" fieldName="theme" label="settings.forms.theme.label" help="settings.forms.theme.help"/>
  132. <!-- show icon -->
  133. <FormCheckbox v-model="user.preferences.showAccountsIcons" @update:model-value="val => savePreference('showAccountsIcons', val)" fieldName="showAccountsIcons" label="settings.forms.show_accounts_icons.label" help="settings.forms.show_accounts_icons.help" />
  134. <!-- Official icons -->
  135. <FormCheckbox v-model="user.preferences.getOfficialIcons" @update:model-value="val => savePreference('getOfficialIcons', val)" fieldName="getOfficialIcons" label="settings.forms.get_official_icons.label" help="settings.forms.get_official_icons.help" />
  136. <!-- password format -->
  137. <FormCheckbox v-model="user.preferences.formatPassword" @update:model-value="val => savePreference('formatPassword', val)" fieldName="formatPassword" label="settings.forms.password_format.label" help="settings.forms.password_format.help" />
  138. <FormToggle v-model="user.preferences.formatPasswordBy" @update:model-value="val => savePreference('formatPasswordBy', val)" :choices="passwordFormats" fieldName="formatPasswordBy" />
  139. <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('groups.groups') }}</h4>
  140. <!-- default group -->
  141. <FormSelect v-model="user.preferences.defaultGroup" @update:model-value="val => savePreference('defaultGroup', val)" :options="groupsList" fieldName="defaultGroup" label="settings.forms.default_group.label" help="settings.forms.default_group.help" />
  142. <!-- retain active group -->
  143. <FormCheckbox v-model="user.preferences.rememberActiveGroup" @update:model-value="val => savePreference('rememberActiveGroup', val)" fieldName="rememberActiveGroup" label="settings.forms.remember_active_group.label" help="settings.forms.remember_active_group.help" />
  144. <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.security') }}</h4>
  145. <!-- auto lock -->
  146. <FormSelect v-model="user.preferences.kickUserAfter" @update:model-value="val => savePreference('kickUserAfter', val)" :options="kickUserAfters" fieldName="kickUserAfter" label="settings.forms.auto_lock.label" help="settings.forms.auto_lock.help" />
  147. <!-- get OTP on request -->
  148. <FormToggle v-model="user.preferences.getOtpOnRequest" @update:model-value="val => savePreference('getOtpOnRequest', val)" :choices="getOtpTriggers" fieldName="getOtpOnRequest" label="settings.forms.otp_generation.label" help="settings.forms.otp_generation.help"/>
  149. <!-- otp as dot -->
  150. <FormCheckbox v-model="user.preferences.showOtpAsDot" @update:model-value="val => savePreference('showOtpAsDot', val)" fieldName="showOtpAsDot" label="settings.forms.show_otp_as_dot.label" help="settings.forms.show_otp_as_dot.help" />
  151. <!-- close otp on copy -->
  152. <FormCheckbox v-model="user.preferences.closeOtpOnCopy" @update:model-value="val => savePreference('closeOtpOnCopy', val)" fieldName="closeOtpOnCopy" label="settings.forms.close_otp_on_copy.label" help="settings.forms.close_otp_on_copy.help" :disabled="!user.preferences.getOtpOnRequest" />
  153. <!-- copy otp on get -->
  154. <FormCheckbox v-model="user.preferences.copyOtpOnDisplay" @update:model-value="val => savePreference('copyOtpOnDisplay', val)" fieldName="copyOtpOnDisplay" label="settings.forms.copy_otp_on_display.label" help="settings.forms.copy_otp_on_display.help" :disabled="!user.preferences.getOtpOnRequest" />
  155. <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.data_input') }}</h4>
  156. <!-- basic qrcode -->
  157. <FormCheckbox v-model="user.preferences.useBasicQrcodeReader" @update:model-value="val => savePreference('useBasicQrcodeReader', val)" fieldName="useBasicQrcodeReader" label="settings.forms.use_basic_qrcode_reader.label" help="settings.forms.use_basic_qrcode_reader.help" />
  158. <!-- direct capture -->
  159. <FormCheckbox v-model="user.preferences.useDirectCapture" @update:model-value="val => savePreference('useDirectCapture', val)" fieldName="useDirectCapture" label="settings.forms.useDirectCapture.label" help="settings.forms.useDirectCapture.help" />
  160. <!-- default capture mode -->
  161. <FormSelect v-model="user.preferences.defaultCaptureMode" @update:model-value="val => savePreference('defaultCaptureMode', val)" :options="captureModes" fieldName="defaultCaptureMode" label="settings.forms.defaultCaptureMode.label" help="settings.forms.defaultCaptureMode.help" />
  162. </div>
  163. <!-- Admin settings -->
  164. <div v-if="user.isAdmin">
  165. <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.administration') }}</h4>
  166. <div class="is-size-7-mobile block has-text-grey">
  167. <p class="mb-2">{{ $t('settings.administration_legend') }}</p>
  168. <p>{{ $t('settings.only_an_admin_can_edit_them') }}</p>
  169. </div>
  170. <!-- Check for update -->
  171. <FormCheckbox :model-value="appSettings.checkForUpdate" @update:model-value="val => saveSetting('checkForUpdate', val)" fieldName="checkForUpdate" label="commons.check_for_update" help="commons.check_for_update_help" />
  172. <VersionChecker />
  173. <!-- protect db -->
  174. <FormCheckbox :model-value="appSettings.useEncryption" @update:model-value="val => saveSetting('useEncryption', val)" fieldName="useEncryption" label="settings.forms.use_encryption.label" help="settings.forms.use_encryption.help" />
  175. <!-- disable registration -->
  176. <FormCheckbox :model-value="appSettings.disableRegistration" @update:model-value="val => saveSetting('disableRegistration', val)" fieldName="disableRegistration" label="settings.forms.disable_registration.label" help="settings.forms.disable_registration.help" />
  177. </div>
  178. </form>
  179. </FormWrapper>
  180. </div>
  181. <VueFooter :showButtons="true">
  182. <ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
  183. </VueFooter>
  184. </div>
  185. </template>