diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-01 12:08:29 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-01 12:08:29 +0300 |
commit | 4def415fbf45e0693b17ea418d378d62ab03a146 (patch) | |
tree | 48fa3f684b33eefbd37e57b7bbe1a17926825e6a /app/assets/javascripts/vue_shared/components/filtered_search_bar | |
parent | a6dce21d917a0a359b3521ec3cef02ab3e6199cf (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/filtered_search_bar')
6 files changed, 322 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_contact.fragment.graphql b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_contact.fragment.graphql new file mode 100644 index 00000000000..38222e4e8c2 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_contact.fragment.graphql @@ -0,0 +1,6 @@ +fragment ContactFragment on CustomerRelationsContact { + id + firstName + lastName + email +} diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_organization.fragment.graphql b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_organization.fragment.graphql new file mode 100644 index 00000000000..a7de3c7f7af --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/crm_organization.fragment.graphql @@ -0,0 +1,4 @@ +fragment OrganizationFragment on CustomerRelationsOrganization { + id + name +} diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_contacts.query.graphql b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_contacts.query.graphql new file mode 100644 index 00000000000..647aaa0f7f8 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_contacts.query.graphql @@ -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 + } + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_organizations.query.graphql b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_organizations.query.graphql new file mode 100644 index 00000000000..c4f4663de45 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/queries/search_crm_organizations.query.graphql @@ -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 + } + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue new file mode 100644 index 00000000000..adfe0559b62 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue new file mode 100644 index 00000000000..e6ab944449e --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue @@ -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> |