1<script> 2import { GlButton } from '@gitlab/ui'; 3import createFlash, { FLASH_TYPES } from '~/flash'; 4import { INTEGRATION_VIEW_CONFIGS, i18n } from '../constants'; 5import IntegrationView from './integration_view.vue'; 6 7function updateClasses(bodyClasses = '', applicationTheme, layout) { 8 // Remove body class for any previous theme, re-add current one 9 document.body.classList.remove(...bodyClasses.split(' ')); 10 document.body.classList.add(applicationTheme); 11 12 // Toggle container-fluid class 13 if (layout === 'fluid') { 14 document 15 .querySelector('.content-wrapper .container-fluid') 16 .classList.remove('container-limited'); 17 } else { 18 document.querySelector('.content-wrapper .container-fluid').classList.add('container-limited'); 19 } 20} 21 22export default { 23 name: 'ProfilePreferences', 24 components: { 25 IntegrationView, 26 GlButton, 27 }, 28 inject: { 29 integrationViews: { 30 default: [], 31 }, 32 themes: { 33 default: [], 34 }, 35 userFields: { 36 default: {}, 37 }, 38 formEl: 'formEl', 39 profilePreferencesPath: 'profilePreferencesPath', 40 bodyClasses: 'bodyClasses', 41 }, 42 integrationViewConfigs: INTEGRATION_VIEW_CONFIGS, 43 i18n, 44 data() { 45 return { 46 isSubmitEnabled: true, 47 darkModeOnCreate: null, 48 darkModeOnSubmit: null, 49 }; 50 }, 51 computed: { 52 applicationThemes() { 53 return this.themes.reduce((themes, theme) => { 54 const { id, ...rest } = theme; 55 return { ...themes, [id]: rest }; 56 }, {}); 57 }, 58 }, 59 created() { 60 this.formEl.addEventListener('ajax:beforeSend', this.handleLoading); 61 this.formEl.addEventListener('ajax:success', this.handleSuccess); 62 this.formEl.addEventListener('ajax:error', this.handleError); 63 this.darkModeOnCreate = this.darkModeSelected(); 64 }, 65 beforeDestroy() { 66 this.formEl.removeEventListener('ajax:beforeSend', this.handleLoading); 67 this.formEl.removeEventListener('ajax:success', this.handleSuccess); 68 this.formEl.removeEventListener('ajax:error', this.handleError); 69 }, 70 methods: { 71 darkModeSelected() { 72 const theme = this.getSelectedTheme(); 73 return theme ? theme.css_class === 'gl-dark' : null; 74 }, 75 getSelectedTheme() { 76 const themeId = new FormData(this.formEl).get('user[theme_id]'); 77 return this.applicationThemes[themeId] ?? null; 78 }, 79 handleLoading() { 80 this.isSubmitEnabled = false; 81 this.darkModeOnSubmit = this.darkModeSelected(); 82 }, 83 handleSuccess(customEvent) { 84 // Reload the page if the theme has changed from light to dark mode or vice versa 85 // to correctly load all required styles. 86 const modeChanged = this.darkModeOnCreate ? !this.darkModeOnSubmit : this.darkModeOnSubmit; 87 if (modeChanged) { 88 window.location.reload(); 89 return; 90 } 91 updateClasses(this.bodyClasses, this.getSelectedTheme().css_class, this.selectedLayout); 92 const { message = this.$options.i18n.defaultSuccess, type = FLASH_TYPES.NOTICE } = 93 customEvent?.detail?.[0] || {}; 94 createFlash({ message, type }); 95 this.isSubmitEnabled = true; 96 }, 97 handleError(customEvent) { 98 const { message = this.$options.i18n.defaultError, type = FLASH_TYPES.ALERT } = 99 customEvent?.detail?.[0] || {}; 100 createFlash({ message, type }); 101 this.isSubmitEnabled = true; 102 }, 103 }, 104}; 105</script> 106 107<template> 108 <div class="row gl-mt-3 js-preferences-form"> 109 <div v-if="integrationViews.length" class="col-sm-12"> 110 <hr data-testid="profile-preferences-integrations-rule" /> 111 </div> 112 <div v-if="integrationViews.length" class="col-lg-4 profile-settings-sidebar"> 113 <h4 class="gl-mt-0" data-testid="profile-preferences-integrations-heading"> 114 {{ $options.i18n.integrations }} 115 </h4> 116 <p> 117 {{ $options.i18n.integrationsDescription }} 118 </p> 119 </div> 120 <div v-if="integrationViews.length" class="col-lg-8"> 121 <integration-view 122 v-for="view in integrationViews" 123 :key="view.name" 124 :help-link="view.help_link" 125 :message="view.message" 126 :message-url="view.message_url" 127 :config="$options.integrationViewConfigs[view.name]" 128 /> 129 </div> 130 <div class="col-sm-12"> 131 <hr /> 132 <gl-button 133 category="primary" 134 variant="confirm" 135 name="commit" 136 type="submit" 137 :disabled="!isSubmitEnabled" 138 :value="$options.i18n.saveChanges" 139 > 140 {{ $options.i18n.saveChanges }} 141 </gl-button> 142 </div> 143 </div> 144</template> 145