Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-15 12:11:43 +00:00
parent 5f431529c8
commit 14771dc276
27 changed files with 308 additions and 123 deletions

View File

@ -62,7 +62,7 @@ export default {
:value="state"
:options="$options.states"
:disabled="disabled"
class="gl-w-auto hide-select-decoration"
class="gl-w-auto hide-select-decoration gl-pl-3"
:class="{ 'gl-bg-transparent! gl-cursor-text!': disabled }"
@change="setState"
/>

View File

@ -144,6 +144,9 @@ export default {
return this.searchKey.length === 0;
},
addAssigneesText() {
if (!this.canUpdate) {
return s__('WorkItem|None');
}
return this.allowsMultipleAssignees
? s__('WorkItem|Add assignees')
: s__('WorkItem|Add assignee');
@ -270,7 +273,7 @@ export default {
:loading="isLoadingUsers"
:view-only="!canUpdate"
:allow-clear-all="isEditing"
class="assignees-selector gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0!"
class="assignees-selector gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0! gl-mx-2"
@input="handleAssigneesInput"
@text-input="debouncedSearchKeyUpdate"
@focus="handleFocus"
@ -280,7 +283,7 @@ export default {
>
<template #empty-placeholder>
<div
class="add-assignees gl-min-w-fit-content gl-display-flex gl-align-items-center gl-text-gray-300 gl-pr-4 gl-top-2"
class="add-assignees gl-min-w-fit-content gl-display-flex gl-align-items-center gl-text-gray-300 gl-pr-4 gl-pl-2 gl-top-2"
data-testid="empty-state"
>
<gl-icon name="profile" />
@ -301,7 +304,7 @@ export default {
:title="token.name"
:data-user-id="getUserId(token.id)"
data-placement="top"
class="gl-text-decoration-none! gl-text-body! gl-display-flex gl-md-display-inline-flex! gl-align-items-center js-user-link"
class="gl-ml-n2 gl-text-decoration-none! gl-text-body! gl-display-flex gl-md-display-inline-flex! gl-align-items-center js-user-link"
>
<gl-avatar :size="24" :src="token.avatarUrl" />
<span class="gl-pl-2">{{ token.name }}</span>

View File

@ -102,11 +102,17 @@ export default {
childrenIds() {
return this.children.map((c) => c.id);
},
childrenCountLabel() {
return this.isLoading && this.children.length === 0 ? '...' : this.children.length;
},
},
methods: {
badgeVariant(state) {
return state === STATE_OPEN ? 'success' : 'info';
},
iconClass(state) {
return state === STATE_OPEN ? 'gl-text-green-500' : 'gl-text-blue-500';
},
toggle() {
this.isOpen = !this.isOpen;
},
@ -237,7 +243,16 @@ export default {
class="gl-px-5 gl-py-3 gl-display-flex gl-justify-content-space-between"
:class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': isOpen }"
>
<h5 class="gl-m-0 gl-line-height-24 gl-flex-grow-1">{{ $options.i18n.title }}</h5>
<div class="gl-display-flex gl-flex-grow-1">
<h5 class="gl-m-0 gl-line-height-24">{{ $options.i18n.title }}</h5>
<span
class="gl-display-inline-flex gl-align-items-center gl-line-height-24 gl-ml-3"
data-testid="children-count"
>
<gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-2 gl-text-gray-500" />
{{ childrenCountLabel }}
</span>
</div>
<gl-button
v-if="canUpdate"
category="secondary"
@ -296,7 +311,11 @@ export default {
data-testid="confidential-icon"
:title="__('Confidential')"
/>
<gl-icon :name="$options.WIDGET_TYPE_TASK_ICON" class="gl-mr-3 gl-text-gray-700" />
<gl-icon
:name="$options.WIDGET_TYPE_TASK_ICON"
class="gl-mr-3"
:class="iconClass(child.state)"
/>
<gl-button
:href="childPath(child.id)"
category="tertiary"

View File

@ -28,7 +28,7 @@ export const i18n = {
};
export const WIDGET_ICONS = {
TASK: 'task-done',
TASK: 'issue-type-task',
};
export const WORK_ITEM_STATUS_TEXT = {

View File

@ -217,7 +217,8 @@ module NotesActions
:note,
:line_code, # LegacyDiffNote
:position, # DiffNote
:confidential
:confidential,
:internal
).tap do |create_params|
create_params.merge!(
params.permit(:merge_request_diff_head_sha, :in_reply_to_discussion_id)

View File

@ -21,7 +21,13 @@ module Mutations
argument :confidential,
GraphQL::Types::Boolean,
required: false,
description: 'Confidentiality flag of a note. Default is false.'
description: 'Confidentiality flag of a note. Default is false.',
deprecated: { reason: :renamed, replacement: 'internal', milestone: '15.3' }
argument :internal,
GraphQL::Types::Boolean,
required: false,
description: 'Internal flag for a note. Default is false.'
def resolve(args)
noteable = authorized_find!(id: args[:noteable_id])
@ -49,7 +55,7 @@ module Mutations
{
noteable: noteable,
note: args[:body],
confidential: args[:confidential]
internal: args[:internal] || args[:confidential]
}
end

View File

@ -37,7 +37,17 @@ module Types
field :confidential, GraphQL::Types::Boolean, null: true,
description: 'Indicates if this note is confidential.',
method: :confidential?
method: :confidential?,
deprecated: {
reason: :renamed,
replacement: 'internal',
milestone: '15.3'
}
field :internal, GraphQL::Types::Boolean, null: true,
description: 'Indicates if this note is internal.',
method: :confidential?
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of the note creation.'
field :discussion, Types::Notes::DiscussionType, null: true,

View File

@ -16,6 +16,14 @@ module Notes
params.merge!(discussion.reply_attributes)
end
# The `confidential` param for notes is deprecated with 15.3
# and renamed to `internal`.
# We still accept `confidential` until the param gets removed from the API.
# Until we have not migrated the database column to `internal` we need to rename
# the parameter. Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/367923.
params[:confidential] = params[:internal] || params[:confidential]
params.delete(:internal)
new_note(params, discussion)
end

View File

@ -1440,7 +1440,8 @@ Input type: `CreateDiffNoteInput`
| ---- | ---- | ----------- |
| <a id="mutationcreatediffnotebody"></a>`body` | [`String!`](#string) | Content of the note. |
| <a id="mutationcreatediffnoteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcreatediffnoteconfidential"></a>`confidential` | [`Boolean`](#boolean) | Confidentiality flag of a note. Default is false. |
| <a id="mutationcreatediffnoteconfidential"></a>`confidential` **{warning-solid}** | [`Boolean`](#boolean) | **Deprecated:** This was renamed. Please use `internal`. Deprecated in 15.3. |
| <a id="mutationcreatediffnoteinternal"></a>`internal` | [`Boolean`](#boolean) | Internal flag for a note. Default is false. |
| <a id="mutationcreatediffnotenoteableid"></a>`noteableId` | [`NoteableID!`](#noteableid) | Global ID of the resource to add a note to. |
| <a id="mutationcreatediffnoteposition"></a>`position` | [`DiffPositionInput!`](#diffpositioninput) | Position of this note on a diff. |
@ -1492,7 +1493,8 @@ Input type: `CreateImageDiffNoteInput`
| ---- | ---- | ----------- |
| <a id="mutationcreateimagediffnotebody"></a>`body` | [`String!`](#string) | Content of the note. |
| <a id="mutationcreateimagediffnoteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcreateimagediffnoteconfidential"></a>`confidential` | [`Boolean`](#boolean) | Confidentiality flag of a note. Default is false. |
| <a id="mutationcreateimagediffnoteconfidential"></a>`confidential` **{warning-solid}** | [`Boolean`](#boolean) | **Deprecated:** This was renamed. Please use `internal`. Deprecated in 15.3. |
| <a id="mutationcreateimagediffnoteinternal"></a>`internal` | [`Boolean`](#boolean) | Internal flag for a note. Default is false. |
| <a id="mutationcreateimagediffnotenoteableid"></a>`noteableId` | [`NoteableID!`](#noteableid) | Global ID of the resource to add a note to. |
| <a id="mutationcreateimagediffnoteposition"></a>`position` | [`DiffImagePositionInput!`](#diffimagepositioninput) | Position of this note on a diff. |
@ -1589,8 +1591,9 @@ Input type: `CreateNoteInput`
| ---- | ---- | ----------- |
| <a id="mutationcreatenotebody"></a>`body` | [`String!`](#string) | Content of the note. |
| <a id="mutationcreatenoteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcreatenoteconfidential"></a>`confidential` | [`Boolean`](#boolean) | Confidentiality flag of a note. Default is false. |
| <a id="mutationcreatenoteconfidential"></a>`confidential` **{warning-solid}** | [`Boolean`](#boolean) | **Deprecated:** This was renamed. Please use `internal`. Deprecated in 15.3. |
| <a id="mutationcreatenotediscussionid"></a>`discussionId` | [`DiscussionID`](#discussionid) | Global ID of the discussion this note is in reply to. |
| <a id="mutationcreatenoteinternal"></a>`internal` | [`Boolean`](#boolean) | Internal flag for a note. Default is false. |
| <a id="mutationcreatenotemergerequestdiffheadsha"></a>`mergeRequestDiffHeadSha` | [`String`](#string) | SHA of the head commit which is used to ensure that the merge request has not been updated since the request was sent. |
| <a id="mutationcreatenotenoteableid"></a>`noteableId` | [`NoteableID!`](#noteableid) | Global ID of the resource to add a note to. |
@ -14845,10 +14848,11 @@ Represents the network policy.
| <a id="noteauthor"></a>`author` | [`UserCore!`](#usercore) | User who wrote this note. |
| <a id="notebody"></a>`body` | [`String!`](#string) | Content of the note. |
| <a id="notebodyhtml"></a>`bodyHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `note`. |
| <a id="noteconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if this note is confidential. |
| <a id="noteconfidential"></a>`confidential` **{warning-solid}** | [`Boolean`](#boolean) | **Deprecated** in 15.3. This was renamed. Use: `internal`. |
| <a id="notecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of the note creation. |
| <a id="notediscussion"></a>`discussion` | [`Discussion`](#discussion) | Discussion this note is a part of. |
| <a id="noteid"></a>`id` | [`NoteID!`](#noteid) | ID of the note. |
| <a id="noteinternal"></a>`internal` | [`Boolean`](#boolean) | Indicates if this note is internal. |
| <a id="noteposition"></a>`position` | [`DiffPosition`](#diffposition) | Position of this note on a diff. |
| <a id="noteproject"></a>`project` | [`Project`](#project) | Project associated with the note. |
| <a id="noteresolvable"></a>`resolvable` | [`Boolean!`](#boolean) | Indicates if the object can be resolved. |

View File

@ -16,11 +16,11 @@ Get the job's artifacts zipped archive of a project.
GET /projects/:id/jobs/:job_id/artifacts
```
| Attribute | Type | Required | Description |
|-------------|----------------|----------|--------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `job_id` | integer | yes | ID of a job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
| Attribute | Type | Required | Description |
|---------------------------|----------------|----------|-------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `job_id` | integer | yes | ID of a job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request using the `PRIVATE-TOKEN` header:
@ -80,12 +80,12 @@ GET /projects/:id/jobs/artifacts/:ref_name/download?job=name
Parameters
| Attribute | Type | Required | Description |
|-------------|----------------|----------|--------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref_name` | string | yes | Branch or tag name in repository. HEAD or SHA references are not supported. |
| `job` | string | yes | The name of the job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
| Attribute | Type | Required | Description |
|---------------------------|----------------|----------|-------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref_name` | string | yes | Branch or tag name in repository. HEAD or SHA references are not supported. |
| `job` | string | yes | The name of the job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request using the `PRIVATE-TOKEN` header:
@ -141,12 +141,12 @@ GET /projects/:id/jobs/:job_id/artifacts/*artifact_path
Parameters
| Attribute | Type | Required | Description |
|-----------------|----------------|----------|------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `job_id` | integer | yes | The unique job identifier. |
| `artifact_path` | string | yes | Path to a file inside the artifacts archive. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
| Attribute | Type | Required | Description |
|---------------------------|----------------|----------|-------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `job_id` | integer | yes | The unique job identifier. |
| `artifact_path` | string | yes | Path to a file inside the artifacts archive. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request:
@ -185,13 +185,13 @@ GET /projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job=name
Parameters:
| Attribute | Type | Required | Description |
|-----------------|----------------|----------|--------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref_name` | string | yes | Branch or tag name in repository. `HEAD` or `SHA` references are not supported. |
| `artifact_path` | string | yes | Path to a file inside the artifacts archive. |
| `job` | string | yes | The name of the job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
| Attribute | Type | Required | Description |
|---------------------------|----------------|----------|-------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref_name` | string | yes | Branch or tag name in repository. `HEAD` or `SHA` references are not supported. |
| `artifact_path` | string | yes | Path to a file inside the artifacts archive. |
| `job` | string | yes | The name of the job. |
| `job_token` **(PREMIUM)** | string | no | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request:

View File

@ -80,7 +80,8 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
"noteable_type": "Issue",
"noteable_iid": 377,
"resolvable": false,
"confidential": false
"confidential": false,
"internal": false
},
{
"id": 305,
@ -101,7 +102,8 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
"noteable_type": "Issue",
"noteable_iid": 121,
"resolvable": false,
"confidential": true
"confidential": true,
"internal": true
}
]
```
@ -145,7 +147,8 @@ Parameters:
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `issue_iid` | integer | yes | The IID of an issue. |
| `body` | string | yes | The content of a note. Limited to 1,000,000 characters. |
| `confidential` | boolean | no | The confidential flag of a note. Default is false. |
| `confidential` | boolean | no | **Deprecated:** will be removed in GitLab 16.0 and renamed to `internal`. The confidential flag of a note. Default is false. |
| `internal` | boolean | no | The internal flag of a note. Overrides `confidential` when both parameters are submitted. Default is false. |
| `created_at` | string | no | Date time string, ISO 8601 formatted. It must be after 1970-01-01. Example: `2016-03-11T03:45:40Z` (requires administrator or project/group owner rights) |
```shell
@ -378,7 +381,8 @@ Parameters:
"noteable_type": "MergeRequest",
"noteable_iid": 2,
"resolvable": false,
"confidential": false
"confidential": false,
"internal": false
}
```
@ -506,7 +510,8 @@ Parameters:
"expires_at": null,
"updated_at": "2013-10-02T07:34:20Z",
"created_at": "2013-10-02T07:34:20Z",
"confidential": false
"confidential": false,
"internal": false
}
```
@ -530,7 +535,8 @@ Parameters:
| `body` | string | yes | The content of a note. Limited to 1,000,000 characters. |
| `epic_id` | integer | yes | The ID of an epic |
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `confidential` | boolean | no | The confidential flag of a note. Default is `false`. |
| `confidential` | boolean | no | **Deprecated:** will be removed in GitLab 16.0 and is renamed to `internal`. The confidential flag of a note. Default is `false`. |
| `internal` | boolean | no | The internal flag of a note. Overrides `confidential` when both parameters are submitted. Default is `false`. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/epics/11/notes?body=note"

View File

@ -64,7 +64,7 @@ build:
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 -w 0)\"}}}" > /kaniko/.docker/config.json
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"

View File

@ -26,6 +26,7 @@ module API
expose :resolved_at, if: ->(note, options) { note.resolvable? }
expose :confidential?, as: :confidential
expose :confidential?, as: :internal
# Avoid N+1 queries as much as possible
expose(:noteable_iid) { |note| note.noteable.iid if NOTEABLE_TYPES_WITH_IID.include?(note.noteable_type) }

View File

@ -73,7 +73,8 @@ module API
params do
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
requires :body, type: String, desc: 'The content of a note'
optional :confidential, type: Boolean, desc: 'Confidentiality note flag, default is false'
optional :confidential, type: Boolean, desc: '[Deprecated in 15.3] Renamed to internal'
optional :internal, type: Boolean, desc: 'Internal note flag, default is false'
optional :created_at, type: String, desc: 'The creation date of the note'
optional :merge_request_diff_head_sha, type: String, desc: 'The SHA of the head commit'
end
@ -87,7 +88,7 @@ module API
note: params[:body],
noteable_type: noteables_str.classify,
noteable_id: noteable.id,
confidential: params[:confidential],
internal: params[:internal] || params[:confidential],
created_at: params[:created_at],
merge_request_diff_head_sha: params[:merge_request_diff_head_sha]
}

View File

@ -460,9 +460,6 @@ msgstr ""
msgid "%{address} is an invalid IP address range"
msgstr ""
msgid "%{attribute} must be between %{min} and %{max}"
msgstr ""
msgid "%{author_link} cloned %{original_issue} to %{new_issue}."
msgstr ""
@ -44371,6 +44368,9 @@ msgstr ""
msgid "WorkItem|No child items are currently assigned. Use child items to prioritize tasks that your team should complete in order to accomplish your goals!"
msgstr ""
msgid "WorkItem|None"
msgstr ""
msgid "WorkItem|Open"
msgstr ""

View File

@ -196,7 +196,7 @@
"yaml": "^2.0.0-10"
},
"devDependencies": {
"@gitlab/eslint-plugin": "15.0.0",
"@gitlab/eslint-plugin": "16.0.0",
"@gitlab/stylelint-config": "4.1.0",
"@graphql-eslint/eslint-plugin": "3.10.7",
"@testing-library/dom": "^7.16.2",

View File

@ -345,34 +345,77 @@ RSpec.describe Projects::NotesController do
}
end
context 'when `confidential` parameter is not provided' do
it 'sets `confidential` to `false` in JSON response' do
context 'when parameter is not provided' do
it 'sets `confidential` and `internal` to `false` in JSON response' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be false
expect(json_response['internal']).to be false
end
end
context 'when `confidential` parameter is `false`' do
let(:extra_note_params) { { confidential: false } }
context 'when is not a confidential note' do
context 'when using the `internal` parameter' do
let(:extra_note_params) { { internal: false } }
it 'sets `confidential` to `false` in JSON response' do
create!
it 'sets `confidential` and `internal` to `false` in JSON response' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be false
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be false
expect(json_response['internal']).to be false
end
end
context 'when using deprecated `confidential` parameter' do
let(:extra_note_params) { { confidential: false } }
it 'sets `confidential` and `internal` to `false` in JSON response' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be false
expect(json_response['internal']).to be false
end
end
end
context 'when `confidential` parameter is `true`' do
let(:extra_note_params) { { confidential: true } }
context 'when is a confidential note' do
context 'when using the `internal` parameter' do
let(:extra_note_params) { { internal: true } }
it 'sets `confidential` to `true` in JSON response' do
create!
it 'sets `confidential` and `internal` to `true` in JSON response' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be true
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be true
expect(json_response['internal']).to be true
end
end
context 'when using deprecated `confidential` parameter' do
let(:extra_note_params) { { confidential: true } }
it 'sets `confidential` and `internal` to `true` in JSON response' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be true
expect(json_response['internal']).to be true
end
end
context 'when `internal` parameter is `true` and `confidential` parameter is `false`' do
let(:extra_note_params) { { internal: true, confidential: false } }
it 'uses the `internal` param as source of truth' do
create!
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['confidential']).to be true
expect(json_response['internal']).to be true
end
end
end
end

View File

@ -67,7 +67,8 @@
"toggle_award_path": { "type": "string" },
"path": { "type": "string" },
"commands_changes": { "type": "object", "additionalProperties": true },
"confidential": { "type": ["boolean", "null"] }
"confidential": { "type": ["boolean", "null"] },
"internal": { "type": ["boolean", "null"] }
},
"required": [
"id", "attachment", "author", "created_at", "updated_at",

View File

@ -32,7 +32,8 @@
"resolvable": { "type": "boolean" },
"resolved_by": { "type": ["string", "null"] },
"resolved_at": { "type": ["string", "null"] },
"confidential": { "type": ["boolean", "null"] }
"confidential": { "type": ["boolean", "null"] },
"internal": { "type": ["boolean", "null"] }
},
"required": [
"id", "body", "attachment", "author", "created_at", "updated_at",

View File

@ -77,6 +77,7 @@ describe('WorkItemLinks', () => {
const findToggleAddFormButton = () => wrapper.findByTestId('toggle-add-form');
const findAddLinksForm = () => wrapper.findByTestId('add-links-form');
const findFirstLinksMenu = () => wrapper.findByTestId('links-menu');
const findChildrenCount = () => wrapper.findByTestId('children-count');
beforeEach(async () => {
await createComponent();
@ -92,7 +93,7 @@ describe('WorkItemLinks', () => {
expect(findLinksBody().exists()).toBe(true);
});
it('expands on click toggle button', async () => {
it('collapses on click toggle button', async () => {
findToggleButton().vm.$emit('click');
await nextTick();
@ -140,6 +141,12 @@ describe('WorkItemLinks', () => {
expect(confidentialIcon.props('name')).toBe('eye-slash');
});
it('displays number if children', () => {
expect(findChildrenCount().exists()).toBe(true);
expect(findChildrenCount().text()).toContain('4');
});
describe('when no permission to update', () => {
beforeEach(async () => {
await createComponent({ response: workItemHierarchyNoUpdatePermissionResponse });

View File

@ -9,6 +9,7 @@ RSpec.describe GitlabSchema.types['Note'] do
body
body_html
confidential
internal
created_at
discussion
id

View File

@ -79,21 +79,29 @@ RSpec.describe 'Adding a Note' do
context 'for an issue' do
let(:noteable) { create(:issue, project: project) }
let(:mutation) do
variables = {
let(:mutation) { graphql_mutation(:create_note, variables) }
let(:variables) do
{
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
body: body,
confidential: true
}
graphql_mutation(:create_note, variables)
body: body
}.merge(variables_extra)
end
before do
project.add_developer(current_user)
end
it_behaves_like 'a Note mutation with confidential notes'
context 'when using internal param' do
let(:variables_extra) { { internal: true } }
it_behaves_like 'a Note mutation with confidential notes'
end
context 'when using deprecated confidential param' do
let(:variables_extra) { { confidential: true } }
it_behaves_like 'a Note mutation with confidential notes'
end
end
context 'when body only contains quick actions' do

View File

@ -170,7 +170,7 @@ RSpec.describe Notes::BuildService do
end
context 'when creating a new confidential comment' do
let(:params) { { confidential: true, noteable: issue } }
let(:params) { { internal: true, noteable: issue } }
shared_examples 'user allowed to set comment as confidential' do
it { expect(new_note.confidential).to be_truthy }
@ -219,6 +219,14 @@ RSpec.describe Notes::BuildService do
it_behaves_like 'user not allowed to set comment as confidential'
end
context 'when using the deprecated `confidential` parameter' do
let(:params) { { internal: true, noteable: issue } }
shared_examples 'user allowed to set comment as confidential' do
it { expect(new_note.confidential).to be_truthy }
end
end
end
context 'when replying to a confidential comment' do

View File

@ -7,37 +7,74 @@ RSpec.describe Notes::CreateService do
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
let(:opts) do
{ note: 'Awesome comment', noteable_type: 'Issue', noteable_id: issue.id, confidential: true }
end
let(:base_opts) { { note: 'Awesome comment', noteable_type: 'Issue', noteable_id: issue.id } }
let(:opts) { base_opts.merge(confidential: true) }
describe '#execute' do
subject(:note) { described_class.new(project, user, opts).execute }
before do
project.add_maintainer(user)
end
context "valid params" do
it 'returns a valid note' do
note = described_class.new(project, user, opts).execute
expect(note).to be_valid
end
it 'returns a persisted note' do
note = described_class.new(project, user, opts).execute
expect(note).to be_persisted
end
it 'note has valid content' do
note = described_class.new(project, user, opts).execute
context 'with internal parameter' do
context 'when confidential' do
let(:opts) { base_opts.merge(internal: true) }
it 'returns a confidential note' do
expect(note).to be_confidential
end
end
context 'when not confidential' do
let(:opts) { base_opts.merge(internal: false) }
it 'returns a confidential note' do
expect(note).not_to be_confidential
end
end
end
context 'with confidential parameter' do
context 'when confidential' do
let(:opts) { base_opts.merge(confidential: true) }
it 'returns a confidential note' do
expect(note).to be_confidential
end
end
context 'when not confidential' do
let(:opts) { base_opts.merge(confidential: false) }
it 'returns a confidential note' do
expect(note).not_to be_confidential
end
end
end
context 'with confidential and internal parameter set' do
let(:opts) { base_opts.merge(internal: true, confidential: false) }
it 'prefers the internal parameter' do
expect(note).to be_confidential
end
end
it 'note has valid content' do
expect(note.note).to eq(opts[:note])
end
it 'note belongs to the correct project' do
note = described_class.new(project, user, opts).execute
expect(note.project).to eq(project)
end
@ -60,8 +97,6 @@ RSpec.describe Notes::CreateService do
end
context 'issue is an incident' do
subject { described_class.new(project, user, opts).execute }
let(:issue) { create(:incident, project: project) }
it_behaves_like 'an incident management tracked event', :incident_management_incident_comment do

View File

@ -94,5 +94,6 @@ RSpec.shared_examples 'a Note mutation with confidential notes' do
expect(mutation_response).to have_key('note')
expect(mutation_response['note']['confidential']).to eq(true)
expect(mutation_response['note']['internal']).to eq(true)
end
end

View File

@ -376,13 +376,28 @@ RSpec.shared_examples 'noteable API with confidential notes' do |parent_type, no
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
end
it "creates a confidential note if confidential is set to true" do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params.merge(confidential: true)
context 'with internal param' do
it "creates a confidential note if internal is set to true" do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params.merge(internal: true)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['body']).to eq('hi!')
expect(json_response['confidential']).to be_truthy
expect(json_response['author']['username']).to eq(user.username)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['body']).to eq('hi!')
expect(json_response['confidential']).to be_truthy
expect(json_response['internal']).to be_truthy
expect(json_response['author']['username']).to eq(user.username)
end
end
context 'with deprecated confidential param' do
it "creates a confidential note if confidential is set to true" do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params.merge(confidential: true)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['body']).to eq('hi!')
expect(json_response['confidential']).to be_truthy
expect(json_response['internal']).to be_truthy
expect(json_response['author']['username']).to eq(user.username)
end
end
end
end

View File

@ -1019,10 +1019,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg==
"@gitlab/eslint-plugin@15.0.0":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-15.0.0.tgz#fbf5da0b6e6812a681552c8043f75af95de45fc4"
integrity sha512-bVKP132SYbtOhvtFRnRSy2W3x9zWbp12dkvaHJCm+3UOe1nFXGXjRfKAdw5w4bjX2Rb3oaM8/TiiUmg6J+2gZQ==
"@gitlab/eslint-plugin@16.0.0":
version "16.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-16.0.0.tgz#83b71bb3f749c6e52138d2c1c17ac623e7b2e3db"
integrity sha512-2n7geoRPkeMAq4GCqyvFzcTgcSrTM7pdCOxfcqIeuTmh/PFGhh+m7YC+YC4enhGOCN8lo08buLZhXkSgWiHSqA==
dependencies:
"@babel/core" "^7.17.0"
"@babel/eslint-parser" "^7.17.0"
@ -1034,7 +1034,7 @@
eslint-plugin-jest "^23.8.2"
eslint-plugin-promise "^4.2.1"
eslint-plugin-unicorn "^40.1.0"
eslint-plugin-vue "^8.5.0"
eslint-plugin-vue "^9.3.0"
lodash "^4.17.21"
"@gitlab/favicon-overlay@2.0.0":
@ -5197,17 +5197,18 @@ eslint-plugin-unicorn@^40.1.0:
semver "^7.3.5"
strip-indent "^3.0.0"
eslint-plugin-vue@^8.5.0:
version "8.7.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz#f13c53547a0c9d64588a675cc5ecc6ccaf63703f"
integrity sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==
eslint-plugin-vue@^9.3.0:
version "9.3.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.3.0.tgz#c3f5ce515dae387e062428725c5cf96098d9da0b"
integrity sha512-iscKKkBZgm6fGZwFt6poRoWC0Wy2dQOlwUPW++CiPoQiw1enctV2Hj5DBzzjJZfyqs+FAXhgzL4q0Ww03AgSmQ==
dependencies:
eslint-utils "^3.0.0"
natural-compare "^1.4.0"
nth-check "^2.0.1"
postcss-selector-parser "^6.0.9"
semver "^7.3.5"
vue-eslint-parser "^8.0.1"
vue-eslint-parser "^9.0.1"
xml-name-validator "^4.0.0"
eslint-rule-composer@^0.3.0:
version "0.3.0"
@ -5230,7 +5231,7 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.0.0, eslint-scope@^7.1.1:
eslint-scope@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
@ -5262,7 +5263,7 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0:
eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
@ -5312,7 +5313,7 @@ eslint@8.21.0:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^9.0.0, espree@^9.3.2, espree@^9.3.3:
espree@^9.3.1, espree@^9.3.2, espree@^9.3.3:
version "9.3.3"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.3.tgz#2dd37c4162bb05f433ad3c1a52ddf8a49dc08e9d"
integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==
@ -10487,10 +10488,10 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.6:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
@ -11898,18 +11899,18 @@ vue-apollo@^3.0.7:
serialize-javascript "^4.0.0"
throttle-debounce "^2.1.0"
vue-eslint-parser@^8.0.1:
version "8.3.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==
vue-eslint-parser@^9.0.1:
version "9.0.3"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.0.3.tgz#0c17a89e0932cc94fa6a79f0726697e13bfe3c96"
integrity sha512-yL+ZDb+9T0ELG4VIFo/2anAOz8SvBdlqEnQnvJ3M7Scq56DvtjY0VY88bByRZB0D4J0u8olBcfrXTVONXsh4og==
dependencies:
debug "^4.3.2"
eslint-scope "^7.0.0"
eslint-visitor-keys "^3.1.0"
espree "^9.0.0"
debug "^4.3.4"
eslint-scope "^7.1.1"
eslint-visitor-keys "^3.3.0"
espree "^9.3.1"
esquery "^1.4.0"
lodash "^4.17.21"
semver "^7.3.5"
semver "^7.3.6"
vue-functional-data-merge@^3.1.0:
version "3.1.0"
@ -12360,6 +12361,11 @@ xml-name-validator@^3.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
xml-name-validator@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
xml@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"