summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-01 18:13:56 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-01 18:13:56 +0000
commit1769b59b9fd05325e3016b1a53a82ae6cf56adb5 (patch)
treea7e81e0c94fce5cc033e802d53d0c08d833fc87d /app
parent05003789d95f2f5d28a2f018d9e1b51ad7ab983c (diff)
downloadgitlab-ce-1769b59b9fd05325e3016b1a53a82ae6cf56adb5.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/issuable/components/csv_export_modal.vue16
-rw-r--r--app/assets/javascripts/issuable/components/csv_import_export_buttons.vue19
-rw-r--r--app/assets/javascripts/issuable/init_csv_import_export_buttons.js11
-rw-r--r--app/assets/javascripts/issuable_bulk_update_sidebar.js15
-rw-r--r--app/assets/javascripts/issuable_list/components/issuable_tabs.vue13
-rw-r--r--app/assets/javascripts/issues_list/components/issues_list_app.vue115
-rw-r--r--app/assets/javascripts/issues_list/index.js25
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js13
-rw-r--r--app/controllers/groups/email_campaigns_controller.rb6
-rw-r--r--app/graphql/types/board_type.rb6
-rw-r--r--app/helpers/issues_helper.rb19
-rw-r--r--app/helpers/tab_helper.rb61
-rw-r--r--app/models/ci/build.rb9
-rw-r--r--app/models/ci/pipeline_artifact.rb2
-rw-r--r--app/models/concerns/ci/artifactable.rb2
-rw-r--r--app/models/repository.rb6
-rw-r--r--app/presenters/search_service_presenter.rb4
-rw-r--r--app/services/merge_requests/merge_to_ref_service.rb8
-rw-r--r--app/views/admin/abuse_reports/index.html.haml10
-rw-r--r--app/views/projects/issues/index.html.haml34
20 files changed, 292 insertions, 102 deletions
diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue
index 78987a5c629..7bdd55ddda3 100644
--- a/app/assets/javascripts/issuable/components/csv_export_modal.vue
+++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue
@@ -12,19 +12,23 @@ export default {
},
inject: {
issuableType: {
- default: '',
- },
- issuableCount: {
- default: 0,
+ default: ISSUABLE_TYPE.issues,
},
email: {
default: '',
},
+ },
+ props: {
exportCsvPath: {
+ type: String,
+ required: false,
default: '',
},
- },
- props: {
+ issuableCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
modalId: {
type: String,
required: true,
diff --git a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
index 14474d44e10..fb4d5aca2f5 100644
--- a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
+++ b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
@@ -53,6 +53,18 @@ export default {
default: false,
},
},
+ props: {
+ exportCsvPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ issuableCount: {
+ type: Number,
+ required: false,
+ default: undefined,
+ },
+ },
computed: {
exportModalId() {
return `${this.issuableType}-export-modal`;
@@ -105,7 +117,12 @@ export default {
>
</gl-dropdown>
</gl-button-group>
- <csv-export-modal v-if="showExportButton" :modal-id="exportModalId" />
+ <csv-export-modal
+ v-if="showExportButton"
+ :modal-id="exportModalId"
+ :export-csv-path="exportCsvPath"
+ :issuable-count="issuableCount"
+ />
<csv-import-modal v-if="showImportButton" :modal-id="importModalId" />
</div>
</template>
diff --git a/app/assets/javascripts/issuable/init_csv_import_export_buttons.js b/app/assets/javascripts/issuable/init_csv_import_export_buttons.js
index 5a720b89d33..83163e3c478 100644
--- a/app/assets/javascripts/issuable/init_csv_import_export_buttons.js
+++ b/app/assets/javascripts/issuable/init_csv_import_export_buttons.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
-import ImportExportButtons from './components/csv_import_export_buttons.vue';
+import CsvImportExportButtons from './components/csv_import_export_buttons.vue';
export default () => {
const el = document.querySelector('.js-csv-import-export-buttons');
@@ -28,9 +28,7 @@ export default () => {
showExportButton: parseBoolean(showExportButton),
showImportButton: parseBoolean(showImportButton),
issuableType,
- issuableCount,
email,
- exportCsvPath,
importCsvIssuesPath,
containerClass,
canEdit: parseBoolean(canEdit),
@@ -39,7 +37,12 @@ export default () => {
showLabel,
},
render(h) {
- return h(ImportExportButtons);
+ return h(CsvImportExportButtons, {
+ props: {
+ exportCsvPath,
+ issuableCount: parseInt(issuableCount, 10),
+ },
+ });
},
});
};
diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js
index 1f707bc955f..97d50dde9f7 100644
--- a/app/assets/javascripts/issuable_bulk_update_sidebar.js
+++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js
@@ -46,14 +46,11 @@ export default class IssuableBulkUpdateSidebar {
this.$bulkEditSubmitBtn.on('click', () => this.prepForSubmit());
this.$checkAllContainer.on('click', () => this.updateFormState());
- issueableEventHub.$on('issuables:updateBulkEdit', () => {
- // Danger! Strong coupling ahead!
- // The bulk update sidebar and its dropdowns look for checkboxes, and get data on which issue
- // is selected by inspecting the DOM. Ideally, we would pass the selected issuable IDs and their properties
- // explicitly, but this component is used in too many places right now to refactor straight away.
-
- this.updateFormState();
- });
+ // The event hub connects this bulk update logic with `issues_list_app.vue`.
+ // We can remove it once we've refactored the issues list page bulk edit sidebar to Vue.
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/325874
+ issueableEventHub.$on('issuables:enableBulkEdit', () => this.toggleBulkEdit(null, true));
+ issueableEventHub.$on('issuables:updateBulkEdit', () => this.updateFormState());
}
initDropdowns() {
@@ -110,7 +107,7 @@ export default class IssuableBulkUpdateSidebar {
}
toggleBulkEdit(e, enable) {
- e.preventDefault();
+ e?.preventDefault();
issueableEventHub.$emit('issuables:toggleBulkEdit', enable);
diff --git a/app/assets/javascripts/issuable_list/components/issuable_tabs.vue b/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
index 57da030e22e..6bc621b52e6 100644
--- a/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
+++ b/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
@@ -26,6 +26,9 @@ export default {
isTabActive(tabName) {
return tabName === this.currentTab;
},
+ isTabCountNumeric(tab) {
+ return Number.isInteger(this.tabCounts[tab.name]);
+ },
},
};
</script>
@@ -44,9 +47,13 @@ export default {
>
<template #title>
<span :title="tab.titleTooltip">{{ tab.title }}</span>
- <gl-badge v-if="tabCounts" variant="neutral" size="sm" class="gl-tab-counter-badge">{{
- tabCounts[tab.name]
- }}</gl-badge>
+ <gl-badge
+ v-if="isTabCountNumeric(tab)"
+ variant="neutral"
+ size="sm"
+ class="gl-tab-counter-badge"
+ >{{ tabCounts[tab.name] }}</gl-badge
+ >
</template>
</gl-tab>
</gl-tabs>
diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue
index d7af388c893..1f26c65475b 100644
--- a/app/assets/javascripts/issues_list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue
@@ -1,9 +1,10 @@
<script>
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { toNumber } from 'lodash';
import createFlash from '~/flash';
+import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
import IssuableList from '~/issuable_list/components/issuable_list_root.vue';
-import { IssuableStatus } from '~/issue_show/constants';
+import { IssuableListTabs, IssuableStates } from '~/issuable_list/constants';
import {
CREATED_DESC,
PAGE_SIZE,
@@ -19,13 +20,18 @@ import IssueCardTimeInfo from './issue_card_time_info.vue';
export default {
CREATED_DESC,
+ IssuableListTabs,
PAGE_SIZE,
sortOptions,
sortParams,
i18n: {
+ calendarLabel: __('Subscribe to calendar'),
reorderError: __('An error occurred while reordering issues.'),
+ rssLabel: __('Subscribe to RSS feed'),
},
components: {
+ CsvImportExportButtons,
+ GlButton,
GlIcon,
IssuableList,
IssueCardTimeInfo,
@@ -35,15 +41,33 @@ export default {
GlTooltip: GlTooltipDirective,
},
inject: {
+ calendarPath: {
+ default: '',
+ },
+ canBulkUpdate: {
+ default: false,
+ },
endpoint: {
default: '',
},
+ exportCsvPath: {
+ default: '',
+ },
fullPath: {
default: '',
},
issuesPath: {
default: '',
},
+ newIssuePath: {
+ default: '',
+ },
+ rssPath: {
+ default: '',
+ },
+ showNewIssueLink: {
+ default: false,
+ },
},
data() {
const orderBy = getParameterByName('order_by');
@@ -53,20 +77,31 @@ export default {
);
return {
- currentPage: toNumber(getParameterByName('page')) || 1,
+ exportCsvPathWithQuery: this.getExportCsvPathWithQuery(),
filters: sortParams[sortKey] || {},
isLoading: false,
issues: [],
+ page: toNumber(getParameterByName('page')) || 1,
showBulkEditSidebar: false,
sortKey: sortKey || CREATED_DESC,
+ state: getParameterByName('state') || IssuableStates.Opened,
totalIssues: 0,
};
},
computed: {
+ tabCounts() {
+ return Object.values(IssuableStates).reduce(
+ (acc, state) => ({
+ ...acc,
+ [state]: this.state === state ? this.totalIssues : undefined,
+ }),
+ {},
+ );
+ },
urlParams() {
return {
- page: this.currentPage,
- state: IssuableStatus.Open,
+ page: this.page,
+ state: this.state,
...this.filters,
};
},
@@ -85,23 +120,24 @@ export default {
eventHub.$off('issuables:toggleBulkEdit');
},
methods: {
- fetchIssues(pageToFetch) {
+ fetchIssues() {
this.isLoading = true;
return axios
.get(this.endpoint, {
params: {
- page: pageToFetch || this.currentPage,
+ page: this.page,
per_page: this.$options.PAGE_SIZE,
- state: IssuableStatus.Open,
+ state: this.state,
with_labels_details: true,
...this.filters,
},
})
.then(({ data, headers }) => {
- this.currentPage = Number(headers['x-page']);
+ this.page = Number(headers['x-page']);
this.totalIssues = Number(headers['x-total']);
this.issues = data.map((issue) => convertObjectPropsToCamelCase(issue, { deep: true }));
+ this.exportCsvPathWithQuery = this.getExportCsvPathWithQuery();
})
.catch(() => {
createFlash({ message: __('An error occurred while loading issues') });
@@ -110,6 +146,9 @@ export default {
this.isLoading = false;
});
},
+ getExportCsvPathWithQuery() {
+ return `${this.exportCsvPath}${window.location.search}`;
+ },
handleUpdateLegacyBulkEdit() {
// If "select all" checkbox was checked, wait for all checkboxes
// to be checked before updating IssuableBulkUpdateSidebar class
@@ -117,8 +156,19 @@ export default {
eventHub.$emit('issuables:updateBulkEdit');
});
},
+ handleBulkUpdateClick() {
+ eventHub.$emit('issuables:enableBulkEdit');
+ },
+ handleClickTab(state) {
+ if (this.state !== state) {
+ this.page = 1;
+ }
+ this.state = state;
+ this.fetchIssues();
+ },
handlePageChange(page) {
- this.fetchIssues(page);
+ this.page = page;
+ this.fetchIssues();
},
handleReorder({ newIndex, oldIndex }) {
const issueToMove = this.issues[oldIndex];
@@ -171,25 +221,60 @@ export default {
:sort-options="$options.sortOptions"
:initial-sort-by="sortKey"
:issuables="issues"
- :tabs="[]"
- current-tab=""
+ :tabs="$options.IssuableListTabs"
+ :current-tab="state"
+ :tab-counts="tabCounts"
:issuables-loading="isLoading"
:is-manual-ordering="isManualOrdering"
:show-bulk-edit-sidebar="showBulkEditSidebar"
:show-pagination-controls="true"
:total-items="totalIssues"
- :current-page="currentPage"
- :previous-page="currentPage - 1"
- :next-page="currentPage + 1"
+ :current-page="page"
+ :previous-page="page - 1"
+ :next-page="page + 1"
:url-params="urlParams"
+ @click-tab="handleClickTab"
@page-change="handlePageChange"
@reorder="handleReorder"
@sort="handleSort"
@update-legacy-bulk-edit="handleUpdateLegacyBulkEdit"
>
+ <template #nav-actions>
+ <gl-button
+ v-gl-tooltip
+ :href="rssPath"
+ icon="rss"
+ :title="$options.i18n.rssLabel"
+ :aria-label="$options.i18n.rssLabel"
+ />
+ <gl-button
+ v-gl-tooltip
+ :href="calendarPath"
+ icon="calendar"
+ :title="$options.i18n.calendarLabel"
+ :aria-label="$options.i18n.calendarLabel"
+ />
+ <csv-import-export-buttons
+ class="gl-mr-3"
+ :export-csv-path="exportCsvPathWithQuery"
+ :issuable-count="totalIssues"
+ />
+ <gl-button
+ v-if="canBulkUpdate"
+ :disabled="showBulkEditSidebar"
+ @click="handleBulkUpdateClick"
+ >
+ {{ __('Edit issues') }}
+ </gl-button>
+ <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm">
+ {{ __('New issue') }}
+ </gl-button>
+ </template>
+
<template #timeframe="{ issuable = {} }">
<issue-card-time-info :issue="issuable" />
</template>
+
<template #statistics="{ issuable = {} }">
<li
v-if="issuable.mergeRequestsCount"
diff --git a/app/assets/javascripts/issues_list/index.js b/app/assets/javascripts/issues_list/index.js
index b55ebf8dbdb..0ba20e43050 100644
--- a/app/assets/javascripts/issues_list/index.js
+++ b/app/assets/javascripts/issues_list/index.js
@@ -73,12 +73,23 @@ export function initIssuesListApp() {
}
const {
+ calendarPath,
+ canBulkUpdate,
+ canEdit,
+ email,
endpoint,
+ exportCsvPath,
fullPath,
hasBlockedIssuesFeature,
hasIssuableHealthStatusFeature,
hasIssueWeightsFeature,
+ importCsvIssuesPath,
issuesPath,
+ maxAttachmentSize,
+ newIssuePath,
+ projectImportJiraPath,
+ rssPath,
+ showNewIssueLink,
} = el.dataset;
return new Vue({
@@ -87,12 +98,26 @@ export function initIssuesListApp() {
// issue is fixed upstream in https://github.com/vuejs/vue-apollo/pull/1153
apolloProvider: {},
provide: {
+ calendarPath,
+ canBulkUpdate: parseBoolean(canBulkUpdate),
endpoint,
fullPath,
hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature),
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
issuesPath,
+ newIssuePath,
+ rssPath,
+ showNewIssueLink: parseBoolean(showNewIssueLink),
+ // For CsvImportExportButtons component
+ canEdit: parseBoolean(canEdit),
+ email,
+ exportCsvPath,
+ importCsvIssuesPath,
+ maxAttachmentSize,
+ projectImportJiraPath,
+ showExportButton: true,
+ showImportButton: true,
},
render: (createComponent) => createComponent(IssuesListApp),
});
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 73eadfe3cbe..fb257228597 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -681,6 +681,19 @@ export const roundOffFloat = (number, precision = 0) => {
};
/**
+ * Method to round values to the nearest half (0.5)
+ *
+ * Eg; roundToNearestHalf(3.141592) = 3, roundToNearestHalf(3.41592) = 3.5
+ *
+ * Refer to spec/javascripts/lib/utils/common_utils_spec.js for
+ * more supported examples.
+ *
+ * @param {Float} number
+ * @returns {Float|Number}
+ */
+export const roundToNearestHalf = (num) => Math.round(num * 2).toFixed() / 2;
+
+/**
* Method to round down values with decimal places
* with provided precision.
*
diff --git a/app/controllers/groups/email_campaigns_controller.rb b/app/controllers/groups/email_campaigns_controller.rb
index 8c3c289dc99..e085cefbc24 100644
--- a/app/controllers/groups/email_campaigns_controller.rb
+++ b/app/controllers/groups/email_campaigns_controller.rb
@@ -19,12 +19,14 @@ class Groups::EmailCampaignsController < Groups::ApplicationController
def track_click
data = {
namespace_id: group.id,
- track: @track,
+ track: @track.to_s,
series: @series,
subject_line: subject_line(@track, @series)
}
- ::Gitlab::Tracking.self_describing_event(EMAIL_CAMPAIGNS_SCHEMA_URL, data: data)
+ context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data)
+
+ ::Gitlab::Tracking.event(self.class.name, 'click', context: [context])
end
def redirect_link
diff --git a/app/graphql/types/board_type.rb b/app/graphql/types/board_type.rb
index f33f3f5e537..42d8eecc366 100644
--- a/app/graphql/types/board_type.rb
+++ b/app/graphql/types/board_type.rb
@@ -20,6 +20,12 @@ module Types
field :hide_closed_list, type: GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether or not closed list is hidden.'
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the board was created.'
+
+ field :updated_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the board was last updated.'
+
field :lists,
Types::BoardListType.connection_type,
null: true,
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 0a9965496b8..7e3c64ff736 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -163,6 +163,25 @@ module IssuesHelper
}
end
+ def issues_list_data(project, current_user, finder)
+ {
+ calendar_path: url_for(safe_params.merge(calendar_url_options)),
+ can_bulk_update: can?(current_user, :admin_issue, project).to_s,
+ can_edit: can?(current_user, :admin_project, project).to_s,
+ email: current_user&.notification_email,
+ endpoint: expose_path(api_v4_projects_issues_path(id: project.id)),
+ export_csv_path: export_csv_project_issues_path(project),
+ full_path: project.full_path,
+ import_csv_issues_path: import_csv_namespace_project_issues_path,
+ issues_path: project_issues_path(project),
+ max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes),
+ new_issue_path: new_project_issue_path(project, issue: { assignee_id: finder.assignee.try(:id), milestone_id: finder.milestones.first.try(:id) }),
+ project_import_jira_path: project_import_jira_path(project),
+ rss_path: url_for(safe_params.merge(rss_url_options)),
+ show_new_issue_link: show_new_issue_link?(project).to_s
+ }
+ end
+
# Overridden in EE
def scoped_labels_available?(parent)
false
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index e81986d4453..1d3242ca44a 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -65,6 +65,13 @@ module TabHelper
# # When `TreeController#index` is requested
# # => '<li>Hello</li>'
#
+ # # Paths, controller and actions can be used at the same time
+ # nav_link(path: 'tree#show', controller: 'admin/appearances') { "Hello" }
+ #
+ # nav_link(path: 'foo#bar', controller: 'tree') { "Hello" }
+ # nav_link(path: 'foo#bar', controller: 'tree', action: 'show') { "Hello" }
+ # nav_link(path: 'foo#bar', action: 'show') { "Hello" }
+ #
# Returns a list item element String
def nav_link(options = {}, &block)
klass = active_nav_link?(options) ? 'active' : ''
@@ -85,34 +92,12 @@ module TabHelper
def active_nav_link?(options)
return false if options[:unless]&.call
- if path = options.delete(:path)
- unless path.respond_to?(:each)
- path = [path]
- end
-
- path.any? do |single_path|
- current_path?(single_path)
- end
- elsif page = options.delete(:page)
- unless page.respond_to?(:each)
- page = [page]
- end
-
- page.any? do |single_page|
- current_page?(single_page)
- end
- else
- c = options.delete(:controller)
- a = options.delete(:action)
+ controller = options.delete(:controller)
+ action = options.delete(:action)
- if c && a
- # When given both options, make sure BOTH are true
- current_controller?(*c) && current_action?(*a)
- else
- # Otherwise check EITHER option
- current_controller?(*c) || current_action?(*a)
- end
- end
+ route_matches_paths?(options.delete(:path)) ||
+ route_matches_pages?(options.delete(:page)) ||
+ route_matches_controllers_and_or_actions?(controller, action)
end
def current_path?(path)
@@ -127,4 +112,26 @@ module TabHelper
'active'
end
end
+
+ private
+
+ def route_matches_paths?(paths)
+ Array(paths).compact.any? do |single_path|
+ current_path?(single_path)
+ end
+ end
+
+ def route_matches_pages?(pages)
+ Array(pages).compact.any? do |single_page|
+ current_page?(single_page)
+ end
+ end
+
+ def route_matches_controllers_and_or_actions?(controller, action)
+ if controller && action
+ current_controller?(*controller) && current_action?(*action)
+ else
+ current_controller?(*controller) || current_action?(*action)
+ end
+ end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 76b97041166..dce9168a9a4 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -73,7 +73,14 @@ module Ci
return unless has_environment?
strong_memoize(:persisted_environment) do
- Environment.find_by(name: expanded_environment_name, project: project)
+ # This code path has caused N+1s in the past, since environments are only indirectly
+ # associated to builds and pipelines; see https://gitlab.com/gitlab-org/gitlab/-/issues/326445
+ # We therefore batch-load them to prevent dormant N+1s until we found a proper solution.
+ BatchLoader.for(expanded_environment_name).batch(key: project_id) do |names, loader, args|
+ Environment.where(name: names, project: args[:key]).find_each do |environment|
+ loader.call(environment.name, environment)
+ end
+ end
end
end
diff --git a/app/models/ci/pipeline_artifact.rb b/app/models/ci/pipeline_artifact.rb
index f538a4cd808..9dfe4252e95 100644
--- a/app/models/ci/pipeline_artifact.rb
+++ b/app/models/ci/pipeline_artifact.rb
@@ -57,3 +57,5 @@ module Ci
end
end
end
+
+Ci::PipelineArtifact.prepend_ee_mod
diff --git a/app/models/concerns/ci/artifactable.rb b/app/models/concerns/ci/artifactable.rb
index 66a02f49030..0d29955268f 100644
--- a/app/models/concerns/ci/artifactable.rb
+++ b/app/models/concerns/ci/artifactable.rb
@@ -42,3 +42,5 @@ module Ci
end
end
end
+
+Ci::Artifactable.prepend_ee_mod
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e675f604b0a..b23b9486cfe 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -829,12 +829,6 @@ class Repository
end
end
- def merge_to_ref(user, source_sha, merge_request, target_ref, message, first_parent_ref, allow_conflicts = false)
- branch = merge_request.target_branch
-
- raw.merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref, allow_conflicts)
- end
-
def delete_refs(*ref_names)
raw.delete_refs(*ref_names)
end
diff --git a/app/presenters/search_service_presenter.rb b/app/presenters/search_service_presenter.rb
index ca5c3094509..e14446bb2f7 100644
--- a/app/presenters/search_service_presenter.rb
+++ b/app/presenters/search_service_presenter.rb
@@ -11,7 +11,9 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated
merge_requests: :with_web_entity_associations,
epics: :with_web_entity_associations,
notes: :with_web_entity_associations,
- milestones: :with_web_entity_associations
+ milestones: :with_web_entity_associations,
+ commits: :with_web_entity_associations,
+ blobs: :with_web_entity_associations
}.freeze
SORT_ENABLED_SCOPES = %w(issues merge_requests).freeze
diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb
index c0115e94903..e07e0c985b4 100644
--- a/app/services/merge_requests/merge_to_ref_service.rb
+++ b/app/services/merge_requests/merge_to_ref_service.rb
@@ -66,7 +66,13 @@ module MergeRequests
end
def commit
- repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message, first_parent_ref, allow_conflicts)
+ repository.merge_to_ref(current_user,
+ source_sha: source,
+ branch: merge_request.target_branch,
+ target_ref: target_ref,
+ message: commit_message,
+ first_parent_ref: first_parent_ref,
+ allow_conflicts: allow_conflicts)
rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError => error
raise MergeError, error.message
end
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index daa766429e0..2af31b93c0b 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -19,13 +19,13 @@
%table.table.responsive-table
%thead.d-none.d-md-table-header-group
%tr
- %th User
- %th Reported by
- %th.wide Message
- %th Action
+ %th= _('User')
+ %th= _('Reported by')
+ %th.wide= _('Message')
+ %th= _('Action')
= render @abuse_reports
= paginate @abuse_reports, theme: 'gitlab'
- else
.empty-state
.text-center
- %h4 There are no abuse reports! #{emoji_icon('tada')}
+ %h4= _("There are no abuse reports!") + emoji_icon('tada')
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 3b35bd7544a..9b043ea3c47 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -13,32 +13,24 @@
issues_path: project_issues_path(@project),
project_path: @project.full_path } }
-- if project_issues(@project).exists?
+- if Feature.enabled?(:vue_issues_list, @project)
+ .js-issues-list{ data: issues_list_data(@project, current_user, finder) }
+ - if @can_bulk_update
+ = render 'shared/issuable/bulk_update_sidebar', type: :issues
+- elsif project_issues(@project).exists?
.top-area
= render 'shared/issuable/nav', type: :issues
= render "projects/issues/nav_btns"
+ = render 'shared/issuable/search_bar', type: :issues
- - if Feature.enabled?(:vue_issues_list, @project)
- - data_endpoint = local_assigns.fetch(:data_endpoint, expose_path(api_v4_projects_issues_path(id: @project.id)))
- .js-issues-list{ data: { endpoint: data_endpoint,
- full_path: @project.full_path,
- has_blocked_issues_feature: Gitlab.ee? && @project.feature_available?(:blocked_issues).to_s,
- has_issuable_health_status_feature: Gitlab.ee? && @project.feature_available?(:issuable_health_status).to_s,
- has_issue_weights_feature: Gitlab.ee? && @project.feature_available?(:issue_weights).to_s,
- issues_path: project_issues_path(@project) } }
- - if @can_bulk_update
- = render 'shared/issuable/bulk_update_sidebar', type: :issues
- - else
- = render 'shared/issuable/search_bar', type: :issues
+ - if @can_bulk_update
+ = render 'shared/issuable/bulk_update_sidebar', type: :issues
- - if @can_bulk_update
- = render 'shared/issuable/bulk_update_sidebar', type: :issues
-
- .issues-holder
- = render 'issues'
- - if new_issue_email
- .issuable-footer.text-center
- .js-issueable-by-email{ data: { initial_email: new_issue_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
+ .issues-holder
+ = render 'issues'
+ - if new_issue_email
+ .issuable-footer.text-center
+ .js-issueable-by-email{ data: { initial_email: new_issue_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
- else
- new_project_issue_button_path = @project.archived? ? false : new_project_issue_path(@project)
= render 'shared/empty_states/issues', new_project_issue_button_path: new_project_issue_button_path, show_import_button: true