Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a6dce21d91
commit
4def415fbf
|
@ -98,6 +98,10 @@ const MilestoneToken = () =>
|
|||
import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue');
|
||||
const ReleaseToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/release_token.vue');
|
||||
const CrmContactToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue');
|
||||
const CrmOrganizationToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue');
|
||||
|
||||
export default {
|
||||
i18n,
|
||||
|
@ -383,7 +387,11 @@ export default {
|
|||
type: TOKEN_TYPE_CONTACT,
|
||||
title: TOKEN_TITLE_CONTACT,
|
||||
icon: 'user',
|
||||
token: GlFilteredSearchToken,
|
||||
token: CrmContactToken,
|
||||
fullPath: this.fullPath,
|
||||
isProject: this.isProject,
|
||||
defaultContacts: DEFAULT_NONE_ANY,
|
||||
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-crm-contacts`,
|
||||
operators: OPERATOR_IS_ONLY,
|
||||
unique: true,
|
||||
});
|
||||
|
@ -394,7 +402,11 @@ export default {
|
|||
type: TOKEN_TYPE_ORGANIZATION,
|
||||
title: TOKEN_TITLE_ORGANIZATION,
|
||||
icon: 'users',
|
||||
token: GlFilteredSearchToken,
|
||||
token: CrmOrganizationToken,
|
||||
fullPath: this.fullPath,
|
||||
isProject: this.isProject,
|
||||
defaultOrganizations: DEFAULT_NONE_ANY,
|
||||
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-crm-organizations`,
|
||||
operators: OPERATOR_IS_ONLY,
|
||||
unique: true,
|
||||
});
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
fragment ContactFragment on CustomerRelationsContact {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
email
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
fragment OrganizationFragment on CustomerRelationsOrganization {
|
||||
id
|
||||
name
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#import "./crm_contact.fragment.graphql"
|
||||
|
||||
query searchCrmContacts(
|
||||
$isProject: Boolean = false
|
||||
$fullPath: ID!
|
||||
$searchString: String
|
||||
$searchIds: [CustomerRelationsContactID!]
|
||||
) {
|
||||
group(fullPath: $fullPath) @skip(if: $isProject) {
|
||||
id
|
||||
contacts(search: $searchString, ids: $searchIds) {
|
||||
nodes {
|
||||
...ContactFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
project(fullPath: $fullPath) @include(if: $isProject) {
|
||||
id
|
||||
group {
|
||||
id
|
||||
contacts(search: $searchString, ids: $searchIds) {
|
||||
nodes {
|
||||
...ContactFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#import "./crm_organization.fragment.graphql"
|
||||
|
||||
query searchCrmOrganizations(
|
||||
$isProject: Boolean = false
|
||||
$fullPath: ID!
|
||||
$searchString: String
|
||||
$searchIds: [CustomerRelationsOrganizationID!]
|
||||
) {
|
||||
group(fullPath: $fullPath) @skip(if: $isProject) {
|
||||
id
|
||||
organizations(search: $searchString, ids: $searchIds) {
|
||||
nodes {
|
||||
...OrganizationFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
project(fullPath: $fullPath) @include(if: $isProject) {
|
||||
id
|
||||
group {
|
||||
id
|
||||
organizations(search: $searchString, ids: $searchIds) {
|
||||
nodes {
|
||||
...OrganizationFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
<script>
|
||||
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
|
||||
import { ITEM_TYPE } from '~/groups/constants';
|
||||
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import createFlash from '~/flash';
|
||||
import { isPositiveInteger } from '~/lib/utils/number_utils';
|
||||
import { __ } from '~/locale';
|
||||
import searchCrmContactsQuery from '../queries/search_crm_contacts.query.graphql';
|
||||
|
||||
import { DEFAULT_NONE_ANY } from '../constants';
|
||||
|
||||
import BaseToken from './base_token.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseToken,
|
||||
GlFilteredSearchSuggestion,
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contacts: this.config.initialContacts || [],
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
defaultContacts() {
|
||||
return this.config.defaultContacts || DEFAULT_NONE_ANY;
|
||||
},
|
||||
namespace() {
|
||||
return this.config.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getActiveContact(contacts, data) {
|
||||
return contacts.find((contact) => {
|
||||
return `${this.formatContactId(contact)}` === data;
|
||||
});
|
||||
},
|
||||
getContactName(contact) {
|
||||
return `${contact.firstName} ${contact.lastName}`;
|
||||
},
|
||||
fetchContacts(searchTerm) {
|
||||
let searchString = null;
|
||||
let searchId = null;
|
||||
if (isPositiveInteger(searchTerm)) {
|
||||
searchId = this.formatContactGraphQLId(searchTerm);
|
||||
} else {
|
||||
searchString = searchTerm;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
this.$apollo
|
||||
.query({
|
||||
query: searchCrmContactsQuery,
|
||||
variables: {
|
||||
fullPath: this.config.fullPath,
|
||||
searchString,
|
||||
searchIds: searchId ? [searchId] : null,
|
||||
isProject: this.config.isProject,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.contacts = this.config.isProject
|
||||
? data[this.namespace]?.group.contacts.nodes
|
||||
: data[this.namespace]?.contacts.nodes;
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
message: __('There was a problem fetching CRM contacts.'),
|
||||
}),
|
||||
)
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
formatContactId(contact) {
|
||||
return `${getIdFromGraphQLId(contact.id)}`;
|
||||
},
|
||||
formatContactGraphQLId(id) {
|
||||
return convertToGraphQLId('CustomerRelations::Contact', id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<base-token
|
||||
:config="config"
|
||||
:value="value"
|
||||
:active="active"
|
||||
:suggestions-loading="loading"
|
||||
:suggestions="contacts"
|
||||
:get-active-token-value="getActiveContact"
|
||||
:default-suggestions="defaultContacts"
|
||||
v-bind="$attrs"
|
||||
@fetch-suggestions="fetchContacts"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template #view="{ viewTokenProps: { inputValue, activeTokenValue } }">
|
||||
{{ activeTokenValue ? getContactName(activeTokenValue) : inputValue }}
|
||||
</template>
|
||||
<template #suggestions-list="{ suggestions }">
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="contact in suggestions"
|
||||
:key="formatContactId(contact)"
|
||||
:value="formatContactId(contact)"
|
||||
>
|
||||
<div>
|
||||
<div>{{ getContactName(contact) }}</div>
|
||||
<div class="gl-font-sm">{{ contact.email }}</div>
|
||||
</div>
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</base-token>
|
||||
</template>
|
|
@ -0,0 +1,125 @@
|
|||
<script>
|
||||
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
|
||||
import { ITEM_TYPE } from '~/groups/constants';
|
||||
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import createFlash from '~/flash';
|
||||
import { isPositiveInteger } from '~/lib/utils/number_utils';
|
||||
import { __ } from '~/locale';
|
||||
import searchCrmOrganizationsQuery from '../queries/search_crm_organizations.query.graphql';
|
||||
|
||||
import { DEFAULT_NONE_ANY } from '../constants';
|
||||
|
||||
import BaseToken from './base_token.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseToken,
|
||||
GlFilteredSearchSuggestion,
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
organizations: this.config.initialOrganizations || [],
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
defaultOrganizations() {
|
||||
return this.config.defaultOrganizations || DEFAULT_NONE_ANY;
|
||||
},
|
||||
namespace() {
|
||||
return this.config.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getActiveOrganization(organizations, data) {
|
||||
return organizations.find((organization) => {
|
||||
return `${this.formatOrganizationId(organization)}` === data;
|
||||
});
|
||||
},
|
||||
fetchOrganizations(searchTerm) {
|
||||
let searchString = null;
|
||||
let searchId = null;
|
||||
if (isPositiveInteger(searchTerm)) {
|
||||
searchId = this.formatOrganizationGraphQLId(searchTerm);
|
||||
} else {
|
||||
searchString = searchTerm;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
|
||||
this.$apollo
|
||||
.query({
|
||||
query: searchCrmOrganizationsQuery,
|
||||
variables: {
|
||||
fullPath: this.config.fullPath,
|
||||
searchString,
|
||||
searchIds: searchId ? [searchId] : null,
|
||||
isProject: this.config.isProject,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.organizations = this.config.isProject
|
||||
? data[this.namespace]?.group.organizations.nodes
|
||||
: data[this.namespace]?.organizations.nodes;
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
message: __('There was a problem fetching CRM organizations.'),
|
||||
}),
|
||||
)
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
formatOrganizationId(organization) {
|
||||
return `${getIdFromGraphQLId(organization.id)}`;
|
||||
},
|
||||
formatOrganizationGraphQLId(id) {
|
||||
return convertToGraphQLId('CustomerRelations::Organization', id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<base-token
|
||||
:config="config"
|
||||
:value="value"
|
||||
:active="active"
|
||||
:suggestions-loading="loading"
|
||||
:suggestions="organizations"
|
||||
:get-active-token-value="getActiveOrganization"
|
||||
:default-suggestions="defaultOrganizations"
|
||||
v-bind="$attrs"
|
||||
@fetch-suggestions="fetchOrganizations"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template #view="{ viewTokenProps: { inputValue, activeTokenValue } }">
|
||||
{{ activeTokenValue ? activeTokenValue.name : inputValue }}
|
||||
</template>
|
||||
<template #suggestions-list="{ suggestions }">
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="organization in suggestions"
|
||||
:key="formatOrganizationId(organization)"
|
||||
:value="formatOrganizationId(organization)"
|
||||
>
|
||||
{{ organization.name }}
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</base-token>
|
||||
</template>
|
|
@ -54,7 +54,8 @@ end
|
|||
|
||||
before_fork do
|
||||
# Signal to the puma killer
|
||||
Gitlab::Cluster::PumaWorkerKillerInitializer.start @config.options unless ENV['DISABLE_PUMA_WORKER_KILLER']
|
||||
enable_puma_worker_killer = !Gitlab::Utils.to_boolean(ENV['DISABLE_PUMA_WORKER_KILLER'])
|
||||
Gitlab::Cluster::PumaWorkerKillerInitializer.start(@config.options) if enable_puma_worker_killer
|
||||
|
||||
# Signal application hooks that we're about to fork
|
||||
Gitlab::Cluster::LifecycleEvents.do_before_fork
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RenameBuildsSidekiqQueuesToNamespaces < Gitlab::Database::Migration[2.0]
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
disable_ddl_transaction!
|
||||
|
||||
BUILD_OLD_QUEUE = 'pipeline_processing:build_finished'
|
||||
BUILD_NEW_QUEUE = 'pipeline_processing:ci_build_finished'
|
||||
|
||||
TRACE_OLD_QUEUE = 'pipeline_background:archive_trace'
|
||||
TRACE_NEW_QUEUE = 'pipeline_background:ci_archive_trace'
|
||||
|
||||
def up
|
||||
sidekiq_queue_migrate BUILD_OLD_QUEUE, to: BUILD_NEW_QUEUE
|
||||
sidekiq_queue_migrate TRACE_OLD_QUEUE, to: TRACE_NEW_QUEUE
|
||||
end
|
||||
|
||||
def down
|
||||
sidekiq_queue_migrate BUILD_NEW_QUEUE, to: BUILD_OLD_QUEUE
|
||||
sidekiq_queue_migrate TRACE_NEW_QUEUE, to: TRACE_OLD_QUEUE
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
aeaa386b52a2a5e30b59fbe57e9c701298fea45219b3ec419866d40c6d2a5e5d
|
|
@ -12,6 +12,9 @@ These instructions assume you have a working instance of GitLab. They guide you
|
|||
1. Making your existing instance the **primary** site.
|
||||
1. Adding **secondary** sites.
|
||||
|
||||
You must use a [GitLab Premium](https://about.gitlab.com/pricing/) license or higher,
|
||||
but you only need one license for all the sites.
|
||||
|
||||
WARNING:
|
||||
The steps below should be followed in the order they appear. **Make sure the GitLab version is the same on all sites.**
|
||||
|
||||
|
|
|
@ -18,8 +18,13 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
|
|||
1. On the top menu, select **Projects > Create new project**.
|
||||
1. Select **Run CI/CD for external repository**.
|
||||
1. Select **Repository by URL**.
|
||||
|
||||
1. Fill in the fields with information from the repository in Bitbucket:
|
||||
- For **Git repository URL**, use the URL from the **Clone this repository** panel in Bitbucket.
|
||||
- Leave the username blank.
|
||||
- You can generate and use a [Bitbucket App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) for the password field.
|
||||
|
||||
GitLab imports the repository and enables [Pull Mirroring](../../user/project/repository/mirror/pull.md).
|
||||
You can check that mirroring is working in the project by going to **Settings > Repository > Mirroring repositories**.
|
||||
|
||||
1. In GitLab, create a
|
||||
[Personal Access Token](../../user/profile/personal_access_tokens.md)
|
||||
|
|
|
@ -142,7 +142,10 @@ When renaming queues, use the `sidekiq_queue_migrate` helper migration method
|
|||
in a **post-deployment migration**:
|
||||
|
||||
```ruby
|
||||
class MigrateTheRenamedSidekiqQueue < Gitlab::Database::Migration[1.0]
|
||||
class MigrateTheRenamedSidekiqQueue < Gitlab::Database::Migration[2.0]
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
sidekiq_queue_migrate 'old_queue_name', to: 'new_queue_name'
|
||||
end
|
||||
|
|
|
@ -5,10 +5,10 @@ module Gitlab
|
|||
class PumaWorkerKillerInitializer
|
||||
def self.start(
|
||||
puma_options,
|
||||
puma_per_worker_max_memory_mb: 1024,
|
||||
puma_master_max_memory_mb: 800,
|
||||
additional_puma_dev_max_memory_mb: 200
|
||||
)
|
||||
puma_per_worker_max_memory_mb: 1200,
|
||||
puma_master_max_memory_mb: 950,
|
||||
additional_puma_dev_max_memory_mb: 200)
|
||||
|
||||
require 'puma_worker_killer'
|
||||
|
||||
PumaWorkerKiller.config do |config|
|
||||
|
|
|
@ -38935,6 +38935,12 @@ msgstr ""
|
|||
msgid "There was a problem communicating with your device."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching CRM contacts."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching CRM organizations."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching branches."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji
|
|||
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
|
||||
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
|
||||
import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue';
|
||||
import CrmContactToken from '~/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue';
|
||||
import CrmOrganizationToken from '~/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue';
|
||||
|
||||
export const mockAuthor1 = {
|
||||
id: 1,
|
||||
|
@ -62,6 +64,128 @@ export const mockMilestones = [
|
|||
mockEscapedMilestone,
|
||||
];
|
||||
|
||||
export const mockCrmContacts = [
|
||||
{
|
||||
id: 'gid://gitlab/CustomerRelations::Contact/1',
|
||||
firstName: 'John',
|
||||
lastName: 'Smith',
|
||||
email: 'john@smith.com',
|
||||
},
|
||||
{
|
||||
id: 'gid://gitlab/CustomerRelations::Contact/2',
|
||||
firstName: 'Andy',
|
||||
lastName: 'Green',
|
||||
email: 'andy@green.net',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockCrmOrganizations = [
|
||||
{
|
||||
id: 'gid://gitlab/CustomerRelations::Organization/1',
|
||||
name: 'First Org Ltd.',
|
||||
},
|
||||
{
|
||||
id: 'gid://gitlab/CustomerRelations::Organization/2',
|
||||
name: 'Organizer S.p.a.',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockProjectCrmContactsQueryResponse = {
|
||||
data: {
|
||||
project: {
|
||||
__typename: 'Project',
|
||||
id: 1,
|
||||
group: {
|
||||
__typename: 'Group',
|
||||
id: 1,
|
||||
contacts: {
|
||||
__typename: 'CustomerRelationsContactConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'CustomerRelationsContact',
|
||||
...mockCrmContacts[0],
|
||||
},
|
||||
{
|
||||
__typename: 'CustomerRelationsContact',
|
||||
...mockCrmContacts[1],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockProjectCrmOrganizationsQueryResponse = {
|
||||
data: {
|
||||
project: {
|
||||
__typename: 'Project',
|
||||
id: 1,
|
||||
group: {
|
||||
__typename: 'Group',
|
||||
id: 1,
|
||||
organizations: {
|
||||
__typename: 'CustomerRelationsOrganizationConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'CustomerRelationsOrganization',
|
||||
...mockCrmOrganizations[0],
|
||||
},
|
||||
{
|
||||
__typename: 'CustomerRelationsOrganization',
|
||||
...mockCrmOrganizations[1],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockGroupCrmContactsQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
__typename: 'Group',
|
||||
id: 1,
|
||||
contacts: {
|
||||
__typename: 'CustomerRelationsContactConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'CustomerRelationsContact',
|
||||
...mockCrmContacts[0],
|
||||
},
|
||||
{
|
||||
__typename: 'CustomerRelationsContact',
|
||||
...mockCrmContacts[1],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockGroupCrmOrganizationsQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
__typename: 'Group',
|
||||
id: 1,
|
||||
organizations: {
|
||||
__typename: 'CustomerRelationsOrganizationConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'CustomerRelationsOrganization',
|
||||
...mockCrmOrganizations[0],
|
||||
},
|
||||
{
|
||||
__typename: 'CustomerRelationsOrganization',
|
||||
...mockCrmOrganizations[1],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const mockEmoji1 = {
|
||||
name: 'thumbsup',
|
||||
};
|
||||
|
@ -134,6 +258,28 @@ export const mockReactionEmojiToken = {
|
|||
fetchEmojis: () => Promise.resolve(mockEmojis),
|
||||
};
|
||||
|
||||
export const mockCrmContactToken = {
|
||||
type: 'crm_contact',
|
||||
title: 'Contact',
|
||||
icon: 'user',
|
||||
token: CrmContactToken,
|
||||
isProject: false,
|
||||
fullPath: 'group',
|
||||
operators: OPERATOR_IS_ONLY,
|
||||
unique: true,
|
||||
};
|
||||
|
||||
export const mockCrmOrganizationToken = {
|
||||
type: 'crm_contact',
|
||||
title: 'Organization',
|
||||
icon: 'user',
|
||||
token: CrmOrganizationToken,
|
||||
isProject: false,
|
||||
fullPath: 'group',
|
||||
operators: OPERATOR_IS_ONLY,
|
||||
unique: true,
|
||||
};
|
||||
|
||||
export const mockMembershipToken = {
|
||||
type: 'with_inherited_permissions',
|
||||
icon: 'group',
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
import {
|
||||
GlFilteredSearchSuggestion,
|
||||
GlFilteredSearchTokenSegment,
|
||||
GlDropdownDivider,
|
||||
} from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
import CrmContactToken from '~/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue';
|
||||
import searchCrmContactsQuery from '~/vue_shared/components/filtered_search_bar/queries/search_crm_contacts.query.graphql';
|
||||
|
||||
import {
|
||||
mockCrmContacts,
|
||||
mockCrmContactToken,
|
||||
mockGroupCrmContactsQueryResponse,
|
||||
mockProjectCrmContactsQueryResponse,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
const defaultStubs = {
|
||||
Portal: true,
|
||||
BaseToken,
|
||||
GlFilteredSearchSuggestionList: {
|
||||
template: '<div></div>',
|
||||
methods: {
|
||||
getValue: () => '=',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('CrmContactToken', () => {
|
||||
Vue.use(VueApollo);
|
||||
|
||||
let wrapper;
|
||||
let fakeApollo;
|
||||
|
||||
const getBaseToken = () => wrapper.findComponent(BaseToken);
|
||||
|
||||
const searchGroupCrmContactsQueryHandler = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockGroupCrmContactsQueryResponse);
|
||||
const searchProjectCrmContactsQueryHandler = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockProjectCrmContactsQueryResponse);
|
||||
|
||||
const mountComponent = ({
|
||||
config = mockCrmContactToken,
|
||||
value = { data: '' },
|
||||
active = false,
|
||||
stubs = defaultStubs,
|
||||
listeners = {},
|
||||
queryHandler = searchGroupCrmContactsQueryHandler,
|
||||
} = {}) => {
|
||||
fakeApollo = createMockApollo([[searchCrmContactsQuery, queryHandler]]);
|
||||
|
||||
wrapper = mount(CrmContactToken, {
|
||||
propsData: {
|
||||
config,
|
||||
value,
|
||||
active,
|
||||
cursorPosition: 'start',
|
||||
},
|
||||
provide: {
|
||||
portalName: 'fake target',
|
||||
alignSuggestions: function fakeAlignSuggestions() {},
|
||||
suggestionsListClass: () => 'custom-class',
|
||||
},
|
||||
stubs,
|
||||
listeners,
|
||||
apolloProvider: fakeApollo,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
fakeApollo = null;
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('fetchContacts', () => {
|
||||
describe('for groups', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchString when search term is a string', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', 'foo');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchGroupCrmContactsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'group',
|
||||
isProject: false,
|
||||
searchString: 'foo',
|
||||
searchIds: null,
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmContacts);
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchId when search term is a number', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', '5');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchGroupCrmContactsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'group',
|
||||
isProject: false,
|
||||
searchString: null,
|
||||
searchIds: ['gid://gitlab/CustomerRelations::Contact/5'],
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmContacts);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for projects', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({
|
||||
config: {
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
},
|
||||
queryHandler: searchProjectCrmContactsQueryHandler,
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchString when search term is a string', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', 'foo');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchProjectCrmContactsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
searchString: 'foo',
|
||||
searchIds: null,
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmContacts);
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchId when search term is a number', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', '5');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchProjectCrmContactsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
searchString: null,
|
||||
searchIds: ['gid://gitlab/CustomerRelations::Contact/5'],
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmContacts);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls `createFlash` with flash error message when request fails', async () => {
|
||||
mountComponent();
|
||||
|
||||
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
|
||||
|
||||
getBaseToken().vm.$emit('fetch-suggestions');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
message: 'There was a problem fetching CRM contacts.',
|
||||
});
|
||||
});
|
||||
|
||||
it('sets `loading` to false when request completes', async () => {
|
||||
mountComponent();
|
||||
|
||||
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
|
||||
|
||||
getBaseToken().vm.$emit('fetch-suggestions');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(getBaseToken().props('suggestionsLoading')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
const defaultContacts = DEFAULT_NONE_ANY;
|
||||
|
||||
it('renders base-token component', () => {
|
||||
mountComponent({
|
||||
config: { ...mockCrmContactToken, initialContacts: mockCrmContacts },
|
||||
value: { data: '1' },
|
||||
});
|
||||
|
||||
const baseTokenEl = wrapper.find(BaseToken);
|
||||
|
||||
expect(baseTokenEl.exists()).toBe(true);
|
||||
expect(baseTokenEl.props()).toMatchObject({
|
||||
suggestions: mockCrmContacts,
|
||||
getActiveTokenValue: wrapper.vm.getActiveContact,
|
||||
});
|
||||
});
|
||||
|
||||
it.each(mockCrmContacts)('renders token item when value is selected', (contact) => {
|
||||
mountComponent({
|
||||
config: { ...mockCrmContactToken, initialContacts: mockCrmContacts },
|
||||
value: { data: `${getIdFromGraphQLId(contact.id)}` },
|
||||
});
|
||||
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
|
||||
expect(tokenSegments).toHaveLength(3); // Contact, =, Contact name
|
||||
expect(tokenSegments.at(2).text()).toBe(`${contact.firstName} ${contact.lastName}`); // Contact name
|
||||
});
|
||||
|
||||
it('renders provided defaultContacts as suggestions', async () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmContactToken, defaultContacts },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
await nextTick();
|
||||
|
||||
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
|
||||
expect(suggestions).toHaveLength(defaultContacts.length);
|
||||
defaultContacts.forEach((contact, index) => {
|
||||
expect(suggestions.at(index).text()).toBe(contact.text);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render divider when no defaultContacts', async () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmContactToken, defaultContacts: [] },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false);
|
||||
expect(wrapper.find(GlDropdownDivider).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders `DEFAULT_NONE_ANY` as default suggestions', () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmContactToken },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
|
||||
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
|
||||
expect(suggestions).toHaveLength(DEFAULT_NONE_ANY.length);
|
||||
DEFAULT_NONE_ANY.forEach((contact, index) => {
|
||||
expect(suggestions.at(index).text()).toBe(contact.text);
|
||||
});
|
||||
});
|
||||
|
||||
it('emits listeners in the base-token', () => {
|
||||
const mockInput = jest.fn();
|
||||
mountComponent({
|
||||
listeners: {
|
||||
input: mockInput,
|
||||
},
|
||||
});
|
||||
wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
|
||||
|
||||
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,282 @@
|
|||
import {
|
||||
GlFilteredSearchSuggestion,
|
||||
GlFilteredSearchTokenSegment,
|
||||
GlDropdownDivider,
|
||||
} from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
import CrmOrganizationToken from '~/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue';
|
||||
import searchCrmOrganizationsQuery from '~/vue_shared/components/filtered_search_bar/queries/search_crm_organizations.query.graphql';
|
||||
|
||||
import {
|
||||
mockCrmOrganizations,
|
||||
mockCrmOrganizationToken,
|
||||
mockGroupCrmOrganizationsQueryResponse,
|
||||
mockProjectCrmOrganizationsQueryResponse,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
const defaultStubs = {
|
||||
Portal: true,
|
||||
BaseToken,
|
||||
GlFilteredSearchSuggestionList: {
|
||||
template: '<div></div>',
|
||||
methods: {
|
||||
getValue: () => '=',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('CrmOrganizationToken', () => {
|
||||
Vue.use(VueApollo);
|
||||
|
||||
let wrapper;
|
||||
let fakeApollo;
|
||||
|
||||
const getBaseToken = () => wrapper.findComponent(BaseToken);
|
||||
|
||||
const searchGroupCrmOrganizationsQueryHandler = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockGroupCrmOrganizationsQueryResponse);
|
||||
const searchProjectCrmOrganizationsQueryHandler = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockProjectCrmOrganizationsQueryResponse);
|
||||
|
||||
const mountComponent = ({
|
||||
config = mockCrmOrganizationToken,
|
||||
value = { data: '' },
|
||||
active = false,
|
||||
stubs = defaultStubs,
|
||||
listeners = {},
|
||||
queryHandler = searchGroupCrmOrganizationsQueryHandler,
|
||||
} = {}) => {
|
||||
fakeApollo = createMockApollo([[searchCrmOrganizationsQuery, queryHandler]]);
|
||||
wrapper = mount(CrmOrganizationToken, {
|
||||
propsData: {
|
||||
config,
|
||||
value,
|
||||
active,
|
||||
cursorPosition: 'start',
|
||||
},
|
||||
provide: {
|
||||
portalName: 'fake target',
|
||||
alignSuggestions: function fakeAlignSuggestions() {},
|
||||
suggestionsListClass: () => 'custom-class',
|
||||
},
|
||||
stubs,
|
||||
listeners,
|
||||
apolloProvider: fakeApollo,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
fakeApollo = null;
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('fetchOrganizations', () => {
|
||||
describe('for groups', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchString when search term is a string', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', 'foo');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchGroupCrmOrganizationsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'group',
|
||||
isProject: false,
|
||||
searchString: 'foo',
|
||||
searchIds: null,
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmOrganizations);
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchId when search term is a number', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', '5');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchGroupCrmOrganizationsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'group',
|
||||
isProject: false,
|
||||
searchString: null,
|
||||
searchIds: ['gid://gitlab/CustomerRelations::Organization/5'],
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmOrganizations);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for projects', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({
|
||||
config: {
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
},
|
||||
queryHandler: searchProjectCrmOrganizationsQueryHandler,
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchString when search term is a string', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', 'foo');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchProjectCrmOrganizationsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
searchString: 'foo',
|
||||
searchIds: null,
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmOrganizations);
|
||||
});
|
||||
|
||||
it('calls the apollo query providing the searchId when search term is a number', async () => {
|
||||
getBaseToken().vm.$emit('fetch-suggestions', '5');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).not.toHaveBeenCalled();
|
||||
expect(searchProjectCrmOrganizationsQueryHandler).toHaveBeenCalledWith({
|
||||
fullPath: 'project',
|
||||
isProject: true,
|
||||
searchString: null,
|
||||
searchIds: ['gid://gitlab/CustomerRelations::Organization/5'],
|
||||
});
|
||||
expect(getBaseToken().props('suggestions')).toEqual(mockCrmOrganizations);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls `createFlash` with flash error message when request fails', async () => {
|
||||
mountComponent();
|
||||
|
||||
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
|
||||
|
||||
getBaseToken().vm.$emit('fetch-suggestions');
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
message: 'There was a problem fetching CRM organizations.',
|
||||
});
|
||||
});
|
||||
|
||||
it('sets `loading` to false when request completes', async () => {
|
||||
mountComponent();
|
||||
|
||||
jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({});
|
||||
|
||||
getBaseToken().vm.$emit('fetch-suggestions');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(getBaseToken().props('suggestionsLoading')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
const defaultOrganizations = DEFAULT_NONE_ANY;
|
||||
|
||||
it('renders base-token component', () => {
|
||||
mountComponent({
|
||||
config: { ...mockCrmOrganizationToken, initialOrganizations: mockCrmOrganizations },
|
||||
value: { data: '1' },
|
||||
});
|
||||
|
||||
const baseTokenEl = wrapper.find(BaseToken);
|
||||
|
||||
expect(baseTokenEl.exists()).toBe(true);
|
||||
expect(baseTokenEl.props()).toMatchObject({
|
||||
suggestions: mockCrmOrganizations,
|
||||
getActiveTokenValue: wrapper.vm.getActiveOrganization,
|
||||
});
|
||||
});
|
||||
|
||||
it.each(mockCrmOrganizations)('renders token item when value is selected', (organization) => {
|
||||
mountComponent({
|
||||
config: { ...mockCrmOrganizationToken, initialOrganizations: mockCrmOrganizations },
|
||||
value: { data: `${getIdFromGraphQLId(organization.id)}` },
|
||||
});
|
||||
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
|
||||
expect(tokenSegments).toHaveLength(3); // Organization, =, Organization name
|
||||
expect(tokenSegments.at(2).text()).toBe(organization.name); // Organization name
|
||||
});
|
||||
|
||||
it('renders provided defaultOrganizations as suggestions', async () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmOrganizationToken, defaultOrganizations },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
await nextTick();
|
||||
|
||||
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
|
||||
expect(suggestions).toHaveLength(defaultOrganizations.length);
|
||||
defaultOrganizations.forEach((organization, index) => {
|
||||
expect(suggestions.at(index).text()).toBe(organization.text);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render divider when no defaultOrganizations', async () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmOrganizationToken, defaultOrganizations: [] },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false);
|
||||
expect(wrapper.find(GlDropdownDivider).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders `DEFAULT_NONE_ANY` as default suggestions', () => {
|
||||
mountComponent({
|
||||
active: true,
|
||||
config: { ...mockCrmOrganizationToken },
|
||||
stubs: { Portal: true },
|
||||
});
|
||||
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
||||
const suggestionsSegment = tokenSegments.at(2);
|
||||
suggestionsSegment.vm.$emit('activate');
|
||||
|
||||
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
|
||||
expect(suggestions).toHaveLength(DEFAULT_NONE_ANY.length);
|
||||
DEFAULT_NONE_ANY.forEach((organization, index) => {
|
||||
expect(suggestions.at(index).text()).toBe(organization.text);
|
||||
});
|
||||
});
|
||||
|
||||
it('emits listeners in the base-token', () => {
|
||||
const mockInput = jest.fn();
|
||||
mountComponent({
|
||||
listeners: {
|
||||
input: mockInput,
|
||||
},
|
||||
});
|
||||
wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
|
||||
|
||||
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/aws/aws-sdk-go v1.43.31
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/getsentry/raven-go v0.2.0
|
||||
github.com/golang-jwt/jwt/v4 v4.4.1
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
|
|
|
@ -451,8 +451,9 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
|
|||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
|
|
Loading…
Reference in New Issue