summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/api.js7
-rw-r--r--app/assets/javascripts/awards_handler.js33
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/actions.js82
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/getters.js23
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/index.js12
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/mutation_types.js7
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/mutations.js21
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/state.js6
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js8
-rw-r--r--app/assets/javascripts/jobs/components/environments_block.vue118
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue24
-rw-r--r--app/assets/javascripts/pages/groups/milestones/show/index.js4
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue6
-rw-r--r--app/assets/javascripts/pages/profiles/show/index.js32
-rw-r--r--app/assets/javascripts/performance_bar/index.js4
-rw-r--r--app/assets/javascripts/performance_bar/services/performance_bar_service.js21
-rw-r--r--app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue3
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_component.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table_row.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue61
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue67
-rw-r--r--app/assets/stylesheets/bootstrap_migration.scss10
-rw-r--r--app/assets/stylesheets/framework/avatar.scss12
-rw-r--r--app/assets/stylesheets/framework/badges.scss2
-rw-r--r--app/assets/stylesheets/framework/buttons.scss4
-rw-r--r--app/assets/stylesheets/framework/callout.scss24
-rw-r--r--app/assets/stylesheets/framework/common.scss12
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss8
-rw-r--r--app/assets/stylesheets/framework/feature_highlight.scss4
-rw-r--r--app/assets/stylesheets/framework/files.scss4
-rw-r--r--app/assets/stylesheets/framework/filters.scss2
-rw-r--r--app/assets/stylesheets/framework/forms.scss2
-rw-r--r--app/assets/stylesheets/framework/header.scss2
-rw-r--r--app/assets/stylesheets/framework/icons.scss2
-rw-r--r--app/assets/stylesheets/framework/issue_box.scss4
-rw-r--r--app/assets/stylesheets/framework/selects.scss6
-rw-r--r--app/assets/stylesheets/framework/variables.scss100
-rw-r--r--app/assets/stylesheets/framework/variables_overrides.scss4
-rw-r--r--app/assets/stylesheets/pages/builds.scss2
-rw-r--r--app/assets/stylesheets/pages/convdev_index.scss12
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss2
-rw-r--r--app/assets/stylesheets/pages/editor.scss4
-rw-r--r--app/assets/stylesheets/pages/environments.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/labels.scss4
-rw-r--r--app/assets/stylesheets/pages/login.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss47
-rw-r--r--app/assets/stylesheets/pages/note_form.scss6
-rw-r--r--app/assets/stylesheets/pages/notes.scss2
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss10
-rw-r--r--app/assets/stylesheets/pages/projects.scss18
-rw-r--r--app/assets/stylesheets/pages/runners.scss10
-rw-r--r--app/assets/stylesheets/pages/search.scss8
-rw-r--r--app/assets/stylesheets/pages/settings.scss4
-rw-r--r--app/assets/stylesheets/pages/stat_graph.scss4
-rw-r--r--app/controllers/concerns/issuable_collections.rb22
-rw-r--r--app/controllers/concerns/renders_commits.rb20
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb2
-rw-r--r--app/controllers/groups/milestones_controller.rb17
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/helpers/commits_helper.rb11
-rw-r--r--app/helpers/import_helper.rb4
-rw-r--r--app/helpers/issues_helper.rb8
-rw-r--r--app/helpers/projects_helper.rb6
-rw-r--r--app/models/ci/pipeline.rb3
-rw-r--r--app/models/commit.rb1
-rw-r--r--app/models/concerns/awardable.rb16
-rw-r--r--app/models/diff_note.rb16
-rw-r--r--app/models/issue.rb47
-rw-r--r--app/models/member.rb2
-rw-r--r--app/models/merge_request_diff.rb4
-rw-r--r--app/models/project.rb16
-rw-r--r--app/models/protected_tag.rb2
-rw-r--r--app/models/remote_mirror.rb9
-rw-r--r--app/models/repository.rb21
-rw-r--r--app/models/user.rb15
-rw-r--r--app/policies/group_policy.rb4
-rw-r--r--app/policies/project_policy.rb4
-rw-r--r--app/services/git_push_service.rb15
-rw-r--r--app/services/groups/destroy_service.rb5
-rw-r--r--app/services/issues/fetch_referenced_merge_requests_service.rb14
-rw-r--r--app/services/issues/referenced_merge_requests_service.rb66
-rw-r--r--app/services/merge_requests/build_service.rb19
-rw-r--r--app/services/milestones/destroy_service.rb20
-rw-r--r--app/services/projects/fork_service.rb8
-rw-r--r--app/services/projects/update_remote_mirror_service.rb1
-rw-r--r--app/services/quick_actions/interpret_service.rb2
-rw-r--r--app/views/admin/hook_logs/show.html.haml3
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/award_emoji/_awards_block.html.haml3
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml2
-rw-r--r--app/views/ci/status/_dropdown_graph_badge.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml2
-rw-r--r--app/views/import/_githubish_status.html.haml2
-rw-r--r--app/views/import/bitbucket/status.html.haml2
-rw-r--r--app/views/import/bitbucket_server/status.html.haml2
-rw-r--r--app/views/projects/_issuable_by_email.html.haml11
-rw-r--r--app/views/projects/commits/_commit_list.html.haml5
-rw-r--r--app/views/projects/commits/_commits.html.haml3
-rw-r--r--app/views/projects/diffs/_line.html.haml4
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml4
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/hook_logs/show.html.haml2
-rw-r--r--app/views/projects/jobs/_sidebar.html.haml2
-rw-r--r--app/views/projects/merge_requests/_how_to_merge.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml13
-rw-r--r--app/views/projects/mirrors/_instructions.html.haml4
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/views/shared/milestones/_delete_button.html.haml14
-rw-r--r--app/views/shared/milestones/_milestone.html.haml5
-rw-r--r--app/views/shared/milestones/_top.html.haml5
-rw-r--r--app/views/snippets/notes/_actions.html.haml2
122 files changed, 906 insertions, 545 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 25fe2ae553e..cd800d75f7a 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -15,6 +15,7 @@ const Api = {
mergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
mergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
groupLabelsPath: '/groups/:namespace_path/-/labels',
+ templatesPath: '/api/:version/templates/:key',
licensePath: '/api/:version/templates/licenses/:key',
gitignorePath: '/api/:version/templates/gitignores/:key',
gitlabCiYmlPath: '/api/:version/templates/gitlab_ci_ymls/:key',
@@ -265,6 +266,12 @@ const Api = {
});
},
+ templates(key, params = {}) {
+ const url = Api.buildUrl(this.templatesPath).replace(':key', key);
+
+ return axios.get(url, { params });
+ },
+
buildUrl(url) {
let urlRoot = '';
if (gon.relative_url_root != null) {
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index e34db893989..5b0c4285339 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -109,8 +109,6 @@ export class AwardsHandler {
}
const $menu = $(`.${this.menuClass}`);
- const $thumbsBtn = $menu.find('[data-name="thumbsup"], [data-name="thumbsdown"]').parent();
- const $userAuthored = this.isUserAuthored($addBtn);
if ($menu.length) {
if ($menu.is('.is-visible')) {
$addBtn.removeClass('is-active');
@@ -134,9 +132,6 @@ export class AwardsHandler {
}, 200);
});
}
-
- $thumbsBtn.toggleClass('disabled', $userAuthored);
- $thumbsBtn.prop('disabled', $userAuthored);
}
// Create the emoji menu with the first category of emojis.
@@ -364,10 +359,6 @@ export class AwardsHandler {
return $emojiButton.hasClass('active');
}
- isUserAuthored($button) {
- return $button.hasClass('js-user-authored');
- }
-
decrementCounter($emojiButton, emoji) {
const counter = $('.js-counter', $emojiButton);
const counterNumber = parseInt(counter.text(), 10);
@@ -474,20 +465,16 @@ export class AwardsHandler {
}
postEmoji($emojiButton, awardUrl, emoji, callback) {
- if (this.isUserAuthored($emojiButton)) {
- this.userAuthored($emojiButton);
- } else {
- axios
- .post(awardUrl, {
- name: emoji,
- })
- .then(({ data }) => {
- if (data.ok) {
- callback();
- }
- })
- .catch(() => flash(__('Something went wrong on our end.')));
- }
+ axios
+ .post(awardUrl, {
+ name: emoji,
+ })
+ .then(({ data }) => {
+ if (data.ok) {
+ callback();
+ }
+ })
+ .catch(() => flash(__('Something went wrong on our end.')));
}
findEmojiIcon(votesBlock, emoji) {
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
new file mode 100644
index 00000000000..43237a29466
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
@@ -0,0 +1,82 @@
+import Api from '~/api';
+import { __ } from '~/locale';
+import * as types from './mutation_types';
+
+export const requestTemplateTypes = ({ commit }) => commit(types.REQUEST_TEMPLATE_TYPES);
+export const receiveTemplateTypesError = ({ commit, dispatch }) => {
+ commit(types.RECEIVE_TEMPLATE_TYPES_ERROR);
+ dispatch(
+ 'setErrorMessage',
+ {
+ text: __('Error loading template types.'),
+ action: () =>
+ dispatch('fetchTemplateTypes').then(() =>
+ dispatch('setErrorMessage', null, { root: true }),
+ ),
+ actionText: __('Please try again'),
+ },
+ { root: true },
+ );
+};
+export const receiveTemplateTypesSuccess = ({ commit }, templates) =>
+ commit(types.RECEIVE_TEMPLATE_TYPES_SUCCESS, templates);
+
+export const fetchTemplateTypes = ({ dispatch, state }) => {
+ if (!Object.keys(state.selectedTemplateType).length) return Promise.reject();
+
+ dispatch('requestTemplateTypes');
+
+ return Api.templates(state.selectedTemplateType.key)
+ .then(({ data }) => dispatch('receiveTemplateTypesSuccess', data))
+ .catch(() => dispatch('receiveTemplateTypesError'));
+};
+
+export const setSelectedTemplateType = ({ commit }, type) =>
+ commit(types.SET_SELECTED_TEMPLATE_TYPE, type);
+
+export const receiveTemplateError = ({ dispatch }, template) => {
+ dispatch(
+ 'setErrorMessage',
+ {
+ text: __('Error loading template.'),
+ action: payload =>
+ dispatch('fetchTemplateTypes', payload).then(() =>
+ dispatch('setErrorMessage', null, { root: true }),
+ ),
+ actionText: __('Please try again'),
+ actionPayload: template,
+ },
+ { root: true },
+ );
+};
+
+export const fetchTemplate = ({ dispatch, state }, template) => {
+ if (template.content) {
+ return dispatch('setFileTemplate', template);
+ }
+
+ return Api.templates(`${state.selectedTemplateType.key}/${template.key || template.name}`)
+ .then(({ data }) => {
+ dispatch('setFileTemplate', data);
+ })
+ .catch(() => dispatch('receiveTemplateError', template));
+};
+
+export const setFileTemplate = ({ dispatch, commit, rootGetters }, template) => {
+ dispatch(
+ 'changeFileContent',
+ { path: rootGetters.activeFile.path, content: template.content },
+ { root: true },
+ );
+ commit(types.SET_UPDATE_SUCCESS, true);
+};
+
+export const undoFileTemplate = ({ dispatch, commit, rootGetters }) => {
+ const file = rootGetters.activeFile;
+
+ dispatch('changeFileContent', { path: file.path, content: file.raw }, { root: true });
+ commit(types.SET_UPDATE_SUCCESS, false);
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/getters.js b/app/assets/javascripts/ide/stores/modules/file_templates/getters.js
new file mode 100644
index 00000000000..38318fd49bf
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/getters.js
@@ -0,0 +1,23 @@
+export const templateTypes = () => [
+ {
+ name: '.gitlab-ci.yml',
+ key: 'gitlab_ci_ymls',
+ },
+ {
+ name: '.gitignore',
+ key: 'gitignores',
+ },
+ {
+ name: 'LICENSE',
+ key: 'licenses',
+ },
+ {
+ name: 'Dockerfile',
+ key: 'dockerfiles',
+ },
+];
+
+export const showFileTemplatesBar = (_, getters) => name =>
+ getters.templateTypes.find(t => t.name === name);
+
+export default () => {};
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/index.js b/app/assets/javascripts/ide/stores/modules/file_templates/index.js
new file mode 100644
index 00000000000..dfa5ef54413
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/index.js
@@ -0,0 +1,12 @@
+import createState from './state';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+
+export default {
+ namespaced: true,
+ actions,
+ state: createState(),
+ getters,
+ mutations,
+};
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/mutation_types.js b/app/assets/javascripts/ide/stores/modules/file_templates/mutation_types.js
new file mode 100644
index 00000000000..cf4499c0264
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/mutation_types.js
@@ -0,0 +1,7 @@
+export const REQUEST_TEMPLATE_TYPES = 'REQUEST_TEMPLATE_TYPES';
+export const RECEIVE_TEMPLATE_TYPES_ERROR = 'RECEIVE_TEMPLATE_TYPES_ERROR';
+export const RECEIVE_TEMPLATE_TYPES_SUCCESS = 'RECEIVE_TEMPLATE_TYPES_SUCCESS';
+
+export const SET_SELECTED_TEMPLATE_TYPE = 'SET_SELECTED_TEMPLATE_TYPE';
+
+export const SET_UPDATE_SUCCESS = 'SET_UPDATE_SUCCESS';
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
new file mode 100644
index 00000000000..e413e61eaaa
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
@@ -0,0 +1,21 @@
+/* eslint-disable no-param-reassign */
+import * as types from './mutation_types';
+
+export default {
+ [types.REQUEST_TEMPLATE_TYPES](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_TEMPLATE_TYPES_ERROR](state) {
+ state.isLoading = false;
+ },
+ [types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, templates) {
+ state.isLoading = false;
+ state.templates = templates;
+ },
+ [types.SET_SELECTED_TEMPLATE_TYPE](state, type) {
+ state.selectedTemplateType = type;
+ },
+ [types.SET_UPDATE_SUCCESS](state, success) {
+ state.updateSuccess = success;
+ },
+};
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/state.js b/app/assets/javascripts/ide/stores/modules/file_templates/state.js
new file mode 100644
index 00000000000..bd4b7d7bc52
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/state.js
@@ -0,0 +1,6 @@
+export default () => ({
+ isLoading: false,
+ templates: [],
+ selectedTemplateType: {},
+ updateSuccess: false,
+});
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 56a8d9430c7..0347f803757 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -146,13 +146,7 @@ export default {
staged: false,
prevPath: '',
moved: false,
- lastCommit: Object.assign(state.entries[file.path].lastCommit, {
- id: lastCommit.commit.id,
- url: lastCommit.commit_path,
- message: lastCommit.commit.message,
- author: lastCommit.commit.author_name,
- updatedAt: lastCommit.commit.authored_date,
- }),
+ lastCommitSha: lastCommit.commit.id,
});
if (prevPath) {
diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue
new file mode 100644
index 00000000000..ca6386595c7
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/environments_block.vue
@@ -0,0 +1,118 @@
+<script>
+ import _ from 'underscore';
+ import CiIcon from '~/vue_shared/components/ci_icon.vue';
+ import { sprintf, __ } from '../../locale';
+
+ export default {
+ components: {
+ CiIcon,
+ },
+ props: {
+ deploymentStatus: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ environment() {
+ let environmentText;
+ switch (this.deploymentStatus.status) {
+ case 'latest':
+ environmentText = sprintf(
+ __('This job is the most recent deployment to %{link}.'),
+ { link: this.environmentLink },
+ false,
+ );
+ break;
+ case 'out_of_date':
+ if (this.hasLastDeployment) {
+ environmentText = sprintf(
+ __(
+ 'This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}.',
+ ),
+ {
+ environmentLink: this.environmentLink,
+ deploymentLink: this.deploymentLink,
+ },
+ false,
+ );
+ } else {
+ environmentText = sprintf(
+ __('This job is an out-of-date deployment to %{environmentLink}.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ }
+
+ break;
+ case 'failed':
+ environmentText = sprintf(
+ __('The deployment of this job to %{environmentLink} did not succeed.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ break;
+ case 'creating':
+ if (this.hasLastDeployment) {
+ environmentText = sprintf(
+ __(
+ 'This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}.',
+ ),
+ {
+ environmentLink: this.environmentLink,
+ deploymentLink: this.deploymentLink,
+ },
+ false,
+ );
+ } else {
+ environmentText = sprintf(
+ __('This job is creating a deployment to %{environmentLink}.'),
+ { environmentLink: this.environmentLink },
+ false,
+ );
+ }
+ break;
+ default:
+ break;
+ }
+ return environmentText;
+ },
+ environmentLink() {
+ return sprintf(
+ '%{startLink}%{name}%{endLink}',
+ {
+ startLink: `<a href="${this.deploymentStatus.environment.path}">`,
+ name: _.escape(this.deploymentStatus.environment.name),
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
+ deploymentLink() {
+ return sprintf(
+ '%{startLink}%{name}%{endLink}',
+ {
+ startLink: `<a href="${this.lastDeployment.path}">`,
+ name: _.escape(this.lastDeployment.name),
+ endLink: '</a>',
+ },
+ false,
+ );
+ },
+ hasLastDeployment() {
+ return this.deploymentStatus.environment.last_deployment;
+ },
+ lastDeployment() {
+ return this.deploymentStatus.environment.last_deployment;
+ },
+ },
+ };
+</script>
+<template>
+ <div class="prepend-top-default js-environment-container">
+ <div class="environment-information">
+ <ci-icon :status="deploymentStatus.icon" />
+ <p v-html="environment"></p>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 225d9f18612..e111d3b9ac2 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -82,29 +82,17 @@ export default {
getAwardHTML(name) {
return glEmojiTag(name);
},
- getAwardClassBindings(awardList, awardName) {
+ getAwardClassBindings(awardList) {
return {
active: this.hasReactionByCurrentUser(awardList),
- disabled: !this.canInteractWithEmoji(awardList, awardName),
+ disabled: !this.canInteractWithEmoji(),
};
},
- canInteractWithEmoji(awardList, awardName) {
- let isAllowed = true;
- const restrictedEmojis = ['thumbsup', 'thumbsdown'];
-
- // Users can not add :+1: and :-1: to their own notes
- if (
- this.getUserData.id === this.noteAuthorId &&
- restrictedEmojis.indexOf(awardName) > -1
- ) {
- isAllowed = false;
- }
-
- return this.getUserData.id && isAllowed;
+ canInteractWithEmoji() {
+ return this.getUserData.id;
},
hasReactionByCurrentUser(awardList) {
- return awardList.filter(award => award.user.id === this.getUserData.id)
- .length;
+ return awardList.filter(award => award.user.id === this.getUserData.id).length;
},
awardTitle(awardsList) {
const hasReactionByCurrentUser = this.hasReactionByCurrentUser(
@@ -197,7 +185,7 @@ export default {
v-tooltip
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
- :class="getAwardClassBindings(awardList, awardName)"
+ :class="getAwardClassBindings(awardList)"
:title="awardTitle(awardList)"
class="btn award-control"
data-boundary="viewport"
diff --git a/app/assets/javascripts/pages/groups/milestones/show/index.js b/app/assets/javascripts/pages/groups/milestones/show/index.js
index 74cc4ba42c1..ebaea5ef3dc 100644
--- a/app/assets/javascripts/pages/groups/milestones/show/index.js
+++ b/app/assets/javascripts/pages/groups/milestones/show/index.js
@@ -1,8 +1,10 @@
import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show';
+import initDeleteMilestoneModal from '~/pages/milestones/shared/delete_milestone_modal_init';
+
import Milestone from '~/milestone';
document.addEventListener('DOMContentLoaded', () => {
initMilestonesShow();
-
+ initDeleteMilestoneModal();
Milestone.initDeprecationMessage();
});
diff --git a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
index 4061c11ba8f..48668562f09 100644
--- a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
+++ b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
@@ -40,8 +40,8 @@
if (this.issueCount === 0 && this.mergeRequestCount === 0) {
return sprintf(
s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle} from this project.
-%{milestoneTitle} is not currently used in any issues or merge requests.`),
+You’re about to permanently delete the milestone %{milestoneTitle}.
+This milestone is not currently used in any issues or merge requests.`),
{
milestoneTitle,
},
@@ -51,7 +51,7 @@ You’re about to permanently delete the milestone %{milestoneTitle} from this p
return sprintf(
s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle} from this project and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
+You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
Once deleted, it cannot be undone or recovered.`),
{
milestoneTitle,
diff --git a/app/assets/javascripts/pages/profiles/show/index.js b/app/assets/javascripts/pages/profiles/show/index.js
index 949219a0837..aea7b649c20 100644
--- a/app/assets/javascripts/pages/profiles/show/index.js
+++ b/app/assets/javascripts/pages/profiles/show/index.js
@@ -3,15 +3,22 @@ import createFlash from '~/flash';
import GfmAutoComplete from '~/gfm_auto_complete';
import EmojiMenu from './emoji_menu';
+const defaultStatusEmoji = 'speech_balloon';
+
document.addEventListener('DOMContentLoaded', () => {
const toggleEmojiMenuButtonSelector = '.js-toggle-emoji-menu';
const toggleEmojiMenuButton = document.querySelector(toggleEmojiMenuButtonSelector);
const statusEmojiField = document.getElementById('js-status-emoji-field');
const statusMessageField = document.getElementById('js-status-message-field');
- const findNoEmojiPlaceholder = () => document.getElementById('js-no-emoji-placeholder');
+ const toggleNoEmojiPlaceholder = (isVisible) => {
+ const placeholderElement = document.getElementById('js-no-emoji-placeholder');
+ placeholderElement.classList.toggle('hidden', !isVisible);
+ };
+
+ const findStatusEmoji = () => toggleEmojiMenuButton.querySelector('gl-emoji');
const removeStatusEmoji = () => {
- const statusEmoji = toggleEmojiMenuButton.querySelector('gl-emoji');
+ const statusEmoji = findStatusEmoji();
if (statusEmoji) {
statusEmoji.remove();
}
@@ -19,7 +26,7 @@ document.addEventListener('DOMContentLoaded', () => {
const selectEmojiCallback = (emoji, emojiTag) => {
statusEmojiField.value = emoji;
- findNoEmojiPlaceholder().classList.add('hidden');
+ toggleNoEmojiPlaceholder(false);
removeStatusEmoji();
toggleEmojiMenuButton.innerHTML += emojiTag;
};
@@ -29,7 +36,7 @@ document.addEventListener('DOMContentLoaded', () => {
statusEmojiField.value = '';
statusMessageField.value = '';
removeStatusEmoji();
- findNoEmojiPlaceholder().classList.remove('hidden');
+ toggleNoEmojiPlaceholder(true);
});
const emojiAutocomplete = new GfmAutoComplete();
@@ -44,6 +51,23 @@ document.addEventListener('DOMContentLoaded', () => {
selectEmojiCallback,
);
emojiMenu.bindEvents();
+
+ const defaultEmojiTag = Emoji.glEmojiTag(defaultStatusEmoji);
+ statusMessageField.addEventListener('input', () => {
+ const hasStatusMessage = statusMessageField.value.trim() !== '';
+ const statusEmoji = findStatusEmoji();
+ if (hasStatusMessage && statusEmoji) {
+ return;
+ }
+
+ if (hasStatusMessage) {
+ toggleNoEmojiPlaceholder(false);
+ toggleEmojiMenuButton.innerHTML += defaultEmojiTag;
+ } else if (statusEmoji.dataset.name === defaultStatusEmoji) {
+ toggleNoEmojiPlaceholder(true);
+ removeStatusEmoji();
+ }
+ });
})
.catch(() => createFlash('Failed to load emoji list!'));
});
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 41880d27516..6e5ef0ac0b2 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -1,5 +1,4 @@
import Vue from 'vue';
-import Flash from '../flash';
import PerformanceBarService from './services/performance_bar_service';
import PerformanceBarStore from './stores/performance_bar_store';
@@ -46,7 +45,8 @@ export default ({ container }) =>
this.store.addRequestDetails(requestId, res.data.data);
})
.catch(() =>
- Flash(`Error getting performance bar results for ${requestId}`),
+ // eslint-disable-next-line no-console
+ console.warn(`Error getting performance bar results for ${requestId}`),
);
},
},
diff --git a/app/assets/javascripts/performance_bar/services/performance_bar_service.js b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
index bc71911ae35..60d9ba62570 100644
--- a/app/assets/javascripts/performance_bar/services/performance_bar_service.js
+++ b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
@@ -11,13 +11,10 @@ export default class PerformanceBarService {
static registerInterceptor(peekUrl, callback) {
const interceptor = response => {
- const requestId = response.headers['x-request-id'];
- // Get the request URL from response.config for Axios, and response for
- // Vue Resource.
- const requestUrl = (response.config || response).url;
- const cachedResponse = response.headers['x-gitlab-from-cache'] === 'true';
+ const [fireCallback, requestId, requestUrl] =
+ PerformanceBarService.callbackParams(response, peekUrl);
- if (requestUrl !== peekUrl && requestId && !cachedResponse) {
+ if (fireCallback) {
callback(requestId, requestUrl);
}
@@ -38,4 +35,16 @@ export default class PerformanceBarService {
vueResourceInterceptor,
);
}
+
+ static callbackParams(response, peekUrl) {
+ const requestId = response.headers && response.headers['x-request-id'];
+ // Get the request URL from response.config for Axios, and response for
+ // Vue Resource.
+ const requestUrl = (response.config || response).url;
+ const apiRequest = requestUrl && requestUrl.match(/^\/api\//);
+ const cachedResponse = response.headers && response.headers['x-gitlab-from-cache'] === 'true';
+ const fireCallback = requestUrl !== peekUrl && requestId && !apiRequest && !cachedResponse;
+
+ return [fireCallback, requestId, requestUrl];
+ }
}
diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
index 8487c8036ee..2ad66f4fe86 100644
--- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
@@ -1,6 +1,5 @@
<script>
import $ from 'jquery';
-import _ from 'underscore';
import JobNameComponent from './job_name_component.vue';
import JobComponent from './job_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
@@ -47,7 +46,7 @@ export default {
computed: {
tooltipText() {
- return _.escape(`${this.job.name} - ${this.job.status.label}`);
+ return `${this.job.name} - ${this.job.status.label}`;
},
},
diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue
index 66f95147193..9ac16b7e541 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue
@@ -1,5 +1,4 @@
<script>
-import _ from 'underscore';
import ActionComponent from './action_component.vue';
import JobNameComponent from './job_name_component.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
@@ -62,7 +61,7 @@ export default {
const textBuilder = [];
if (this.job.name) {
- textBuilder.push(_.escape(this.job.name));
+ textBuilder.push(this.job.name);
}
if (this.job.name && this.status.tooltip) {
@@ -106,7 +105,6 @@ export default {
:class="cssClassJobName"
:data-boundary="tooltipBoundary"
data-container="body"
- data-html="true"
class="js-pipeline-graph-job-link"
>
@@ -122,7 +120,6 @@ export default {
:title="tooltipText"
:class="cssClassJobName"
class="js-job-component-tooltip non-details-job-component"
- data-html="true"
data-container="body"
>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
index 804822a3ea8..29b347824de 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
@@ -330,7 +330,7 @@ export default {
<pipelines-artifacts-component
v-if="pipeline.details.artifacts.length"
:artifacts="pipeline.details.artifacts"
- class="d-none d-sm-none d-md-block"
+ class="d-md-block"
/>
<loading-button
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index 21f21232596..d530ab2767b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -1,5 +1,6 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import timeagoMixin from '../../vue_shared/mixins/timeago';
import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
@@ -16,6 +17,7 @@ export default {
MemoryUsage,
StatusIcon,
Icon,
+ TooltipOnTruncate,
},
directives: {
tooltip,
@@ -88,14 +90,20 @@ export default {
<span>
Deployed to
</span>
- <a
- :href="deployment.url"
- target="_blank"
- rel="noopener noreferrer nofollow"
- class="deploy-link js-deploy-meta"
+ <tooltip-on-truncate
+ :title="deployment.name"
+ truncate-target="child"
+ class="deploy-link label-truncate"
>
- {{ deployment.name }}
- </a>
+ <a
+ :href="deployment.url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="js-deploy-meta"
+ >
+ {{ deployment.name }}
+ </a>
+ </tooltip-on-truncate>
</template>
<span
v-tooltip
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index a4c2289c590..72bd28ae03f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -1,18 +1,17 @@
<script>
-import tooltip from '~/vue_shared/directives/tooltip';
-import { n__ } from '~/locale';
+import _ from 'underscore';
+import { n__, s__, sprintf } from '~/locale';
import { mergeUrlParams, webIDEUrl } from '~/lib/utils/url_utility';
import Icon from '~/vue_shared/components/icon.vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
export default {
name: 'MRWidgetHeader',
- directives: {
- tooltip,
- },
components: {
Icon,
clipboardButton,
+ TooltipOnTruncate,
},
props: {
mr: {
@@ -24,8 +23,12 @@ export default {
shouldShowCommitsBehindText() {
return this.mr.divergedCommitsCount > 0;
},
- commitsText() {
- return n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount);
+ commitsBehindText() {
+ return sprintf(s__('mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch'), {
+ commitsBehindLinkStart: `<a href="${_.escape(this.mr.targetBranchPath)}">`,
+ commitsBehind: n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount),
+ commitsBehindLinkEnd: '</a>',
+ }, false);
},
branchNameClipboardData() {
// This supports code in app/assets/javascripts/copy_to_clipboard.js that
@@ -36,12 +39,6 @@ export default {
gfm: `\`${this.mr.sourceBranch}\``,
});
},
- isSourceBranchLong() {
- return this.isBranchTitleLong(this.mr.sourceBranch);
- },
- isTargetBranchLong() {
- return this.isBranchTitleLong(this.mr.targetBranch);
- },
webIdePath() {
return mergeUrlParams({
target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
@@ -49,11 +46,6 @@ export default {
}, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
},
},
- methods: {
- isBranchTitleLong(branchTitle) {
- return branchTitle.length > 32;
- },
- },
};
</script>
<template>
@@ -65,30 +57,21 @@ export default {
<div class="normal">
<strong>
{{ s__("mrWidget|Request to merge") }}
- <span
- :class="{ 'label-truncated': isSourceBranchLong }"
- :title="isSourceBranchLong ? mr.sourceBranch : ''"
- :v-tooltip="isSourceBranchLong"
- class="label-branch js-source-branch"
- data-placement="bottom"
+ <tooltip-on-truncate
+ :title="mr.sourceBranch"
+ truncate-target="child"
+ class="label-branch label-truncate js-source-branch"
v-html="mr.sourceBranchLink"
- >
- </span>
-
- <clipboard-button
+ /><clipboard-button
:text="branchNameClipboardData"
:title="__('Copy branch name to clipboard')"
css-class="btn-default btn-transparent btn-clipboard"
/>
-
{{ s__("mrWidget|into") }}
-
- <span
- :v-tooltip="isTargetBranchLong"
- :class="{ 'label-truncatedtooltip': isTargetBranchLong }"
- :title="isTargetBranchLong ? mr.targetBranch : ''"
- class="label-branch"
- data-placement="bottom"
+ <tooltip-on-truncate
+ :title="mr.targetBranch"
+ truncate-target="child"
+ class="label-branch label-truncate"
>
<a
:href="mr.targetBranchTreePath"
@@ -96,15 +79,13 @@ export default {
>
{{ mr.targetBranch }}
</a>
- </span>
+ </tooltip-on-truncate>
</strong>
<div
v-if="shouldShowCommitsBehindText"
class="diverged-commits-count"
+ v-html="commitsBehindText"
>
- <span class="monospace">{{ mr.sourceBranch }}</span>
- is {{ commitsText }}
- <span class="monospace">{{ mr.targetBranch }}</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index 4a3fd01fa39..fee41b239e8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -3,6 +3,7 @@
import PipelineStage from '~/pipelines/components/stage.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
export default {
name: 'MRWidgetPipeline',
@@ -10,6 +11,7 @@ export default {
PipelineStage,
CiIcon,
Icon,
+ TooltipOnTruncate,
},
props: {
pipeline: {
@@ -30,6 +32,10 @@ export default {
type: String,
required: false,
},
+ sourceBranch: {
+ type: String,
+ required: false,
+ },
},
computed: {
hasPipeline() {
@@ -107,11 +113,12 @@ export default {
>
{{ pipeline.commit.short_id }}</a>
on
- <span
- class="label-branch"
+ <tooltip-on-truncate
+ :title="sourceBranch"
+ truncate-target="child"
+ class="label-branch label-truncate"
v-html="sourceBranchLink"
- >
- </span>
+ />
</template>
</div>
<div
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 80593d1f34a..dc6be025f11 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -254,6 +254,7 @@ export default {
:pipeline="mr.pipeline"
:ci-status="mr.ciStatus"
:has-ci="mr.hasCI"
+ :source-branch="mr.sourceBranch"
:source-branch-link="mr.sourceBranchLink"
/>
<deployment
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index f44d361c47e..78fde463507 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -71,7 +71,11 @@ export default {
},
methods: {
getPercent(count) {
- return roundOffFloat((count / this.totalCount) * 100, 1);
+ const percent = roundOffFloat((count / this.totalCount) * 100, 1);
+ if (percent > 0 && percent < 1) {
+ return '< 1';
+ }
+ return percent;
},
barStyle(percent) {
return `width: ${percent}%;`;
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
new file mode 100644
index 00000000000..125826da6c3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
@@ -0,0 +1,67 @@
+<script>
+import _ from 'underscore';
+import tooltip from '../directives/tooltip';
+
+export default {
+ directives: {
+ tooltip,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ placement: {
+ type: String,
+ required: false,
+ default: 'top',
+ },
+ truncateTarget: {
+ type: [String, Function],
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ showTooltip: false,
+ };
+ },
+ mounted() {
+ const target = this.selectTarget();
+
+ if (target && target.scrollWidth > target.offsetWidth) {
+ this.showTooltip = true;
+ }
+ },
+ methods: {
+ selectTarget() {
+ if (_.isFunction(this.truncateTarget)) {
+ return this.truncateTarget(this.$el);
+ } else if (this.truncateTarget === 'child') {
+ return this.$el.childNodes[0];
+ }
+
+ return this.$el;
+ },
+ },
+};
+</script>
+
+<template>
+ <span
+ v-tooltip
+ v-if="showTooltip"
+ :title="title"
+ :data-placement="placement"
+ class="js-show-tooltip"
+ >
+ <slot></slot>
+ </span>
+ <span
+ v-else
+ >
+ <slot></slot>
+ </span>
+</template>
diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss
index e8e707cf90c..c91f5e279ea 100644
--- a/app/assets/stylesheets/bootstrap_migration.scss
+++ b/app/assets/stylesheets/bootstrap_migration.scss
@@ -4,11 +4,11 @@
$text-color: $gl-text-color;
-$brand-primary: $gl-primary;
-$brand-success: $gl-success;
-$brand-info: $gl-info;
-$brand-warning: $gl-warning;
-$brand-danger: $gl-danger;
+$brand-primary: $blue-500;
+$brand-success: $green-500;
+$brand-info: $blue-500;
+$brand-warning: $orange-500;
+$brand-danger: $red-500;
$border-radius-base: 3px !default;
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 4c7c399a3ca..9dd0384a228 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -8,7 +8,7 @@
float: left;
margin-right: 15px;
border-radius: $avatar-radius;
- border: 1px solid $avatar-border;
+ border: 1px solid $gray-normal;
&.s16 { @include avatar-size(16px, 6px); }
&.s18 { @include avatar-size(18px, 6px); }
&.s19 { @include avatar-size(19px, 6px); }
@@ -36,7 +36,7 @@
width: 40px;
height: 40px;
padding: 0;
- background: $avatar-background;
+ background: $gray-lightest;
overflow: hidden;
&.avatar-inline {
@@ -62,7 +62,7 @@
}
&:not([href]):hover {
- border-color: darken($avatar-border, 10%);
+ border-color: darken($gray-normal, 10%);
}
}
@@ -70,7 +70,7 @@
text-align: center;
vertical-align: top;
color: $identicon-fg-color;
- background-color: $identicon-gray;
+ background-color: $gray-darker;
// Sizes
&.s16 { font-size: 12px; line-height: 1.33; }
@@ -94,7 +94,7 @@
&.bg4 { background-color: $identicon-blue; }
&.bg5 { background-color: $identicon-teal; }
&.bg6 { background-color: $identicon-orange; }
- &.bg7 { background-color: $identicon-gray; }
+ &.bg7 { background-color: $gray-darker; }
}
.avatar-container {
@@ -122,7 +122,7 @@
.avatar-counter {
background-color: $gray-darkest;
color: $white-light;
- border: 1px solid $avatar-border;
+ border: 1px solid $gray-normal;
border-radius: 1em;
font-family: $regular-font;
font-size: 9px;
diff --git a/app/assets/stylesheets/framework/badges.scss b/app/assets/stylesheets/framework/badges.scss
index 57df9b969c3..c6060161dec 100644
--- a/app/assets/stylesheets/framework/badges.scss
+++ b/app/assets/stylesheets/framework/badges.scss
@@ -1,6 +1,6 @@
.badge.badge-pill {
font-weight: $gl-font-weight-normal;
background-color: $badge-bg;
- color: $badge-color;
+ color: $gl-text-color-secondary;
vertical-align: baseline;
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 0dc7aa4ef68..72b4ed0ac33 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -452,14 +452,14 @@
}
.btn-missing {
- color: $notes-light-color;
+ color: $gl-text-color-secondary;
border: 1px dashed $border-gray-normal-dashed;
border-radius: $border-radius-default;
&:hover,
&:active,
&:focus {
- color: $notes-light-color;
+ color: $gl-text-color-secondary;
background-color: $white-normal;
}
}
diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss
index 1bd94c0acba..bdd7f09d926 100644
--- a/app/assets/stylesheets/framework/callout.scss
+++ b/app/assets/stylesheets/framework/callout.scss
@@ -25,25 +25,25 @@
/* Variations */
.bs-callout-danger {
- background-color: $callout-danger-bg;
- border-color: $callout-danger-border;
- color: $callout-danger-color;
+ background-color: $red-100;
+ border-color: $red-200;
+ color: $red-700;
}
.bs-callout-warning {
- background-color: $callout-warning-bg;
- border-color: $callout-warning-border;
- color: $callout-warning-color;
+ background-color: $orange-100;
+ border-color: $orange-200;
+ color: $orange-700;
}
.bs-callout-info {
- background-color: $callout-info-bg;
- border-color: $callout-info-border;
- color: $callout-info-color;
+ background-color: $blue-100;
+ border-color: $blue-200;
+ color: $blue-700;
}
.bs-callout-success {
- background-color: $callout-success-bg;
- border-color: $callout-success-border;
- color: $callout-success-color;
+ background-color: $green-100;
+ border-color: $green-200;
+ color: $green-700;
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 79ca6e61e9a..72e27f9ad16 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -1,8 +1,8 @@
/** COLORS **/
-.cgray { color: $common-gray; }
+.cgray { color: $gl-text-color; }
.clgray { color: $common-gray-light; }
-.cred { color: $common-red; }
-.cgreen { color: $common-green; }
+.cred { color: $red-500; }
+.cgreen { color: $green-600; }
.cdark { color: $common-gray-dark; }
.text-plain,
@@ -44,10 +44,10 @@
}
.hint { font-style: italic; color: $hint-color; }
-.light { color: $common-gray; }
+.light { color: $gl-text-color; }
.slead {
- color: $common-gray;
+ color: $gl-text-color;
font-size: 14px;
margin-bottom: 12px;
font-weight: $gl-font-weight-normal;
@@ -352,7 +352,7 @@ img.emoji {
border-color: $border-color !important;
.dz-upload {
- background: $gl-success !important;
+ background: $green-500 !important;
}
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 83bc3776178..8a224dc517e 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -147,7 +147,7 @@
}
@mixin dropdown-item-hover {
- background-color: $dropdown-item-hover-bg;
+ background-color: $gray-darker;
color: $gl-text-color;
outline: 0;
@@ -195,7 +195,7 @@
text-decoration: none;
.badge.badge-pill {
- background-color: darken($dropdown-link-hover-bg, 5%);
+ background-color: darken($blue-50, 5%);
}
}
@@ -233,7 +233,7 @@
font-weight: $gl-font-weight-normal;
padding: 8px 0;
background-color: $white-light;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
@@ -874,7 +874,7 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
overflow-y: auto;
li.section-empty.section-failure {
- color: $callout-danger-color;
+ color: $red-700;
}
.frequent-items-list-item-container a {
diff --git a/app/assets/stylesheets/framework/feature_highlight.scss b/app/assets/stylesheets/framework/feature_highlight.scss
index cad915bc86f..85cabf43e9e 100644
--- a/app/assets/stylesheets/framework/feature_highlight.scss
+++ b/app/assets/stylesheets/framework/feature_highlight.scss
@@ -72,11 +72,11 @@
.feature-highlight-popover {
width: 240px;
padding: 0;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
box-shadow: 0 2px 4px $dropdown-shadow-color;
&.right > .arrow {
- border-right-color: $dropdown-border-color;
+ border-right-color: $border-color;
}
.popover-body {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 3bdf5bfc93a..1d3512bbb4c 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -312,11 +312,11 @@ span.idiff {
text-decoration: none;
.new-file {
- color: $notify-new-file;
+ color: $green-600;
}
.deleted-file {
- color: $notify-deleted-file;
+ color: $red-700;
}
}
}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 9b09ed0ed0a..abfe350677e 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -206,7 +206,7 @@
&.focus,
&.focus:hover {
border-color: $blue-300;
- box-shadow: 0 0 4px $search-input-focus-shadow-color;
+ box-shadow: 0 0 4px $dropdown-input-focus-shadow;
}
gl-emoji {
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index a70eece8f68..afd888af672 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -8,7 +8,7 @@ input {
input[type='text'].danger {
background: $input-danger-bg !important;
- border-color: $input-danger-border;
+ border-color: $red-400;
text-shadow: 0 1px 1px $white-light;
}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index e7e13d35d8e..11a30d83f03 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -554,7 +554,7 @@
float: left;
margin-right: 5px;
border-radius: 50%;
- border: 1px solid $avatar-border;
+ border: 1px solid $gray-normal;
}
.with-performance-bar .navbar-gitlab {
diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index d1f7ff4438b..f002edced8a 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -11,7 +11,7 @@
.ci-status-icon-failed {
svg {
- fill: $gl-danger;
+ fill: $red-500;
}
&.add-border {
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index da5f80d9d37..2d672e62e08 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -26,12 +26,12 @@
&.status-box-closed,
&.status-box-mr-closed {
- background-color: $gl-danger;
+ background-color: $red-500;
}
&.status-box-issue-closed,
&.status-box-mr-merged {
- background-color: $gl-primary;
+ background-color: $blue-500;
}
&.status-box-open {
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 88d2f0aaf85..3ae2c7078d6 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -58,7 +58,7 @@
.select2-drop.select2-drop-above {
box-shadow: 0 2px 4px $dropdown-shadow-color;
border-radius: $border-radius-base;
- border: 1px solid $dropdown-border-color;
+ border: 1px solid $border-color;
min-width: 175px;
color: $gl-text-color;
z-index: 999;
@@ -69,7 +69,7 @@
}
.select2-drop.select2-drop-above.select2-drop-active {
- border-top: 1px solid $dropdown-border-color;
+ border-top: 1px solid $border-color;
margin-top: -6px;
}
@@ -193,7 +193,7 @@
color: $gl-text-color;
.select2-result-label {
- background: $dropdown-item-hover-bg;
+ background: $gray-darker;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 96508a71bd8..2781d910b8d 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -297,19 +297,9 @@ $tanuki-yellow: #fca326;
/*
* State colors:
*/
-$gl-primary: $blue-500;
-$gl-success: $green-500;
-$gl-success-focus: rgba($gl-success, 0.4);
-$gl-info: $blue-500;
-$gl-warning: $orange-500;
-$gl-danger: $red-500;
+$green-500-focus: rgba($green-500, 0.4);
$gl-btn-active-background: rgba(0, 0, 0, 0.16);
$gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background;
-// Bootstrap override states
-$success: $gl-success;
-$info: $gl-info;
-$warning: $gl-warning;
-$danger: $gl-danger;
/*
* Commit Diff Colors
@@ -329,10 +319,9 @@ $line-select-yellow-dark: #f0e2bd;
$dark-diff-match-bg: rgba(255, 255, 255, 0.3);
$dark-diff-match-color: rgba(255, 255, 255, 0.1);
$file-mode-changed: #777;
-$file-mode-changed: #777;
-$diff-image-info-color: grey;
+$diff-image-info-color: gray;
$diff-swipe-border: #999;
-$diff-view-modes-color: grey;
+$diff-view-modes-color: gray;
$diff-view-modes-border: #c1c1c1;
$diff-jagged-border-gradient-color: darken($white-normal, 8%);
@@ -352,9 +341,7 @@ $dropdown-min-height: 40px;
$dropdown-max-height: 312px;
$dropdown-vertical-offset: 4px;
$dropdown-link-color: #555;
-$dropdown-link-hover-bg: $blue-50;
$dropdown-empty-row-bg: rgba(#000, 0.04);
-$dropdown-border-color: $border-color;
$dropdown-shadow-color: rgba(#000, 0.1);
$dropdown-divider-color: rgba(#000, 0.1);
$dropdown-title-btn-color: #bfbfbf;
@@ -364,7 +351,6 @@ $dropdown-input-focus-shadow: rgba($blue-300, 0.4);
$dropdown-loading-bg: rgba(#fff, 0.6);
$dropdown-chevron-size: 10px;
$dropdown-toggle-active-border-color: darken($border-color, 14%);
-$dropdown-item-hover-bg: $gray-darker;
$dropdown-fade-mask-height: 32px;
$dropdown-member-form-control-width: 163px;
@@ -372,7 +358,6 @@ $dropdown-member-form-control-width: 163px;
* Filtered Search
*/
$filtered-search-term-shadow-color: rgba(0, 0, 0, 0.09);
-$dropdown-hover-color: $blue-400;
/*
* Contextual Sidebar
@@ -387,7 +372,7 @@ $sidebar-milestone-toggle-bottom-margin: 10px;
* Buttons
*/
$btn-active-gray: #ececec;
-$btn-active-gray-light: e4e7ed;
+$btn-active-gray-light: #e4e7ed;
$btn-white-active: #848484;
$gl-btn-padding: 10px;
$gl-btn-line-height: 16px;
@@ -398,7 +383,6 @@ $gl-btn-horz-padding: 12px;
* Badges
*/
$badge-bg: rgba(0, 0, 0, 0.07);
-$badge-color: $gl-text-color-secondary;
/*
* Pagination
@@ -406,21 +390,12 @@ $badge-color: $gl-text-color-secondary;
$pagination-padding-y: 6px;
$pagination-padding-x: 16px;
$pagination-line-height: 20px;
-$pagination-border-color: $border-color;
-$pagination-active-bg: $blue-600;
-$pagination-active-border-color: $blue-600;
-$pagination-hover-bg: $blue-50;
-$pagination-hover-border-color: $border-color;
-$pagination-hover-color: $gl-text-color;
$pagination-disabled-color: #cdcdcd;
-$pagination-disabled-bg: $gray-light;
-$pagination-disabled-border-color: $border-color;
/*
* Status icons
*/
$status-icon-size: 22px;
-$status-icon-margin: $gl-btn-padding;
/*
* Award emoji
@@ -433,16 +408,13 @@ $award-emoji-positive-add-lines: #bb9c13;
* Search Box
*/
$search-input-border-color: rgba($blue-400, 0.8);
-$search-input-focus-shadow-color: $dropdown-input-focus-shadow;
$search-input-width: 240px;
$search-input-active-width: 320px;
-$location-badge-active-bg: $blue-500;
$location-icon-color: #e7e9ed;
/*
* Notes
*/
-$notes-light-color: $gl-text-color-secondary;
$note-disabled-comment-color: #b2b2b2;
$note-targe3-outside: #fffff0;
$note-targe3-inside: #ffffd3;
@@ -463,7 +435,6 @@ $identicon-indigo: #e8eaf6;
$identicon-blue: #e3f2fd;
$identicon-teal: #e0f2f1;
$identicon-orange: #fbe9e7;
-$identicon-gray: $gray-darker;
$identicon-fg-color: #555555;
/*
@@ -479,7 +450,6 @@ $calendar-user-contrib-text: #959494;
$cycle-analytics-box-padding: 30px;
$cycle-analytics-box-text-color: #8c8c8c;
$cycle-analytics-big-font: 19px;
-$cycle-analytics-dark-text: $gl-text-color;
$cycle-analytics-light-gray: #bfbfbf;
$cycle-analytics-dismiss-icon-color: #b2b2b2;
@@ -507,9 +477,6 @@ $issue-board-list-difference-md: $issue-board-list-difference-sm + $issue-boards
* Avatar
*/
$avatar-radius: 50%;
-$avatar-border: $gray-normal;
-$avatar-border-hover: $gray-darker;
-$avatar-background: $gray-lightest;
$gl-avatar-size: 40px;
/*
@@ -525,22 +492,6 @@ $blame-blue: #254e77;
$builds-trace-bg: #111;
/*
-* Callout
-*/
-$callout-danger-bg: $red-100;
-$callout-danger-border: $red-200;
-$callout-danger-color: $red-700;
-$callout-warning-bg: $orange-100;
-$callout-warning-border: $orange-200;
-$callout-warning-color: $orange-700;
-$callout-info-bg: $blue-100;
-$callout-info-border: $blue-200;
-$callout-info-color: $blue-700;
-$callout-success-bg: $green-100;
-$callout-success-border: $green-200;
-$callout-success-color: $green-700;
-
-/*
* Commit Page
*/
$commit-max-width-marker-color: rgba(0, 0, 0, 0);
@@ -549,16 +500,8 @@ $commit-message-text-area-bg: rgba(0, 0, 0, 0);
/*
* Common
*/
-$common-gray: $gl-text-color;
$common-gray-light: #bbb;
$common-gray-dark: #444;
-$common-red: $red-500;
-$common-green: $green-600;
-
-/*
-* Editor
-*/
-$editor-cancel-color: $red-600;
/*
* Events
@@ -579,7 +522,6 @@ $logs-p-color: #333;
*/
$input-height: 34px;
$input-danger-bg: #f2dede;
-$input-danger-border: $red-400;
$input-group-addon-bg: #f7f8fa;
$gl-field-focus-shadow: rgba(0, 0, 0, 0.075);
$gl-field-focus-shadow-error: rgba($red-500, 0.6);
@@ -626,16 +568,9 @@ $fade-mask-transition-duration: 0.1s;
$fade-mask-transition-curve: ease-in-out;
/*
-* Lint
-*/
-$lint-incorrect-color: $red-500;
-$lint-correct-color: $green-500;
-
-/*
* Login
*/
$login-brand-holder-color: #888;
-$login-devise-error-color: $red-700;
/*
* Nav
@@ -648,15 +583,12 @@ $nav-toggle-gray: #666;
*/
$notify-details: #777;
$notify-footer: #777;
-$notify-new-file: $green-600;
-$notify-deleted-file: $red-700;
/*
* Projects
*/
$project-option-descr-color: #54565b;
$project-breadcrumb-color: #999;
-$project-private-forks-notice-odd: $green-600;
$project-network-controls-color: #888;
$feature-toggle-color: #fff;
@@ -665,21 +597,10 @@ $feature-toggle-color-disabled: #999;
$feature-toggle-color-enabled: #4a8bee;
/*
-* Runners
-*/
-$runner-state-shared-bg: $green-400;
-$runner-state-specific-bg: $blue-400;
-$runner-status-online-color: $green-600;
-$runner-status-offline-color: $gray-darkest;
-$runner-status-paused-color: $red-500;
-
-/*
Stat Graph
*/
$stat-graph-common-bg: #f3f3f3;
-$stat-graph-area-fill: $green-500;
$stat-graph-axis-fill: #aaa;
-$stat-graph-orange-fill: $orange-500;
$stat-graph-selection-fill: #333;
$stat-graph-selection-stroke: #333;
@@ -692,7 +613,6 @@ $select2-drop-shadow2: rgba(31, 37, 50, 0.317647);
/*
* Todo
*/
-$todo-alert-blue: $blue-500;
$todo-body-pre-color: #777;
$todo-body-border: #ddd;
@@ -715,7 +635,6 @@ $ui-dev-kit-example-border: #ddd;
/*
Pipeline Graph
*/
-$stage-hover-bg: $gray-darker;
$ci-action-icon-size: 22px;
$ci-action-icon-size-lg: 24px;
$pipeline-dropdown-line-height: 20px;
@@ -743,13 +662,6 @@ Animation Functions
$dropdown-animation-timing: cubic-bezier(0.23, 1, 0.32, 1);
/*
-Convdev Index
-*/
-$color-high-score: $green-400;
-$color-average-score: $orange-400;
-$color-low-score: $red-400;
-
-/*
Performance Bar
*/
$perf-bar-text: #999;
@@ -790,9 +702,5 @@ Modals
*/
$modal-body-height: 134px;
-/*
-Prometheus
-*/
-$prometheus-table-row-highlight-color: $theme-gray-100;
$priority-label-empty-state-width: 114px;
diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss
index b9c343fa2e9..7d90452e1f4 100644
--- a/app/assets/stylesheets/framework/variables_overrides.scss
+++ b/app/assets/stylesheets/framework/variables_overrides.scss
@@ -14,3 +14,7 @@ $btn-line-height: 20px;
$table-accent-bg: $gray-light;
$card-border-color: $border-color;
$card-cap-bg: $gray-light;
+$success: $green-500;
+$info: $blue-500;
+$warning: $orange-500;
+$danger: $red-500;
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 1696d18584d..14ba8b1df83 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -397,7 +397,7 @@
}
&:hover {
- background-color: $dropdown-item-hover-bg;
+ background-color: $gray-darker;
}
.icon-retry {
diff --git a/app/assets/stylesheets/pages/convdev_index.scss b/app/assets/stylesheets/pages/convdev_index.scss
index bd338326154..52fcdf4a405 100644
--- a/app/assets/stylesheets/pages/convdev_index.scss
+++ b/app/assets/stylesheets/pages/convdev_index.scss
@@ -80,7 +80,7 @@ $space-between-cards: 8px;
}
.convdev-card-low {
- border-top-color: $color-low-score;
+ border-top-color: $red-400;
.board-card-score-big {
background-color: $red-50;
@@ -88,7 +88,7 @@ $space-between-cards: 8px;
}
.convdev-card-average {
- border-top-color: $color-average-score;
+ border-top-color: $orange-400;
.board-card-score-big {
background-color: $orange-50;
@@ -96,7 +96,7 @@ $space-between-cards: 8px;
}
.convdev-card-high {
- border-top-color: $color-high-score;
+ border-top-color: $green-400;
.board-card-score-big {
background-color: $green-50;
@@ -243,13 +243,13 @@ $space-between-cards: 8px;
}
.convdev-high-score {
- color: $color-high-score;
+ color: $green-400;
}
.convdev-average-score {
- color: $color-average-score;
+ color: $orange-400;
}
.convdev-low-score {
- color: $color-low-score;
+ color: $red-400;
}
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index bc4c90711d7..f0228768b5a 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -285,7 +285,7 @@
.total-time {
font-size: $cycle-analytics-big-font;
- color: $cycle-analytics-dark-text;
+ color: $gl-text-color;
span {
color: $gl-text-color;
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 892da152b5f..04570c057d1 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -23,10 +23,10 @@
}
.cancel-btn {
- color: $editor-cancel-color;
+ color: $red-600;
&:hover {
- color: $editor-cancel-color;
+ color: $red-600;
}
}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 179c0964567..196f6ae6d8c 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -501,5 +501,5 @@
}
.prometheus-table-row-highlight {
- background-color: $prometheus-table-row-highlight-color;
+ background-color: $theme-gray-100;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 6f0f82964c8..9ac47a771a5 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -144,7 +144,7 @@
color: $blue-800;
.avatar {
- border-color: rgba($avatar-border, .2);
+ border-color: rgba($gray-normal, .2);
}
}
@@ -231,7 +231,7 @@
}
a.edit-link:not([href]):hover {
- color: rgba($avatar-border, .2);
+ color: rgba($gray-normal, .2);
}
.lock-edit, // uses same style, different js behaviour
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index d32943fceec..d2b9470be69 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -67,7 +67,7 @@
.dropdown-labels-error {
padding: 5px 10px;
margin-bottom: 10px;
- background-color: $gl-danger;
+ background-color: $red-500;
color: $white-light;
}
@@ -117,7 +117,7 @@
color: $blue-600;
&.remove-row {
- color: $gl-danger;
+ color: $red-500;
}
}
}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 8a4a2caa6c9..c9e5fb9c579 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -186,7 +186,7 @@
h2 {
margin-top: 0;
font-size: 14px;
- color: $login-devise-error-color;
+ color: $red-700;
}
}
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 621321101cd..7b8cad254c7 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -195,12 +195,13 @@
.ci-widget-content {
display: flex;
align-items: center;
+ flex: 1;
}
}
.mr-widget-icon {
font-size: 22px;
- margin-right: $status-icon-margin;
+ margin-right: $gl-btn-padding;
}
.ci-status-icon svg {
@@ -222,6 +223,7 @@
.normal {
flex: 1;
+ flex-basis: auto;
}
.capitalize {
@@ -235,22 +237,23 @@
font-weight: normal;
overflow: hidden;
word-break: break-all;
+ }
- &.label-truncated {
- position: relative;
- display: inline-block;
- width: 250px;
- margin-bottom: -3px;
- white-space: nowrap;
- text-overflow: clip;
- line-height: 14px;
-
- &::after {
- position: absolute;
- content: '...';
- right: 0;
- font-family: $regular-font;
- background-color: $gray-light;
+ .deploy-link,
+ .label-branch {
+ &.label-truncate {
+ // NOTE: This selector targets its children because some of the HTML comes from
+ // 'source_branch_link'. Once this external HTML is no longer used, we could
+ // simplify this.
+ > a,
+ > span {
+ display: inline-block;
+ max-width: 12.5em;
+ margin-bottom: -3px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ line-height: 14px;
+ overflow: hidden;
}
}
}
@@ -281,7 +284,7 @@
margin-bottom: 0;
&.has-conflicts .fa-exclamation-triangle {
- color: $gl-warning;
+ color: $orange-500;
}
time {
@@ -313,7 +316,7 @@
}
.danger {
- color: $gl-danger;
+ color: $red-500;
}
.spacing,
@@ -514,7 +517,7 @@
}
.mr-links {
- padding-left: $status-icon-size + $status-icon-margin;
+ padding-left: $status-icon-size + $gl-btn-padding;
}
.mr-info-list {
@@ -582,7 +585,7 @@
@include media-breakpoint-down(md) {
flex-direction: column;
- align-items: flex-start;
+ align-items: stretch;
.branch-actions {
margin-top: 16px;
@@ -593,13 +596,13 @@
.branch-actions {
align-self: center;
margin-left: $gl-padding;
+ white-space: nowrap;
}
}
}
.diverged-commits-count {
color: $gl-text-color-secondary;
- font-size: 12px;
}
}
@@ -918,7 +921,7 @@
flex: 1;
flex-direction: row;
- @include media-breakpoint-down(md) {
+ @include media-breakpoint-down(sm) {
flex-direction: column;
.stage-cell .stage-container {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 4f861d43f55..ac7b701c2e2 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -74,13 +74,13 @@
}
&.is-dropzone-hover {
- border-color: $gl-success;
+ border-color: $green-500;
box-shadow: 0 0 2px $black-transparent,
- 0 0 4px $gl-success-focus;
+ 0 0 4px $green-500-focus;
.comment-toolbar,
.nav-links {
- border-color: $gl-success;
+ border-color: $green-500;
}
}
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 2e1b2126887..fce04c58c24 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -443,7 +443,7 @@ ul.notes {
.note-headline-light,
.discussion-headline-light {
- color: $notes-light-color;
+ color: $gl-text-color-secondary;
}
.discussion-headline-light {
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index ad057ed3c83..8bb8b83dc5e 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -19,7 +19,7 @@
background-color: $white-light;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
color: $gl-text-color;
}
@@ -595,7 +595,7 @@
a.build-content:hover,
button.build-content:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
}
@@ -668,7 +668,7 @@
display: block;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
svg {
@@ -835,7 +835,7 @@ button.mini-pipeline-graph-dropdown-toggle {
display: block;
&:hover {
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
border: 1px solid $dropdown-toggle-active-border-color;
svg {
@@ -934,7 +934,7 @@ button.mini-pipeline-graph-dropdown-toggle {
&:focus {
outline: none;
text-decoration: none;
- background-color: $stage-hover-bg;
+ background-color: $gray-darker;
}
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index c11916454c8..a95e78931b1 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -394,23 +394,23 @@
}
.vs-public {
- color: $gl-primary;
+ color: $blue-500;
}
.vs-internal {
- color: $gl-warning;
+ color: $orange-500;
}
.vs-private {
- color: $gl-success;
+ color: $green-500;
}
.lfs-enabled {
- color: $gl-success;
+ color: $green-500;
}
.lfs-disabled {
- color: $gl-warning;
+ color: $orange-500;
}
.breadcrumb.repo-breadcrumb {
@@ -731,7 +731,7 @@
background-color: transparent;
font-size: $gl-font-size;
line-height: $gl-btn-line-height;
- color: $notes-light-color;
+ color: $gl-text-color-secondary;
}
.stat-link {
@@ -900,7 +900,7 @@ pre.light-well {
.private-forks-notice .private-fork-icon {
i:nth-child(1) {
- color: $project-private-forks-notice-odd;
+ color: $green-600;
}
i:nth-child(2) {
@@ -1128,12 +1128,12 @@ pre.light-well {
.project-ci-body {
.incorrect-syntax {
font-size: 18px;
- color: $lint-incorrect-color;
+ color: $red-500;
}
.correct-syntax {
font-size: 18px;
- color: $lint-correct-color;
+ color: $green-500;
}
}
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index 2734faec558..59f01f3e958 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -4,24 +4,24 @@
color: $white-light;
&.runner-state-shared {
- background: $runner-state-shared-bg;
+ background: $green-400;
}
&.runner-state-specific {
- background: $runner-state-specific-bg;
+ background: $blue-400;
}
}
.runner-status-online {
- color: $runner-status-online-color;
+ color: $green-600;
}
.runner-status-offline {
- color: $runner-status-offline-color;
+ color: $gray-darkest;
}
.runner-status-paused {
- color: $runner-status-paused-color;
+ color: $red-500;
}
.runner {
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 5b3a468cd1c..77119aea9e2 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -24,12 +24,12 @@ $search-avatar-size: 16px;
.form-control:hover,
:not[readonly] {
border-color: lighten($blue-300, 20%);
- box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
+ box-shadow: 0 0 4px lighten($dropdown-input-focus-shadow, 20%);
}
input[type='checkbox']:hover {
- box-shadow: 0 0 2px 2px lighten($search-input-focus-shadow-color, 20%),
- 0 0 0 1px lighten($search-input-focus-shadow-color, 20%);
+ box-shadow: 0 0 2px 2px lighten($dropdown-input-focus-shadow, 20%),
+ 0 0 0 1px lighten($dropdown-input-focus-shadow, 20%);
}
.search {
@@ -181,7 +181,7 @@ input[type='checkbox']:hover {
width: $search-avatar-size;
height: $search-avatar-size;
border-radius: 50%;
- border: 1px solid $avatar-border;
+ border: 1px solid $gray-normal;
}
}
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 5aa4cdec9c3..e351dd7c0bb 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -120,11 +120,11 @@
}
.warning-title {
- color: $gl-warning;
+ color: $orange-500;
}
.danger-title {
- color: $gl-danger;
+ color: $red-500;
}
.integration-settings-form {
diff --git a/app/assets/stylesheets/pages/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
index 3f6f5f06075..d331edaa302 100644
--- a/app/assets/stylesheets/pages/stat_graph.scss
+++ b/app/assets/stylesheets/pages/stat_graph.scss
@@ -5,7 +5,7 @@
}
.area {
- fill: $stat-graph-area-fill;
+ fill: $green-500;
fill-opacity: 0.5;
}
@@ -54,7 +54,7 @@
}
.area-contributor {
- fill: $stat-graph-orange-fill;
+ fill: $orange-500;
}
}
}
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 2ef2ee76855..22b39f47bf0 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -107,11 +107,15 @@ module IssuableCollections
end
def set_sort_order_from_cookie
- key = 'issuable_sort'
+ cookies[remember_sorting_key] = params[:sort] if params[:sort].present?
+ # fallback to legacy cookie value for backward compatibility
+ cookies[remember_sorting_key] ||= cookies['issuable_sort']
+ cookies[remember_sorting_key] = update_cookie_value(cookies[remember_sorting_key])
+ params[:sort] = cookies[remember_sorting_key]
+ end
- cookies[key] = params[:sort] if params[:sort].present?
- cookies[key] = update_cookie_value(cookies[key])
- params[:sort] = cookies[key]
+ def remember_sorting_key
+ @remember_sorting_key ||= "#{collection_type.downcase}_sort"
end
def default_sort_order
@@ -140,16 +144,14 @@ module IssuableCollections
end
def finder
- strong_memoize(:finder) do
- issuable_finder_for(finder_type)
- end
+ @finder ||= issuable_finder_for(finder_type)
end
def collection_type
- @collection_type ||= case finder
- when IssuesFinder
+ @collection_type ||= case finder_type.name
+ when 'IssuesFinder'
'Issue'
- when MergeRequestsFinder
+ when 'MergeRequestsFinder'
'MergeRequest'
end
end
diff --git a/app/controllers/concerns/renders_commits.rb b/app/controllers/concerns/renders_commits.rb
index fb41dc1e8a8..b1c9b1e532f 100644
--- a/app/controllers/concerns/renders_commits.rb
+++ b/app/controllers/concerns/renders_commits.rb
@@ -1,4 +1,24 @@
module RendersCommits
+ def limited_commits(commits)
+ if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ [
+ commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE),
+ commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE
+ ]
+ else
+ [commits, 0]
+ end
+ end
+
+ # This is used as a helper method in a controller.
+ # rubocop: disable Gitlab/ModuleWithInstanceVariables
+ def set_commits_for_rendering(commits)
+ @total_commit_count = commits.size
+ limited, @hidden_commit_count = limited_commits(commits)
+ prepare_commits_for_rendering(limited)
+ end
+ # rubocop: enable Gitlab/ModuleWithInstanceVariables
+
def prepare_commits_for_rendering(commits)
Banzai::CommitRenderer.render(commits, @project, current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index ba5b7d33f87..ae0b815f85e 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -5,7 +5,7 @@ module ToggleAwardEmoji
authenticate_user!
name = params.require(:name)
- if awardable.user_can_award?(current_user, name)
+ if awardable.user_can_award?(current_user)
awardable.toggle_award_emoji(name, current_user)
todoable = to_todoable(awardable)
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 9bd51de7e97..6bdc0f79ef2 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -2,8 +2,8 @@ class Groups::MilestonesController < Groups::ApplicationController
include MilestoneActions
before_action :group_projects
- before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels]
- before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update]
+ before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels, :destroy]
+ before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
def index
respond_to do |format|
@@ -56,10 +56,21 @@ class Groups::MilestonesController < Groups::ApplicationController
redirect_to milestone_path
end
+ def destroy
+ return render_404 if @milestone.legacy_group_milestone?
+
+ Milestones::DestroyService.new(group, current_user).execute(@milestone)
+
+ respond_to do |format|
+ format.html { redirect_to group_milestones_path(group), status: :see_other }
+ format.js { head :ok }
+ end
+ end
+
private
def authorize_admin_milestones!
- return render_404 unless can?(current_user, :admin_milestones, group)
+ return render_404 unless can?(current_user, :admin_milestone, group)
end
def milestone_params
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 44b176d304e..53637780a07 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -101,7 +101,7 @@ class Projects::CommitController < Projects::ApplicationController
@branch_name = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch
- create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked.",
+ create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked into #{@branch_name}.",
success_path: -> { successful_change_path }, failure_path: failed_change_path)
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 36faea8056e..5546bef850b 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -63,7 +63,7 @@ class Projects::CommitsController < Projects::ApplicationController
end
@commits = @commits.with_pipeline_status
- @commits = prepare_commits_for_rendering(@commits)
+ @commits = set_commits_for_rendering(@commits)
end
# Rails 5 sets request.format from the extension.
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index f93e500a07a..a1e12821caf 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -78,7 +78,7 @@ class Projects::CompareController < Projects::ApplicationController
end
def define_commits
- @commits = compare.present? ? prepare_commits_for_rendering(compare.commits) : []
+ @commits = compare.present? ? set_commits_for_rendering(@compare.commits) : []
end
def define_diffs
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ef8159aa553..c3ac8e107fb 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -113,7 +113,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def referenced_merge_requests
- @merge_requests, @closed_by_merge_requests = ::Issues::FetchReferencedMergeRequestsService.new(project, current_user).execute(issue)
+ @merge_requests, @closed_by_merge_requests = ::Issues::ReferencedMergeRequestsService.new(project, current_user).execute(issue)
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 81129456ad8..03d0290ac1d 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -101,7 +101,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
- @commits = prepare_commits_for_rendering(@merge_request.commits)
+ @commits = set_commits_for_rendering(@merge_request.commits)
@commit = @merge_request.diff_head_commit
@labels = LabelsFinder.new(current_user, project_id: @project.id).execute
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 1b069fe507b..d31b58972ca 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -79,7 +79,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# Get commits from repository
# or from cache if already merged
@commits =
- prepare_commits_for_rendering(@merge_request.commits.with_pipeline_status)
+ set_commits_for_rendering(@merge_request.commits.with_pipeline_status)
render json: { html: view_to_html_string('projects/merge_requests/_commits') }
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 89fe90fd801..7a942c44ac4 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -210,17 +210,6 @@ module CommitsHelper
Sanitize.clean(string, remove_contents: true)
end
- def limited_commits(commits)
- if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
- [
- commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE),
- commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE
- ]
- else
- [commits, 0]
- end
- end
-
def commit_path(project, commit, merge_request: nil)
if merge_request&.persisted?
diffs_project_merge_request_path(project, merge_request, commit_id: commit.id)
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index 4664b1728c4..c65f1565425 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -5,6 +5,10 @@ module ImportHelper
false
end
+ def sanitize_project_name(name)
+ name.gsub(/[^\w\-]/, '-')
+ end
+
def import_project_target(owner, name)
namespace = current_user.can_create_group? ? owner : current_user.namespace_path
"#{namespace}/#{name}"
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 96dc7ae1185..5b27d1d9404 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -92,14 +92,6 @@ module IssuesHelper
end
end
- def award_user_authored_class(award)
- if award == 'thumbsdown' || award == 'thumbsup'
- 'user-authored js-user-authored'
- else
- ''
- end
- end
-
def awards_sort(awards)
awards.sort_by do |award, award_emojis|
if award == "thumbsup"
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 6b4079b4113..18b3badda8d 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -447,7 +447,7 @@ module ProjectsHelper
end
def project_permissions_panel_data(project)
- data = {
+ {
currentSettings: project_permissions_settings(project),
canChangeVisibilityLevel: can_change_visibility_level?(project, current_user),
allowedVisibilityOptions: project_allowed_visibility_levels(project),
@@ -457,8 +457,10 @@ module ProjectsHelper
lfsAvailable: Gitlab.config.lfs.enabled,
lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
}
+ end
- data.to_json.html_safe
+ def project_permissions_panel_data_json(project)
+ project_permissions_panel_data(project).to_json.html_safe
end
def project_allowed_visibility_levels(project)
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index e4aed76f611..526bf7af99b 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -649,8 +649,7 @@ module Ci
def keep_around_commits
return unless project
- project.repository.keep_around(self.sha)
- project.repository.keep_around(self.before_sha)
+ project.repository.keep_around(self.sha, self.before_sha)
end
def valid_source
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 27fbdc3e386..594972ad344 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -193,6 +193,7 @@ class Commit
# otherwise returns commit message without first line
def description
return safe_message if full_title.length >= 100
+ return no_commit_message if safe_message.blank?
safe_message.split("\n", 2)[1].try(:chomp)
end
diff --git a/app/models/concerns/awardable.rb b/app/models/concerns/awardable.rb
index 49981db0d80..4200253053a 100644
--- a/app/models/concerns/awardable.rb
+++ b/app/models/concerns/awardable.rb
@@ -76,12 +76,8 @@ module Awardable
true
end
- def awardable_votes?(name)
- AwardEmoji::UPVOTE_NAME == name || AwardEmoji::DOWNVOTE_NAME == name
- end
-
- def user_can_award?(current_user, name)
- awardable_by_user?(current_user, name) && Ability.allowed?(current_user, :award_emoji, self)
+ def user_can_award?(current_user)
+ Ability.allowed?(current_user, :award_emoji, self)
end
def user_authored?(current_user)
@@ -117,12 +113,4 @@ module Awardable
def normalize_name(name)
Gitlab::Emoji.normalize_emoji_name(name)
end
-
- def awardable_by_user?(current_user, name)
- if user_authored?(current_user)
- !awardable_votes?(normalize_name(name))
- else
- true
- end
- end
end
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 58d949315e0..716cf6574d3 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -191,14 +191,18 @@ class DiffNote < Note
end
def keep_around_commits
- project.repository.keep_around(self.original_position.base_sha)
- project.repository.keep_around(self.original_position.start_sha)
- project.repository.keep_around(self.original_position.head_sha)
+ shas = [
+ self.original_position.base_sha,
+ self.original_position.start_sha,
+ self.original_position.head_sha
+ ]
if self.position != self.original_position
- project.repository.keep_around(self.position.base_sha)
- project.repository.keep_around(self.position.start_sha)
- project.repository.keep_around(self.position.head_sha)
+ shas << self.position.base_sha
+ shas << self.position.start_sha
+ shas << self.position.head_sha
end
+
+ project.repository.keep_around(*shas)
end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 94cf12f3c2b..d0cd7461daa 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -170,27 +170,6 @@ class Issue < ActiveRecord::Base
"#{project.to_reference(from, full: full)}#{reference}"
end
- def referenced_merge_requests(current_user = nil)
- ext = all_references(current_user)
-
- notes_with_associations.each do |object|
- object.all_references(current_user, extractor: ext)
- end
-
- merge_requests = ext.merge_requests.sort_by(&:iid)
-
- cross_project_filter = -> (merge_requests) do
- merge_requests.select { |mr| mr.target_project == project }
- end
-
- Ability.merge_requests_readable_by_user(
- merge_requests, current_user,
- filters: {
- read_cross_project: cross_project_filter
- }
- )
- end
-
# All branches containing the current issue's ID, except for
# those with a merge request open referencing the current issue.
def related_branches(current_user)
@@ -198,7 +177,11 @@ class Issue < ActiveRecord::Base
branch =~ /\A#{iid}-(?!\d+-stable)/i
end
- branches_with_merge_request = self.referenced_merge_requests(current_user).map(&:source_branch)
+ branches_with_merge_request =
+ Issues::ReferencedMergeRequestsService
+ .new(project, current_user)
+ .referenced_merge_requests(self)
+ .map(&:source_branch)
branches_with_iid - branches_with_merge_request
end
@@ -225,26 +208,6 @@ class Issue < ActiveRecord::Base
project
end
- # From all notes on this issue, we'll select the system notes about linked
- # merge requests. Of those, the MRs closing `self` are returned.
- def closed_by_merge_requests(current_user = nil)
- return [] unless open?
-
- ext = all_references(current_user)
-
- notes.system.each do |note|
- note.all_references(current_user, extractor: ext)
- end
-
- merge_requests = ext.merge_requests.select(&:open?)
- if merge_requests.any?
- ids = MergeRequestsClosingIssues.where(merge_request_id: merge_requests.map(&:id), issue_id: id).pluck(:merge_request_id)
- merge_requests.select { |mr| mr.id.in?(ids) }
- else
- []
- end
- end
-
def moved?
!moved_to.nil?
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 05c0bc8cb97..d9b4e8d2ac6 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -103,7 +103,7 @@ class Member < ActiveRecord::Base
def filter_by_2fa(value)
case value
when 'enabled'
- left_join_users.merge(User.with_two_factor_indistinct)
+ left_join_users.merge(User.with_two_factor)
when 'disabled'
left_join_users.merge(User.without_two_factor)
else
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index d9393b4e545..bbe4f6f7969 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -314,9 +314,7 @@ class MergeRequestDiff < ActiveRecord::Base
def keep_around_commits
[repository, merge_request.source_project.repository].uniq.each do |repo|
- repo.keep_around(start_commit_sha)
- repo.keep_around(head_commit_sha)
- repo.keep_around(base_commit_sha)
+ repo.keep_around(start_commit_sha, head_commit_sha, base_commit_sha)
end
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 8f631d7f0ed..67593c9b2fe 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -85,8 +85,7 @@ class Project < ActiveRecord::Base
after_create :create_project_feature, unless: :project_feature
after_create -> { SiteStatistic.track(STATISTICS_ATTRIBUTE) }
- before_destroy ->(project) { project.project_feature.untrack_statistics_for_deletion! }
- after_destroy -> { SiteStatistic.untrack(STATISTICS_ATTRIBUTE) }
+ before_destroy :untrack_site_statistics
after_create :create_ci_cd_settings,
unless: :ci_cd_settings,
@@ -2072,13 +2071,19 @@ class Project < ActiveRecord::Base
private
def rename_or_migrate_repository!
- if Gitlab::CurrentSettings.hashed_storage_enabled? && storage_version != LATEST_STORAGE_VERSION
+ if Gitlab::CurrentSettings.hashed_storage_enabled? &&
+ storage_upgradable? &&
+ Feature.disabled?(:skip_hashed_storage_upgrade) # kill switch in case we need to disable upgrade behavior
::Projects::HashedStorageMigrationService.new(self, full_path_was).execute
else
storage.rename_repo
end
end
+ def storage_upgradable?
+ storage_version != LATEST_STORAGE_VERSION
+ end
+
def after_rename_repository(full_path_before, path_before)
execute_rename_repository_hooks!(full_path_before)
@@ -2093,6 +2098,11 @@ class Project < ActiveRecord::Base
Gitlab::PagesTransfer.new.rename_project(path_before, self.path, namespace.full_path)
end
+ def untrack_site_statistics
+ SiteStatistic.untrack(STATISTICS_ATTRIBUTE)
+ self.project_feature.untrack_statistics_for_deletion!
+ end
+
def execute_rename_repository_hooks!(full_path_before)
# When we import a project overwriting the original project, there
# is a move operation. In that case we don't want to send the instructions.
diff --git a/app/models/protected_tag.rb b/app/models/protected_tag.rb
index a36f0d36262..94746141945 100644
--- a/app/models/protected_tag.rb
+++ b/app/models/protected_tag.rb
@@ -4,6 +4,8 @@ class ProtectedTag < ActiveRecord::Base
include Gitlab::ShellAdapter
include ProtectedRef
+ validates :name, uniqueness: { scope: :project_id }
+
protected_ref_access_levels :create
def self.protected?(project, ref_name)
diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb
index 833faf3bc82..c1f53b5da4f 100644
--- a/app/models/remote_mirror.rb
+++ b/app/models/remote_mirror.rb
@@ -150,6 +150,15 @@ class RemoteMirror < ActiveRecord::Base
result.to_s
end
+ def ensure_remote!
+ return unless project
+ return unless remote_name && url
+
+ # If this fails or the remote already exists, we won't know due to
+ # https://gitlab.com/gitlab-org/gitaly/issues/1317
+ project.repository.add_remote(remote_name, url)
+ end
+
private
def raw
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 69f375dc6f3..cf255c8951f 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -247,15 +247,22 @@ class Repository
# Git GC will delete commits from the repository that are no longer in any
# branches or tags, but we want to keep some of these commits around, for
# example if they have comments or CI builds.
- def keep_around(sha)
- return unless sha.present? && commit_by(oid: sha)
+ #
+ # For Geo's sake, pass in multiple shas rather than calling it multiple times,
+ # to avoid unnecessary syncing.
+ def keep_around(*shas)
+ shas.each do |sha|
+ begin
+ next unless sha.present? && commit_by(oid: sha)
- return if kept_around?(sha)
+ next if kept_around?(sha)
- # This will still fail if the file is corrupted (e.g. 0 bytes)
- raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
- rescue Gitlab::Git::CommandError => ex
- Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
+ # This will still fail if the file is corrupted (e.g. 0 bytes)
+ raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
+ rescue Gitlab::Git::CommandError => ex
+ Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
+ end
+ end
end
def kept_around?(sha)
diff --git a/app/models/user.rb b/app/models/user.rb
index a6ba90794d6..f21ca1c569f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -289,13 +289,16 @@ class User < ActiveRecord::Base
end
end
- def self.with_two_factor_indistinct
- joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id")
- .where("u2f.id IS NOT NULL OR users.otp_required_for_login = ?", true)
- end
-
def self.with_two_factor
- with_two_factor_indistinct.distinct(arel_table[:id])
+ with_u2f_registrations = <<-SQL
+ EXISTS (
+ SELECT *
+ FROM u2f_registrations AS u2f
+ WHERE u2f.user_id = users.id
+ ) OR users.otp_required_for_login = ?
+ SQL
+
+ where(with_u2f_registrations, true)
end
def self.without_two_factor
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index a8d7a05f509..73c93b22c95 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -53,7 +53,7 @@ class GroupPolicy < BasePolicy
rule { has_access }.enable :read_namespace
- rule { developer }.enable :admin_milestones
+ rule { developer }.enable :admin_milestone
rule { reporter }.policy do
enable :admin_label
@@ -72,6 +72,8 @@ class GroupPolicy < BasePolicy
enable :admin_namespace
enable :admin_group_member
enable :change_visibility_level
+
+ enable :set_note_created_at
end
rule { can?(:read_nested_project_resources) }.policy do
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 00c58f15013..fd6cc504a3b 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -143,6 +143,10 @@ class ProjectPolicy < BasePolicy
enable :destroy_merge_request
enable :destroy_issue
enable :remove_pages
+
+ enable :set_issue_iid
+ enable :set_issue_created_at
+ enable :set_note_created_at
end
rule { can?(:guest_access) }.policy do
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 637c1df4ad9..26e90e8cf8c 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -140,7 +140,6 @@ class GitPushService < BaseService
EventCreateService.new.push(project, current_user, build_push_data)
Ci::CreatePipelineService.new(project, current_user, build_push_data).execute(:push)
- SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks)
project.execute_hooks(build_push_data.dup, :push_hooks)
project.execute_services(build_push_data.dup, :push_hooks)
@@ -159,7 +158,7 @@ class GitPushService < BaseService
end
def process_default_branch
- offset = [push_commits_count - PROCESS_COMMIT_LIMIT, 0].max
+ offset = [push_commits_count_for_ref - PROCESS_COMMIT_LIMIT, 0].max
@push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT)
project.after_create_default_branch
@@ -173,7 +172,7 @@ class GitPushService < BaseService
params[:newrev],
params[:ref],
@push_commits,
- commits_count: push_commits_count)
+ commits_count: commits_count)
end
def push_to_existing_branch?
@@ -214,8 +213,14 @@ class GitPushService < BaseService
end
end
- def push_commits_count
- strong_memoize(:push_commits_count) do
+ def commits_count
+ return push_commits_count_for_ref if default_branch? && push_to_new_branch?
+
+ Array(@push_commits).size
+ end
+
+ def push_commits_count_for_ref
+ strong_memoize(:push_commits_count_for_ref) do
project.repository.commit_count_for_ref(params[:ref])
end
end
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index 12aeba4af71..93d84bd8a9c 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -12,12 +12,15 @@ module Groups
def execute
group.prepare_for_destroy
- group.projects.each do |project|
+ group.projects.includes(:project_feature).each do |project|
# Execute the destruction of the models immediately to ensure atomic cleanup.
success = ::Projects::DestroyService.new(project, current_user).execute
raise DestroyError, "Project #{project.id} can't be deleted" unless success
end
+ # reload the relation to prevent triggering destroy hooks on the projects again
+ group.projects.reload
+
group.children.each do |group|
# This needs to be synchronous since the namespace gets destroyed below
DestroyService.new(group, current_user).execute
diff --git a/app/services/issues/fetch_referenced_merge_requests_service.rb b/app/services/issues/fetch_referenced_merge_requests_service.rb
deleted file mode 100644
index 5e84f3c81c9..00000000000
--- a/app/services/issues/fetch_referenced_merge_requests_service.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Issues
- class FetchReferencedMergeRequestsService < Issues::BaseService
- def execute(issue)
- referenced_merge_requests = issue.referenced_merge_requests(current_user)
- referenced_merge_requests = Gitlab::IssuableSorter.sort(project, referenced_merge_requests) { |i| i.iid.to_s }
- closed_by_merge_requests = issue.closed_by_merge_requests(current_user)
- closed_by_merge_requests = Gitlab::IssuableSorter.sort(project, closed_by_merge_requests) { |i| i.iid.to_s }
-
- [referenced_merge_requests, closed_by_merge_requests]
- end
- end
-end
diff --git a/app/services/issues/referenced_merge_requests_service.rb b/app/services/issues/referenced_merge_requests_service.rb
new file mode 100644
index 00000000000..40d78502697
--- /dev/null
+++ b/app/services/issues/referenced_merge_requests_service.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Issues
+ class ReferencedMergeRequestsService < Issues::BaseService
+ def execute(issue)
+ referenced = referenced_merge_requests(issue)
+ closed_by = closed_by_merge_requests(issue)
+ preloader = ActiveRecord::Associations::Preloader.new
+
+ preloader.preload(referenced + closed_by,
+ head_pipeline: { project: [:route, { namespace: :route }] })
+
+ [sort_by_iid(referenced), sort_by_iid(closed_by)]
+ end
+
+ def referenced_merge_requests(issue)
+ merge_requests = extract_merge_requests(issue)
+
+ cross_project_filter = -> (merge_requests) do
+ merge_requests.select { |mr| mr.target_project == project }
+ end
+
+ Ability.merge_requests_readable_by_user(
+ merge_requests,
+ current_user,
+ filters: {
+ read_cross_project: cross_project_filter
+ }
+ )
+ end
+
+ def closed_by_merge_requests(issue)
+ return [] unless issue.open?
+
+ merge_requests = extract_merge_requests(issue, filter: :system).select(&:open?)
+
+ return [] if merge_requests.empty?
+
+ ids = MergeRequestsClosingIssues.where(merge_request_id: merge_requests.map(&:id), issue_id: issue.id).pluck(:merge_request_id)
+ merge_requests.select { |mr| mr.id.in?(ids) }
+ end
+
+ private
+
+ def extract_merge_requests(issue, filter: nil)
+ ext = issue.all_references(current_user)
+ notes = issue_notes(issue)
+ notes = notes.select(&filter) if filter
+
+ notes.each do |note|
+ note.all_references(current_user, extractor: ext)
+ end
+
+ ext.merge_requests
+ end
+
+ def issue_notes(issue)
+ @issue_notes ||= {}
+ @issue_notes[issue] ||= issue.notes.includes(:author)
+ end
+
+ def sort_by_iid(merge_requests)
+ Gitlab::IssuableSorter.sort(project, merge_requests) { |mr| mr.iid.to_s }
+ end
+ end
+end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index bc988eb2a26..55750269bb4 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -128,8 +128,7 @@ module MergeRequests
#
def assign_title_and_description
assign_title_and_description_from_single_commit
- assign_title_from_issue if target_project.issues_enabled? || target_project.external_issue_tracker
-
+ merge_request.title ||= title_from_issue if target_project.issues_enabled? || target_project.external_issue_tracker
merge_request.title ||= source_branch.titleize.humanize
merge_request.title = wip_title if compare_commits.empty?
@@ -159,20 +158,18 @@ module MergeRequests
merge_request.description ||= commit.description.try(:strip)
end
- def assign_title_from_issue
+ def title_from_issue
return unless issue
- merge_request.title = "Resolve \"#{issue.title}\"" if issue.is_a?(Issue)
+ return "Resolve \"#{issue.title}\"" if issue.is_a?(Issue)
- return if merge_request.title.present?
+ return if issue_iid.blank?
- if issue_iid.present?
- title_parts = ["Resolve #{issue.to_reference}"]
- branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize
+ title_parts = ["Resolve #{issue.to_reference}"]
+ branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize
- title_parts << "\"#{branch_title}\"" if branch_title.present?
- merge_request.title = title_parts.join(' ')
- end
+ title_parts << "\"#{branch_title}\"" if branch_title.present?
+ title_parts.join(' ')
end
def issue_iid
diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb
index 15c04525075..7cda802c120 100644
--- a/app/services/milestones/destroy_service.rb
+++ b/app/services/milestones/destroy_service.rb
@@ -3,8 +3,6 @@
module Milestones
class DestroyService < Milestones::BaseService
def execute(milestone)
- return unless milestone.project_milestone?
-
Milestone.transaction do
update_params = { milestone: nil }
@@ -16,15 +14,21 @@ module Milestones
MergeRequests::UpdateService.new(parent, current_user, update_params).execute(merge_request)
end
- event_service.destroy_milestone(milestone, current_user)
-
- Event.for_milestone_id(milestone.id).each do |event|
- event.target_id = nil
- event.save
- end
+ log_destroy_event_for(milestone)
milestone.destroy
end
end
+
+ def log_destroy_event_for(milestone)
+ return if milestone.group_milestone?
+
+ event_service.destroy_milestone(milestone, current_user)
+
+ Event.for_milestone_id(milestone.id).each do |event|
+ event.target_id = nil
+ event.save
+ end
+ end
end
end
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 33ad2120a75..cbbb88a9410 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -17,6 +17,14 @@ module Projects
link_fork_network(fork_to_project)
+ # A forked project stores its LFS objects in the `forked_from_project`.
+ # So the LFS objects become inaccessible, and therefore delete them from
+ # the database so they'll get cleaned up.
+ #
+ # TODO: refactor this to get the correct lfs objects when implementing
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/39769
+ fork_to_project.lfs_objects_projects.delete_all
+
fork_to_project
end
diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb
index 4651f7c4f8f..591b38b8151 100644
--- a/app/services/projects/update_remote_mirror_service.rb
+++ b/app/services/projects/update_remote_mirror_service.rb
@@ -10,6 +10,7 @@ module Projects
return success unless remote_mirror.enabled?
begin
+ remote_mirror.ensure_remote!
repository.fetch_remote(remote_mirror.remote_name, no_tags: true)
opts = {}
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 8838ed06324..a4c4c9e4812 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -402,7 +402,7 @@ module QuickActions
match[1] if match
end
command :award do |name|
- if name && issuable.user_can_award?(current_user, name)
+ if name && issuable.user_can_award?(current_user)
@updates[:emoji_award] = name
end
end
diff --git a/app/views/admin/hook_logs/show.html.haml b/app/views/admin/hook_logs/show.html.haml
index 2eb3ac85722..86729dbe7bc 100644
--- a/app/views/admin/hook_logs/show.html.haml
+++ b/app/views/admin/hook_logs/show.html.haml
@@ -4,7 +4,6 @@
%hr
-= link_to 'Resend Request', retry_admin_hook_hook_log_path(@hook, @hook_log), class: "btn btn-default float-right prepend-left-10"
+= link_to 'Resend Request', retry_admin_hook_hook_log_path(@hook, @hook_log), method: :post, class: "btn btn-default float-right prepend-left-10"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
-
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 029efadd75d..a74e052707f 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -39,6 +39,10 @@
%strong= email.email
= link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-sm btn btn-remove float-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.fa.fa-times
+ %li
+ %span.light ID:
+ %strong
+ = @user.id
%li.two-factor-status
%span.light Two-factor Authentication:
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 8ca9fb4512e..30d7b21b1b8 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -3,7 +3,7 @@
.awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: toggle_award_url(awardable) } }
- awards_sort(grouped_emojis).each do |emoji, awards|
%button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button",
- class: [(award_state_class(awardable, awards, current_user)), (award_user_authored_class(emoji) if user_authored)],
+ class: [(award_state_class(awardable, awards, current_user))],
data: { placement: "bottom", title: award_user_list(awards, current_user) } }
= emoji_icon(emoji)
%span.award-control-text.js-counter
@@ -13,7 +13,6 @@
.award-menu-holder.js-award-holder
%button.btn.award-control.has-tooltip.js-add-award{ type: 'button',
'aria-label': _('Add reaction'),
- class: ("js-user-authored" if user_authored),
data: { title: _('Add reaction'), placement: "bottom" } }
%span{ class: "award-control-icon award-control-icon-neutral" }= custom_icon('emoji_slightly_smiling_face')
%span{ class: "award-control-icon award-control-icon-positive" }= custom_icon('emoji_smiley')
diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml
index 13f96b9747c..c26eb873718 100644
--- a/app/views/ci/runner/_how_to_setup_runner.html.haml
+++ b/app/views/ci/runner/_how_to_setup_runner.html.haml
@@ -1,6 +1,6 @@
- link = link_to _("Install GitLab Runner"), 'https://docs.gitlab.com/runner/install/', target: '_blank'
.append-bottom-10
- %h4= _("Setup a #{type} Runner manually")
+ %h4= _("Setup a %{type} Runner manually") % { type: type }
%ol
%li
diff --git a/app/views/ci/status/_dropdown_graph_badge.html.haml b/app/views/ci/status/_dropdown_graph_badge.html.haml
index 8b0463db000..9de9143e8b1 100644
--- a/app/views/ci/status/_dropdown_graph_badge.html.haml
+++ b/app/views/ci/status/_dropdown_graph_badge.html.haml
@@ -6,12 +6,12 @@
- tooltip = "#{subject.name} - #{status.status_tooltip}"
- if status.has_details?
- = link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item', data: { toggle: 'tooltip', title: tooltip, html: 'true', container: 'body' } do
+ = link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item', data: { toggle: 'tooltip', title: tooltip, container: 'body' } do
%span{ class: klass }= sprite_icon(status.icon)
%span.ci-build-text= subject.name
- else
- .menu-item.mini-pipeline-graph-dropdown-item{ data: { toggle: 'tooltip', html: 'true', title: tooltip, container: 'body' } }
+ .menu-item.mini-pipeline-graph-dropdown-item{ data: { toggle: 'tooltip', title: tooltip, container: 'body' } }
%span{ class: klass }= sprite_icon(status.icon)
%span.ci-build-text= subject.name
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index f5f621507b8..b6424df55cd 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -5,7 +5,7 @@
.nav-controls
= render 'shared/milestones_sort_dropdown'
- - if can?(current_user, :admin_milestones, @group)
+ - if can?(current_user, :admin_milestone, @group)
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
.milestones
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index f0d1e837317..f4a29ed18dc 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -45,7 +45,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.name), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do
= has_ci_cd_only_params? ? _('Connect') : _('Import')
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index a75b7aa9dd2..3b1b5e55302 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -63,7 +63,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.slug), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: 'btn btn-import js-add-to-import' do
= _('Import')
diff --git a/app/views/import/bitbucket_server/status.html.haml b/app/views/import/bitbucket_server/status.html.haml
index 3d05a5e696f..ae09e0dfa18 100644
--- a/app/views/import/bitbucket_server/status.html.haml
+++ b/app/views/import/bitbucket_server/status.html.haml
@@ -61,7 +61,7 @@
= text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true
%span.input-group-prepend
.input-group-text /
- = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
+ = text_field_tag :path, sanitize_project_name(repo.slug), class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: 'btn btn-import js-add-to-import' do
Import
diff --git a/app/views/projects/_issuable_by_email.html.haml b/app/views/projects/_issuable_by_email.html.haml
index 22adf5b4008..d59191a6f87 100644
--- a/app/views/projects/_issuable_by_email.html.haml
+++ b/app/views/projects/_issuable_by_email.html.haml
@@ -19,9 +19,16 @@
= text_field_tag :issuable_email, email, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#issuable_email', class: 'btn btn-clipboard input-group-text btn-transparent d-none d-sm-block')
+
+ - if issuable_type == 'issue'
+ - enter_title_text = _('Enter the issue title')
+ - enter_description_text = _('Enter the issue description')
+ - else
+ - enter_title_text = _('Enter the merge request title')
+ - enter_description_text = _('Enter the merge request description')
= mail_to email, class: 'btn btn-clipboard btn-transparent',
- subject: _("Enter the #{name} title"),
- body: _("Enter the #{name} description"),
+ subject: enter_title_text,
+ body: enter_description_text,
title: _('Send email'),
data: { toggle: 'tooltip', placement: 'bottom' } do
= sprite_icon('mail')
diff --git a/app/views/projects/commits/_commit_list.html.haml b/app/views/projects/commits/_commit_list.html.haml
index 8f8eb2c3d5a..6ed65d07202 100644
--- a/app/views/projects/commits/_commit_list.html.haml
+++ b/app/views/projects/commits/_commit_list.html.haml
@@ -1,9 +1,10 @@
-- commits, hidden = limited_commits(@commits)
+- commits = @commits
+- hidden = @hidden_commit_count
- commits = Commit.decorate(commits, @project)
.card
.card-header
- Commits (#{@commits.count})
+ Commits (#{@total_commit_count})
- if hidden > 0
%ul.content-list
- commits.each do |commit|
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index ac6852751be..ec05ff50f25 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -2,7 +2,8 @@
- project = local_assigns.fetch(:project) { merge_request&.project }
- ref = local_assigns.fetch(:ref) { merge_request&.source_branch }
-- commits, hidden = limited_commits(@commits)
+- commits = @commits
+- hidden = @hidden_commit_count
- commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits|
%li.commit-header.js-commit-header{ data: { day: day } }
diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml
index cd0fb21f8a7..ffdca500abe 100644
--- a/app/views/projects/diffs/_line.html.haml
+++ b/app/views/projects/diffs/_line.html.haml
@@ -32,9 +32,9 @@
%a{ href: "##{line_code}", data: { linenumber: link_text } }
%td.line_content.noteable_line{ class: type }<
- if email
- %pre= line.text
+ %pre= line.rich_text
- else
- = diff_line_content(line.text)
+ = diff_line_content(line.rich_text)
- if line_discussions&.any?
- discussion_expanded = local_assigns.fetch(:discussion_expanded, line_discussions.any?(&:expanded?))
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 1f0ca211074..e47361354f3 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -24,7 +24,7 @@
- discussion_left = discussions_left.try(:first)
- if discussion_left && discussion_left.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_left.id }
- %td.line_content.parallel.noteable_line.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.text)
+ %td.line_content.parallel.noteable_line.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.left-side
@@ -45,7 +45,7 @@
- discussion_right = discussions_right.try(:first)
- if discussion_right && discussion_right.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_right.id }
- %td.line_content.parallel.noteable_line.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.text)
+ %td.line_content.parallel.noteable_line.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.right-side
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 30544dde451..e37a444c1c9 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -78,7 +78,7 @@
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "sharing-permissions-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-shared-permissions' }
-# haml-lint:disable InlineJavaScript
- %script.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data(@project)
+ %script.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data_json(@project)
.js-project-permissions-form
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml
index e51efa85df0..bd8ca5e7d70 100644
--- a/app/views/projects/hook_logs/show.html.haml
+++ b/app/views/projects/hook_logs/show.html.haml
@@ -4,6 +4,6 @@
Request details
.col-lg-9
- = link_to 'Resend Request', retry_project_hook_hook_log_path(@project, @hook, @hook_log), class: "btn btn-default float-right prepend-left-10"
+ = link_to 'Resend Request', retry_project_hook_hook_log_path(@project, @hook, @hook_log), method: :post, class: "btn btn-default float-right prepend-left-10"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml
index 86b2b8bf2f7..acc1e17b811 100644
--- a/app/views/projects/jobs/_sidebar.html.haml
+++ b/app/views/projects/jobs/_sidebar.html.haml
@@ -82,7 +82,7 @@
- builds.select{|build| build.status == build_status}.each do |build|
.build-job{ class: sidebar_build_class(build, @build), data: { stage: build.stage } }
- tooltip = sanitize(build.tooltip_message.dup)
- = link_to(project_job_path(@project, build), data: { toggle: 'tooltip', html: 'true', title: tooltip, container: 'body' }) do
+ = link_to(project_job_path(@project, build), data: { toggle: 'tooltip', title: tooltip, container: 'body' }) do
= sprite_icon('arrow-right', size:16, css_class: 'icon-arrow-right')
%span{ class: "ci-status-icon-#{build.status}" }
= ci_icon_for_status(build.status)
diff --git a/app/views/projects/merge_requests/_how_to_merge.html.haml b/app/views/projects/merge_requests/_how_to_merge.html.haml
index 62dd21ef6e0..d3871453b9f 100644
--- a/app/views/projects/merge_requests/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/_how_to_merge.html.haml
@@ -1,5 +1,5 @@
#modal_merge_info.modal{ tabindex: '-1' }
- .modal-dialog
+ .modal-dialog.modal-lg
.modal-content
.modal-header
%h3.modal-title Check out, review, and merge locally
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index f7a5d85500f..d5c4134dee2 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -33,7 +33,7 @@
%li.commits-tab.new-tab
= link_to url_for(safe_params), data: {target: 'div#commits', action: 'new', toggle: 'tabvue'} do
Commits
- %span.badge.badge-pill= @commits.size
+ %span.badge.badge-pill= @total_commit_count
- if @pipelines.any?
%li.builds-tab
= link_to url_for(safe_params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tabvue'} do
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 2a9e20c2caa..0a684f9016a 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -43,18 +43,7 @@
- else
= link_to 'Reopen milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-nr btn-grouped"
- %button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { toggle: 'modal',
- target: '#delete-milestone-modal',
- milestone_id: @milestone.id,
- milestone_title: markdown_field(@milestone, :title),
- milestone_url: project_milestone_path(@project, @milestone),
- milestone_issue_count: @milestone.issues.count,
- milestone_merge_request_count: @milestone.merge_requests.count },
- disabled: true }
- = _('Delete')
- = icon('spin spinner', class: 'js-loading-icon hidden' )
-
- #delete-milestone-modal
+ = render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml
index e051f9e6331..35a6885318a 100644
--- a/app/views/projects/mirrors/_instructions.html.haml
+++ b/app/views/projects/mirrors/_instructions.html.haml
@@ -4,7 +4,9 @@
= _('The repository must be accessible over <code>http://</code>,
<code>https://</code>, <code>ssh://</code> and <code>git://</code>.').html_safe
%li= _('Include the username in the URL if required: <code>https://username@gitlab.company.com/group/project.git</code>.').html_safe
- %li= _("The update action will time out after #{import_will_timeout_message(Gitlab.config.gitlab_shell.git_timeout)} minutes. For big repositories, use a clone/push combination.")
+ %li
+ - minutes = Gitlab.config.gitlab_shell.git_timeout / 60
+ = _("The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination.") % { number_of_minutes: minutes }
%li= _('The Git LFS objects will <strong>not</strong> be synced.').html_safe
%li
= _('This user will be the author of all events in the activity feed that are the result of an update,
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index b4fe1cabdfd..e9008d60098 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -40,7 +40,7 @@
- if note.emoji_awardable?
- user_authored = note.user_authored?(current_user)
.note-actions-item
- = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji #{'js-user-authored' if user_authored} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
+ = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
diff --git a/app/views/shared/milestones/_delete_button.html.haml b/app/views/shared/milestones/_delete_button.html.haml
new file mode 100644
index 00000000000..e236c24b088
--- /dev/null
+++ b/app/views/shared/milestones/_delete_button.html.haml
@@ -0,0 +1,14 @@
+- milestone_url = @milestone.project_milestone? ? project_milestone_path(@project, @milestone) : group_milestone_path(@group, @milestone)
+
+%button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { toggle: 'modal',
+ target: '#delete-milestone-modal',
+ milestone_id: @milestone.id,
+ milestone_title: markdown_field(@milestone, :title),
+ milestone_url: milestone_url,
+ milestone_issue_count: @milestone.issues.count,
+ milestone_merge_request_count: @milestone.merge_requests.count },
+ disabled: true }
+ = _('Delete')
+ = icon('spin spinner', class: 'js-loading-icon hidden' )
+
+#delete-milestone-modal
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index c559945a9c9..3dd2842be4f 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -16,6 +16,9 @@
= milestone_date_range(milestone)
%div
= render('shared/milestone_expired', milestone: milestone)
+ - if milestone.group_milestone?
+ .label-badge.label-badge-blue.d-inline-block
+ = milestone.group.full_name
- if milestone.legacy_group_milestone?
.projects
- milestone.milestones.each do |milestone|
@@ -49,7 +52,7 @@
- unless milestone.active?
= link_to 'Reopen Milestone', project_milestone_path(@project, milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- if @group
- - if can?(current_user, :admin_milestones, @group)
+ - if can?(current_user, :admin_milestone, @group)
- if milestone.closed?
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
- else
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index 320e3788a0f..0499b04a482 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -23,7 +23,7 @@
= milestone_date_range(milestone)
- if group
.float-right
- - if can?(current_user, :admin_milestones, group)
+ - if can?(current_user, :admin_milestone, group)
- if milestone.group_milestone?
= link_to edit_group_milestone_path(group, milestone), class: "btn btn btn-grouped" do
Edit
@@ -32,6 +32,9 @@
- else
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
+ - unless is_dynamic_milestone
+ = render 'shared/milestones/delete_button'
+
= render 'shared/milestones/deprecation_message' if is_dynamic_milestone
.detail-page-description.milestone-detail
diff --git a/app/views/snippets/notes/_actions.html.haml b/app/views/snippets/notes/_actions.html.haml
index 3a50324770d..e1f7ee80ebb 100644
--- a/app/views/snippets/notes/_actions.html.haml
+++ b/app/views/snippets/notes/_actions.html.haml
@@ -2,7 +2,7 @@
- if note.emoji_awardable?
- user_authored = note.user_authored?(current_user)
.note-actions-item
- = link_to '#', title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji #{'js-user-authored' if user_authored} has-tooltip", data: { position: 'right' } do
+ = link_to '#', title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip", data: { position: 'right' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')