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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-07 12:10:26 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-07 12:10:26 +0300
commitf4c6fbb86fbec3e5917e317b3490232d98531881 (patch)
treea2648b816d6be98456303f4059e342fe850c6c7e /app
parent362b615a84bf303d5b5b1c3168d6592fb4306d9d (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/api.js12
-rw-r--r--app/assets/javascripts/api/markdown_api.js11
-rw-r--r--app/assets/javascripts/cycle_analytics/components/base.vue13
-rw-r--r--app/assets/javascripts/cycle_analytics/store/actions.js9
-rw-r--r--app/assets/javascripts/cycle_analytics/store/mutations.js3
-rw-r--r--app/assets/javascripts/cycle_analytics/store/state.js1
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js15
-rw-r--r--app/assets/javascripts/repository/components/blob_header_edit.vue13
-rw-r--r--app/assets/javascripts/rest_api.js1
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_actions_cell.vue121
-rw-r--r--app/assets/javascripts/runner/components/runner_list.vue6
-rw-r--r--app/assets/javascripts/runner/graphql/get_runners.query.graphql13
-rw-r--r--app/assets/javascripts/runner/graphql/runner_node.fragment.graphql13
-rw-r--r--app/assets/javascripts/runner/graphql/update_runner.mutation.graphql10
-rw-r--r--app/assets/javascripts/runner/runner_list/runner_list_app.vue5
-rw-r--r--app/assets/javascripts/search/store/actions.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue23
-rw-r--r--app/controllers/projects/blob_controller.rb1
-rw-r--r--app/models/protected_branch.rb2
-rw-r--r--app/views/projects/protected_branches/shared/_branches_list.html.haml10
-rw-r--r--app/views/projects/protected_branches/shared/_create_protected_branch.html.haml13
-rw-r--r--app/views/shared/projects/protected_branches/_update_protected_branch.html.haml5
22 files changed, 244 insertions, 57 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index e67c56bc825..5d69340c9a8 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -1,4 +1,4 @@
-import { deprecatedCreateFlash as flash } from '~/flash';
+import createFlash from '~/flash';
import { __ } from '~/locale';
import axios from './lib/utils/axios_utils';
import { joinPaths } from './lib/utils/url_utility';
@@ -454,7 +454,9 @@ const Api = {
})
.then(({ data }) => (callback ? callback(data) : data))
.catch(() => {
- flash(__('Something went wrong while fetching projects'));
+ createFlash({
+ message: __('Something went wrong while fetching projects'),
+ });
if (callback) {
callback();
}
@@ -642,7 +644,11 @@ const Api = {
params: { ...defaults, ...options },
})
.then(({ data }) => callback(data))
- .catch(() => flash(__('Something went wrong while fetching projects')));
+ .catch(() =>
+ createFlash({
+ message: __('Something went wrong while fetching projects'),
+ }),
+ );
},
branches(id, query = '', options = {}) {
diff --git a/app/assets/javascripts/api/markdown_api.js b/app/assets/javascripts/api/markdown_api.js
new file mode 100644
index 00000000000..5c9c1713bd8
--- /dev/null
+++ b/app/assets/javascripts/api/markdown_api.js
@@ -0,0 +1,11 @@
+import axios from '../lib/utils/axios_utils';
+import { buildApiUrl } from './api_utils';
+
+const MARKDOWN_PATH = '/api/:version/markdown';
+
+export function getMarkdown(options) {
+ const url = buildApiUrl(MARKDOWN_PATH);
+ return axios.post(url, {
+ ...options,
+ });
+}
diff --git a/app/assets/javascripts/cycle_analytics/components/base.vue b/app/assets/javascripts/cycle_analytics/components/base.vue
index e3703fc066d..8c1fecac3fc 100644
--- a/app/assets/javascripts/cycle_analytics/components/base.vue
+++ b/app/assets/javascripts/cycle_analytics/components/base.vue
@@ -54,6 +54,7 @@ export default {
'isEmptyStage',
'selectedStage',
'selectedStageEvents',
+ 'selectedStageError',
'stages',
'summary',
'startDate',
@@ -72,6 +73,14 @@ export default {
selectedStageReady() {
return !this.isLoadingStage && this.selectedStage;
},
+ emptyStageTitle() {
+ return this.selectedStageError
+ ? this.selectedStageError
+ : __("We don't have enough data to show this stage.");
+ },
+ emptyStageText() {
+ return !this.selectedStageError ? this.selectedStage.emptyStageText : '';
+ },
},
methods: {
...mapActions([
@@ -206,9 +215,9 @@ export default {
<gl-empty-state
v-if="displayNotEnoughData"
class="js-empty-state"
- :description="selectedStage.emptyStageText"
+ :description="emptyStageText"
:svg-path="noDataSvgPath"
- :title="__('We don\'t have enough data to show this stage.')"
+ :title="emptyStageTitle"
/>
<component
:is="selectedStage.component"
diff --git a/app/assets/javascripts/cycle_analytics/store/actions.js b/app/assets/javascripts/cycle_analytics/store/actions.js
index fe3c6d6b3ba..40e1c01f78b 100644
--- a/app/assets/javascripts/cycle_analytics/store/actions.js
+++ b/app/assets/javascripts/cycle_analytics/store/actions.js
@@ -33,7 +33,14 @@ export const fetchStageData = ({ state: { requestPath, selectedStage, startDate
.get(`${requestPath}/events/${selectedStage.name}.json`, {
params: { 'cycle_analytics[start_date]': startDate },
})
- .then(({ data }) => commit(types.RECEIVE_STAGE_DATA_SUCCESS, data))
+ .then(({ data }) => {
+ // when there's a query timeout, the request succeeds but the error is encoded in the response data
+ if (data?.error) {
+ commit(types.RECEIVE_STAGE_DATA_ERROR, data.error);
+ } else {
+ commit(types.RECEIVE_STAGE_DATA_SUCCESS, data);
+ }
+ })
.catch(() => commit(types.RECEIVE_STAGE_DATA_ERROR));
};
diff --git a/app/assets/javascripts/cycle_analytics/store/mutations.js b/app/assets/javascripts/cycle_analytics/store/mutations.js
index d5038630503..4d999b056b7 100644
--- a/app/assets/javascripts/cycle_analytics/store/mutations.js
+++ b/app/assets/javascripts/cycle_analytics/store/mutations.js
@@ -44,10 +44,11 @@ export default {
state.selectedStageEvents = decorateEvents(events, selectedStage);
state.hasError = false;
},
- [types.RECEIVE_STAGE_DATA_ERROR](state) {
+ [types.RECEIVE_STAGE_DATA_ERROR](state, error) {
state.isLoadingStage = false;
state.isEmptyStage = true;
state.selectedStageEvents = [];
state.hasError = true;
+ state.selectedStageError = error;
},
};
diff --git a/app/assets/javascripts/cycle_analytics/store/state.js b/app/assets/javascripts/cycle_analytics/store/state.js
index 5db4e1878a9..b488340943a 100644
--- a/app/assets/javascripts/cycle_analytics/store/state.js
+++ b/app/assets/javascripts/cycle_analytics/store/state.js
@@ -9,6 +9,7 @@ export default () => ({
stats: [],
selectedStage: {},
selectedStageEvents: [],
+ selectedStageError: '',
medians: {},
hasError: false,
isLoading: false,
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 0a038febb9f..b0bd95264b1 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -884,21 +884,6 @@ export const approximateDuration = (seconds = 0) => {
};
/**
- * A utility function which helps creating a date object
- * for a specific date. Accepts the year, month and day
- * returning a date object for the given params.
- *
- * @param {Int} year the full year as a number i.e. 2020
- * @param {Int} month the month index i.e. January => 0
- * @param {Int} day the day as a number i.e. 23
- *
- * @return {Date} the date object from the params
- */
-export const dateFromParams = (year, month, day) => {
- return new Date(year, month, day);
-};
-
-/**
* A utility function which computes the difference in seconds
* between 2 dates.
*
diff --git a/app/assets/javascripts/repository/components/blob_header_edit.vue b/app/assets/javascripts/repository/components/blob_header_edit.vue
index 49128096d42..3d97ebe89e4 100644
--- a/app/assets/javascripts/repository/components/blob_header_edit.vue
+++ b/app/assets/javascripts/repository/components/blob_header_edit.vue
@@ -1,6 +1,8 @@
<script>
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
+import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
i18n: {
@@ -9,7 +11,9 @@ export default {
},
components: {
GlButton,
+ WebIdeLink,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
editPath: {
type: String,
@@ -24,7 +28,14 @@ export default {
</script>
<template>
- <div>
+ <web-ide-link
+ v-if="glFeatures.consolidatedEditButton"
+ class="gl-mr-3"
+ :edit-url="editPath"
+ :web-ide-url="webIdePath"
+ :is-blob="true"
+ />
+ <div v-else>
<gl-button class="gl-mr-2" category="primary" variant="confirm" :href="editPath">
{{ $options.i18n.edit }}
</gl-button>
diff --git a/app/assets/javascripts/rest_api.js b/app/assets/javascripts/rest_api.js
index ea8f87001f0..3e9e3e6f265 100644
--- a/app/assets/javascripts/rest_api.js
+++ b/app/assets/javascripts/rest_api.js
@@ -1,6 +1,7 @@
export * from './api/groups_api';
export * from './api/projects_api';
export * from './api/user_api';
+export * from './api/markdown_api';
// Note: It's not possible to spy on methods imported from this file in
// Jest tests. See https://stackoverflow.com/a/53307822/1063392.
diff --git a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
new file mode 100644
index 00000000000..1ed07c39fd5
--- /dev/null
+++ b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
@@ -0,0 +1,121 @@
+<script>
+import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { __ } from '~/locale';
+import updateRunnerMutation from '~/runner/graphql/update_runner.mutation.graphql';
+
+const i18n = {
+ I18N_EDIT: __('Edit'),
+ I18N_PAUSE: __('Pause'),
+ I18N_RESUME: __('Resume'),
+};
+
+export default {
+ components: {
+ GlButton,
+ GlButtonGroup,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ updating: false,
+ };
+ },
+ computed: {
+ runnerNumericalId() {
+ return getIdFromGraphQLId(this.runner.id);
+ },
+ runnerUrl() {
+ // TODO implement using webUrl from the API
+ return `${gon.gitlab_url || ''}/admin/runners/${this.runnerNumericalId}`;
+ },
+ isActive() {
+ return this.runner.active;
+ },
+ toggleActiveIcon() {
+ return this.isActive ? 'pause' : 'play';
+ },
+ toggleActiveTitle() {
+ if (this.updating) {
+ // Prevent a "sticky" tooltip: If this button is disabled,
+ // mouseout listeners will not run and the tooltip will
+ // stay stuck on the button.
+ return '';
+ }
+ return this.isActive ? i18n.I18N_PAUSE : i18n.I18N_RESUME;
+ },
+ },
+ methods: {
+ async onToggleActive() {
+ this.updating = true;
+ // TODO In HAML iteration we had a confirmation modal via:
+ // data-confirm="_('Are you sure?')"
+ // this may not have to ported, this is an easily reversible operation
+
+ try {
+ const toggledActive = !this.runner.active;
+
+ const {
+ data: {
+ runnerUpdate: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: updateRunnerMutation,
+ variables: {
+ input: {
+ id: this.runner.id,
+ active: toggledActive,
+ },
+ },
+ });
+
+ if (errors && errors.length) {
+ this.onError(new Error(errors[0]));
+ }
+ } catch (e) {
+ this.onError(e);
+ } finally {
+ this.updating = false;
+ }
+ },
+
+ onError(error) {
+ // TODO Render errors when "delete" action is done
+ // `active` toggle would not fail due to user input.
+ throw error;
+ },
+ },
+ i18n,
+};
+</script>
+
+<template>
+ <gl-button-group>
+ <gl-button
+ v-gl-tooltip.hover.viewport
+ :title="$options.i18n.I18N_EDIT"
+ :aria-label="$options.i18n.I18N_EDIT"
+ icon="pencil"
+ :href="runnerUrl"
+ data-testid="edit-runner"
+ />
+ <gl-button
+ v-gl-tooltip.hover.viewport
+ :title="toggleActiveTitle"
+ :aria-label="toggleActiveTitle"
+ :icon="toggleActiveIcon"
+ :loading="updating"
+ data-testid="toggle-active-runner"
+ @click="onToggleActive"
+ />
+ <!-- TODO add delete action to update runners -->
+ </gl-button-group>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue
index 39d354db46d..41adbbb55f6 100644
--- a/app/assets/javascripts/runner/components/runner_list.vue
+++ b/app/assets/javascripts/runner/components/runner_list.vue
@@ -3,6 +3,7 @@ import { GlTable, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { formatNumber, sprintf, __, s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import RunnerActionsCell from './cells/runner_actions_cell.vue';
import RunnerNameCell from './cells/runner_name_cell.vue';
import RunnerTypeCell from './cells/runner_type_cell.vue';
import RunnerTags from './runner_tags.vue';
@@ -32,6 +33,7 @@ export default {
GlTable,
GlSkeletonLoader,
TimeAgo,
+ RunnerActionsCell,
RunnerNameCell,
RunnerTags,
RunnerTypeCell,
@@ -132,8 +134,8 @@ export default {
<template v-else>{{ __('Never') }}</template>
</template>
- <template #cell(actions)>
- <!-- TODO add actions to update runners -->
+ <template #cell(actions)="{ item }">
+ <runner-actions-cell :runner="item" />
</template>
</gl-table>
</div>
diff --git a/app/assets/javascripts/runner/graphql/get_runners.query.graphql b/app/assets/javascripts/runner/graphql/get_runners.query.graphql
index 3864dd5bf37..84b7e2547f5 100644
--- a/app/assets/javascripts/runner/graphql/get_runners.query.graphql
+++ b/app/assets/javascripts/runner/graphql/get_runners.query.graphql
@@ -1,3 +1,4 @@
+#import "~/runner/graphql/runner_node.fragment.graphql"
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query getRunners(
@@ -19,17 +20,7 @@ query getRunners(
sort: $sort
) {
nodes {
- id
- description
- runnerType
- shortSha
- version
- revision
- ipAddress
- active
- locked
- tagList
- contactedAt
+ ...RunnerNode
}
pageInfo {
...PageInfo
diff --git a/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql b/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql
new file mode 100644
index 00000000000..0835e3c7c09
--- /dev/null
+++ b/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql
@@ -0,0 +1,13 @@
+fragment RunnerNode on CiRunner {
+ id
+ description
+ runnerType
+ shortSha
+ version
+ revision
+ ipAddress
+ active
+ locked
+ tagList
+ contactedAt
+}
diff --git a/app/assets/javascripts/runner/graphql/update_runner.mutation.graphql b/app/assets/javascripts/runner/graphql/update_runner.mutation.graphql
new file mode 100644
index 00000000000..d17147b871b
--- /dev/null
+++ b/app/assets/javascripts/runner/graphql/update_runner.mutation.graphql
@@ -0,0 +1,10 @@
+#import "~/runner/graphql/runner_node.fragment.graphql"
+
+mutation runnerUpdate($input: RunnerUpdateInput!) {
+ runnerUpdate(input: $input) {
+ runner {
+ ...RunnerNode
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/runner/runner_list/runner_list_app.vue b/app/assets/javascripts/runner/runner_list/runner_list_app.vue
index 93d1cf38b9b..d53774709ba 100644
--- a/app/assets/javascripts/runner/runner_list/runner_list_app.vue
+++ b/app/assets/javascripts/runner/runner_list/runner_list_app.vue
@@ -1,5 +1,6 @@
<script>
import * as Sentry from '@sentry/browser';
+import { fetchPolicies } from '~/lib/graphql';
import { updateHistory } from '~/lib/utils/url_utility';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue';
@@ -43,6 +44,10 @@ export default {
apollo: {
runners: {
query: getRunnersQuery,
+ // Runners can be updated by users directly in this list.
+ // A "cache and network" policy prevents outdated filtered
+ // results.
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
variables() {
return this.variables;
},
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index 0af679644f3..0c3f273fec7 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -29,6 +29,7 @@ export const fetchProjects = ({ commit, state }, search) => {
};
if (groupId) {
+ // TODO (https://gitlab.com/gitlab-org/gitlab/-/issues/323331): For errors `createFlash` is called twice; in `callback` and in `Api.groupProjects`
Api.groupProjects(groupId, search, {}, callback);
} else {
// The .catch() is due to the API method not handling a rejection properly
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index a666b11ba62..07de525b1fa 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -22,7 +22,13 @@ import { __ } from '~/locale';
import SmartInterval from '~/smart_interval';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import MergeRequest from '../../../merge_request';
-import { AUTO_MERGE_STRATEGIES, DANGER, CONFIRM, WARNING } from '../../constants';
+import {
+ AUTO_MERGE_STRATEGIES,
+ DANGER,
+ CONFIRM,
+ WARNING,
+ MT_MERGE_STRATEGY,
+} from '../../constants';
import eventHub from '../../event_hub';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import MergeRequestStore from '../../stores/mr_widget_store';
@@ -223,7 +229,7 @@ export default {
return PIPELINE_SUCCESS_STATE;
},
mergeButtonVariant() {
- if (this.status === PIPELINE_FAILED_STATE) {
+ if (this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed) {
return DANGER;
}
@@ -286,6 +292,9 @@ export default {
shaMismatchLink() {
return this.mr.mergeRequestDiffsPath;
},
+ showDangerMessageForMergeTrain() {
+ return this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY && this.isPipelineFailed;
+ },
},
mounted() {
if (this.glFeatures.mergeRequestWidgetGraphql) {
@@ -499,7 +508,7 @@ export default {
v-if="shouldShowMergeImmediatelyDropdown"
v-gl-tooltip.hover.focus="__('Select merge moment')"
:disabled="isMergeButtonDisabled"
- variant="info"
+ :variant="mergeButtonVariant"
data-qa-selector="merge_moment_dropdown"
toggle-class="btn-icon js-merge-moment"
>
@@ -579,6 +588,14 @@ export default {
</gl-sprintf>
</span>
</div>
+
+ <div
+ v-if="showDangerMessageForMergeTrain"
+ class="gl-mt-5 gl-text-gray-500"
+ data-testid="failed-pipeline-merge-train-text"
+ >
+ {{ __('The latest pipeline for this merge request did not complete successfully.') }}
+ </div>
</div>
</div>
<merge-train-helper-text
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 17af44672d9..c6c9237292d 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -39,6 +39,7 @@ class Projects::BlobController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
+ push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
end
def new
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 889eaed138d..3df8fe31826 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -30,8 +30,6 @@ class ProtectedBranch < ApplicationRecord
end
def self.allow_force_push?(project, ref_name)
- return false unless ::Feature.enabled?(:allow_force_push_to_protected_branches, project, default_enabled: :yaml)
-
project.protected_branches.allowing_force_push.matching(ref_name).any?
end
diff --git a/app/views/projects/protected_branches/shared/_branches_list.html.haml b/app/views/projects/protected_branches/shared/_branches_list.html.haml
index 2691513c994..091ee6acc4b 100644
--- a/app/views/projects/protected_branches/shared/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/shared/_branches_list.html.haml
@@ -22,12 +22,10 @@
= s_("ProtectedBranch|Allowed to merge")
%th
= s_("ProtectedBranch|Allowed to push")
-
- - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml)
- %th
- = s_("ProtectedBranch|Allow force push")
- %span.has-tooltip{ data: { container: 'body' }, title: s_('ProtectedBranch|Allow force push for all users with push access.'), 'aria-hidden': 'true' }
- = sprite_icon('question', size: 16, css_class: 'gl-text-gray-500')
+ %th
+ = s_("ProtectedBranch|Allow force push")
+ %span.has-tooltip{ data: { container: 'body' }, title: s_('ProtectedBranch|Allow force push for all users with push access.'), 'aria-hidden': 'true' }
+ = sprite_icon('question', size: 16, css_class: 'gl-text-gray-500')
= render_if_exists 'projects/protected_branches/ee/code_owner_approval_table_head'
diff --git a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
index 9fdcea96c00..d302efd5492 100644
--- a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
+++ b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
@@ -21,13 +21,12 @@
= f.label :push_access_levels_attributes, s_("ProtectedBranch|Allowed to push:"), class: 'col-md-2 text-left text-md-right'
.col-md-10
= yield :push_access_levels
- - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml)
- .form-group.row
- = f.label :allow_force_push, s_("ProtectedBranch|Allow force push:"), class: 'col-md-2 gl-text-left text-md-right'
- .col-md-10
- = render "shared/buttons/project_feature_toggle", class_list: "js-force-push-toggle project-feature-toggle"
- .form-text.gl-text-gray-600.gl-mt-0
- = s_("ProtectedBranch|Allow force push for all users with push access.")
+ .form-group.row
+ = f.label :allow_force_push, s_("ProtectedBranch|Allow force push:"), class: 'col-md-2 gl-text-left text-md-right'
+ .col-md-10
+ = render "shared/buttons/project_feature_toggle", class_list: "js-force-push-toggle project-feature-toggle"
+ .form-text.gl-text-gray-600.gl-mt-0
+ = s_("ProtectedBranch|Allow force push for all users with push access.")
= render_if_exists 'projects/protected_branches/ee/code_owner_approval_form', f: f
.card-footer
= f.submit s_('ProtectedBranch|Protect'), class: 'gl-button btn btn-confirm', disabled: true, data: { qa_selector: 'protect_button' }
diff --git a/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml b/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml
index 6a362866f41..c000917bb45 100644
--- a/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml
+++ b/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml
@@ -33,6 +33,5 @@
%p.small
= _('Members of %{group} can also push to this branch: %{branch}') % { group: (group_push_access_levels.size > 1 ? 'these groups' : 'this group'), branch: group_push_access_levels.map(&:humanize).to_sentence }
-- if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml)
- %td
- = render "shared/buttons/project_feature_toggle", is_checked: protected_branch.allow_force_push, label: s_("ProtectedBranch|Toggle allow force push"), class_list: "js-force-push-toggle project-feature-toggle", data: { qa_selector: 'force_push_toggle_button', qa_branch_name: protected_branch.name }
+%td
+ = render "shared/buttons/project_feature_toggle", is_checked: protected_branch.allow_force_push, label: s_("ProtectedBranch|Toggle allow force push"), class_list: "js-force-push-toggle project-feature-toggle", data: { qa_selector: 'force_push_toggle_button', qa_branch_name: protected_branch.name }