All files / app/assets/javascripts/profile/preferences/components profile_preferences.vue

11.76% Statements 4/34
3.7% Branches 1/27
7.14% Functions 1/14
11.76% Lines 4/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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