Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 21:42:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 21:42:06 +0300
commit6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch)
tree78be5963ec075d80116a932011d695dd33910b4e /app/assets/javascripts/deploy_freeze
parent1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff)
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'app/assets/javascripts/deploy_freeze')
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue149
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_settings.vue18
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue83
-rw-r--r--app/assets/javascripts/deploy_freeze/index.js22
-rw-r--r--app/assets/javascripts/deploy_freeze/store/actions.js63
-rw-r--r--app/assets/javascripts/deploy_freeze/store/index.js14
-rw-r--r--app/assets/javascripts/deploy_freeze/store/mutation_types.js12
-rw-r--r--app/assets/javascripts/deploy_freeze/store/mutations.js54
-rw-r--r--app/assets/javascripts/deploy_freeze/store/state.js17
9 files changed, 432 insertions, 0 deletions
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
new file mode 100644
index 00000000000..afc1c2cda8e
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
@@ -0,0 +1,149 @@
+<script>
+import { GlFormGroup, GlFormInput, GlModal, GlSprintf, GlLink } from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import { isValidCron } from 'cron-validator';
+import { mapComputed } from '~/vuex_shared/bindings';
+import { __ } from '~/locale';
+import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlFormInput,
+ GlModal,
+ GlSprintf,
+ GlLink,
+ TimezoneDropdown,
+ },
+ modalOptions: {
+ ref: 'modal',
+ modalId: 'deploy-freeze-modal',
+ title: __('Add deploy freeze'),
+ actionCancel: {
+ text: __('Cancel'),
+ },
+ static: true,
+ lazy: true,
+ },
+ translations: {
+ cronPlaceholder: __('* * * * *'),
+ cronSyntaxInstructions: __(
+ 'Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}',
+ ),
+ },
+ computed: {
+ ...mapState([
+ 'projectId',
+ 'selectedTimezone',
+ 'timezoneData',
+ 'freezeStartCron',
+ 'freezeEndCron',
+ ]),
+ ...mapComputed([
+ { key: 'freezeStartCron', updateFn: 'setFreezeStartCron' },
+ { key: 'freezeEndCron', updateFn: 'setFreezeEndCron' },
+ ]),
+ addDeployFreezeButton() {
+ return {
+ text: __('Add deploy freeze'),
+ attributes: [
+ { variant: 'success' },
+ {
+ disabled:
+ !isValidCron(this.freezeStartCron) ||
+ !isValidCron(this.freezeEndCron) ||
+ !this.selectedTimezone,
+ },
+ ],
+ };
+ },
+ invalidFreezeStartCron() {
+ return this.invalidCronMessage(this.freezeStartCronState);
+ },
+ freezeStartCronState() {
+ return Boolean(!this.freezeStartCron || isValidCron(this.freezeStartCron));
+ },
+ invalidFreezeEndCron() {
+ return this.invalidCronMessage(this.freezeEndCronState);
+ },
+ freezeEndCronState() {
+ return Boolean(!this.freezeEndCron || isValidCron(this.freezeEndCron));
+ },
+ timezone: {
+ get() {
+ return this.selectedTimezone;
+ },
+ set(selectedTimezone) {
+ this.setSelectedTimezone(selectedTimezone);
+ },
+ },
+ },
+ methods: {
+ ...mapActions(['addFreezePeriod', 'setSelectedTimezone', 'resetModal']),
+ resetModalHandler() {
+ this.resetModal();
+ },
+ invalidCronMessage(validCronState) {
+ if (!validCronState) {
+ return __('This Cron pattern is invalid');
+ }
+ return '';
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ v-bind="$options.modalOptions"
+ :action-primary="addDeployFreezeButton"
+ @primary="addFreezePeriod"
+ @canceled="resetModalHandler"
+ >
+ <p>
+ <gl-sprintf :message="$options.translations.cronSyntaxInstructions">
+ <template #cronSyntax="{ content }">
+ <gl-link href="https://crontab.guru/" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <gl-form-group
+ :label="__('Freeze start')"
+ label-for="deploy-freeze-start"
+ :invalid-feedback="invalidFreezeStartCron"
+ :state="freezeStartCronState"
+ >
+ <gl-form-input
+ id="deploy-freeze-start"
+ v-model="freezeStartCron"
+ class="gl-font-monospace!"
+ data-qa-selector="deploy_freeze_start_field"
+ :placeholder="this.$options.translations.cronPlaceholder"
+ :state="freezeStartCronState"
+ trim
+ />
+ </gl-form-group>
+
+ <gl-form-group
+ :label="__('Freeze end')"
+ label-for="deploy-freeze-end"
+ :invalid-feedback="invalidFreezeEndCron"
+ :state="freezeEndCronState"
+ >
+ <gl-form-input
+ id="deploy-freeze-end"
+ v-model="freezeEndCron"
+ class="gl-font-monospace!"
+ data-qa-selector="deploy_freeze_end_field"
+ :placeholder="this.$options.translations.cronPlaceholder"
+ :state="freezeEndCronState"
+ trim
+ />
+ </gl-form-group>
+
+ <gl-form-group :label="__('Cron time zone')" label-for="cron-time-zone-dropdown">
+ <timezone-dropdown v-model="timezone" :timezone-data="timezoneData" />
+ </gl-form-group>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_settings.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_settings.vue
new file mode 100644
index 00000000000..fc2ed10f3ca
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_settings.vue
@@ -0,0 +1,18 @@
+<script>
+import DeployFreezeTable from './deploy_freeze_table.vue';
+import DeployFreezeModal from './deploy_freeze_modal.vue';
+
+export default {
+ components: {
+ DeployFreezeTable,
+ DeployFreezeModal,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <deploy-freeze-table />
+ <deploy-freeze-modal />
+ </div>
+</template>
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
new file mode 100644
index 00000000000..159f5ddd755
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
@@ -0,0 +1,83 @@
+<script>
+import { GlTable, GlButton, GlModalDirective, GlSprintf } from '@gitlab/ui';
+import { mapState, mapActions } from 'vuex';
+import { s__, __ } from '~/locale';
+
+export default {
+ fields: [
+ {
+ key: 'freezeStart',
+ label: s__('DeployFreeze|Freeze start'),
+ },
+ {
+ key: 'freezeEnd',
+ label: s__('DeployFreeze|Freeze end'),
+ },
+ {
+ key: 'cronTimezone',
+ label: s__('DeployFreeze|Time zone'),
+ },
+ ],
+ translations: {
+ addDeployFreeze: __('Add deploy freeze'),
+ },
+ components: {
+ GlTable,
+ GlButton,
+ GlSprintf,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ computed: {
+ ...mapState(['freezePeriods']),
+ tableIsNotEmpty() {
+ return this.freezePeriods?.length > 0;
+ },
+ },
+ mounted() {
+ this.fetchFreezePeriods();
+ },
+ methods: {
+ ...mapActions(['fetchFreezePeriods']),
+ },
+};
+</script>
+
+<template>
+ <div class="deploy-freeze-table">
+ <gl-table
+ data-testid="deploy-freeze-table"
+ :items="freezePeriods"
+ :fields="$options.fields"
+ show-empty
+ stacked="lg"
+ >
+ <template #empty>
+ <p data-testid="empty-freeze-periods" class="gl-text-center text-plain">
+ <gl-sprintf
+ :message="
+ s__(
+ 'DeployFreeze|No deploy freezes exist for this project. To add one, click %{strongStart}Add deploy freeze%{strongEnd}',
+ )
+ "
+ >
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </p>
+ </template>
+ </gl-table>
+ <div class="gl-display-flex gl-justify-content-center">
+ <gl-button
+ v-gl-modal.deploy-freeze-modal
+ data-testid="add-deploy-freeze"
+ category="primary"
+ variant="success"
+ >
+ {{ $options.translations.addDeployFreeze }}
+ </gl-button>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/deploy_freeze/index.js b/app/assets/javascripts/deploy_freeze/index.js
new file mode 100644
index 00000000000..fd3f52b6da1
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import DeployFreezeSettings from './components/deploy_freeze_settings.vue';
+import createStore from './store';
+
+export default () => {
+ const el = document.getElementById('js-deploy-freeze-table');
+
+ const { projectId, timezoneData } = el.dataset;
+
+ const store = createStore({
+ projectId,
+ timezoneData: JSON.parse(timezoneData),
+ });
+
+ return new Vue({
+ el,
+ store,
+ render(createElement) {
+ return createElement(DeployFreezeSettings);
+ },
+ });
+};
diff --git a/app/assets/javascripts/deploy_freeze/store/actions.js b/app/assets/javascripts/deploy_freeze/store/actions.js
new file mode 100644
index 00000000000..2fbbba5a128
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/store/actions.js
@@ -0,0 +1,63 @@
+import * as types from './mutation_types';
+import Api from '~/api';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import { __ } from '~/locale';
+
+export const requestAddFreezePeriod = ({ commit }) => {
+ commit(types.REQUEST_ADD_FREEZE_PERIOD);
+};
+
+export const receiveAddFreezePeriodSuccess = ({ commit }) => {
+ commit(types.RECEIVE_ADD_FREEZE_PERIOD_SUCCESS);
+};
+
+export const receiveAddFreezePeriodError = ({ commit }, error) => {
+ commit(types.RECEIVE_ADD_FREEZE_PERIOD_ERROR, error);
+};
+
+export const addFreezePeriod = ({ state, dispatch, commit }) => {
+ dispatch('requestAddFreezePeriod');
+
+ return Api.createFreezePeriod(state.projectId, {
+ freeze_start: state.freezeStartCron,
+ freeze_end: state.freezeEndCron,
+ cron_timezone: state.selectedTimezoneIdentifier,
+ })
+ .then(() => {
+ dispatch('receiveAddFreezePeriodSuccess');
+ commit(types.RESET_MODAL);
+ dispatch('fetchFreezePeriods');
+ })
+ .catch(error => {
+ createFlash(__('Error: Unable to create deploy freeze'));
+ dispatch('receiveAddFreezePeriodError', error);
+ });
+};
+
+export const fetchFreezePeriods = ({ commit, state }) => {
+ commit(types.REQUEST_FREEZE_PERIODS);
+
+ return Api.freezePeriods(state.projectId)
+ .then(({ data }) => {
+ commit(types.RECEIVE_FREEZE_PERIODS_SUCCESS, data);
+ })
+ .catch(() => {
+ createFlash(__('There was an error fetching the deploy freezes.'));
+ });
+};
+
+export const setSelectedTimezone = ({ commit }, timezone) => {
+ commit(types.SET_SELECTED_TIMEZONE, timezone);
+};
+
+export const setFreezeStartCron = ({ commit }, { freezeStartCron }) => {
+ commit(types.SET_FREEZE_START_CRON, freezeStartCron);
+};
+
+export const setFreezeEndCron = ({ commit }, { freezeEndCron }) => {
+ commit(types.SET_FREEZE_END_CRON, freezeEndCron);
+};
+
+export const resetModal = ({ commit }) => {
+ commit(types.RESET_MODAL);
+};
diff --git a/app/assets/javascripts/deploy_freeze/store/index.js b/app/assets/javascripts/deploy_freeze/store/index.js
new file mode 100644
index 00000000000..ca7ea8c783c
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/store/index.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import mutations from './mutations';
+import createState from './state';
+
+Vue.use(Vuex);
+
+export default initialState =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: createState(initialState),
+ });
diff --git a/app/assets/javascripts/deploy_freeze/store/mutation_types.js b/app/assets/javascripts/deploy_freeze/store/mutation_types.js
new file mode 100644
index 00000000000..47a4874a5cf
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/store/mutation_types.js
@@ -0,0 +1,12 @@
+export const REQUEST_FREEZE_PERIODS = 'REQUEST_FREEZE_PERIODS';
+export const RECEIVE_FREEZE_PERIODS_SUCCESS = 'RECEIVE_FREEZE_PERIODS_SUCCESS';
+
+export const REQUEST_ADD_FREEZE_PERIOD = 'REQUEST_ADD_FREEZE_PERIOD';
+export const RECEIVE_ADD_FREEZE_PERIOD_SUCCESS = 'RECEIVE_ADD_FREEZE_PERIOD_SUCCESS';
+export const RECEIVE_ADD_FREEZE_PERIOD_ERROR = 'RECEIVE_ADD_FREEZE_PERIOD_ERROR';
+
+export const SET_SELECTED_TIMEZONE = 'SET_SELECTED_TIMEZONE';
+export const SET_FREEZE_START_CRON = 'SET_FREEZE_START_CRON';
+export const SET_FREEZE_END_CRON = 'SET_FREEZE_END_CRON';
+
+export const RESET_MODAL = 'RESET_MODAL';
diff --git a/app/assets/javascripts/deploy_freeze/store/mutations.js b/app/assets/javascripts/deploy_freeze/store/mutations.js
new file mode 100644
index 00000000000..89ce1dc5428
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/store/mutations.js
@@ -0,0 +1,54 @@
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import * as types from './mutation_types';
+
+const formatTimezoneName = (freezePeriod, timezoneList) =>
+ convertObjectPropsToCamelCase({
+ ...freezePeriod,
+ cron_timezone: timezoneList.find(tz => tz.identifier === freezePeriod.cron_timezone)?.name,
+ });
+
+export default {
+ [types.REQUEST_FREEZE_PERIODS](state) {
+ state.isLoading = true;
+ },
+
+ [types.RECEIVE_FREEZE_PERIODS_SUCCESS](state, freezePeriods) {
+ state.isLoading = false;
+ state.freezePeriods = freezePeriods.map(freezePeriod =>
+ formatTimezoneName(freezePeriod, state.timezoneData),
+ );
+ },
+
+ [types.REQUEST_ADD_FREEZE_PERIOD](state) {
+ state.isLoading = true;
+ },
+
+ [types.RECEIVE_ADD_FREEZE_PERIOD_SUCCESS](state) {
+ state.isLoading = false;
+ },
+
+ [types.RECEIVE_ADD_FREEZE_PERIOD_ERROR](state, error) {
+ state.isLoading = false;
+ state.error = error;
+ },
+
+ [types.SET_SELECTED_TIMEZONE](state, timezone) {
+ state.selectedTimezone = timezone.formattedTimezone;
+ state.selectedTimezoneIdentifier = timezone.identifier;
+ },
+
+ [types.SET_FREEZE_START_CRON](state, freezeStartCron) {
+ state.freezeStartCron = freezeStartCron;
+ },
+
+ [types.SET_FREEZE_END_CRON](state, freezeEndCron) {
+ state.freezeEndCron = freezeEndCron;
+ },
+
+ [types.RESET_MODAL](state) {
+ state.freezeStartCron = '';
+ state.freezeEndCron = '';
+ state.selectedTimezone = '';
+ state.selectedTimezoneIdentifier = '';
+ },
+};
diff --git a/app/assets/javascripts/deploy_freeze/store/state.js b/app/assets/javascripts/deploy_freeze/store/state.js
new file mode 100644
index 00000000000..4cc38c097b6
--- /dev/null
+++ b/app/assets/javascripts/deploy_freeze/store/state.js
@@ -0,0 +1,17 @@
+export default ({
+ projectId,
+ freezePeriods = [],
+ timezoneData = [],
+ selectedTimezone = '',
+ selectedTimezoneIdentifier = '',
+ freezeStartCron = '',
+ freezeEndCron = '',
+}) => ({
+ projectId,
+ freezePeriods,
+ timezoneData,
+ selectedTimezone,
+ selectedTimezoneIdentifier,
+ freezeStartCron,
+ freezeEndCron,
+});