Skip to content

Commit 10c5624

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 68dc19a commit 10c5624

File tree

40 files changed

+1509
-387
lines changed

40 files changed

+1509
-387
lines changed

.gitlab-ci.yml

+3-8
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,15 @@ workflow:
104104
# If `$GITLAB_INTERNAL` isn't set, don't create a pipeline.
105105
- if: '$GITLAB_INTERNAL == null'
106106
when: never
107-
# For last 3 stable branches, create a pipeline with failure notifications.
108-
- if: '$CI_COMMIT_BRANCH =~ /^15-[6|7|8]-stable(-ee)?$/'
107+
# For stable, auto-deploy, and security branches, create a pipeline.
108+
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
109109
variables:
110110
<<: *ruby2-variables
111111
NOTIFY_PIPELINE_FAILURE_CHANNEL: "releases"
112+
PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
112113
CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
113114
BROKEN_BRANCH_INCIDENTS_PROJECT: "gitlab-org/release/tasks"
114115
BROKEN_BRANCH_INCIDENTS_PROJECT_TOKEN: "${BROKEN_STABLE_INCIDENTS_PROJECT_TOKEN}"
115-
PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
116-
# For stable, auto-deploy, and security branches, create a pipeline.
117-
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
118-
variables:
119-
<<: *ruby2-variables
120-
PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline'
121116
- if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
122117
variables:
123118
<<: *ruby2-variables

CHANGELOG.md

