diff options
26 files changed, 226 insertions, 35 deletions
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 7f6758ef97b..db3905bf80f 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -8.10.0 +8.11.0 diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index d32747b5053..688ba7b268d 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -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; } diff --git a/app/assets/javascripts/issue_show/utils/update_description.js b/app/assets/javascripts/issue_show/utils/update_description.js new file mode 100644 index 00000000000..315f6c23b02 --- /dev/null +++ b/app/assets/javascripts/issue_show/utils/update_description.js @@ -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; diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index f3f3bf15295..64d0a713b13 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -122,7 +122,7 @@ export default { }, }, series: this.scatterSeries, - dataZoom: this.dataZoomConfig, + dataZoom: [this.dataZoomConfig], }; }, dataZoomConfig() { diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue index a08f732dda7..30c830d78f9 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue @@ -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" diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb index d0f4904c34e..b64b18505b6 100644 --- a/app/controllers/boards/lists_controller.rb +++ b/app/controllers/boards/lists_controller.rb @@ -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) diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb index a597cc9af32..ccfc38d97b2 100644 --- a/app/controllers/projects/git_http_client_controller.rb +++ b/app/controllers/projects/git_http_client_controller.rb @@ -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 diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb index eb417ac4f5f..6f9a063cb16 100644 --- a/app/services/boards/lists/create_service.rb +++ b/app/services/boards/lists/create_service.rb @@ -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 diff --git a/app/services/boards/lists/update_service.rb b/app/services/boards/lists/update_service.rb index ad96e42f756..4a463372c82 100644 --- a/app/services/boards/lists/update_service.rb +++ b/app/services/boards/lists/update_service.rb @@ -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') diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml index 53bb3c7487d..7187afc7754 100644 --- a/app/views/projects/pipelines/_info.html.haml +++ b/app/views/projects/pipelines/_info.html.haml @@ -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 diff --git a/changelogs/unreleased/61933-toggling-a-task-inside-a-collapsible-section-collapses-all-sections.yml b/changelogs/unreleased/61933-toggling-a-task-inside-a-collapsible-section-collapses-all-sections.yml new file mode 100644 index 00000000000..2239bffcd5e --- /dev/null +++ b/changelogs/unreleased/61933-toggling-a-task-inside-a-collapsible-section-collapses-all-sections.yml @@ -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 diff --git a/changelogs/unreleased/ac-workhorse-8-11-0.yml b/changelogs/unreleased/ac-workhorse-8-11-0.yml new file mode 100644 index 00000000000..1f86416449e --- /dev/null +++ b/changelogs/unreleased/ac-workhorse-8-11-0.yml @@ -0,0 +1,5 @@ +--- +title: Handle wiki and graphql attachments in gitlab-workhorse +merge_request: 17690 +author: +type: performance diff --git a/changelogs/unreleased/patch-29.yml b/changelogs/unreleased/patch-29.yml new file mode 100644 index 00000000000..e5e1d639a69 --- /dev/null +++ b/changelogs/unreleased/patch-29.yml @@ -0,0 +1,5 @@ +--- +title: Better job naming for Docker.gitlab-ci.yml +merge_request: 17218 +author: luca.orlandi@gmail.com +type: other diff --git a/db/migrate/20190901174200_add_max_issue_count_to_list.rb b/db/migrate/20190901174200_add_max_issue_count_to_list.rb new file mode 100644 index 00000000000..59359f28d6a --- /dev/null +++ b/db/migrate/20190901174200_add_max_issue_count_to_list.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index a4d244e556f..6674e00950a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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" diff --git a/doc/api/boards.md b/doc/api/boards.md index 151ab5487dd..b9c2a984dc5 100644 --- a/doc/api/boards.md +++ b/doc/api/boards.md @@ -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 } ``` diff --git a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml index f6d240b7b6d..15cdbf63cb1 100644 --- a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ca62f137ac3..de2406ceb1d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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." diff --git a/spec/fixtures/api/schemas/list.json b/spec/fixtures/api/schemas/list.json index b76ec115293..7603892e198 100644 --- a/spec/fixtures/api/schemas/list.json +++ b/spec/fixtures/api/schemas/list.json @@ -35,7 +35,8 @@ } }, "title": { "type": "string" }, - "position": { "type": ["integer", "null"] } + "position": { "type": ["integer", "null"] }, + "max_issue_count": { "type": "integer" } }, "additionalProperties": true } diff --git a/spec/fixtures/api/schemas/public_api/v4/board.json b/spec/fixtures/api/schemas/public_api/v4/board.json index d667f1d631c..8dc3999baa2 100644 --- a/spec/fixtures/api/schemas/public_api/v4/board.json +++ b/spec/fixtures/api/schemas/public_api/v4/board.json @@ -76,7 +76,8 @@ "name": { "type": "string" } } }, - "position": { "type": ["integer", "null"] } + "position": { "type": ["integer", "null"] }, + "max_issue_count": { "type": "integer" } }, "additionalProperties": false } diff --git a/spec/frontend/issue_show/store_spec.js b/spec/frontend/issue_show/store_spec.js new file mode 100644 index 00000000000..b7fd70bf00e --- /dev/null +++ b/spec/frontend/issue_show/store_spec.js @@ -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); + }); + }); +}); diff --git a/spec/frontend/issue_show/utils/update_description_spec.js b/spec/frontend/issue_show/utils/update_description_spec.js new file mode 100644 index 00000000000..b2c6bd3c302 --- /dev/null +++ b/spec/frontend/issue_show/utils/update_description_spec.js @@ -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); + }); + }); +}); diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index c3d1440c34e..9fce040fd8c 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -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> diff --git a/spec/javascripts/monitoring/charts/time_series_spec.js b/spec/javascripts/monitoring/charts/time_series_spec.js index f6a5ed03c0d..091ab06523e 100644 --- a/spec/javascripts/monitoring/charts/time_series_spec.js +++ b/spec/javascripts/monitoring/charts/time_series_spec.js @@ -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', () => { diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 2f178648838..f87b0cdd3c6 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -717,6 +717,7 @@ List: - updated_at - milestone_id - user_id +- max_issue_count ExternalPullRequest: - id - created_at diff --git a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb index 455f7b117b2..1ead9ec2738 100644 --- a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb +++ b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb @@ -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/' } |