Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
aabf412bc1
commit
b1d7b01241
|
|
@ -1 +1 @@
|
|||
8.10.0
|
||||
8.11.0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import _ from 'underscore';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import updateDescription from '../utils/update_description';
|
||||
|
||||
export default class Store {
|
||||
constructor(initialState) {
|
||||
|
|
@ -19,8 +21,15 @@ export default class Store {
|
|||
}
|
||||
|
||||
Object.assign(this.state, convertObjectPropsToCamelCase(data));
|
||||
// find if there is an open details node inside of the issue description.
|
||||
const descriptionSection = document.body.querySelector(
|
||||
'.detail-page-description.content-block',
|
||||
);
|
||||
const details =
|
||||
!_.isNull(descriptionSection) && descriptionSection.getElementsByTagName('details');
|
||||
|
||||
this.state.descriptionHtml = updateDescription(data.description, details);
|
||||
this.state.titleHtml = data.title;
|
||||
this.state.descriptionHtml = data.description;
|
||||
this.state.lock_version = data.lock_version;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import _ from 'underscore';
|
||||
|
||||
/**
|
||||
* Function that replaces the open attribute for the <details> element.
|
||||
*
|
||||
* @param {String} descriptionHtml - The html string passed back from the server as a result of polling
|
||||
* @param {Array} details - All detail nodes inside of the issue description.
|
||||
*/
|
||||
|
||||
const updateDescription = (descriptionHtml = '', details) => {
|
||||
let detailNodes = details;
|
||||
|
||||
if (_.isEmpty(details)) {
|
||||
detailNodes = [];
|
||||
}
|
||||
|
||||
const placeholder = document.createElement('div');
|
||||
placeholder.innerHTML = descriptionHtml;
|
||||
|
||||
const newDetails = placeholder.getElementsByTagName('details');
|
||||
|
||||
if (newDetails.length !== detailNodes.length) {
|
||||
return descriptionHtml;
|
||||
}
|
||||
|
||||
Array.from(newDetails).forEach((el, i) => {
|
||||
/*
|
||||
* <details> has an open attribute that can have a value, "", "true", "false"
|
||||
* and will show the dropdown, which is why we are setting the attribute
|
||||
* explicitly to true.
|
||||
*/
|
||||
if (detailNodes[i].open) el.setAttribute('open', true);
|
||||
});
|
||||
|
||||
return placeholder.innerHTML;
|
||||
};
|
||||
|
||||
export default updateDescription;
|
||||
|
|
@ -122,7 +122,7 @@ export default {
|
|||
},
|
||||
},
|
||||
series: this.scatterSeries,
|
||||
dataZoom: this.dataZoomConfig,
|
||||
dataZoom: [this.dataZoomConfig],
|
||||
};
|
||||
},
|
||||
dataZoomConfig() {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export default {
|
|||
v-gl-tooltip
|
||||
:title="
|
||||
__(
|
||||
'Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results.',
|
||||
'Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for Pipelines for Merged Results.',
|
||||
)
|
||||
"
|
||||
class="js-pipeline-url-detached badge badge-info"
|
||||
|
|
|
|||
|
|
@ -64,12 +64,16 @@ module Boards
|
|||
%i[label_id]
|
||||
end
|
||||
|
||||
def list_update_attrs
|
||||
%i[collapsed position]
|
||||
end
|
||||
|
||||
def create_list_params
|
||||
params.require(:list).permit(list_creation_attrs)
|
||||
end
|
||||
|
||||
def update_list_params
|
||||
params.require(:list).permit(:collapsed, :position)
|
||||
params.require(:list).permit(list_update_attrs)
|
||||
end
|
||||
|
||||
def serialize_as_json(resource)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This file should be identical in GitLab Community Edition and Enterprise Edition
|
||||
|
||||
class Projects::GitHttpClientController < Projects::ApplicationController
|
||||
include ActionController::HttpAuthentication::Basic
|
||||
include KerberosSpnegoHelper
|
||||
|
|
|
|||
|
|
@ -43,7 +43,11 @@ module Boards
|
|||
end
|
||||
|
||||
def create_list(board, type, target, position)
|
||||
board.lists.create(type => target, list_type: type, position: position)
|
||||
board.lists.create(create_list_attributes(type, target, position))
|
||||
end
|
||||
|
||||
def create_list_attributes(type, target, position)
|
||||
{ type => target, list_type: type, position: position }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,16 +4,22 @@ module Boards
|
|||
module Lists
|
||||
class UpdateService < Boards::BaseService
|
||||
def execute(list)
|
||||
update_preferences_result = update_preferences(list) if can_read?(list)
|
||||
update_position_result = update_position(list) if can_admin?(list)
|
||||
|
||||
if update_preferences_result || update_position_result
|
||||
if execute_by_params(list)
|
||||
success(list: list)
|
||||
else
|
||||
error(list.errors.messages, 422)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def execute_by_params(list)
|
||||
update_preferences_result = update_preferences(list) if can_read?(list)
|
||||
update_position_result = update_position(list) if can_admin?(list)
|
||||
|
||||
update_preferences_result || update_position_result
|
||||
end
|
||||
|
||||
def update_preferences(list)
|
||||
return unless preferences?
|
||||
|
||||
|
|
@ -50,3 +56,5 @@ module Boards
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Boards::Lists::UpdateService.prepend_if_ee('EE::Boards::Lists::UpdateService')
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
} }
|
||||
Auto DevOps
|
||||
- if @pipeline.detached_merge_request_pipeline?
|
||||
%span.js-pipeline-url-mergerequest.badge.badge-info.has-tooltip{ title: _('Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results.') }
|
||||
%span.js-pipeline-url-mergerequest.badge.badge-info.has-tooltip{ title: _('Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for Pipelines for Merged Results.') }
|
||||
detached
|
||||
- if @pipeline.stuck?
|
||||
%span.js-pipeline-url-stuck.badge.badge-warning
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: When user toggles task list item, keep details open until user closes the details
|
||||
manually
|
||||
merge_request: 16153
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Handle wiki and graphql attachments in gitlab-workhorse
|
||||
merge_request: 17690
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Better job naming for Docker.gitlab-ci.yml
|
||||
merge_request: 17218
|
||||
author: luca.orlandi@gmail.com
|
||||
type: other
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMaxIssueCountToList < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
disable_ddl_transaction!
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
add_column_with_default :lists, :max_issue_count, :integer, default: 0
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :lists, :max_issue_count
|
||||
end
|
||||
end
|
||||
|
|
@ -2014,6 +2014,7 @@ ActiveRecord::Schema.define(version: 2019_09_19_162036) do
|
|||
t.datetime "updated_at", null: false
|
||||
t.integer "user_id"
|
||||
t.integer "milestone_id"
|
||||
t.integer "max_issue_count", default: 0, null: false
|
||||
t.index ["board_id", "label_id"], name: "index_lists_on_board_id_and_label_id", unique: true
|
||||
t.index ["label_id"], name: "index_lists_on_label_id"
|
||||
t.index ["list_type"], name: "index_lists_on_list_type"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
|
|
@ -57,7 +58,8 @@ Example response:
|
|||
"color" : "#FF0000",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 2
|
||||
"position" : 2,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
|
|
@ -66,7 +68,8 @@ Example response:
|
|||
"color" : "#FF5F00",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 3
|
||||
"position" : 3,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -117,7 +120,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
|
|
@ -126,7 +130,8 @@ Example response:
|
|||
"color" : "#FF0000",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 2
|
||||
"position" : 2,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
|
|
@ -135,7 +140,8 @@ Example response:
|
|||
"color" : "#FF5F00",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 3
|
||||
"position" : 3,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -185,7 +191,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
|
|
@ -194,7 +201,8 @@ Example response:
|
|||
"color" : "#FF0000",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 2
|
||||
"position" : 2,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
|
|
@ -203,7 +211,8 @@ Example response:
|
|||
"color" : "#FF5F00",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 3
|
||||
"position" : 3,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -336,7 +345,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
|
|
@ -345,7 +355,8 @@ Example response:
|
|||
"color" : "#FF0000",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 2
|
||||
"position" : 2,
|
||||
"max_issue_count": 0
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
|
|
@ -354,7 +365,8 @@ Example response:
|
|||
"color" : "#FF5F00",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 3
|
||||
"position" : 3,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
|
@ -387,7 +399,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -427,7 +440,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -460,7 +474,8 @@ Example response:
|
|||
"color" : "#F0AD4E",
|
||||
"description" : null
|
||||
},
|
||||
"position" : 1
|
||||
"position" : 1,
|
||||
"max_issue_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
build-master:
|
||||
docker-build-master:
|
||||
# Official docker image.
|
||||
image: docker:latest
|
||||
stage: build
|
||||
|
|
@ -12,7 +12,7 @@ build-master:
|
|||
only:
|
||||
- master
|
||||
|
||||
build:
|
||||
docker-build:
|
||||
# Official docker image.
|
||||
image: docker:latest
|
||||
stage: build
|
||||
|
|
|
|||
|
|
@ -11176,7 +11176,7 @@ msgstr ""
|
|||
msgid "Pipelines for last year"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more on the documentation for Pipelines for Merged Results."
|
||||
msgid "Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for Pipelines for Merged Results."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines settings for '%{project_name}' were successfully updated."
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@
|
|||
}
|
||||
},
|
||||
"title": { "type": "string" },
|
||||
"position": { "type": ["integer", "null"] }
|
||||
"position": { "type": ["integer", "null"] },
|
||||
"max_issue_count": { "type": "integer" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@
|
|||
"name": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"position": { "type": ["integer", "null"] }
|
||||
"position": { "type": ["integer", "null"] },
|
||||
"max_issue_count": { "type": "integer" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import Store from '~/issue_show/stores';
|
||||
import updateDescription from '~/issue_show/utils/update_description';
|
||||
|
||||
jest.mock('~/issue_show/utils/update_description');
|
||||
|
||||
describe('Store', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = new Store({
|
||||
descriptionHtml: '<p>This is a description</p>',
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateState', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `
|
||||
<div class="detail-page-description content-block">
|
||||
<details open>
|
||||
<summary>One</summary>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Two</summary>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.getElementsByTagName('html')[0].innerHTML = '';
|
||||
});
|
||||
|
||||
it('calls updateDetailsState', () => {
|
||||
store.updateState({ description: '' });
|
||||
|
||||
expect(updateDescription).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import updateDescription from '~/issue_show/utils/update_description';
|
||||
|
||||
describe('updateDescription', () => {
|
||||
it('returns the correct value to be set as descriptionHtml', () => {
|
||||
const actual = updateDescription(
|
||||
'<details><summary>One</summary></details><details><summary>Two</summary></details>',
|
||||
[{ open: true }, { open: false }], // mocking NodeList from the dom.
|
||||
);
|
||||
|
||||
expect(actual).toEqual(
|
||||
'<details open="true"><summary>One</summary></details><details><summary>Two</summary></details>',
|
||||
);
|
||||
});
|
||||
|
||||
describe('when description details returned from api is different then whats currently on the dom', () => {
|
||||
it('returns the description from the api', () => {
|
||||
const dataDescription = '<details><summary>One</summary></details>';
|
||||
|
||||
const actual = updateDescription(dataDescription, []);
|
||||
|
||||
expect(actual).toEqual(dataDescription);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -23,6 +23,14 @@ describe('Issuable output', () => {
|
|||
beforeEach(done => {
|
||||
setFixtures(`
|
||||
<div>
|
||||
<div class="detail-page-description content-block">
|
||||
<details open>
|
||||
<summary>One</summary>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Two</summary>
|
||||
</details>
|
||||
</div>
|
||||
<div class="flash-container"></div>
|
||||
<span id="task_status"></span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -140,6 +140,16 @@ describe('Time series component', () => {
|
|||
expect(timeSeriesChart.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('contains an svg object within an array to properly render icon', () => {
|
||||
timeSeriesChart.vm.$nextTick(() => {
|
||||
expect(timeSeriesChart.vm.chartOptions.dataZoom).toEqual([
|
||||
{
|
||||
handleIcon: `path://${mockSvgPathContent}`,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onResize', () => {
|
||||
|
|
|
|||
|
|
@ -717,6 +717,7 @@ List:
|
|||
- updated_at
|
||||
- milestone_id
|
||||
- user_id
|
||||
- max_issue_count
|
||||
ExternalPullRequest:
|
||||
- id
|
||||
- created_at
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f }
|
||||
|
||||
RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
|
||||
let(:chat_service) { described_class.new }
|
||||
let(:webhook_url) { 'https://example.gitlab.com/' }
|
||||
|
|
|
|||
Loading…
Reference in New Issue