Skip to content
Snippets Groups Projects
Verified Commit 054cb968 authored by Oiza Baiye's avatar Oiza Baiye :two: Committed by GitLab
Browse files

Surface user.type to frontend

Add the 'type' field to the User fragment enabling
the frontend to filter specific user types in future.

Changelog: added
parent 33d2d584
No related branches found
No related tags found
3 merge requests!181325Fix ambiguous `created_at` in project.rb,!179611Draft: Rebase CR approach for zoekt assignments,!175972FE: Surface user type to frontend
#import "~/graphql_shared/fragments/user.fragment.graphql"
fragment UserWithType on User {
...User
type
}
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/graphql_shared/fragments/user_with_type.fragment.graphql"
#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
query issueAssignees($fullPath: ID!, $iid: String!) {
......@@ -7,12 +7,12 @@ query issueAssignees($fullPath: ID!, $iid: String!) {
issuable: issue(iid: $iid) {
id
author {
...User
...UserWithType
...UserAvailability
}
assignees {
nodes {
...User
...UserWithType
...UserAvailability
}
}
......
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/graphql_shared/fragments/user_with_type.fragment.graphql"
#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
query getMrAssignees($fullPath: ID!, $iid: String!) {
......@@ -7,7 +7,7 @@ query getMrAssignees($fullPath: ID!, $iid: String!) {
issuable: mergeRequest(iid: $iid) {
id
author {
...User
...UserWithType
...UserAvailability
mergeRequestInteraction {
canMerge
......@@ -15,7 +15,7 @@ query getMrAssignees($fullPath: ID!, $iid: String!) {
}
assignees {
nodes {
...User
...UserWithType
...UserAvailability
mergeRequestInteraction {
canMerge
......
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
#import "~/graphql_shared/fragments/user_with_type.fragment.graphql"
mutation issueSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullPath: ID!) {
issuableSetAssignees: issueSetAssignees(
......@@ -9,7 +9,7 @@ mutation issueSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullP
id
assignees {
nodes {
...User
...UserWithType
...UserAvailability
}
}
......
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/graphql_shared/fragments/user_with_type.fragment.graphql"
#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
mutation mergeRequestSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullPath: ID!) {
......@@ -9,7 +9,7 @@ mutation mergeRequestSetAssignees($iid: String!, $assigneeUsernames: [String!]!,
id
assignees {
nodes {
...User
...UserWithType
...UserAvailability
mergeRequestInteraction {
canMerge
......
......@@ -13,9 +13,15 @@ import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assig
import SidebarInviteMembers from '~/sidebar/components/assignees/sidebar_invite_members.vue';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import getIssueAssigneesQuery from '~/sidebar/queries/get_issue_assignees.query.graphql';
import getMrAssigneesQuery from '~/sidebar/queries/get_mr_assignees.query.graphql';
import updateIssueAssigneesMutation from '~/sidebar/queries/update_issue_assignees.mutation.graphql';
import UserSelect from '~/vue_shared/components/user_select/user_select.vue';
import { issuableQueryResponse, updateIssueAssigneesMutationResponse } from '../../mock_data';
import {
issuableQueryResponse,
updateIssueAssigneesMutationResponse,
mrAssigneesQueryResponse,
} from '../../mock_data';
import { userTypes } from '../../constants';
jest.mock('~/alert');
......@@ -33,6 +39,7 @@ const initialAssignees = [
name: 'test',
username: 'test',
webUrl: '/test',
type: userTypes.human,
},
];
......@@ -51,12 +58,14 @@ describe('Sidebar assignees widget', () => {
const createComponent = ({
issuableQueryHandler = jest.fn().mockResolvedValue(issuableQueryResponse),
updateIssueAssigneesMutationHandler = updateIssueAssigneesMutationSuccess,
mrQueryHandler = jest.fn().mockResolvedValue(mrAssigneesQueryResponse),
props = {},
provide = {},
} = {}) => {
fakeApollo = createMockApollo([
[getIssueAssigneesQuery, issuableQueryHandler],
[updateIssueAssigneesMutation, updateIssueAssigneesMutationHandler],
[getMrAssigneesQuery, mrQueryHandler],
]);
wrapper = shallowMount(SidebarAssigneesWidget, {
apolloProvider: fakeApollo,
......@@ -155,6 +164,7 @@ describe('Sidebar assignees widget', () => {
webUrl: '/franc',
webPath: '/franc',
status: null,
type: userTypes.human,
},
]);
});
......@@ -184,6 +194,7 @@ describe('Sidebar assignees widget', () => {
});
await waitForPromises();
await nextTick();
expect(
findAssignees()
......@@ -221,6 +232,7 @@ describe('Sidebar assignees widget', () => {
webUrl: '/root',
webPath: '/root',
status: null,
type: userTypes.human,
},
],
id: 'gid://gitlab/Issue/1',
......@@ -396,7 +408,10 @@ describe('Sidebar assignees widget', () => {
});
it('does not render invite members link on non-issue sidebar', async () => {
createComponent({ props: { issuableType: TYPE_MERGE_REQUEST } });
createComponent({
props: { issuableType: TYPE_MERGE_REQUEST },
});
await waitForPromises();
expect(findInviteMembersLink().exists()).toBe(false);
});
......
// as defined in app/models/concerns/has_user_type.rb
export const userTypes = {
human: 'HUMAN',
support_bot: 'SUPPORT_BOT',
alert_bot: 'ALERT_BOT',
visual_review_bot: 'VISUAL_REVIEW_BOT',
service_user: 'SERVICE_USER',
ghost: 'GHOST',
project_bot: 'PROJECT_BOT',
migration_bot: 'MIGRATION_BOT',
security_bot: 'SECURITY_BOT',
automation_bot: 'AUTOMATION_BOT',
security_policy_bot: 'SECURITY_POLICY_BOT',
admin_bot: 'ADMIN_BOT',
suggested_reviewers_bot: 'SUGGESTED_REVIEWERS_BOT',
service_account: 'SERVICE_ACCOUNT',
llm_bot: 'LLM_BOT',
placeholder: 'PLACEHOLDER',
duo_code_review_bot: 'DUO_CODE_REVIEW_BOT',
import_user: 'IMPORT_USER',
};
import { userTypes } from './constants';
const RESPONSE_MAP = {
GET: {
'/gitlab-org/gitlab-shell/issues/5.json': {
......@@ -363,6 +365,7 @@ export const issuableQueryResponse = {
webUrl: 'root',
webPath: '/root',
status: null,
type: userTypes.human,
},
assignees: {
nodes: [
......@@ -376,6 +379,7 @@ export const issuableQueryResponse = {
webUrl: '/franc',
webPath: '/franc',
status: null,
type: userTypes.human,
},
],
},
......@@ -466,6 +470,7 @@ export const updateIssueAssigneesMutationResponse = {
webUrl: '/root',
webPath: '/root',
status: null,
type: userTypes.human,
},
],
__typename: 'UserConnection',
......@@ -505,8 +510,16 @@ export const subscriptionResponse = {
},
};
export const mockUser1 = {
__typename: 'UserCore',
export const createMockUser = (userDetails) => {
return {
__typename: 'UserCore',
status: null,
canMerge: false,
...userDetails,
};
};
export const mockUser1 = createMockUser({
id: 'gid://gitlab/User/1',
avatarUrl:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
......@@ -514,20 +527,25 @@ export const mockUser1 = {
username: 'root',
webUrl: '/root',
webPath: '/root',
status: null,
canMerge: false,
});
export const mockUserWithType1 = {
...mockUser1,
type: userTypes.human,
};
export const mockUser2 = {
__typename: 'UserCore',
export const mockUser2 = createMockUser({
id: 'gid://gitlab/User/5',
avatarUrl: '/avatar2',
name: 'rookie',
username: 'rookie',
webUrl: 'rookie',
webPath: '/rookie',
status: null,
canMerge: false,
});
export const mockUserWithType2 = {
...mockUser2,
type: userTypes.human,
};
export const searchResponse = {
......@@ -732,6 +750,39 @@ export const participantsQueryResponse = {
},
};
export const mrAssigneesQueryResponse = {
data: {
workspace: {
__typename: 'Project',
id: '1',
issuable: {
__typename: 'MergeRequest',
id: 'gid://gitlab/MergeRequest/1',
iid: '1',
author: {
id: '1',
avatarUrl: '/avatar',
name: 'root',
username: 'root',
webUrl: 'root',
webPath: '/root',
status: null,
type: userTypes.human,
mergeRequestInteraction: {
canMerge: true,
},
},
assignees: {
nodes: [],
},
userPermissions: {
canMerge: true,
},
},
},
},
};
export const mockGroupPath = 'gitlab-org';
export const mockProjectPath = `${mockGroupPath}/some-project`;
......
......@@ -214,7 +214,6 @@ describe('User select dropdown', () => {
},
});
await waitForPromises();
expect(findUnselectedParticipantByIndex(0).props('user')).toMatchObject(mockUser2);
});
......@@ -230,8 +229,8 @@ describe('User select dropdown', () => {
});
await waitForPromises();
expect(findUnselectedParticipantByIndex(0).props('user')).toEqual(currentUser);
expect(findUnselectedParticipantByIndex(1).props('user')).toMatchObject(issuableAuthor);
expect(findUnselectedParticipantByIndex(0).props('user')).toEqual(mockUser2);
expect(findUnselectedParticipantByIndex(1).props('user')).toMatchObject(mockUser1);
});
it('displays author in a designated position if author is not assigned and not a project member', async () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment