Commit c05c2df8 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 05addc486095
......@@ -75,16 +75,18 @@
changes: *code-backstage-qa-patterns
when: on_success
.rails:rules:master-refs:
.rails:rules:master-refs-code-backstage-qa:
rules:
- <<: *if-master-refs
changes: *code-backstage-qa-patterns
when: on_success
.rails:rules:master-refs-ee-only:
.rails:rules:master-refs-code-backstage-qa-ee-only:
rules:
- <<: *if-not-ee
when: never
- <<: *if-master-refs
changes: *code-backstage-qa-patterns
when: on_success
.rails:rules:ee-only:
......@@ -330,12 +332,12 @@ coverage:
rspec quarantine pg9:
extends:
- .rspec-base-quarantine
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
.rspec-base-pg10:
extends:
- .rspec-base
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
- .use-pg10
rspec unit pg10:
......@@ -357,7 +359,7 @@ rspec system pg10:
rspec-ee quarantine pg9:
extends:
- .rspec-base-quarantine
- .rails:rules:master-refs-ee-only
- .rails:rules:master-refs-code-backstage-qa-ee-only
variables:
RSPEC_OPTS: "--tag quarantine -- ee/spec/"
......@@ -365,25 +367,25 @@ rspec-ee migration pg10:
extends:
- .rspec-ee-base-pg10
- .rspec-base-migration
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
parallel: 2
rspec-ee unit pg10:
extends:
- .rspec-ee-base-pg10
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
parallel: 10
rspec-ee integration pg10:
extends:
- .rspec-ee-base-pg10
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
parallel: 3
rspec-ee system pg10:
extends:
- .rspec-ee-base-pg10
- .rails:rules:master-refs
- .rails:rules:master-refs-code-backstage-qa
parallel: 5
# ee + master-only jobs #
#########################
......
<script>
import { GlButton, GlButtonGroup, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import {
RICH_BLOB_VIEWER,
RICH_BLOB_VIEWER_TITLE,
SIMPLE_BLOB_VIEWER,
SIMPLE_BLOB_VIEWER_TITLE,
} from './constants';
export default {
components: {
GlIcon,
GlButtonGroup,
GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
blob: {
type: Object,
required: true,
},
},
data() {
return {
viewer: this.blob.richViewer ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER,
};
},
computed: {
isSimpleViewer() {
return this.viewer === SIMPLE_BLOB_VIEWER;
},
isRichViewer() {
return this.viewer === RICH_BLOB_VIEWER;
},
},
methods: {
switchToViewer(viewer) {
if (viewer !== this.viewer) {
this.viewer = viewer;
this.$emit('switch-viewer', viewer);
}
},
},
SIMPLE_BLOB_VIEWER,
RICH_BLOB_VIEWER,
SIMPLE_BLOB_VIEWER_TITLE,
RICH_BLOB_VIEWER_TITLE,
};
</script>
<template>
<gl-button-group class="js-blob-viewer-switcher ml-2">
<gl-button
v-gl-tooltip.hover
:aria-label="$options.SIMPLE_BLOB_VIEWER_TITLE"
:title="$options.SIMPLE_BLOB_VIEWER_TITLE"
:selected="isSimpleViewer"
:class="{ active: isSimpleViewer }"
@click="switchToViewer($options.SIMPLE_BLOB_VIEWER)"
>
<gl-icon name="code" :size="14" />
</gl-button>
<gl-button
v-gl-tooltip.hover
:aria-label="$options.RICH_BLOB_VIEWER_TITLE"
:title="$options.RICH_BLOB_VIEWER_TITLE"
:selected="isRichViewer"
:class="{ active: isRichViewer }"
@click="switchToViewer($options.RICH_BLOB_VIEWER)"
>
<gl-icon name="document" :size="14" />
</gl-button>
</gl-button-group>
</template>
......@@ -3,3 +3,9 @@ import { __ } from '~/locale';
export const BTN_COPY_CONTENTS_TITLE = __('Copy file contents');
export const BTN_RAW_TITLE = __('Open raw');
export const BTN_DOWNLOAD_TITLE = __('Download');
export const SIMPLE_BLOB_VIEWER = 'simple';
export const SIMPLE_BLOB_VIEWER_TITLE = __('Display source');
export const RICH_BLOB_VIEWER = 'rich';
export const RICH_BLOB_VIEWER_TITLE = __('Display rendered file');
......@@ -161,50 +161,7 @@ class List {
}
addMultipleIssues(issues, listFrom, newIndex) {
let moveBeforeId = null;
let moveAfterId = null;
const listHasIssues = issues.every(issue => this.findIssue(issue.id));
if (!listHasIssues) {
if (newIndex !== undefined) {
if (this.issues[newIndex - 1]) {
moveBeforeId = this.issues[newIndex - 1].id;
}
if (this.issues[newIndex]) {
moveAfterId = this.issues[newIndex].id;
}
this.issues.splice(newIndex, 0, ...issues);
} else {
this.issues.push(...issues);
}
if (this.label) {
issues.forEach(issue => issue.addLabel(this.label));
}
if (this.assignee) {
if (listFrom && listFrom.type === 'assignee') {
issues.forEach(issue => issue.removeAssignee(listFrom.assignee));
}
issues.forEach(issue => issue.addAssignee(this.assignee));
}
if (IS_EE && this.milestone) {
if (listFrom && listFrom.type === 'milestone') {
issues.forEach(issue => issue.removeMilestone(listFrom.milestone));
}
issues.forEach(issue => issue.addMilestone(this.milestone));
}
if (listFrom) {
this.issuesSize += issues.length;
this.updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId);
}
}
boardsStore.addMultipleListIssues(this, issues, listFrom, newIndex);
}
addIssue(issue, listFrom, newIndex) {
......
......@@ -131,6 +131,53 @@ const boardsStore = {
listFrom.update();
},
addMultipleListIssues(list, issues, listFrom, newIndex) {
let moveBeforeId = null;
let moveAfterId = null;
const listHasIssues = issues.every(issue => list.findIssue(issue.id));
if (!listHasIssues) {
if (newIndex !== undefined) {
if (list.issues[newIndex - 1]) {
moveBeforeId = list.issues[newIndex - 1].id;
}
if (list.issues[newIndex]) {
moveAfterId = list.issues[newIndex].id;
}
list.issues.splice(newIndex, 0, ...issues);
} else {
list.issues.push(...issues);
}
if (list.label) {
issues.forEach(issue => issue.addLabel(list.label));
}
if (list.assignee) {
if (listFrom && listFrom.type === 'assignee') {
issues.forEach(issue => issue.removeAssignee(listFrom.assignee));
}
issues.forEach(issue => issue.addAssignee(list.assignee));
}
if (IS_EE && list.milestone) {
if (listFrom && listFrom.type === 'milestone') {
issues.forEach(issue => issue.removeMilestone(listFrom.milestone));
}
issues.forEach(issue => issue.addMilestone(list.milestone));
}
if (listFrom) {
list.issuesSize += issues.length;
list.updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId);
}
}
},
startMoving(list, issue) {
Object.assign(this.moving, { list, issue });
},
......
import 'core-js/stable';
// Browser polyfills
import 'formdata-polyfill';
import './polyfills/custom_event';
......
......@@ -168,6 +168,7 @@ export default {
'setIndexPath',
'fetchPaginatedResults',
'updateStatus',
'removeIgnoredResolvedErrors',
]),
setSearchText(text) {
this.errorSearchQuery = text;
......@@ -196,9 +197,9 @@ export default {
updateIssueStatus(errorId, status) {
this.updateStatus({
endpoint: this.getIssueUpdatePath(errorId),
redirectUrl: this.listPath,
status,
});
this.removeIgnoredResolvedErrors(errorId);
},
},
};
......@@ -235,7 +236,6 @@ export default {
</gl-dropdown>
<div class="filtered-search-input-container flex-fill">
<gl-form-input
v-model="errorSearchQuery"
class="pl-2 filtered-search"
:disabled="loading"
:placeholder="__('Search or filter results…')"
......
......@@ -100,4 +100,8 @@ export const fetchPaginatedResults = ({ commit, dispatch }, cursor) => {
dispatch('startPolling');
};
export const removeIgnoredResolvedErrors = ({ commit }, error) => {
commit(types.REMOVE_IGNORED_RESOLVED_ERRORS, error);
};
export default () => {};
......@@ -9,3 +9,4 @@ export const SET_ENDPOINT = 'SET_ENDPOINT';
export const SET_SORT_FIELD = 'SET_SORT_FIELD';
export const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY';
export const SET_CURSOR = 'SET_CURSOR';
export const REMOVE_IGNORED_RESOLVED_ERRORS = 'REMOVE_IGNORED_RESOLVED_ERRORS';
......@@ -59,4 +59,7 @@ export default {
[types.SET_ENDPOINT](state, endpoint) {
state.endpoint = endpoint;
},
[types.REMOVE_IGNORED_RESOLVED_ERRORS](state, error) {
state.errors = state.errors.filter(err => err.id !== error);
},
};
import _ from 'underscore';
import { isMatch } from 'lodash';
import { __, s__, sprintf } from '~/locale';
import { getDisplayName } from '../utils';
......@@ -7,7 +7,7 @@ export const hasProjects = state => Boolean(state.projects) && state.projects.le
export const isProjectInvalid = (state, getters) =>
Boolean(state.selectedProject) &&
getters.hasProjects &&
!state.projects.some(project => _.isMatch(state.selectedProject, project));
!state.projects.some(project => isMatch(state.selectedProject, project));
export const dropdownLabel = (state, getters) => {
if (state.selectedProject !== null) {
......
import _ from 'underscore';
import { pick } from 'lodash';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import * as types from './mutation_types';
import { projectKeys } from '../utils';
......@@ -12,7 +12,7 @@ export default {
.map(convertObjectPropsToCamelCase)
// The `pick` strips out extra properties returned from Sentry.
// Such properties could be problematic later, e.g. when checking whether `projects` contains `selectedProject`
.map(project => _.pick(project, projectKeys));
.map(project => pick(project, projectKeys));
},
[types.RESET_CONNECT](state) {
state.connectSuccessful = false;
......@@ -29,10 +29,7 @@ export default {
state.operationsSettingsEndpoint = operationsSettingsEndpoint;
if (project) {
state.selectedProject = _.pick(
convertObjectPropsToCamelCase(JSON.parse(project)),
projectKeys,
);
state.selectedProject = pick(convertObjectPropsToCamelCase(JSON.parse(project)), projectKeys);
}
},
[types.UPDATE_API_HOST](state, apiHost) {
......
fragment Author on User {
avatarUrl
name
username
webUrl
}
......@@ -10,6 +10,7 @@ import pipelineHeader from './components/header_component.vue';
import eventHub from './event_hub';
import TestReports from './components/test_reports/test_reports.vue';
import testReportsStore from './stores/test_reports';
import axios from '~/lib/utils/axios_utils';
Vue.use(Translate);
......@@ -111,5 +112,12 @@ export default () => {
return createElement('test-reports');
},
});
axios
.get(dataset.testReportEndpoint)
.then(({ data }) => {
document.querySelector('.js-test-report-badge-counter').innerHTML = data.total_count;
})
.catch(() => {});
}
};
fragment Author on Snippet {
author {
name,
avatarUrl,
username,
webUrl
}
}
\ No newline at end of file
#import '../fragments/snippetBase.fragment.graphql'
#import '../fragments/project.fragment.graphql'
#import '../fragments/author.fragment.graphql'
#import "~/graphql_shared/fragments/author.fragment.graphql"
query GetSnippetQuery($ids: [ID!]) {
snippets(ids: $ids) {
......@@ -8,7 +8,9 @@ query GetSnippetQuery($ids: [ID!]) {
node {
...SnippetBase
...Project
...Author
author {
...Author
}
}
}
}
......
......@@ -8,16 +8,13 @@ class KeysFinder
'md5' => 'fingerprint'
}.freeze
def initialize(current_user, params)
@current_user = current_user
def initialize(params)
@params = params
end
def execute
raise GitLabAccessDeniedError unless current_user.admin?
keys = by_key_type
keys = by_user(keys)
keys = by_users(keys)
keys = sort(keys)
by_fingerprint(keys)
......@@ -25,7 +22,7 @@ def execute
private
attr_reader :current_user, :params
attr_reader :params
def by_key_type
if params[:key_type] == 'ssh'
......@@ -39,10 +36,10 @@ def sort(keys)
keys.order_last_used_at_desc
end
def by_user(keys)
return keys unless params[:user]
def by_users(keys)
return keys unless params[:users]
keys.for_user(params[:user])
keys.for_user(params[:users])
end
def by_fingerprint(keys)
......
......@@ -18,7 +18,7 @@
%li.js-tests-tab-link
= link_to test_report_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-tests', action: 'test_report', toggle: 'tab' }, class: 'test-tab' do
= s_('TestReports|Tests')
%span.badge.badge-pill= pipeline.test_reports.total_count
%span.badge.badge-pill.js-test-report-badge-counter
= render_if_exists "projects/pipelines/tabs_holder", pipeline: @pipeline, project: @project
.tab-content
......
---
title: Support for table of contents tag in GitLab Flavored Markdown
merge_request: 24196
author:
type: added
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment