Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-30 00:09:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-30 00:09:52 +0300
commitb86a07e9b7332bf5d2815716b2220299ffd7a223 (patch)
tree29206bd07a8af3885fe6c9d35f2e51daafadc38e
parent12a62cd94406f23fc3782e4914ca282196eb25f6 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/issue_templates/Feature proposal.md14
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue6
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue2
-rw-r--r--app/assets/javascripts/error_tracking/components/stacktrace_entry.vue4
-rw-r--r--app/assets/javascripts/incidents_settings/components/pagerduty_form.vue2
-rw-r--r--app/assets/javascripts/mr_notes/init_notes.js6
-rw-r--r--app/assets/javascripts/notes/components/discussion_navigator.vue (renamed from app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue)0
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_custom_renderer.js16
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_softbreak.js7
-rw-r--r--app/assets/stylesheets/components/dashboard_skeleton.scss2
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss2
-rw-r--r--app/assets/stylesheets/components/rich_content_editor.scss4
-rw-r--r--app/assets/stylesheets/framework/common.scss4
-rw-r--r--app/assets/stylesheets/framework/typography.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/alert_management/severity-icons.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss2
-rw-r--r--app/graphql/mutations/notes/update/base.rb2
-rw-r--r--app/graphql/mutations/notes/update/note.rb7
-rw-r--r--app/serializers/merge_request_poll_widget_entity.rb4
-rw-r--r--changelogs/unreleased/207472-api-update-note-conf.yml5
-rw-r--r--changelogs/unreleased/207473-graphl-update-note-conf.yml5
-rw-r--r--changelogs/unreleased/218526-remove-again-gitlab-issue-tracker-service.yml5
-rw-r--r--changelogs/unreleased/224119-replace-gray-400-value-replace-usages-with-gray-200.yml5
-rw-r--r--changelogs/unreleased/fix-ordered-lists-single-marker-bug.yml6
-rw-r--r--changelogs/unreleased/id-enable-pipelines-serializer-ff.yml5
-rw-r--r--db/post_migrate/20200727100631_remove_again_gitlab_issue_tracker_service_records.rb28
-rw-r--r--db/schema_migrations/202007271006311
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql68
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json219
-rw-r--r--doc/api/graphql/reference/index.md16
-rw-r--r--doc/api/notes.md9
-rw-r--r--doc/university/training/topics/explore_gitlab.md11
-rw-r--r--lib/api/helpers/notes_helpers.rb5
-rw-r--r--lib/api/notes.rb3
-rw-r--r--package.json4
-rw-r--r--spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap4
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap2
-rw-r--r--spec/frontend/notes/components/discussion_navigator_spec.js (renamed from spec/frontend/notes/components/discussion_keyboard_navigator_spec.js)8
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js17
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js9
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js23
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/note_spec.rb39
-rw-r--r--spec/services/notes/update_service_spec.rb10
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb55
-rw-r--r--yarn.lock18
48 files changed, 592 insertions, 97 deletions
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md
index 589310b4cef..dc32ce1288d 100644
--- a/.gitlab/issue_templates/Feature proposal.md
+++ b/.gitlab/issue_templates/Feature proposal.md
@@ -87,4 +87,18 @@ In which enterprise tier should this feature go? See https://about.gitlab.com/ha
### Links / references
+<!-- Label reminders - you should have one of each of the following labels if you can find the correct ones!
+
+Type - for example ~feature ~bug ~documentation ~meta /label ~"feature::addition" ~"feature::maintenance" ~tooling ~"tooling::pipelines" ~"tooling::workflow" per https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#type-labels
+
+DevOps stage - for example ~"devops::secure"
+
+Group - for example ~"group::composition analysis"
+
+Category - for example ~"Category:Dependency Scanning"
+<!-- Label reminders - you should have one of each of the following labels if you can figure out the correct ones! -->
+/label ~"devops::
+/label ~"group::
+/label ~"Category:
+
/label ~feature
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
index 18c9f82f052..56ecf0d9c55 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
@@ -435,7 +435,7 @@ export default {
data-testid="alert-settings-select"
@change="resetFormValues"
/>
- <span class="gl-text-gray-400">
+ <span class="gl-text-gray-200">
<gl-sprintf :message="$options.i18n.integrationsInfo">
<template #link="{ content }">
<gl-link
@@ -474,7 +474,7 @@ export default {
:placeholder="baseUrlPlaceholder"
:disabled="!selectedService.active"
/>
- <span class="gl-text-gray-400">
+ <span class="gl-text-gray-200">
{{ $options.i18n.apiBaseUrlHelpText }}
</span>
</gl-form-group>
@@ -489,7 +489,7 @@ export default {
/>
</template>
</gl-form-input-group>
- <span class="gl-text-gray-400">
+ <span class="gl-text-gray-200">
{{ prometheusInfo }}
</span>
</gl-form-group>
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
index 7e9b720d269..09d7c0329a9 100644
--- a/app/assets/javascripts/clusters_list/components/clusters.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -231,7 +231,7 @@ export default {
<gl-skeleton-loading v-else-if="loadingNodes" :lines="1" :class="contentAlignClasses" />
- <small v-else class="gl-font-sm gl-font-style-italic gl-text-gray-400">{{
+ <small v-else class="gl-font-sm gl-font-style-italic gl-text-gray-200">{{
__('Unknown')
}}</small>
</template>
diff --git a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
index c22f34b5a8d..c6825d7af45 100644
--- a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
+++ b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
@@ -99,7 +99,7 @@ export default {
<gl-sprintf v-if="errorFn" :message="__('%{spanStart}in%{spanEnd} %{errorFn}')">
<template #span="{content}">
- <span class="gl-text-gray-400">{{ content }}&nbsp;</span>
+ <span class="gl-text-gray-200">{{ content }}&nbsp;</span>
</template>
<template #errorFn>
<strong>{{ errorFn }}&nbsp;</strong>
@@ -108,7 +108,7 @@ export default {
<gl-sprintf :message="__('%{spanStart}at line%{spanEnd} %{errorLine}%{errorColumn}')">
<template #span="{content}">
- <span class="gl-text-gray-400">{{ content }}&nbsp;</span>
+ <span class="gl-text-gray-200">{{ content }}&nbsp;</span>
</template>
<template #errorLine>
<strong>{{ errorLine }}</strong>
diff --git a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
index 027848db6e9..7b37fddd630 100644
--- a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
@@ -135,7 +135,7 @@ export default {
</template>
</gl-form-input-group>
- <div class="gl-text-gray-400 gl-pt-2">
+ <div class="gl-text-gray-200 gl-pt-2">
<gl-sprintf :message="$options.i18n.webhookUrl.helpText">
<template #docsLink>
<gl-link
diff --git a/app/assets/javascripts/mr_notes/init_notes.js b/app/assets/javascripts/mr_notes/init_notes.js
index 0fd4b1e7f4a..2be7cc951fc 100644
--- a/app/assets/javascripts/mr_notes/init_notes.js
+++ b/app/assets/javascripts/mr_notes/init_notes.js
@@ -3,7 +3,7 @@ import Vue from 'vue';
import { mapActions, mapState, mapGetters } from 'vuex';
import store from '~/mr_notes/stores';
import notesApp from '../notes/components/notes_app.vue';
-import discussionKeyboardNavigator from '../notes/components/discussion_keyboard_navigator.vue';
+import discussionNavigator from '../notes/components/discussion_navigator.vue';
import initWidget from '../vue_merge_request_widget';
import { parseBoolean } from '~/lib/utils/common_utils';
@@ -71,11 +71,11 @@ export default () => {
},
},
render(createElement) {
- // NOTE: Even though `discussionKeyboardNavigator` is added to the `notes-app`,
+ // NOTE: Even though `discussionNavigator` is added to the `notes-app`,
// it adds a global key listener so it works on the diffs tab as well.
// If we create a single Vue app for all of the MR tabs, we should move this
// up the tree, to the root.
- return createElement(discussionKeyboardNavigator, [
+ return createElement(discussionNavigator, [
createElement('notes-app', {
props: {
noteableData: this.noteableData,
diff --git a/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue b/app/assets/javascripts/notes/components/discussion_navigator.vue
index facc53e27a6..facc53e27a6 100644
--- a/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue
+++ b/app/assets/javascripts/notes/components/discussion_navigator.vue
diff --git a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
index caf13bc898b..e11b0cd67cc 100644
--- a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
@@ -38,13 +38,6 @@ export default {
},
);
},
- heightStyle() {
- return {
- minHeight: '32px',
- width: '0px',
- visibility: 'hidden',
- };
- },
iconClasses() {
return `${this.iconClass} ic-${this.iconName}`;
},
@@ -60,7 +53,9 @@ export default {
}"
class="item-body d-flex align-items-center py-2 px-3"
>
- <div class="item-contents d-flex align-items-center flex-wrap flex-grow-1 flex-xl-nowrap">
+ <div
+ class="item-contents gl-display-flex gl-align-items-center gl-flex-wrap gl-flex-grow-1 flex-xl-nowrap gl-min-h-7"
+ >
<!-- Title area: Status icon (XL) and title -->
<div class="item-title d-flex align-items-xl-center mb-xl-0">
<div ref="iconElementXL">
@@ -159,9 +154,5 @@ export default {
>
<icon :size="16" class="btn-item-remove-icon" name="close" />
</button>
-
- <!-- This element serves to set the issue card's height at a minimum of 32 px. -->
- <!-- It fixes #59594: when the remove button is missing, issues have inconsistent heights. -->
- <span :style="heightStyle"></span>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_custom_renderer.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_custom_renderer.js
index 70d29b5b3df..bd374a54d98 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_custom_renderer.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_custom_renderer.js
@@ -5,12 +5,14 @@ import renderIdentifierInstanceText from './renderers/render_identifier_instance
import renderIdentifierParagraph from './renderers/render_identifier_paragraph';
import renderEmbeddedRubyText from './renderers/render_embedded_ruby_text';
import renderFontAwesomeHtmlInline from './renderers/render_font_awesome_html_inline';
+import renderSoftbreak from './renderers/render_softbreak';
const htmlInlineRenderers = [renderFontAwesomeHtmlInline];
const htmlBlockRenderers = [renderBlockHtml];
const listRenderers = [renderKramdownList];
const paragraphRenderers = [renderIdentifierParagraph];
const textRenderers = [renderKramdownText, renderEmbeddedRubyText, renderIdentifierInstanceText];
+const softbreakRenderers = [renderSoftbreak];
const executeRenderer = (renderers, node, context) => {
const availableRenderer = renderers.find(renderer => renderer.canRender(node, context));
@@ -29,7 +31,14 @@ const buildCustomRendererFunctions = (customRenderers, defaults) => {
};
const buildCustomHTMLRenderer = (
- customRenderers = { htmlBlock: [], htmlInline: [], list: [], paragraph: [], text: [] },
+ customRenderers = {
+ htmlBlock: [],
+ htmlInline: [],
+ list: [],
+ paragraph: [],
+ text: [],
+ softbreak: [],
+ },
) => {
const defaults = {
htmlBlock(node, context) {
@@ -57,6 +66,11 @@ const buildCustomHTMLRenderer = (
return executeRenderer(allTextRenderers, node, context);
},
+ softbreak(node, context) {
+ const allSoftbreakRenderers = [...customRenderers.softbreak, ...softbreakRenderers];
+
+ return executeRenderer(allSoftbreakRenderers, node, context);
+ },
};
return {
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js
index 89a0df395d3..868ede9426e 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js
@@ -69,7 +69,7 @@ const buildHTMLToMarkdownRender = (baseRenderer, formattingPreferences = {}) =>
[orderedListItemNode](node, subContent) {
const baseResult = baseRenderer.convert(node, subContent);
- return incrementListMarker ? baseResult : baseResult.replace(/^(\s*)\d\./, '$11.');
+ return incrementListMarker ? baseResult : baseResult.replace(/^(\s*)\d+?\./, '$11.');
},
[emphasisNode](node, subContent) {
const result = baseRenderer.convert(node, subContent);
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_softbreak.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_softbreak.js
new file mode 100644
index 00000000000..389ade5f27a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_softbreak.js
@@ -0,0 +1,7 @@
+const canRender = node => ['emph', 'strong'].includes(node.parent?.type);
+const render = () => ({
+ type: 'text',
+ content: ' ',
+});
+
+export default { canRender, render };
diff --git a/app/assets/stylesheets/components/dashboard_skeleton.scss b/app/assets/stylesheets/components/dashboard_skeleton.scss
index a35222bca95..1f257d96d94 100644
--- a/app/assets/stylesheets/components/dashboard_skeleton.scss
+++ b/app/assets/stylesheets/components/dashboard_skeleton.scss
@@ -41,7 +41,7 @@
}
&-extra {
- background-color: $gray-400;
+ background-color: $gray-200;
font-size: 10px;
line-height: $gl-line-height;
width: $gl-padding;
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index dd749b4df1a..499aa6440da 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -104,7 +104,7 @@ $item-remove-button-space: 42px;
.bullet-separator {
font-size: 9px;
- color: $gray-400;
+ color: $gray-200;
}
}
diff --git a/app/assets/stylesheets/components/rich_content_editor.scss b/app/assets/stylesheets/components/rich_content_editor.scss
index 8d31b386d9e..425c67ee188 100644
--- a/app/assets/stylesheets/components/rich_content_editor.scss
+++ b/app/assets/stylesheets/components/rich_content_editor.scss
@@ -20,11 +20,11 @@
.tui-popup-wrapper {
@include gl-overflow-hidden;
@include gl-rounded-base;
- @include gl-border-gray-400;
+ @include gl-border-gray-200;
hr {
@include gl-m-0;
- @include gl-bg-gray-400;
+ @include gl-bg-gray-200;
}
button {
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index f92db122209..0c1f19e9420 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -74,7 +74,7 @@
.hint {
font-style: italic;
- color: $gl-gray-400;
+ color: $gl-gray-200;
}
.light { color: $gl-text-color; }
@@ -168,7 +168,7 @@ table {
}
p.time {
- color: $gl-gray-400;
+ color: $gl-gray-200;
font-size: 90%;
margin: 30px 3px 3px 2px;
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index b002ced9393..8758fe15870 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -89,10 +89,10 @@
background-color: $gray-10;
border-width: 1px;
border-style: solid;
- border-color: $gray-100 $gray-100 $gray-400;
+ border-color: $gray-100 $gray-100 $gray-200;
border-image: none;
border-radius: 3px;
- box-shadow: 0 -1px 0 $gray-400 inset;
+ box-shadow: 0 -1px 0 $gray-200 inset;
}
h1 {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index f7c0617a135..11a948eb2e5 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -166,7 +166,7 @@ $gray-50: #f0f0f0 !default;
$gray-100: #dbdbdb !default;
$gray-200: #bfbfbf !default;
$gray-300: #999 !default;
-$gray-400: #bababa !default;
+$gray-400: #868686 !default;
$gray-500: #a7a7a7 !default;
$gray-600: #919191 !default;
$gray-700: #707070 !default;
diff --git a/app/assets/stylesheets/pages/alert_management/severity-icons.scss b/app/assets/stylesheets/pages/alert_management/severity-icons.scss
index 0e00d78e53a..6004697b3e1 100644
--- a/app/assets/stylesheets/pages/alert_management/severity-icons.scss
+++ b/app/assets/stylesheets/pages/alert_management/severity-icons.scss
@@ -21,6 +21,6 @@
}
.icon-unknown {
- color: $gray-400;
+ color: $gray-200;
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 5abf8e1c64f..5e4c43d5b1e 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -825,7 +825,7 @@
}
.repository-language-bar-tooltip-share {
- color: $gray-400;
+ color: $gray-200;
}
pre.light-well {
diff --git a/app/graphql/mutations/notes/update/base.rb b/app/graphql/mutations/notes/update/base.rb
index 9a53337f253..8a2a78a29ec 100644
--- a/app/graphql/mutations/notes/update/base.rb
+++ b/app/graphql/mutations/notes/update/base.rb
@@ -40,7 +40,7 @@ module Mutations
end
def note_params(_note, args)
- { note: args[:body] }.compact
+ { note: args[:body], confidential: args[:confidential] }.compact
end
end
end
diff --git a/app/graphql/mutations/notes/update/note.rb b/app/graphql/mutations/notes/update/note.rb
index 03a174fc8d9..ca97dad6ded 100644
--- a/app/graphql/mutations/notes/update/note.rb
+++ b/app/graphql/mutations/notes/update/note.rb
@@ -8,9 +8,14 @@ module Mutations
argument :body,
GraphQL::STRING_TYPE,
- required: true,
+ required: false,
description: copy_field_description(Types::Notes::NoteType, :body)
+ argument :confidential,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'The confidentiality flag of a note. Default is false.'
+
private
def pre_update_checks!(note, _args)
diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb
index c27d571245b..99d6211b487 100644
--- a/app/serializers/merge_request_poll_widget_entity.rb
+++ b/app/serializers/merge_request_poll_widget_entity.rb
@@ -20,7 +20,7 @@ class MergeRequestPollWidgetEntity < Grape::Entity
expose :merge_user, using: UserEntity
expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) { presenter(mr).can_read_pipeline? } do |merge_request, options|
- if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project)
+ if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project, default_enabled: true)
MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
else
PipelineDetailsEntity.represent(merge_request.actual_head_pipeline, options)
@@ -28,7 +28,7 @@ class MergeRequestPollWidgetEntity < Grape::Entity
end
expose :merge_pipeline, if: ->(mr, _) { mr.merged? && can?(request.current_user, :read_pipeline, mr.target_project)} do |merge_request, options|
- if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project)
+ if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project, default_enabled: true)
MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
else
PipelineDetailsEntity.represent(merge_request.merge_pipeline, options)
diff --git a/changelogs/unreleased/207472-api-update-note-conf.yml b/changelogs/unreleased/207472-api-update-note-conf.yml
new file mode 100644
index 00000000000..4b2df2e4fe2
--- /dev/null
+++ b/changelogs/unreleased/207472-api-update-note-conf.yml
@@ -0,0 +1,5 @@
+---
+title: Add confidential attribute to public API for notes update
+merge_request: 37932
+author:
+type: added
diff --git a/changelogs/unreleased/207473-graphl-update-note-conf.yml b/changelogs/unreleased/207473-graphl-update-note-conf.yml
new file mode 100644
index 00000000000..e49f2805ae0
--- /dev/null
+++ b/changelogs/unreleased/207473-graphl-update-note-conf.yml
@@ -0,0 +1,5 @@
+---
+title: Add confidential attribute to graphQL for notes update
+merge_request: 37920
+author:
+type: added
diff --git a/changelogs/unreleased/218526-remove-again-gitlab-issue-tracker-service.yml b/changelogs/unreleased/218526-remove-again-gitlab-issue-tracker-service.yml
new file mode 100644
index 00000000000..93094d8623e
--- /dev/null
+++ b/changelogs/unreleased/218526-remove-again-gitlab-issue-tracker-service.yml
@@ -0,0 +1,5 @@
+---
+title: Remove GitlabIssueTrackerService database records
+merge_request: 37931
+author:
+type: other
diff --git a/changelogs/unreleased/224119-replace-gray-400-value-replace-usages-with-gray-200.yml b/changelogs/unreleased/224119-replace-gray-400-value-replace-usages-with-gray-200.yml
new file mode 100644
index 00000000000..f46f4675041
--- /dev/null
+++ b/changelogs/unreleased/224119-replace-gray-400-value-replace-usages-with-gray-200.yml
@@ -0,0 +1,5 @@
+---
+title: Update $gray-400 hex and replace instances of $gray-400 with $gray-200
+merge_request: 37813
+author:
+type: other
diff --git a/changelogs/unreleased/fix-ordered-lists-single-marker-bug.yml b/changelogs/unreleased/fix-ordered-lists-single-marker-bug.yml
new file mode 100644
index 00000000000..9ef32919ab8
--- /dev/null
+++ b/changelogs/unreleased/fix-ordered-lists-single-marker-bug.yml
@@ -0,0 +1,6 @@
+---
+title: 'Static Site Editor: Fix ordered list formatting bug and rendering bug in strong
+ and emphasis nodes with softbreaks'
+merge_request: 37964
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-enable-pipelines-serializer-ff.yml b/changelogs/unreleased/id-enable-pipelines-serializer-ff.yml
new file mode 100644
index 00000000000..2e7587f2662
--- /dev/null
+++ b/changelogs/unreleased/id-enable-pipelines-serializer-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Serialize fewer pipeline fields for MR widget
+merge_request: 38215
+author:
+type: performance
diff --git a/db/post_migrate/20200727100631_remove_again_gitlab_issue_tracker_service_records.rb b/db/post_migrate/20200727100631_remove_again_gitlab_issue_tracker_service_records.rb
new file mode 100644
index 00000000000..b61da82aef8
--- /dev/null
+++ b/db/post_migrate/20200727100631_remove_again_gitlab_issue_tracker_service_records.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class RemoveAgainGitlabIssueTrackerServiceRecords < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+ BATCH_SIZE = 5000
+
+ disable_ddl_transaction!
+
+ class Service < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'services'
+
+ def self.gitlab_issue_tracker_service
+ where(type: 'GitlabIssueTrackerService')
+ end
+ end
+
+ def up
+ Service.each_batch(of: BATCH_SIZE) do |services|
+ services.gitlab_issue_tracker_service.delete_all
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20200727100631 b/db/schema_migrations/20200727100631
new file mode 100644
index 00000000000..aa724c13995
--- /dev/null
+++ b/db/schema_migrations/20200727100631
@@ -0,0 +1 @@
+83c1dca01d4e56c22f6c1cda249c9b162eb7c31e2b164629bf51ea9aa9dd8fb5 \ No newline at end of file
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index ec602222f3b..c86f405dfb9 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -5664,6 +5664,11 @@ type Group {
): VulnerabilitiesCountByDayAndSeverityConnection
"""
+ Represents vulnerable project counts for each grade
+ """
+ vulnerabilityGrades: [VulnerableProjectsByGrade!]!
+
+ """
Vulnerability scanners reported on the project vulnerabilties of the group and its subgroups
"""
vulnerabilityScanners(
@@ -5817,6 +5822,11 @@ type InstanceSecurityDashboard {
): ProjectConnection!
"""
+ Represents vulnerable project counts for each grade
+ """
+ vulnerabilityGrades: [VulnerableProjectsByGrade!]!
+
+ """
Vulnerability scanners reported on the vulnerabilties from projects selected in Instance Security Dashboard
"""
vulnerabilityScanners(
@@ -14312,7 +14322,7 @@ input UpdateNoteInput {
"""
Content of the note
"""
- body: String!
+ body: String
"""
A unique identifier for the client performing the mutation.
@@ -14320,6 +14330,11 @@ input UpdateNoteInput {
clientMutationId: String
"""
+ The confidentiality flag of a note. Default is false.
+ """
+ confidential: Boolean
+
+ """
The global id of the note to update
"""
id: ID!
@@ -15041,6 +15056,17 @@ type VulnerabilityEdge {
}
"""
+The grade of the vulnerable project
+"""
+enum VulnerabilityGrade {
+ A
+ B
+ C
+ D
+ F
+}
+
+"""
Represents a vulnerability identifier.
"""
type VulnerabilityIdentifier {
@@ -15480,4 +15506,44 @@ type VulnerablePackage {
The name of the vulnerable package
"""
name: String
+}
+
+"""
+Represents vulnerability letter grades with associated projects
+"""
+type VulnerableProjectsByGrade {
+ """
+ Number of projects within this grade
+ """
+ count: Int!
+
+ """
+ Grade based on the highest severity vulnerability present
+ """
+ grade: VulnerabilityGrade!
+
+ """
+ Projects within this grade
+ """
+ projects(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): ProjectConnection!
} \ No newline at end of file
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 838bd1cc0a2..773367b3783 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -15569,6 +15569,32 @@
"deprecationReason": null
},
{
+ "name": "vulnerabilityGrades",
+ "description": "Represents vulnerable project counts for each grade",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VulnerableProjectsByGrade",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "vulnerabilityScanners",
"description": "Vulnerability scanners reported on the project vulnerabilties of the group and its subgroups",
"args": [
@@ -16021,6 +16047,32 @@
"deprecationReason": null
},
{
+ "name": "vulnerabilityGrades",
+ "description": "Represents vulnerable project counts for each grade",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VulnerableProjectsByGrade",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "vulnerabilityScanners",
"description": "Vulnerability scanners reported on the vulnerabilties from projects selected in Instance Security Dashboard",
"args": [
@@ -42306,13 +42358,19 @@
"name": "body",
"description": "Content of the note",
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "confidential",
+ "description": "The confidentiality flag of a note. Default is false.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
},
"defaultValue": null
},
@@ -44349,6 +44407,47 @@
"possibleTypes": null
},
{
+ "kind": "ENUM",
+ "name": "VulnerabilityGrade",
+ "description": "The grade of the vulnerable project",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "A",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "B",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "C",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "D",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "F",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "VulnerabilityIdentifier",
"description": "Represents a vulnerability identifier.",
@@ -45708,6 +45807,112 @@
},
{
"kind": "OBJECT",
+ "name": "VulnerableProjectsByGrade",
+ "description": "Represents vulnerability letter grades with associated projects",
+ "fields": [
+ {
+ "name": "count",
+ "description": "Number of projects within this grade",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "grade",
+ "description": "Grade based on the highest severity vulnerability present",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "VulnerabilityGrade",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "projects",
+ "description": "Projects within this grade",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ProjectConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "__Directive",
"description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",
"fields": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 73df0156fe6..5eaff5350eb 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -862,6 +862,7 @@ Autogenerated return type of EpicTreeReorder
| `twoFactorGracePeriod` | Int | Time before two-factor authentication is enforced |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
| `visibility` | String | Visibility of the namespace |
+| `vulnerabilityGrades` | VulnerableProjectsByGrade! => Array | Represents vulnerable project counts for each grade |
| `webUrl` | String! | Web URL of the group |
## GroupMember
@@ -884,6 +885,12 @@ Represents a Group Member
| --- | ---- | ---------- |
| `readGroup` | Boolean! | Indicates the user can perform `read_group` on this resource |
+## InstanceSecurityDashboard
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `vulnerabilityGrades` | VulnerableProjectsByGrade! => Array | Represents vulnerable project counts for each grade |
+
## Issue
| Name | Type | Description |
@@ -2395,3 +2402,12 @@ Represents a vulnerable package. Used in vulnerability dependency data
| Name | Type | Description |
| --- | ---- | ---------- |
| `name` | String | The name of the vulnerable package |
+
+## VulnerableProjectsByGrade
+
+Represents vulnerability letter grades with associated projects
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `count` | Int! | Number of projects within this grade |
+| `grade` | VulnerabilityGrade! | Grade based on the highest severity vulnerability present |
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 6b25494c577..3a68454507a 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -145,10 +145,11 @@ PUT /projects/:id/issues/:issue_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
-- `issue_iid` (required) - The IID of an issue
-- `note_id` (required) - The ID of a note
-- `body` (required) - The content of a note. Limited to 1,000,000 characters.
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding).
+- `issue_iid` (required) - The IID of an issue.
+- `note_id` (required) - The ID of a note.
+- `body` (optional) - The content of a note. Limited to 1,000,000 characters.
+- `confidential` (optional) - The confidential flag of a note.
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note"
diff --git a/doc/university/training/topics/explore_gitlab.md b/doc/university/training/topics/explore_gitlab.md
index 4ca931d0e26..8678f8fd9eb 100644
--- a/doc/university/training/topics/explore_gitlab.md
+++ b/doc/university/training/topics/explore_gitlab.md
@@ -1,12 +1,5 @@
---
-comments: false
+redirect_to: '../../../gitlab-basics/README.md'
---
-# Explore GitLab projects
-
-- Dashboard
-- User Preferences
-- Issues
-- Milestones and Labels
-- Manage project members
-- Project settings
+This document was moved to [another location](../../../gitlab-basics/README.md).
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index f88624ed63e..f61bcfe963e 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -17,8 +17,9 @@ module API
authorize! :admin_note, note
opts = {
- note: params[:body]
- }
+ note: params[:body],
+ confidential: params[:confidential]
+ }.compact
parent = noteable_parent(noteable)
project = parent if parent.is_a?(Project)
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index bfd09dcd496..e4989243f3d 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -101,7 +101,8 @@ module API
params do
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
requires :note_id, type: Integer, desc: 'The ID of a note'
- requires :body, type: String, desc: 'The content of a note'
+ optional :body, type: String, allow_blank: false, desc: 'The content of a note'
+ optional :confidential, type: Boolean, desc: 'Confidentiality note flag'
end
put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
noteable = find_noteable(noteable_type, params[:noteable_id])
diff --git a/package.json b/package.json
index 0ec8aade436..17d74efec32 100644
--- a/package.json
+++ b/package.json
@@ -42,8 +42,8 @@
"@babel/plugin-syntax-import-meta": "^7.10.1",
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
- "@gitlab/svgs": "1.155.0",
- "@gitlab/ui": "17.37.0",
+ "@gitlab/svgs": "1.156.0",
+ "@gitlab/ui": "17.39.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
"@sentry/browser": "^5.10.2",
diff --git a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
index 1f5c3a80fbb..96c5cc5b980 100644
--- a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
+++ b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
@@ -13,14 +13,14 @@ exports[`AlertsSettingsForm with default values renders the initial template 1`]
</div>
<gl-form-stub>
<gl-form-group-stub label=\\"Integrations\\" label-for=\\"integrations\\" label-class=\\"label-bold\\">
- <gl-form-select-stub options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-400\\"><gl-sprintf-stub message=\\"Learn more about our %{linkStart}upcoming integrations%{linkEnd}\\"></gl-sprintf-stub></span>
+ <gl-form-select-stub options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-200\\"><gl-sprintf-stub message=\\"Learn more about our %{linkStart}upcoming integrations%{linkEnd}\\"></gl-sprintf-stub></span>
</gl-form-group-stub>
<gl-form-group-stub label=\\"Active\\" label-for=\\"activated\\" label-class=\\"label-bold\\">
<toggle-button-stub id=\\"activated\\"></toggle-button-stub>
</gl-form-group-stub>
<!---->
<gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\" label-class=\\"label-bold\\">
- <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-400\\">
+ <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-200\\">
</span>
</gl-form-group-stub>
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
index 17ada722034..4ac20275319 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
@@ -35,7 +35,7 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
/>
<div
- class="gl-text-gray-400 gl-pt-2"
+ class="gl-text-gray-200 gl-pt-2"
>
<gl-sprintf-stub
message="Create a GitLab issue for each PagerDuty incident by %{docsLink}"
diff --git a/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js b/spec/frontend/notes/components/discussion_navigator_spec.js
index fd0383f3b9d..122814b8e3f 100644
--- a/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js
+++ b/spec/frontend/notes/components/discussion_navigator_spec.js
@@ -2,10 +2,10 @@
import 'mousetrap';
import Vue from 'vue';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import DiscussionKeyboardNavigator from '~/notes/components/discussion_keyboard_navigator.vue';
+import DiscussionNavigator from '~/notes/components/discussion_navigator.vue';
import eventHub from '~/notes/event_hub';
-describe('notes/components/discussion_keyboard_navigator', () => {
+describe('notes/components/discussion_navigator', () => {
const localVue = createLocalVue();
let wrapper;
@@ -13,7 +13,7 @@ describe('notes/components/discussion_keyboard_navigator', () => {
let jumpToPreviousDiscussion;
const createComponent = () => {
- wrapper = shallowMount(DiscussionKeyboardNavigator, {
+ wrapper = shallowMount(DiscussionNavigator, {
mixins: [
localVue.extend({
methods: {
@@ -43,7 +43,7 @@ describe('notes/components/discussion_keyboard_navigator', () => {
beforeEach(() => {
onSpy = jest.spyOn(eventHub, '$on');
- vm = new (Vue.extend(DiscussionKeyboardNavigator))();
+ vm = new (Vue.extend(DiscussionNavigator))();
});
it('listens for jumpToFirstUnresolvedDiscussion events', () => {
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js
index 70317d333d9..b9b93b274d2 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js
@@ -1,5 +1,6 @@
import Editor from '@toast-ui/editor';
import { registerHTMLToMarkdownRenderer } from '~/vue_shared/components/rich_content_editor/services/editor_service';
+import buildMarkdownToHTMLRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
describe('vue_shared/components/rich_content_editor', () => {
let editor;
@@ -7,6 +8,7 @@ describe('vue_shared/components/rich_content_editor', () => {
const buildEditor = () => {
editor = new Editor({
el: document.body,
+ customHTMLRenderer: buildMarkdownToHTMLRenderer(),
});
registerHTMLToMarkdownRenderer(editor);
@@ -49,4 +51,19 @@ describe('vue_shared/components/rich_content_editor', () => {
expect(markdown).toBe('**strong text**_emphasis text_');
});
});
+
+ describe('Markdown to HTML', () => {
+ it.each`
+ input | output
+ ${'markdown with _emphasized\ntext_'} | ${'<p>markdown with <em>emphasized text</em></p>\n'}
+ ${'markdown with **strong\ntext**'} | ${'<p>markdown with <strong>strong text</strong></p>\n'}
+ `(
+ 'does not transform softbreaks inside (_) and strong (**) nodes into <br/> tags',
+ ({ input, output }) => {
+ editor.setMarkdown(input);
+
+ expect(editor.getHtml()).toBe(output);
+ },
+ );
+ });
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
index 2bbd3572d4b..a90d3528d60 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
@@ -70,10 +70,11 @@ describe('HTMLToMarkdownRenderer', () => {
describe('OL LI visitor', () => {
it.each`
- listItem | result | incrementListMarker | action
- ${'2. list item'} | ${'1. list item'} | ${false} | ${'increments'}
- ${' 3. list item'} | ${' 1. list item'} | ${false} | ${'increments'}
- ${'3. list item'} | ${'3. list item'} | ${true} | ${'does not increment'}
+ listItem | result | incrementListMarker | action
+ ${'2. list item'} | ${'1. list item'} | ${false} | ${'increments'}
+ ${' 3. list item'} | ${' 1. list item'} | ${false} | ${'increments'}
+ ${' 123. list item'} | ${' 1. list item'} | ${false} | ${'increments'}
+ ${'3. list item'} | ${'3. list item'} | ${true} | ${'does not increment'}
`(
'$action a list item counter when incrementListMaker is $incrementListMarker',
({ listItem, result, incrementListMarker }) => {
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js
new file mode 100644
index 00000000000..3c3d2354cb9
--- /dev/null
+++ b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js
@@ -0,0 +1,23 @@
+import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_softbreak';
+
+describe('Render softbreak renderer', () => {
+ describe('canRender', () => {
+ it.each`
+ node | parentType | result
+ ${{ parent: { type: 'emph' } }} | ${'emph'} | ${true}
+ ${{ parent: { type: 'strong' } }} | ${'strong'} | ${true}
+ ${{ parent: { type: 'paragraph' } }} | ${'paragraph'} | ${false}
+ `('returns $result when node parent type is $parentType ', ({ node, result }) => {
+ expect(renderer.canRender(node)).toBe(result);
+ });
+ });
+
+ describe('render', () => {
+ it('returns text node with a break line', () => {
+ expect(renderer.render()).toEqual({
+ type: 'text',
+ content: ' ',
+ });
+ });
+ });
+});
diff --git a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
index 38378310d9f..0d93afe9434 100644
--- a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
@@ -8,11 +8,9 @@ RSpec.describe 'Updating a Note' do
let!(:note) { create(:note, note: original_body) }
let(:original_body) { 'Initial body text' }
let(:updated_body) { 'Updated body text' }
+ let(:params) { { body: updated_body, confidential: true } }
let(:mutation) do
- variables = {
- id: GitlabSchema.id_from_object(note).to_s,
- body: updated_body
- }
+ variables = params.merge(id: GitlabSchema.id_from_object(note).to_s)
graphql_mutation(:update_note, variables)
end
@@ -31,6 +29,7 @@ RSpec.describe 'Updating a Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(note.reload.note).to eq(original_body)
+ expect(note.confidential).to be_falsey
end
end
@@ -43,12 +42,40 @@ RSpec.describe 'Updating a Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(note.reload.note).to eq(updated_body)
+ expect(note.confidential).to be_truthy
end
it 'returns the updated Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['note']['body']).to eq(updated_body)
+ expect(mutation_response['note']['confidential']).to be_truthy
+ end
+
+ context 'when only confidential param is present' do
+ let(:params) { { confidential: true } }
+
+ it 'updates only the note confidentiality' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(note.reload.note).to eq(original_body)
+ expect(note.confidential).to be_truthy
+ end
+ end
+
+ context 'when only body param is present' do
+ let(:params) { { body: updated_body } }
+
+ before do
+ note.update_column(:confidential, true)
+ end
+
+ it 'updates only the note body' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(note.reload.note).to eq(updated_body)
+ expect(note.confidential).to be_truthy
+ end
end
context 'when there are ActiveRecord validation errors' do
@@ -60,12 +87,14 @@ RSpec.describe 'Updating a Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(note.reload.note).to eq(original_body)
+ expect(note.confidential).to be_falsey
end
- it 'returns the Note with its original body' do
+ it 'returns the original Note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['note']['body']).to eq(original_body)
+ expect(mutation_response['note']['confidential']).to be_falsey
end
end
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 70dea99de4a..cfdfb10d65d 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -36,6 +36,16 @@ RSpec.describe Notes::UpdateService do
end
end
+ context 'with system note' do
+ before do
+ note.update_column(:system, true)
+ end
+
+ it 'does not update the note' do
+ expect { update_note(note: 'new text') }.not_to change { note.reload.note }
+ end
+ end
+
context 'suggestions' do
it 'refreshes note suggestions' do
markdown = <<-MARKDOWN.strip_heredoc
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 07d38d472cc..7066f803f9d 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -277,12 +277,53 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
- it 'returns modified note' do
- put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "notes/#{note.id}", user), params: { body: 'Hello!' }
+ let(:params) { { body: 'Hello!', confidential: false } }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['body']).to eq('Hello!')
+ subject do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user), params: params
+ end
+
+ context 'when eveything is ok' do
+ before do
+ note.update!(confidential: true)
+ end
+
+ context 'with multiple params present' do
+ before do
+ subject
+ end
+
+ it 'returns modified note' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['body']).to eq('Hello!')
+ expect(json_response['confidential']).to be_falsey
+ end
+
+ it 'updates the note' do
+ expect(note.reload.note).to eq('Hello!')
+ expect(note.confidential).to be_falsey
+ end
+ end
+
+ context 'when only body param is present' do
+ let(:params) { { body: 'Hello!' } }
+
+ it 'updates only the note text' do
+ expect { subject }.not_to change { note.reload.confidential }
+
+ expect(note.note).to eq('Hello!')
+ end
+ end
+
+ context 'when only confidential param is present' do
+ let(:params) { { confidential: false } }
+
+ it 'updates only the note text' do
+ expect { subject }.not_to change { note.reload.note }
+
+ expect(note.confidential).to be_falsey
+ end
+ end
end
it 'returns a 404 error when note id not found' do
@@ -292,9 +333,9 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
expect(response).to have_gitlab_http_status(:not_found)
end
- it 'returns a 400 bad request error if body not given' do
+ it 'returns a 400 bad request error if body is empty' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "notes/#{note.id}", user)
+ "notes/#{note.id}", user), params: { body: '' }
expect(response).to have_gitlab_http_status(:bad_request)
end
diff --git a/yarn.lock b/yarn.lock
index d1a4a937692..7db20de8d49 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -843,15 +843,15 @@
eslint-plugin-vue "^6.2.1"
vue-eslint-parser "^7.0.0"
-"@gitlab/svgs@1.155.0":
- version "1.155.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.155.0.tgz#c3b0abd868660486cf0e4b3a1bc018980812ca5b"
- integrity sha512-gyu94CjiTOaEuwJ3GXtoKRwIOc79S+vh8o72jS4cH0h7SzLkloM9kEusPCWZsbhoLpbzTX0ncJBnyfwkWNvDZg==
-
-"@gitlab/ui@17.37.0":
- version "17.37.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.37.0.tgz#1d6116b9820ff6d343886cb870ad90922ed354ce"
- integrity sha512-Xq9WHhKchpr0EpCYTf+YZTMwRgRqyZ9V3byjGL54iY/a3iXfSm8EbRUIIjIe2nNLaXfJTUasms+e5WWUtWBl/w==
+"@gitlab/svgs@1.156.0":
+ version "1.156.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.156.0.tgz#2af56246b5d71000ec81abb1281e811a921cdfd1"
+ integrity sha512-+b670Sxkjo80Wb4GKMZQ+xvuwu9sVvql8aS9nzw63FLn84QyqXS+jMjvyDqPAW5kly6B1Eg4Kljq0YawJ0ySBg==
+
+"@gitlab/ui@17.39.0":
+ version "17.39.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.39.0.tgz#04417471ac094323581482d354a33cdf0a21ec86"
+ integrity sha512-3KPrw+1cwF+ibY5zo01b6EsSOE2Kgflu7FGmrvJMvEgpK4w2shloGEts4vEJbPEGBpUzpjr3gQinNcoeIYu/JA==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"