Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-09-25 15:06:16 +00:00
parent aabf412bc1
commit b1d7b01241
26 changed files with 226 additions and 35 deletions

View File

@ -1 +1 @@
8.10.0
8.11.0

View File

@ -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;
}

View File

@ -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;

View File

@ -122,7 +122,7 @@ export default {
},
},
series: this.scatterSeries,
dataZoom: this.dataZoomConfig,
dataZoom: [this.dataZoomConfig],
};
},
dataZoomConfig() {

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
---
title: Handle wiki and graphql attachments in gitlab-workhorse
merge_request: 17690
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Better job naming for Docker.gitlab-ci.yml
merge_request: 17218
author: luca.orlandi@gmail.com
type: other

View File

@ -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

View File

@ -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"

View File

@ -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
}
```

View File

@ -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

View File

@ -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."

View File

@ -35,7 +35,8 @@
}
},
"title": { "type": "string" },
"position": { "type": ["integer", "null"] }
"position": { "type": ["integer", "null"] },
"max_issue_count": { "type": "integer" }
},
"additionalProperties": true
}

View File

@ -76,7 +76,8 @@
"name": { "type": "string" }
}
},
"position": { "type": ["integer", "null"] }
"position": { "type": ["integer", "null"] },
"max_issue_count": { "type": "integer" }
},
"additionalProperties": false
}

View File

@ -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);
});
});
});

View File

@ -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);
});
});
});

View File

@ -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>

View File

@ -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', () => {

View File

@ -717,6 +717,7 @@ List:
- updated_at
- milestone_id
- user_id
- max_issue_count
ExternalPullRequest:
- id
- created_at

View File

@ -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/' }