diff --git a/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql
index 8155451fb7cef46862911d753c20947f5622a37a..854842839eb3238329a5fa9c4f7f0041137fae48 100644
--- a/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql
+++ b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql
@@ -11,6 +11,7 @@ query projectAutocompleteUsersSearchWithMRPermissions(
users: autocompleteUsers(search: $search) {
...User
...UserAvailability
+ compositeIdentityEnforced @gl_introduced(version: "18.7.0")
mergeRequestInteraction(id: $mergeRequestId) {
canMerge
}
diff --git a/app/assets/javascripts/merge_requests/components/reviewers/reviewer_dropdown.vue b/app/assets/javascripts/merge_requests/components/reviewers/reviewer_dropdown.vue
index a43cb8119d4fedd910be2e1a897e901d3e3e3380..8eef48bc5e720cbbd9a16bcfecc74f226e3acb83 100644
--- a/app/assets/javascripts/merge_requests/components/reviewers/reviewer_dropdown.vue
+++ b/app/assets/javascripts/merge_requests/components/reviewers/reviewer_dropdown.vue
@@ -1,6 +1,6 @@
@@ -49,10 +57,13 @@ export default {
>
-
+
{{ content }}
+
+ {{ __('Agent') }}
+
diff --git a/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql b/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql
index 171eca50eabecaad1b2e8f279c2c813a44335fd4..0a928448f2e4cbe13ed4880bcba488898e906330 100644
--- a/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql
+++ b/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql
@@ -15,6 +15,7 @@ query alertAssignees(
nodes {
...User
...UserAvailability
+ compositeIdentityEnforced @gl_introduced(version: "18.7.0")
}
}
}
diff --git a/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql b/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql
index 6df2a1f5829d700a805bca9f917da20d9565678a..fb7e701eb632a7f68c785b4177b96830607d7527 100644
--- a/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql
+++ b/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql
@@ -9,11 +9,13 @@ query issueAssignees($fullPath: ID!, $iid: String!) {
author {
...UserWithType
...UserAvailability
+ compositeIdentityEnforced @gl_introduced(version: "18.7.0")
}
assignees {
nodes {
...UserWithType
...UserAvailability
+ compositeIdentityEnforced @gl_introduced(version: "18.7.0")
}
}
}
diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb
index 8d5bcb0a8fdecbd644d2d9b42c74131eb8e7b61e..b2c2427d6d1cdbaf28289329ab3869f15e6e9200 100644
--- a/app/graphql/types/user_interface.rb
+++ b/app/graphql/types/user_interface.rb
@@ -267,6 +267,12 @@ module UserInterface
description: 'Personal access tokens of the user.',
experiment: { milestone: '18.6' }
+ field :composite_identity_enforced,
+ GraphQL::Types::Boolean,
+ null: false,
+ description: 'Indicates if the user has composite identity enforcement enabled.',
+ method: :composite_identity_enforced?
+
definition_methods do
def resolve_type(object, context)
# in the absence of other information, we cannot tell - just default to
diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md
index 17ce62c8f4a3a89fd681f0aeca47ee39f34093c1..22e94d9e0d6e2ca765397b3a5e28eb7a6ee09b77 100644
--- a/doc/api/graphql/reference/_index.md
+++ b/doc/api/graphql/reference/_index.md
@@ -24885,6 +24885,7 @@ A user with add-on data.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -29916,6 +29917,7 @@ The currently authenticated GitLab user.
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `codeSuggestionsContexts` {{< icon name="warning-solid" >}} | [`[String!]!`](#string) | **Introduced** in GitLab 17.9. **Status**: Experiment. List of additional contexts enabled for Code Suggestions. |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `duoChatAvailable` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Introduced** in GitLab 16.8. **Status**: Experiment. User access to AI chat feature. |
@@ -37542,6 +37544,7 @@ A user assigned to a merge request.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -38000,6 +38003,7 @@ The author of the merge request.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -38509,6 +38513,7 @@ A user participating in a merge request.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -38986,6 +38991,7 @@ A user assigned to a merge request as a reviewer.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -47670,6 +47676,7 @@ Core representation of a GitLab user.
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
@@ -57998,6 +58005,7 @@ Implementations:
| `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| `commitEmail` | [`String`](#string) | User's default commit email. |
+| `compositeIdentityEnforced` | [`Boolean!`](#boolean) | Indicates if the user has composite identity enforcement enabled. |
| `createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
| `discord` | [`String`](#string) | Discord ID of the user. |
| `email` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
diff --git a/spec/frontend/merge_requests/components/reviewers/reviewer_dropdown_spec.js b/spec/frontend/merge_requests/components/reviewers/reviewer_dropdown_spec.js
index 4d77934a6a3a57218bab9f0a7f55660ee1d29b4b..d1388e75fc1635f97237e6ea1c6d6f44c6f2714c 100644
--- a/spec/frontend/merge_requests/components/reviewers/reviewer_dropdown_spec.js
+++ b/spec/frontend/merge_requests/components/reviewers/reviewer_dropdown_spec.js
@@ -28,6 +28,7 @@ const createMockUser = ({ id = 1, name = 'Administrator', username = 'root' } =
webUrl: `/${username}`,
webPath: `/${username}`,
status: null,
+ compositeIdentityEnforced: false,
mergeRequestInteraction: {
canMerge: true,
applicableApprovalRules: [],
diff --git a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
index e54ba31a30c0916da8f2f9ffd24075d738badd89..b5fd5b9b0526c3a957083ee122b65200537a6b9e 100644
--- a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
+++ b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
@@ -1,4 +1,5 @@
-import { mount } from '@vue/test-utils';
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue';
@@ -8,9 +9,15 @@ const containerClasses = 'gl-cool-class gl-over-9000';
describe('UserNameWithStatus', () => {
let wrapper;
+ const findBusyBadge = () => wrapper.find('[data-testid="busy-badge"]');
+ const findAgentBadge = () => wrapper.find('[data-testid="agent-badge"]');
+
function createComponent(props = {}) {
- wrapper = mount(UserNameWithStatus, {
+ wrapper = shallowMount(UserNameWithStatus, {
propsData: { name, containerClasses, ...props },
+ stubs: {
+ GlSprintf,
+ },
});
}
@@ -22,22 +29,62 @@ describe('UserNameWithStatus', () => {
expect(wrapper.html()).toContain(name);
});
- it('will not render "Busy"', () => {
- expect(wrapper.html()).not.toContain('Busy');
- });
-
it('will render all relevant containerClasses', () => {
const classes = wrapper.find('span').classes().join(' ');
expect(classes).toBe(containerClasses);
});
- describe(`with availability="${AVAILABILITY_STATUS.BUSY}"`, () => {
+ describe('when user is not busy and is not agent', () => {
+ it('will not render "Busy" badge', () => {
+ expect(findBusyBadge().exists()).toBe(false);
+ });
+
+ it('will not render agent badge', () => {
+ expect(findAgentBadge().exists()).toBe(false);
+ });
+ });
+
+ describe(`when user is busy`, () => {
beforeEach(() => {
createComponent({ availability: AVAILABILITY_STATUS.BUSY });
});
- it('will render "Busy"', () => {
- expect(wrapper.text()).toContain('Busy');
+ it('will render "Busy" badge', () => {
+ expect(findBusyBadge().exists()).toBe(true);
+ expect(findBusyBadge().text()).toBe('Busy');
+ });
+
+ it('will not render agent badge', () => {
+ expect(findAgentBadge().exists()).toBe(false);
+ });
+ });
+
+ describe('when user is agent', () => {
+ beforeEach(() => {
+ createComponent({ compositeIdentityEnforced: true });
+ });
+
+ it('will render agent badge', () => {
+ expect(findAgentBadge().exists()).toBe(true);
+ expect(findAgentBadge().text()).toBe('Agent');
+ });
+
+ it('will not render busy badge', () => {
+ expect(findBusyBadge().exists()).toBe(false);
+ });
+ });
+
+ describe('when user is busy and is agent', () => {
+ beforeEach(() => {
+ createComponent({
+ availability: AVAILABILITY_STATUS.BUSY,
+ compositeIdentityEnforced: true,
+ });
+ });
+
+ it('will render both busy and agent badges', () => {
+ expect(findBusyBadge().exists()).toBe(true);
+ expect(findAgentBadge().exists()).toBe(true);
});
});
diff --git a/spec/services/groups/participants_service_spec.rb b/spec/services/groups/participants_service_spec.rb
index 7760f58dfe800230d4cb09de42d4d32c9895b119..868d1be50d1d4b1e7c124d41a95a8be5237d19a8 100644
--- a/spec/services/groups/participants_service_spec.rb
+++ b/spec/services/groups/participants_service_spec.rb
@@ -120,8 +120,7 @@ def user_to_autocompletable(user)
username: user.username,
name: user.name,
avatar_url: user.avatar_url,
- availability: user&.status&.availability,
- composite_identity_enforced: user.composite_identity_enforced
+ availability: user&.status&.availability
}
end
end