+723
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
<script>
2-
import {
3-
GlDropdown,
4-
GlDropdownDivider,
5-
GlDropdownItem,
6-
GlIcon,
7-
GlLoadingIcon,
8-
GlSearchBoxByType,
9-
} from '@gitlab/ui';
2+
import { GlTokenSelector } from '@gitlab/ui';
103
import { debounce } from 'lodash';
114
import { createAlert } from '~/flash';
125
import axios from '~/lib/utils/axios_utils';
6+
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
137
import { __, sprintf } from '~/locale';
148
159
export default {
1610
components: {
17-
GlDropdown,
18-
GlDropdownDivider,
19-
GlDropdownItem,
20-
GlSearchBoxByType,
21-
GlIcon,
22-
GlLoadingIcon,
11+
GlTokenSelector,
2312
},
2413
inject: ['environmentsEndpoint'],
14+
props: {
15+
selected: {
16+
type: Array,
17+
required: true,
18+
},
19+
},
2520
data() {
2621
return {
2722
environmentSearch: '',
@@ -32,24 +27,54 @@ export default {
3227
translations: {
3328
addEnvironmentsLabel: __('Add environment'),
3429
noResultsLabel: __('No matching results'),
30+
loadingResultsLabel: __('Loading...'),
31+
allEnvironments: __('All environments'),
3532
},
3633
computed: {
3734
createEnvironmentLabel() {
3835
return sprintf(__('Create %{environment}'), { environment: this.environmentSearch });
3936
},
37+
selectedEnvironmentNames() {
38+
return this.selected.map(({ name }) => name);
39+
},
40+
dropdownItems() {
41+
return this.results.filter(({ name }) => !this.isSelected(name));
42+
},
43+
hasNoSearchResults() {
44+
return !this.dropdownItems.length;
45+
},
46+
searchItemAlreadySelected() {
47+
return this.isSelected(this.environmentSearch);
48+
},
49+
},
50+
created() {
51+
this.debouncedHandleSearch = debounce(this.handleSearch, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
52+
},
53+
destroyed() {
54+
this.debouncedHandleSearch.cancel();
4055
},
4156
methods: {
42-
addEnvironment(newEnvironment) {
43-
this.$emit('add', newEnvironment);
57+
isSelected(name) {
58+
return this.selectedEnvironmentNames.includes(name);
59+
},
60+
addEnvironment({ name }) {
61+
this.$emit('add', name);
62+
this.environmentSearch = '';
63+
},
64+
removeEnvironment({ name }) {
65+
this.$emit('remove', name);
4466
this.environmentSearch = '';
45-
this.results = [];
4667
},
47-
fetchEnvironments: debounce(function debouncedFetchEnvironments() {
68+
handleSearch(query = '') {
69+
this.environmentSearch = query;
70+
this.fetchEnvironments();
71+
},
72+
async fetchEnvironments() {
4873
this.isLoading = true;
49-
axios
74+
await axios
5075
.get(this.environmentsEndpoint, { params: { query: this.environmentSearch } })
51-
.then(({ data }) => {
52-
this.results = data || [];
76+
.then(({ data = [] }) => {
77+
this.results = data.map((text, index) => ({ id: index, name: text }));
5378
})
5479
.catch(() => {
5580
createAlert({
@@ -59,44 +84,28 @@ export default {
5984
.finally(() => {
6085
this.isLoading = false;
6186
});
62-
}, 250),
63-
setFocus() {
64-
this.$refs.searchBox.focusInput();
6587
},
6688
},
6789
};
6890
</script>
6991
<template>
70-
<gl-dropdown class="js-new-environments-dropdown" @shown="setFocus">
71-
<template #button-content>
72-
<span class="d-md-none mr-1">
73-
{{ $options.translations.addEnvironmentsLabel }}
74-
</span>
75-
<gl-icon class="d-none d-md-inline-flex gl-mr-1" name="plus" />
76-
</template>
77-
<gl-search-box-by-type
78-
ref="searchBox"
79-
v-model.trim="environmentSearch"
80-
@focus="fetchEnvironments"
81-
@keyup="fetchEnvironments"
82-
/>
83-
<gl-loading-icon v-if="isLoading" size="sm" />
84-
<gl-dropdown-item
85-
v-for="environment in results"
86-
v-else-if="results.length"
87-
:key="environment"
88-
@click="addEnvironment(environment)"
89-
>
90-
{{ environment }}
91-
</gl-dropdown-item>
92-
<template v-else-if="environmentSearch.length">
93-
<span ref="noResults" class="text-secondary gl-p-3">
94-
{{ $options.translations.noMatchingResults }}
95-
</span>
96-
<gl-dropdown-divider />
97-
<gl-dropdown-item @click="addEnvironment(environmentSearch)">
98-
{{ createEnvironmentLabel }}
99-
</gl-dropdown-item>
92+
<gl-token-selector
93+
data-testid="new-environment-selector"
94+
:selected-tokens="selected"
95+
:label-text="$options.translations.addEnvironmentsLabel"
96+
:dropdown-items="dropdownItems"
97+
:loading="isLoading"
98+
:hide-dropdown-with-no-items="searchItemAlreadySelected && hasNoSearchResults"
99+
:allow-user-defined-tokens="!searchItemAlreadySelected"
100+
@focus.once="fetchEnvironments"
101+
@text-input="debouncedHandleSearch"
102+
@token-add="addEnvironment"
103+
@token-remove="removeEnvironment"
104+
>
105+
<template #user-defined-token-content>
106+
{{ createEnvironmentLabel }}
100107
</template>
101-
</gl-dropdown>
108+
<template #no-results-content>{{ $options.translations.noResultsLabel }}</template>
109+
<template #loading-content>{{ $options.translations.loadingResultsLabel }}</template>
110+
</gl-token-selector>
102111
</template>

app/assets/javascripts/feature_flags/components/strategy.vue

+57-40
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<script>
2-
import { GlAlert, GlButton, GlFormSelect, GlFormGroup, GlIcon, GlLink, GlToken } from '@gitlab/ui';
3-
import { isNumber } from 'lodash';
2+
import { GlAlert, GlButton, GlFormSelect, GlFormGroup, GlIcon, GlLink } from '@gitlab/ui';
3+
import { isNumber, uniqueId } from 'lodash';
44
import Vue from 'vue';
55
import { s__, __ } from '~/locale';
66
import {
77
EMPTY_PARAMETERS,
88
STRATEGY_SELECTIONS,
99
ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
10+
ALL_ENVIRONMENTS_NAME,
1011
} from '../constants';
1112
1213
import NewEnvironmentsDropdown from './new_environments_dropdown.vue';
@@ -20,7 +21,6 @@ export default {
2021
GlFormSelect,
2122
GlIcon,
2223
GlLink,
23-
GlToken,
2424
NewEnvironmentsDropdown,
2525
StrategyParameters,
2626
},
@@ -79,25 +79,45 @@ export default {
7979
appliesToAllEnvironments() {
8080
return (
8181
this.filteredEnvironments.length === 1 &&
82-
this.filteredEnvironments[0].environmentScope === '*'
82+
this.filteredEnvironments[0].environmentScope === ALL_ENVIRONMENTS_NAME
8383
);
8484
},
8585
filteredEnvironments() {
8686
return this.environments.filter((e) => !e.shouldBeDestroyed);
8787
},
88+
selectableEnvironments() {
89+
return this.environments.filter(
90+
(e) => !e.shouldBeDestroyed && e.environmentScope !== ALL_ENVIRONMENTS_NAME,
91+
);
92+
},
93+
filteredEnvironmentsOptions() {
94+
return this.selectableEnvironments.map(({ id, environmentScope: name }) => ({
95+
id: id || uniqueId('env_'),
96+
name,
97+
}));
98+
},
8899
isPercentUserRollout() {
89100
return this.formStrategy.name === ROLLOUT_STRATEGY_PERCENT_ROLLOUT;
90101
},
91102
},
92103
methods: {
93104
addEnvironment(environment) {
94105
const allEnvironmentsScope = this.environments.find(
95-
(scope) => scope.environmentScope === '*',
106+
(scope) => scope.environmentScope === ALL_ENVIRONMENTS_NAME,
96107
);
97108
if (allEnvironmentsScope) {
98109
allEnvironmentsScope.shouldBeDestroyed = true;
99110
}
100-
this.environments.push({ environmentScope: environment });
111+
112+
const foundEnv = this.environments.find(
113+
({ environmentScope }) => environmentScope === environment,
114+
);
115+
if (isNumber(foundEnv?.id)) {
116+
Vue.set(foundEnv, 'shouldBeDestroyed', false);
117+
} else {
118+
this.environments.push({ environmentScope: environment });
119+
}
120+
101121
this.onStrategyChange({ ...this.formStrategy, scopes: this.environments });
102122
},
103123
onStrategyTypeChange(name) {
@@ -111,11 +131,15 @@ export default {
111131
this.$emit('change', s);
112132
this.formStrategy = s;
113133
},
114-
removeScope(environment) {
115-
if (isNumber(environment.id)) {
134+
removeScope(target) {
135+
const environment = this.environments.find(
136+
({ environmentScope }) => environmentScope === target,
137+
);
138+
139+
if (isNumber(environment?.id)) {
116140
Vue.set(environment, 'shouldBeDestroyed', true);
117141
} else {
118-
this.environments = this.environments.filter((e) => e !== environment);
142+
this.environments = this.environments.filter((e) => e.environmentScope !== target);
119143
}
120144
if (this.filteredEnvironments.length === 0) {
121145
this.environments.push({ environmentScope: '*' });
@@ -133,7 +157,7 @@ export default {
133157
134158
<div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-100 gl-py-6">
135159
<div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row flex-md-wrap">
136-
<div class="mr-5">
160+
<div class="gl-mr-7">
137161
<gl-form-group :label="$options.i18n.strategyTypeLabel" :label-for="strategyTypeId">
138162
<template #description>
139163
{{ $options.i18n.strategyTypeDescription }}
@@ -171,39 +195,32 @@ export default {
171195
</div>
172196
</div>
173197
174-
<label class="gl-display-block" :for="environmentsDropdownId">{{
175-
$options.i18n.environmentsLabel
176-
}}</label>
177-
<div class="gl-display-flex gl-flex-direction-column">
178-
<div
179-
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-md-align-items-center"
180-
>
181-
<new-environments-dropdown
182-
:id="environmentsDropdownId"
183-
class="gl-mr-3"
184-
@add="addEnvironment"
185-
/>
186-
<span v-if="appliesToAllEnvironments" class="text-secondary gl-mt-3 mt-md-0 ml-md-3">
187-
{{ $options.i18n.allEnvironments }}
188-
</span>
189-
<div v-else class="gl-display-flex gl-align-items-center gl-flex-wrap">
190-
<gl-token
191-
v-for="environment in filteredEnvironments"
192-
:key="environment.id"
193-
class="gl-mt-3 gl-mr-3 gl-mb-3 mt-md-0 mr-md-0 ml-md-2 rounded-pill"
194-
@close="removeScope(environment)"
198+
<gl-form-group :label="$options.i18n.environmentsLabel" :label-for="environmentsDropdownId">
199+
<div class="row">
200+
<div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-w-full">
201+
<div class="gl-w-full gl-md-w-auto col-md-4">
202+
<new-environments-dropdown
203+
:id="environmentsDropdownId"
204+
:selected="filteredEnvironmentsOptions"
205+
@remove="removeScope"
206+
@add="addEnvironment"
207+
/>
208+
</div>
209+
<span
210+
v-if="appliesToAllEnvironments"
211+
class="gl-flex-gl-text-secondary gl-mt-2 gl-pl-5 gl-md-pl-0"
195212
>
196-
{{ environment.environmentScope }}
197-
</gl-token>
213+
{{ $options.i18n.allEnvironments }}
214+
</span>
198215
</div>
199216
</div>
200-
</div>
201-
<span class="gl-display-inline-block gl-py-3">
202-
{{ $options.i18n.environmentsSelectDescription }}
203-
</span>
204-
<gl-link :href="environmentsScopeDocsPath" target="_blank">
205-
<gl-icon name="question" />
206-
</gl-link>
217+
<template #description>
218+
{{ $options.i18n.environmentsSelectDescription }}
219+
<gl-link :href="environmentsScopeDocsPath" target="_blank">
220+
<gl-icon name="question" />
221+
</gl-link>
222+
</template>
223+
</gl-form-group>
207224
</div>
208225
</div>
209226
</template>

0 commit comments

Comments
 (0)