diff options
159 files changed, 955 insertions, 625 deletions
diff --git a/.rubocop_todo/style/open_struct_use.yml b/.rubocop_todo/style/open_struct_use.yml index 54ae23d232a..18b1015a6ba 100644 --- a/.rubocop_todo/style/open_struct_use.yml +++ b/.rubocop_todo/style/open_struct_use.yml @@ -12,11 +12,9 @@ Style/OpenStructUse: - lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb - lib/gitlab/testing/request_inspector_middleware.rb - lib/mattermost/session.rb - - spec/controllers/groups/clusters_controller_spec.rb - spec/controllers/projects/clusters_controller_spec.rb - spec/factories/go_module_versions.rb - spec/factories/wiki_pages.rb - - spec/features/projects/clusters_spec.rb - spec/graphql/mutations/branches/create_spec.rb - spec/graphql/mutations/clusters/agent_tokens/create_spec.rb - spec/graphql/mutations/clusters/agents/create_spec.rb diff --git a/app/assets/javascripts/access_tokens/graphql/queries/get_projects.query.graphql b/app/assets/javascripts/access_tokens/graphql/queries/get_projects.query.graphql index 09278e1776a..cdc8a952ead 100644 --- a/app/assets/javascripts/access_tokens/graphql/queries/get_projects.query.graphql +++ b/app/assets/javascripts/access_tokens/graphql/queries/get_projects.query.graphql @@ -22,6 +22,7 @@ query accessTokensGetProjects( avatarUrl } pageInfo { + __typename ...PageInfo } } diff --git a/app/assets/javascripts/actioncable_link.js b/app/assets/javascripts/actioncable_link.js index 895a34ba157..cf53d9e21b4 100644 --- a/app/assets/javascripts/actioncable_link.js +++ b/app/assets/javascripts/actioncable_link.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; import { print } from 'graphql'; import cable from '~/actioncable_consumer'; import { uuids } from '~/lib/utils/uuids'; diff --git a/app/assets/javascripts/alert_management/list.js b/app/assets/javascripts/alert_management/list.js index b23f8a8eba4..42cbeef56bf 100644 --- a/app/assets/javascripts/alert_management/list.js +++ b/app/assets/javascripts/alert_management/list.js @@ -1,4 +1,4 @@ -import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import { defaultDataIdFromObject } from '@apollo/client/core'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; diff --git a/app/assets/javascripts/alerts_settings/graphql.js b/app/assets/javascripts/alerts_settings/graphql.js index b64e2e3eefa..36a98145457 100644 --- a/app/assets/javascripts/alerts_settings/graphql.js +++ b/app/assets/javascripts/alerts_settings/graphql.js @@ -1,15 +1,9 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import produce from 'immer'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; -import introspectionQueryResultData from './graphql/fragmentTypes.json'; import getCurrentIntegrationQuery from './graphql/queries/get_current_integration.query.graphql'; -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); - Vue.use(VueApollo); const resolvers = { @@ -55,9 +49,5 @@ const resolvers = { }; export default new VueApollo({ - defaultClient: createDefaultClient(resolvers, { - cacheConfig: { - fragmentMatcher, - }, - }), + defaultClient: createDefaultClient(resolvers), }); diff --git a/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json b/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json deleted file mode 100644 index 07dfc43aa6c..00000000000 --- a/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"UNION","name":"AlertManagementIntegration","possibleTypes":[{"name":"AlertManagementHttpIntegration"},{"name":"AlertManagementPrometheusIntegration"}]}]}} diff --git a/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql b/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql index 3cd3f2d92f8..ac9304391f9 100644 --- a/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql @@ -5,6 +5,7 @@ query getIntegrations($projectPath: ID!) { id alertManagementIntegrations { nodes { + __typename ...IntegrationItem } } diff --git a/app/assets/javascripts/analytics/usage_trends/graphql/fragments/count.fragment.graphql b/app/assets/javascripts/analytics/usage_trends/graphql/fragments/count.fragment.graphql index 2bde5973600..b353bcdfd0e 100644 --- a/app/assets/javascripts/analytics/usage_trends/graphql/fragments/count.fragment.graphql +++ b/app/assets/javascripts/analytics/usage_trends/graphql/fragments/count.fragment.graphql @@ -1,4 +1,5 @@ fragment Count on UsageTrendsMeasurement { + __typename count recordedAt } diff --git a/app/assets/javascripts/boards/graphql.js b/app/assets/javascripts/boards/graphql.js index 64938cb42ed..95863d4d5ac 100644 --- a/app/assets/javascripts/boards/graphql.js +++ b/app/assets/javascripts/boards/graphql.js @@ -1,10 +1,5 @@ -import { IntrospectionFragmentMatcher, defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import { defaultDataIdFromObject } from '@apollo/client/core'; import createDefaultClient from '~/lib/graphql'; -import introspectionQueryResultData from '~/sidebar/fragmentTypes.json'; - -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); export const gqlClient = createDefaultClient( {}, @@ -14,8 +9,6 @@ export const gqlClient = createDefaultClient( // eslint-disable-next-line no-underscore-dangle return object.__typename === 'BoardList' ? object.iid : defaultDataIdFromObject(object); }, - - fragmentMatcher, }, }, ); diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js index ed32579a9c3..26dd8b99f98 100644 --- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js +++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js @@ -1,27 +1,14 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; import store from '~/boards/stores'; import createDefaultClient from '~/lib/graphql'; import { parseBoolean } from '~/lib/utils/common_utils'; -import introspectionQueryResultData from '~/sidebar/fragmentTypes.json'; Vue.use(VueApollo); -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); - const apolloProvider = new VueApollo({ - defaultClient: createDefaultClient( - {}, - { - cacheConfig: { - fragmentMatcher, - }, - }, - ), + defaultClient: createDefaultClient(), }); export default (params = {}) => { diff --git a/app/assets/javascripts/captcha/apollo_captcha_link.js b/app/assets/javascripts/captcha/apollo_captcha_link.js index e49abc10b29..d63ffaf5f1a 100644 --- a/app/assets/javascripts/captcha/apollo_captcha_link.js +++ b/app/assets/javascripts/captcha/apollo_captcha_link.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; export const apolloCaptchaLink = new ApolloLink((operation, forward) => forward(operation).flatMap((result) => { diff --git a/app/assets/javascripts/clusters/agents/graphql/provider.js b/app/assets/javascripts/clusters/agents/graphql/provider.js index 8b068fa1eee..9153c5252b3 100644 --- a/app/assets/javascripts/clusters/agents/graphql/provider.js +++ b/app/assets/javascripts/clusters/agents/graphql/provider.js @@ -1,25 +1,10 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; -import { vulnerabilityLocationTypes } from '~/graphql_shared/fragment_types/vulnerability_location_types'; Vue.use(VueApollo); -// We create a fragment matcher so that we can create a fragment from an interface -// Without this, Apollo throws a heuristic fragment matcher warning -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData: vulnerabilityLocationTypes, -}); - -const defaultClient = createDefaultClient( - {}, - { - cacheConfig: { - fragmentMatcher, - }, - }, -); +const defaultClient = createDefaultClient(); export default new VueApollo({ defaultClient, diff --git a/app/assets/javascripts/design_management/graphql.js b/app/assets/javascripts/design_management/graphql.js index 5cf32cb7fe3..8c44c5a5d0a 100644 --- a/app/assets/javascripts/design_management/graphql.js +++ b/app/assets/javascripts/design_management/graphql.js @@ -1,11 +1,10 @@ -import { defaultDataIdFromObject, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; +import { defaultDataIdFromObject } from '@apollo/client/core'; import produce from 'immer'; import { uniqueId } from 'lodash'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; import axios from '~/lib/utils/axios_utils'; -import introspectionQueryResultData from './graphql/fragmentTypes.json'; import activeDiscussionQuery from './graphql/queries/active_discussion.query.graphql'; import getDesignQuery from './graphql/queries/get_design.query.graphql'; import typeDefs from './graphql/typedefs.graphql'; @@ -13,10 +12,6 @@ import { addPendingTodoToStore } from './utils/cache_update'; import { extractTodoIdFromDeletePath, createPendingTodo } from './utils/design_management_utils'; import { CREATE_DESIGN_TODO_EXISTS_ERROR } from './utils/error_messages'; -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); - Vue.use(VueApollo); const resolvers = { @@ -85,7 +80,6 @@ const defaultClient = createDefaultClient( } return defaultDataIdFromObject(object); }, - fragmentMatcher, }, typeDefs, }, diff --git a/app/assets/javascripts/design_management/graphql/fragmentTypes.json b/app/assets/javascripts/design_management/graphql/fragmentTypes.json deleted file mode 100644 index 0953231ea4c..00000000000 --- a/app/assets/javascripts/design_management/graphql/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"INTERFACE","name":"User","possibleTypes":[{"name":"UserCore"}]},{"kind":"UNION","name":"NoteableType","possibleTypes":[{"name":"Design"},{"name":"Issue"},{"name":"MergeRequest"}]}]}} diff --git a/app/assets/javascripts/graphql_shared/fragment_types/vulnerability_location_types.js b/app/assets/javascripts/graphql_shared/fragment_types/vulnerability_location_types.js deleted file mode 100644 index 30888e20a46..00000000000 --- a/app/assets/javascripts/graphql_shared/fragment_types/vulnerability_location_types.js +++ /dev/null @@ -1,17 +0,0 @@ -export const vulnerabilityLocationTypes = { - __schema: { - types: [ - { - kind: 'UNION', - name: 'VulnerabilityLocation', - possibleTypes: [ - { name: 'VulnerabilityLocationContainerScanning' }, - { name: 'VulnerabilityLocationDast' }, - { name: 'VulnerabilityLocationDependencyScanning' }, - { name: 'VulnerabilityLocationSast' }, - { name: 'VulnerabilityLocationSecretDetection' }, - ], - }, - ], - }, -}; diff --git a/app/assets/javascripts/graphql_shared/possibleTypes.json b/app/assets/javascripts/graphql_shared/possibleTypes.json new file mode 100644 index 00000000000..9a24d2a3afc --- /dev/null +++ b/app/assets/javascripts/graphql_shared/possibleTypes.json @@ -0,0 +1 @@ +{"AlertManagementIntegration":["AlertManagementHttpIntegration","AlertManagementPrometheusIntegration"],"CurrentUserTodos":["BoardEpic","Design","Epic","EpicIssue","Issue","MergeRequest"],"DependencyLinkMetadata":["NugetDependencyLinkMetadata"],"DesignFields":["Design","DesignAtVersion"],"Entry":["Blob","Submodule","TreeEntry"],"Eventable":["BoardEpic","Epic"],"Issuable":["Epic","Issue","MergeRequest"],"JobNeedUnion":["CiBuildNeed","CiJob"],"MemberInterface":["GroupMember","ProjectMember"],"NoteableInterface":["AlertManagementAlert","BoardEpic","Design","Epic","EpicIssue","Issue","MergeRequest","Snippet","Vulnerability"],"NoteableType":["Design","Issue","MergeRequest"],"OrchestrationPolicy":["ScanExecutionPolicy","ScanResultPolicy"],"PackageFileMetadata":["ConanFileMetadata","HelmFileMetadata"],"PackageMetadata":["ComposerMetadata","ConanMetadata","MavenMetadata","NugetMetadata","PypiMetadata"],"ResolvableInterface":["Discussion","Note"],"Service":["BaseService","JiraService"],"TimeboxReportInterface":["Iteration","Milestone"],"User":["MergeRequestAssignee","MergeRequestReviewer","UserCore"],"VulnerabilityDetail":["VulnerabilityDetailBase","VulnerabilityDetailBoolean","VulnerabilityDetailCode","VulnerabilityDetailCommit","VulnerabilityDetailDiff","VulnerabilityDetailFileLocation","VulnerabilityDetailInt","VulnerabilityDetailList","VulnerabilityDetailMarkdown","VulnerabilityDetailModuleLocation","VulnerabilityDetailTable","VulnerabilityDetailText","VulnerabilityDetailUrl"],"VulnerabilityLocation":["VulnerabilityLocationClusterImageScanning","VulnerabilityLocationContainerScanning","VulnerabilityLocationCoverageFuzzing","VulnerabilityLocationDast","VulnerabilityLocationDependencyScanning","VulnerabilityLocationGeneric","VulnerabilityLocationSast","VulnerabilityLocationSecretDetection"]} diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue index a2bb6c3cd77..3866a7b3305 100644 --- a/app/assets/javascripts/issues/list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue @@ -181,6 +181,9 @@ export default { return data[this.namespace]?.issues.nodes ?? []; }, result({ data }) { + if (!data) { + return; + } this.pageInfo = data[this.namespace]?.issues.pageInfo ?? {}; this.exportCsvPathWithQuery = this.getExportCsvPathWithQuery(); }, diff --git a/app/assets/javascripts/issues/list/queries/issue.fragment.graphql b/app/assets/javascripts/issues/list/queries/issue.fragment.graphql index 07dae3fd756..430d494deab 100644 --- a/app/assets/javascripts/issues/list/queries/issue.fragment.graphql +++ b/app/assets/javascripts/issues/list/queries/issue.fragment.graphql @@ -1,4 +1,5 @@ fragment IssueFragment on Issue { + __typename id iid closedAt @@ -18,6 +19,7 @@ fragment IssueFragment on Issue { webUrl assignees { nodes { + __typename id avatarUrl name @@ -26,6 +28,7 @@ fragment IssueFragment on Issue { } } author { + __typename id avatarUrl name diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue index c786d35ac68..81f42c1e293 100644 --- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue +++ b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue @@ -51,7 +51,9 @@ export default { }, data() { return { - jobs: {}, + jobs: { + list: [], + }, hasError: false, isAlertDismissed: false, scope: null, diff --git a/app/assets/javascripts/lib/apollo/instrumentation_link.js b/app/assets/javascripts/lib/apollo/instrumentation_link.js index 2ab364557b8..bbe16d260e7 100644 --- a/app/assets/javascripts/lib/apollo/instrumentation_link.js +++ b/app/assets/javascripts/lib/apollo/instrumentation_link.js @@ -1,4 +1,4 @@ -import { ApolloLink } from 'apollo-link'; +import { ApolloLink } from '@apollo/client/core'; import { memoize } from 'lodash'; export const FEATURE_CATEGORY_HEADER = 'x-gitlab-feature-category'; diff --git a/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js b/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js index 9b7901685b6..b2a86ac257b 100644 --- a/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js +++ b/app/assets/javascripts/lib/apollo/suppress_network_errors_during_navigation_link.js @@ -1,5 +1,5 @@ -import { Observable } from 'apollo-link'; -import { onError } from 'apollo-link-error'; +import { Observable } from '@apollo/client/core'; +import { onError } from '@apollo/client/link/error'; import { isNavigatingAway } from '~/lib/utils/is_navigating_away'; /** diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js index df2e85afe24..0fb7bf52562 100644 --- a/app/assets/javascripts/lib/graphql.js +++ b/app/assets/javascripts/lib/graphql.js @@ -1,11 +1,9 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; -import { ApolloLink } from 'apollo-link'; -import { BatchHttpLink } from 'apollo-link-batch-http'; -import { HttpLink } from 'apollo-link-http'; +import { ApolloClient, InMemoryCache, ApolloLink, HttpLink } from '@apollo/client/core'; +import { BatchHttpLink } from '@apollo/client/link/batch-http'; import { createUploadLink } from 'apollo-upload-client'; import ActionCableLink from '~/actioncable_link'; import { apolloCaptchaLink } from '~/captcha/apollo_captcha_link'; +import possibleTypes from '~/graphql_shared/possibleTypes.json'; import { StartupJSLink } from '~/lib/utils/apollo_startup_js_link'; import csrf from '~/lib/utils/csrf'; import { objectToQuery, queryToObject } from '~/lib/utils/url_utility'; @@ -21,6 +19,33 @@ export const fetchPolicies = { CACHE_ONLY: 'cache-only', }; +export const typePolicies = { + Repository: { + merge: true, + }, + UserPermissions: { + merge: true, + }, + MergeRequestPermissions: { + merge: true, + }, + ContainerRepositoryConnection: { + merge: true, + }, + TimelogConnection: { + merge: true, + }, + BranchList: { + merge: true, + }, + InstanceSecurityDashboard: { + merge: true, + }, + PipelinePermissions: { + merge: true, + }, +}; + export const stripWhitespaceFromQuery = (url, path) => { /* eslint-disable-next-line no-unused-vars */ const [_, params] = url.split(path); @@ -46,6 +71,30 @@ export const stripWhitespaceFromQuery = (url, path) => { return `${path}?${reassembled}`; }; +const acs = []; + +let pendingApolloMutations = 0; + +// ### Why track pendingApolloMutations, but calculate pendingApolloRequests? +// +// In Apollo 2, we had a single link for counting operations. +// +// With Apollo 3, the `forward().map(...)` of deduped queries is never called. +// So, we resorted to calculating the sum of `inFlightLinkObservables?.size`. +// However! Mutations don't use `inFLightLinkObservables`, but since they are likely +// not deduped we can count them... +// +// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55062#note_838943715 +// https://www.apollographql.com/docs/react/v2/networking/network-layer/#query-deduplication +Object.defineProperty(window, 'pendingApolloRequests', { + get() { + return acs.reduce( + (sum, ac) => sum + (ac?.queryManager?.inFlightLinkObservables?.size || 0), + pendingApolloMutations, + ); + }, +}); + export default (resolvers = {}, config = {}) => { const { baseUrl, @@ -56,6 +105,7 @@ export default (resolvers = {}, config = {}) => { path = '/api/graphql', useGet = false, } = config; + let ac = null; let uri = `${gon.relative_url_root || ''}${path}`; if (baseUrl) { @@ -75,16 +125,6 @@ export default (resolvers = {}, config = {}) => { batchMax, }; - const requestCounterLink = new ApolloLink((operation, forward) => { - window.pendingApolloRequests = window.pendingApolloRequests || 0; - window.pendingApolloRequests += 1; - - return forward(operation).map((response) => { - window.pendingApolloRequests -= 1; - return response; - }); - }); - /* This custom fetcher intervention is to deal with an issue where we are using GET to access eTag polling, but Apollo Client adds excessive whitespace, which causes the @@ -138,6 +178,22 @@ export default (resolvers = {}, config = {}) => { ); }; + const hasMutation = (operation) => + (operation?.query?.definitions || []).some((x) => x.operation === 'mutation'); + + const requestCounterLink = new ApolloLink((operation, forward) => { + if (hasMutation(operation)) { + pendingApolloMutations += 1; + } + + return forward(operation).map((response) => { + if (hasMutation(operation)) { + pendingApolloMutations -= 1; + } + return response; + }); + }); + const appLink = ApolloLink.split( hasSubscriptionOperation, new ActionCableLink(), @@ -155,19 +211,23 @@ export default (resolvers = {}, config = {}) => { ), ); - return new ApolloClient({ + ac = new ApolloClient({ typeDefs, link: appLink, cache: new InMemoryCache({ + typePolicies, + possibleTypes, ...cacheConfig, - freezeResults: true, }), resolvers, - assumeImmutableResults: true, defaultOptions: { query: { fetchPolicy, }, }, }); + + acs.push(ac); + + return ac; }; diff --git a/app/assets/javascripts/lib/utils/apollo_startup_js_link.js b/app/assets/javascripts/lib/utils/apollo_startup_js_link.js index 014823f3831..f240226e991 100644 --- a/app/assets/javascripts/lib/utils/apollo_startup_js_link.js +++ b/app/assets/javascripts/lib/utils/apollo_startup_js_link.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; import { parse } from 'graphql'; import { isEqual, pickBy } from 'lodash'; diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue index ad3a3596991..e2acebf39d6 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue @@ -96,6 +96,9 @@ export default { return data[this.graphqlResource]?.containerRepositories.nodes; }, result({ data }) { + if (!data) { + return; + } this.pageInfo = data[this.graphqlResource]?.containerRepositories?.pageInfo; this.containerRepositoriesCount = data[this.graphqlResource]?.containerRepositoriesCount; }, diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragmentTypes.json b/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragmentTypes.json deleted file mode 100644 index c61a653d10b..00000000000 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/fragmentTypes.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "__schema": { - "types": [ - { - "kind": "UNION", - "name": "PackageMetadata", - "possibleTypes": [ - { "name": "ComposerMetadata" }, - { "name": "ConanMetadata" }, - { "name": "MavenMetadata" }, - { "name": "NugetMetadata" }, - { "name": "PypiMetadata" } - ] - } - ] - } -} diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/index.js b/app/assets/javascripts/packages_and_registries/package_registry/graphql/index.js index 21d6fbc9e1f..56f95fa2c1f 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/index.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/index.js @@ -1,22 +1,9 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; -import introspectionQueryResultData from './fragmentTypes.json'; - -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); Vue.use(VueApollo); export const apolloProvider = new VueApollo({ - defaultClient: createDefaultClient( - {}, - { - cacheConfig: { - fragmentMatcher, - }, - }, - ), + defaultClient: createDefaultClient(), }); diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue index 42c40cda601..d50945e0be2 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue @@ -2,7 +2,8 @@ import { GlProgressBar, GlSprintf, GlAlert } from '@gitlab/ui'; import eventHub from '~/invite_members/event_hub'; import { s__ } from '~/locale'; -import { ACTION_LABELS, ACTION_SECTIONS } from '../constants'; +import { getCookie, removeCookie, parseBoolean } from '~/lib/utils/common_utils'; +import { ACTION_LABELS, ACTION_SECTIONS, INVITE_MODAL_OPEN_COOKIE } from '../constants'; import LearnGitlabSectionCard from './learn_gitlab_section_card.vue'; export default { @@ -26,7 +27,7 @@ export default { required: true, type: Object, }, - inviteMembersOpen: { + inviteMembers: { type: Boolean, required: false, default: false, @@ -53,7 +54,7 @@ export default { }, }, mounted() { - if (this.inviteMembersOpen) { + if (this.inviteMembers && this.getCookieForInviteMembers()) { this.openInviteMembersModal('celebrate'); } @@ -63,6 +64,13 @@ export default { eventHub.$off('showSuccessfulInvitationsAlert', this.handleShowSuccessfulInvitationsAlert); }, methods: { + getCookieForInviteMembers() { + const value = parseBoolean(getCookie(INVITE_MODAL_OPEN_COOKIE)); + + removeCookie(INVITE_MODAL_OPEN_COOKIE); + + return value; + }, openInviteMembersModal(mode) { eventHub.$emit('openModal', { mode, inviteeType: 'members', source: 'learn-gitlab' }); }, diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js index 8a88ad299b4..880cf699e5e 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js @@ -95,3 +95,5 @@ export const ACTION_SECTIONS = { ), }, }; + +export const INVITE_MODAL_OPEN_COOKIE = 'confetti_post_signup'; diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js index 1f91cc46946..c62cab1a425 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils'; import LearnGitlab from '../components/learn_gitlab.vue'; function initLearnGitlab() { @@ -13,13 +13,13 @@ function initLearnGitlab() { const actions = convertObjectPropsToCamelCase(JSON.parse(el.dataset.actions)); const sections = convertObjectPropsToCamelCase(JSON.parse(el.dataset.sections)); const project = convertObjectPropsToCamelCase(JSON.parse(el.dataset.project)); - const { inviteMembersOpen } = el.dataset; + const { inviteMembers } = el.dataset; return new Vue({ el, render(createElement) { return createElement(LearnGitlab, { - props: { actions, sections, project, inviteMembersOpen }, + props: { actions, sections, project, inviteMembers: parseBoolean(inviteMembers) }, }); }, }); diff --git a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue index 72b492a5877..4b9c98135ec 100644 --- a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue +++ b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue @@ -49,7 +49,7 @@ export default { pipelineEtag: { query: getPipelineEtag, update(data) { - return data.etags.pipeline; + return data.etags?.pipeline; }, }, pipeline: { diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index 604f87a0cda..1da50c55a68 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -196,7 +196,7 @@ export default { currentBranch: { query: getCurrentBranch, update(data) { - return data.workBranches.current.name; + return data.workBranches?.current?.name; }, }, starterTemplate: { @@ -214,7 +214,7 @@ export default { return data.project?.ciTemplate?.content || ''; }, result({ data }) { - this.updateCiConfig(data.project?.ciTemplate?.content || ''); + this.updateCiConfig(data?.project?.ciTemplate?.content || ''); }, error() { this.reportFailure(LOAD_FAILURE_UNKNOWN); diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue index 6f35cdac641..99fb5c146ba 100644 --- a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue +++ b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue @@ -36,6 +36,9 @@ export default { return data.project?.pipeline?.jobs?.nodes || []; }, result({ data }) { + if (!data) { + return; + } this.jobsPageInfo = data.project?.pipeline?.jobs?.pageInfo || {}; }, error() { diff --git a/app/assets/javascripts/pipelines/graphql/fragmentTypes.json b/app/assets/javascripts/pipelines/graphql/fragmentTypes.json deleted file mode 100644 index 4601b74b5c1..00000000000 --- a/app/assets/javascripts/pipelines/graphql/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"UNION","name":"JobNeedUnion","possibleTypes":[{"name":"CiBuildNeed"},{"name":"CiJob"}]}]}}
\ No newline at end of file diff --git a/app/assets/javascripts/pipelines/pipeline_shared_client.js b/app/assets/javascripts/pipelines/pipeline_shared_client.js index 84276588d6a..c3be487caae 100644 --- a/app/assets/javascripts/pipelines/pipeline_shared_client.js +++ b/app/assets/javascripts/pipelines/pipeline_shared_client.js @@ -1,19 +1,10 @@ import VueApollo from 'vue-apollo'; -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import createDefaultClient from '~/lib/graphql'; -import introspectionQueryResultData from './graphql/fragmentTypes.json'; - -export const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); export const apolloProvider = new VueApollo({ defaultClient: createDefaultClient( {}, { - cacheConfig: { - fragmentMatcher, - }, useGet: true, }, ), diff --git a/app/assets/javascripts/related_issues/components/add_issuable_form.vue b/app/assets/javascripts/related_issues/components/add_issuable_form.vue index f936c03c5d3..9ee2e7a4ffd 100644 --- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue +++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue @@ -9,6 +9,8 @@ import { linkedIssueTypesMap, addRelatedIssueErrorMap, addRelatedItemErrorMap, + issuablesFormCategoryHeaderTextMap, + issuablesFormInputTextMap, } from '../constants'; import RelatedIssuableInput from './related_issuable_input.vue'; @@ -134,6 +136,12 @@ export default { epics: mergeUrlParams({ confidential_only: true }, this.autoCompleteSources.epics), }; }, + issuableCategoryHeaderText() { + return issuablesFormCategoryHeaderTextMap[this.issuableType]; + }, + issuableInputText() { + return issuablesFormInputTextMap[this.issuableType]; + }, }, methods: { onPendingIssuableRemoveRequest(params) { @@ -162,7 +170,7 @@ export default { <form @submit.prevent="onFormSubmit"> <template v-if="showCategorizedIssues"> <gl-form-group - :label="__('The current issue')" + :label="issuableCategoryHeaderText" label-for="linked-issue-type-radio" label-class="label-bold" class="mb-2" @@ -175,7 +183,7 @@ export default { /> </gl-form-group> <p class="bold"> - {{ __('the following issue(s)') }} + {{ issuableInputText }} </p> </template> <related-issuable-input diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue index 94535e1b8c9..bc97fab9ad2 100644 --- a/app/assets/javascripts/related_issues/components/related_issues_block.vue +++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue @@ -5,6 +5,9 @@ import { issuableQaClassMap, linkedIssueTypesMap, linkedIssueTypesTextMap, + issuablesBlockHeaderTextMap, + issuablesBlockHelpTextMap, + issuablesBlockAddButtonTextMap, } from '../constants'; import AddIssuableForm from './add_issuable_form.vue'; import RelatedIssuesList from './related_issues_list.vue'; @@ -105,6 +108,15 @@ export default { hasBody() { return this.isFormVisible || this.shouldShowTokenBody; }, + headerText() { + return issuablesBlockHeaderTextMap[this.issuableType]; + }, + helpLinkText() { + return issuablesBlockHelpTextMap[this.issuableType]; + }, + addIssuableButtonText() { + return issuablesBlockAddButtonTextMap[this.issuableType]; + }, badgeLabel() { return this.isFetching && this.relatedIssues.length === 0 ? '...' : this.relatedIssues.length; }, @@ -138,13 +150,14 @@ export default { href="#related-issues" aria-hidden="true" /> - <slot name="header-text">{{ __('Linked issues') }}</slot> + <slot name="header-text">{{ headerText }}</slot> <gl-link v-if="hasHelpPath" :href="helpPath" target="_blank" class="gl-display-flex gl-align-items-center gl-ml-2 gl-text-gray-500" - :aria-label="__('Read more about related issues')" + data-testid="help-link" + :aria-label="helpLinkText" > <gl-icon name="question" :size="12" /> </gl-link> @@ -160,7 +173,7 @@ export default { v-if="canAdmin" data-qa-selector="related_issues_plus_button" icon="plus" - :aria-label="__('Add a related issue')" + :aria-label="addIssuableButtonText" :class="qaClass" @click="$emit('toggleAddRelatedIssuesForm', $event)" /> diff --git a/app/assets/javascripts/related_issues/constants.js b/app/assets/javascripts/related_issues/constants.js index 89eae069a24..f911468d8f1 100644 --- a/app/assets/javascripts/related_issues/constants.js +++ b/app/assets/javascripts/related_issues/constants.js @@ -104,3 +104,28 @@ export const PathIdSeparator = { Epic: '&', Issue: '#', }; + +export const issuablesBlockHeaderTextMap = { + [issuableTypesMap.ISSUE]: __('Linked issues'), + [issuableTypesMap.EPIC]: __('Linked epics'), +}; + +export const issuablesBlockHelpTextMap = { + [issuableTypesMap.ISSUE]: __('Read more about related issues'), + [issuableTypesMap.EPIC]: __('Read more about related epics'), +}; + +export const issuablesBlockAddButtonTextMap = { + [issuableTypesMap.ISSUE]: __('Add a related issue'), + [issuableTypesMap.EPIC]: __('Add a related epic'), +}; + +export const issuablesFormCategoryHeaderTextMap = { + [issuableTypesMap.ISSUE]: __('The current issue'), + [issuableTypesMap.EPIC]: __('The current epic'), +}; + +export const issuablesFormInputTextMap = { + [issuableTypesMap.ISSUE]: __('the following issue(s)'), + [issuableTypesMap.EPIC]: __('the following epic(s)'), +}; diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js index 0ee99df1455..bd9845e616b 100644 --- a/app/assets/javascripts/related_issues/index.js +++ b/app/assets/javascripts/related_issues/index.js @@ -8,6 +8,7 @@ export default function initRelatedIssues() { // eslint-disable-next-line no-new new Vue({ el: relatedIssuesRootElement, + name: 'RelatedIssuesApp', components: { relatedIssuesRoot: RelatedIssuesRoot, }, diff --git a/app/assets/javascripts/repository/fragmentTypes.json b/app/assets/javascripts/repository/fragmentTypes.json deleted file mode 100644 index 949ebca432b..00000000000 --- a/app/assets/javascripts/repository/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"INTERFACE","name":"Entry","possibleTypes":[{"name":"Blob"},{"name":"Submodule"},{"name":"TreeEntry"}]}]}} diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js index 96d712ce9b4..29aabe1b00f 100644 --- a/app/assets/javascripts/repository/graphql.js +++ b/app/assets/javascripts/repository/graphql.js @@ -1,19 +1,11 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; import axios from '~/lib/utils/axios_utils'; -import introspectionQueryResultData from './fragmentTypes.json'; import { fetchLogsTree } from './log_tree'; Vue.use(VueApollo); -// We create a fragment matcher so that we can create a fragment from an interface -// Without this, Apollo throws a heuristic fragment matcher warning -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); - const defaultClient = createDefaultClient( { Query: { @@ -43,7 +35,6 @@ const defaultClient = createDefaultClient( }, { cacheConfig: { - fragmentMatcher, dataIdFromObject: (obj) => { /* eslint-disable @gitlab/require-i18n-strings */ // eslint-disable-next-line no-underscore-dangle diff --git a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql b/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql index f7bcd683718..986dd16b992 100644 --- a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql +++ b/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql @@ -28,10 +28,12 @@ query getGroupRunners( edges { webUrl node { + __typename ...RunnerNode } } pageInfo { + __typename ...PageInfo } } diff --git a/app/assets/javascripts/runner/graphql/get_runner.query.graphql b/app/assets/javascripts/runner/graphql/get_runner.query.graphql index 59c55eae060..f6ce8281c64 100644 --- a/app/assets/javascripts/runner/graphql/get_runner.query.graphql +++ b/app/assets/javascripts/runner/graphql/get_runner.query.graphql @@ -4,6 +4,7 @@ query getRunner($id: CiRunnerID!) { # We have an id in deeply nested fragment # eslint-disable-next-line @graphql-eslint/require-id-when-available runner(id: $id) { + __typename ...RunnerDetails } } diff --git a/app/assets/javascripts/runner/graphql/get_runners.query.graphql b/app/assets/javascripts/runner/graphql/get_runners.query.graphql index 05df399fa6a..ed03a8c34ae 100644 --- a/app/assets/javascripts/runner/graphql/get_runners.query.graphql +++ b/app/assets/javascripts/runner/graphql/get_runners.query.graphql @@ -29,6 +29,7 @@ query getRunners( editAdminUrl } pageInfo { + __typename ...PageInfo } } diff --git a/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql b/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql index 4a771d779dc..fbdef817f2f 100644 --- a/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql @@ -1,4 +1,5 @@ fragment RunnerNode on CiRunner { + __typename id description runnerType diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue index 5b4dc20e9c8..18654b73ab3 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue @@ -96,6 +96,9 @@ export default { return data.workspace?.issuable; }, result({ data }) { + if (!data) { + return; + } const issuable = data.workspace?.issuable; if (issuable) { this.selected = cloneDeep(issuable.assignees.nodes); diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue index dc0f2b54a7b..f234c5ea3c9 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue @@ -66,6 +66,9 @@ export default { return data.workspace?.issuable?.confidential || false; }, result({ data }) { + if (!data) { + return; + } this.$emit('confidentialityUpdated', data.workspace?.issuable?.confidential); }, error() { diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue index 404bcc3122a..be7a89c2869 100644 --- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue +++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue @@ -86,6 +86,9 @@ export default { return data.workspace?.issuable || {}; }, result({ data }) { + if (!data) { + return; + } this.$emit(`${this.dateType}Updated`, data.workspace?.issuable?.[this.dateType]); }, error() { diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue index 701833c4e95..7a10a9f3a4c 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue @@ -61,6 +61,9 @@ export default { return data.workspace?.issuable?.subscribed || false; }, result({ data }) { + if (!data) { + return; + } this.emailsDisabled = this.parentIsGroup ? data.workspace?.emailsDisabled : data.workspace?.issuable?.emailsDisabled; diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue index 8c56c3cbd57..eabba619af5 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue @@ -59,6 +59,10 @@ export default { return data.workspace?.issuable?.currentUserTodos.nodes[0]?.id; }, result({ data }) { + if (!data) { + return; + } + const currentUserTodos = data.workspace?.issuable?.currentUserTodos?.nodes ?? []; this.todoId = currentUserTodos[0]?.id; this.$emit('todoUpdated', currentUserTodos.length > 0); diff --git a/app/assets/javascripts/sidebar/fragmentTypes.json b/app/assets/javascripts/sidebar/fragmentTypes.json deleted file mode 100644 index a1c68bba454..00000000000 --- a/app/assets/javascripts/sidebar/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"UNION","name":"Issuable","possibleTypes":[{"name":"Issue"},{"name":"MergeRequest"}]}, {"kind":"INTERFACE","name":"User","possibleTypes":[{"name":"UserCore"}]}]}} diff --git a/app/assets/javascripts/sidebar/graphql.js b/app/assets/javascripts/sidebar/graphql.js index c5d94cfa5e8..fc757922f09 100644 --- a/app/assets/javascripts/sidebar/graphql.js +++ b/app/assets/javascripts/sidebar/graphql.js @@ -1,14 +1,8 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import produce from 'immer'; import VueApollo from 'vue-apollo'; import getIssueStateQuery from '~/issues/show/queries/get_issue_state.query.graphql'; import { resolvers as workItemResolvers } from '~/work_items/graphql/resolvers'; import createDefaultClient from '~/lib/graphql'; -import introspectionQueryResultData from './fragmentTypes.json'; - -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); const resolvers = { ...workItemResolvers, @@ -24,11 +18,7 @@ const resolvers = { }, }; -export const defaultClient = createDefaultClient(resolvers, { - cacheConfig: { - fragmentMatcher, - }, -}); +export const defaultClient = createDefaultClient(resolvers); export const apolloProvider = new VueApollo({ defaultClient, diff --git a/app/assets/javascripts/terraform/index.js b/app/assets/javascripts/terraform/index.js index 1b8cab0d51e..34261f3c4db 100644 --- a/app/assets/javascripts/terraform/index.js +++ b/app/assets/javascripts/terraform/index.js @@ -1,5 +1,5 @@ +import { defaultDataIdFromObject } from '@apollo/client/core'; import { GlToast } from '@gitlab/ui'; -import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql index 0b8396b4461..25c44beaf18 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/get_state.query.graphql @@ -3,7 +3,6 @@ query getState($projectPath: ID!, $iid: String!) { id archived onlyAllowMergeIfPipelineSucceeds - mergeRequest(iid: $iid) { id autoMergeEnabled diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql index 2d79d35cf24..ad93a3a7371 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql @@ -4,6 +4,7 @@ query autoMergeEnabled($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { id mergeRequest(iid: $iid) { + id ...autoMergeEnabled } } diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql index f713739f65a..556ecee254d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql @@ -2,6 +2,7 @@ query readyToMerge($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { + id ...ReadyToMerge } } diff --git a/app/assets/javascripts/vue_shared/alert_details/index.js b/app/assets/javascripts/vue_shared/alert_details/index.js index 9f1da9ae173..8a0de3b74bc 100644 --- a/app/assets/javascripts/vue_shared/alert_details/index.js +++ b/app/assets/javascripts/vue_shared/alert_details/index.js @@ -1,4 +1,4 @@ -import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import { defaultDataIdFromObject } from '@apollo/client/core'; import produce from 'immer'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue index 138284c9f6b..8008b85bbdb 100644 --- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue +++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue @@ -31,10 +31,6 @@ export default { type: Object, required: true, }, - enableLabelPermalinks: { - type: Boolean, - required: true, - }, labelFilterParam: { type: String, required: false, @@ -142,11 +138,8 @@ export default { return label.title || label.name; }, labelTarget(label) { - if (this.enableLabelPermalinks) { - const value = encodeURIComponent(this.labelTitle(label)); - return `?${this.labelFilterParam}[]=${value}`; - } - return '#'; + const value = encodeURIComponent(this.labelTitle(label)); + return `?${this.labelFilterParam}[]=${value}`; }, /** * This is needed as an independent method since diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue index 6fd2baeb2c6..028d48e7e8a 100644 --- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue +++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue @@ -133,11 +133,6 @@ export default { required: false, default: 2, }, - enableLabelPermalinks: { - type: Boolean, - required: false, - default: true, - }, labelFilterParam: { type: String, required: false, @@ -321,7 +316,6 @@ export default { :data-qa-issuable-title="issuable.title" :issuable-symbol="issuableSymbol" :issuable="issuable" - :enable-label-permalinks="enableLabelPermalinks" :label-filter-param="labelFilterParam" :show-checkbox="showBulkEditSidebar" :checked="issuableChecked(issuable)" diff --git a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue index 12f2bc71505..f6d85599dba 100644 --- a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue +++ b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue @@ -102,8 +102,8 @@ export default { error(error) { this.showError(error); }, - result({ loading }) { - if (loading) { + result({ loading, data }) { + if (loading || !data) { return; } diff --git a/app/assets/javascripts/work_items/graphql/fragmentTypes.json b/app/assets/javascripts/work_items/graphql/fragmentTypes.json deleted file mode 100644 index 3b837e84ee9..00000000000 --- a/app/assets/javascripts/work_items/graphql/fragmentTypes.json +++ /dev/null @@ -1 +0,0 @@ -{"__schema":{"types":[{"kind":"INTERFACE","name":"LocalWorkItemWidget","possibleTypes":[{"name":"LocalTitleWidget"}]}]}} diff --git a/app/assets/javascripts/work_items/graphql/provider.js b/app/assets/javascripts/work_items/graphql/provider.js index fb536a425c0..676fffb12d8 100644 --- a/app/assets/javascripts/work_items/graphql/provider.js +++ b/app/assets/javascripts/work_items/graphql/provider.js @@ -1,23 +1,14 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import createDefaultClient from '~/lib/graphql'; import workItemQuery from './work_item.query.graphql'; -import introspectionQueryResultData from './fragmentTypes.json'; import { resolvers } from './resolvers'; import typeDefs from './typedefs.graphql'; -const fragmentMatcher = new IntrospectionFragmentMatcher({ - introspectionQueryResultData, -}); - export function createApolloProvider() { Vue.use(VueApollo); const defaultClient = createDefaultClient(resolvers, { - cacheConfig: { - fragmentMatcher, - }, typeDefs, }); diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb index 63ae34f5ed3..f7f78ab3229 100644 --- a/app/controllers/admin/runners_controller.rb +++ b/app/controllers/admin/runners_controller.rb @@ -34,7 +34,7 @@ class Admin::RunnersController < Admin::ApplicationController end def destroy - @runner.destroy + Ci::UnregisterRunnerService.new(@runner).execute redirect_to admin_runners_path, status: :found end diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb index d171df12eac..b194aeff80d 100644 --- a/app/controllers/groups/runners_controller.rb +++ b/app/controllers/groups/runners_controller.rb @@ -35,7 +35,7 @@ class Groups::RunnersController < Groups::ApplicationController if @runner.belongs_to_more_than_one_project? redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found, alert: _('Runner was not deleted because it is assigned to multiple projects.') else - @runner.destroy + Ci::UnregisterRunnerService.new(@runner).execute redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found end diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb index 62a9f8a4625..192a29730d9 100644 --- a/app/controllers/projects/runners_controller.rb +++ b/app/controllers/projects/runners_controller.rb @@ -23,7 +23,7 @@ class Projects::RunnersController < Projects::ApplicationController def destroy if @runner.only_for?(project) - @runner.destroy + Ci::UnregisterRunnerService.new(@runner).execute end redirect_to project_runners_path(@project), status: :found diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb index 88dc426398b..21c3d55881c 100644 --- a/app/graphql/mutations/ci/runner/delete.rb +++ b/app/graphql/mutations/ci/runner/delete.rb @@ -20,7 +20,7 @@ module Mutations error = authenticate_delete_runner!(runner) return { errors: [error] } if error - runner.destroy! + ::Ci::UnregisterRunnerService.new(runner).execute { errors: runner.errors.full_messages } end diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb index 88b8cefd8d2..3e76239396a 100644 --- a/app/graphql/mutations/work_items/create.rb +++ b/app/graphql/mutations/work_items/create.rb @@ -32,13 +32,13 @@ module Mutations params = global_id_compatibility_params(attributes).merge(author_id: current_user.id) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) - work_item = ::WorkItems::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute + create_result = ::WorkItems::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute - check_spam_action_response!(work_item) + check_spam_action_response!(create_result[:work_item]) if create_result[:work_item] { - work_item: work_item.valid? ? work_item : nil, - errors: errors_on_object(work_item) + work_item: create_result.success? ? create_result[:work_item] : nil, + errors: create_result.errors } end diff --git a/app/services/ci/unregister_runner_service.rb b/app/services/ci/unregister_runner_service.rb new file mode 100644 index 00000000000..97d9852b7ed --- /dev/null +++ b/app/services/ci/unregister_runner_service.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Ci + class UnregisterRunnerService + attr_reader :runner + + # @param [Ci::Runner] runner the runner to unregister/destroy + def initialize(runner) + @runner = runner + end + + def execute + @runner&.destroy + end + end +end diff --git a/app/services/work_items/create_service.rb b/app/services/work_items/create_service.rb index 49f7b89158b..705735fe403 100644 --- a/app/services/work_items/create_service.rb +++ b/app/services/work_items/create_service.rb @@ -2,6 +2,8 @@ module WorkItems class CreateService + include ::Services::ReturnServiceResponses + def initialize(project:, current_user: nil, params: {}, spam_params:) @create_service = ::Issues::CreateService.new( project: project, @@ -10,10 +12,28 @@ module WorkItems spam_params: spam_params, build_service: ::WorkItems::BuildService.new(project: project, current_user: current_user, params: params) ) + @current_user = current_user + @project = project end def execute - @create_service.execute + unless @current_user.can?(:create_work_item, @project) + return error(_('Operation not allowed'), :forbidden) + end + + work_item = @create_service.execute + + if work_item.valid? + success(payload(work_item)) + else + error(work_item.errors.full_messages, :unprocessable_entity, pass_back: payload(work_item)) + end + end + + private + + def payload(work_item) + { work_item: work_item } end end end diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml index d73d171798e..fcd52f33121 100644 --- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml +++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml @@ -5,4 +5,4 @@ = form_tag path do %input{ :name => "_method", :type => "hidden", :value => "delete" }/ - = submit_tag _('Revoke'), class: 'gl-button btn btn-danger btn-sm', data: { confirm: _('Are you sure?') } + = submit_tag _('Revoke'), class: 'gl-button btn btn-danger btn-sm', aria: { label: s_('AuthorizedApplication|Revoke application') }, data: { confirm: s_('AuthorizedApplication|Are you sure you want to revoke this application?'), confirm_btn_variant: 'danger' } diff --git a/app/views/projects/learn_gitlab/index.html.haml b/app/views/projects/learn_gitlab/index.html.haml index 6bca145dc18..9924b172875 100644 --- a/app/views/projects/learn_gitlab/index.html.haml +++ b/app/views/projects/learn_gitlab/index.html.haml @@ -2,7 +2,6 @@ - page_title _("Learn GitLab") - add_page_specific_style 'page_bundles/learn_gitlab' - data = learn_gitlab_data(@project) -- invite_members_open = session.delete(:confetti_post_signup) = render 'projects/invite_members_modal', project: @project @@ -10,4 +9,4 @@ - e.control do #js-learn-gitlab-app{ data: data } - e.candidate do - #js-learn-gitlab-app{ data: data.merge(invite_members_open: invite_members_open) } + #js-learn-gitlab-app{ data: data.merge(invite_members: 'true') } diff --git a/config/webpack.config.js b/config/webpack.config.js index c010a12745f..7b559c8881b 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -150,6 +150,8 @@ function generateEntries() { } const alias = { + // Map Apollo client to apollo/client/core to prevent react related imports from being loaded + '@apollo/client$': '@apollo/client/core', '~': path.join(ROOT_PATH, 'app/assets/javascripts'), emojis: path.join(ROOT_PATH, 'fixtures/emojis'), empty_states: path.join(ROOT_PATH, 'app/views/shared/empty_states'), diff --git a/config/webpack.vendor.config.js b/config/webpack.vendor.config.js index 84fd993ed14..30d60c0b5e6 100644 --- a/config/webpack.vendor.config.js +++ b/config/webpack.vendor.config.js @@ -47,7 +47,7 @@ module.exports = { 'bootstrap/dist/js/bootstrap.js', 'sortablejs/modular/sortable.esm.js', 'popper.js', - 'apollo-client', + '@apollo/client/core', 'source-map', 'mousetrap', ], diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md index 14512286ade..d0e65b8c4eb 100644 --- a/doc/api/graphql/index.md +++ b/doc/api/graphql/index.md @@ -152,7 +152,7 @@ Root-level queries are defined in ### Multiplex queries GitLab supports batching queries into a single request using -[apollo-link-batch-http](https://www.apollographql.com/docs/link/links/batch-http/). More +[`@apollo/client/link/batch-http`](https://www.apollographql.com/docs/react/api/link/apollo-link-batch-http/). More information about multiplexed queries is also available for [GraphQL Ruby](https://graphql-ruby.org/queries/multiplex.html), the library GitLab uses on the backend. diff --git a/doc/api/lint.md b/doc/api/lint.md index f8d871d070d..e432b3b276f 100644 --- a/doc/api/lint.md +++ b/doc/api/lint.md @@ -171,6 +171,7 @@ POST /projects/:id/ci/lint | `content` | string | yes | The CI/CD configuration content. | | `dry_run` | boolean | no | Run [pipeline creation simulation](../ci/lint.md#simulate-a-pipeline), or only do static check. This is false by default. | | `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. | +| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. | Example request: @@ -220,6 +221,7 @@ GET /projects/:id/ci/lint | ---------- | ------- | -------- | -------- | | `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. | | `include_jobs` | boolean | no | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. This is false by default. | +| `ref` | string | no | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. | Example request: diff --git a/doc/user/project/milestones/burndown_and_burnup_charts.md b/doc/user/project/milestones/burndown_and_burnup_charts.md index c6becc59ddc..05cc424e5ee 100644 --- a/doc/user/project/milestones/burndown_and_burnup_charts.md +++ b/doc/user/project/milestones/burndown_and_burnup_charts.md @@ -73,10 +73,8 @@ The chart indicates the project's progress throughout that milestone (for issues In particular, it shows how many issues were or are still open for a given day in the milestone's corresponding period. -The burndown chart can also be toggled to display the cumulative open issue -weight for a given day. When using this feature, make sure issue weights have -been properly assigned, since an open issue with no weight adds zero to the -cumulative value. +You can also toggle the burndown chart to display the +[cumulative open issue weight](#switch-between-number-of-issues-and-issue-weight) for a given day. ### Fixed burndown charts @@ -123,12 +121,21 @@ To view a group's burnup chart: ### How burnup charts work Burnup charts have separate lines for total work and completed work. The total line -shows when scope is reduced or added to a milestone. The completed work is a count -of issues closed. +shows changes to the scope of a milestone. When an open issue is moved to another +milestone, the "total issues" goes down but the "completed issues" stays the same. +The completed work is a count of issues closed. When an issue is closed, the "total +issues" remains the same and "completed issues" goes up. -Burnup charts can show either the total number of issues or total weight for each -day of the milestone. Use the toggle above the charts to switch between total -and weight. +## Switch between number of issues and issue weight + +In both burndown or burnup charts you can view them +either by the total number of issues +or the total weight for each day of the milestone. + +To switch between the two settings, select either **Issues** or **Issue weight** above the charts. + +When sorting by weight, make sure all your issues +have weight assigned, because issues with no weight don't show on the chart. <!-- ## Troubleshooting diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md index f9742e8d3c6..4501cf500b0 100644 --- a/doc/user/project/milestones/index.md +++ b/doc/user/project/milestones/index.md @@ -151,10 +151,10 @@ There are also tabs below these that show the following: ### Burndown Charts -The milestone view contains a [burndown chart](burndown_and_burnup_charts.md), +The milestone view contains a [burndown and burnup chart](burndown_and_burnup_charts.md), showing the progress of completing a milestone. -![burndown chart](img/burndown_chart_v13_6.png) +![burndown chart](img/burndown_and_burnup_charts_v13_6.png) ### Milestone sidebar diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 9dcb10dd5e2..4df9600322c 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -57,7 +57,7 @@ module API delete '/', feature_category: :runner do authenticate_runner! - destroy_conditionally!(current_runner) + destroy_conditionally!(current_runner) { ::Ci::UnregisterRunnerService.new(current_runner).execute } end desc 'Validates authentication credentials' do diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb index 12c336e0938..4cef4212634 100644 --- a/lib/api/ci/runners.rb +++ b/lib/api/ci/runners.rb @@ -110,7 +110,7 @@ module API authenticate_delete_runner!(runner) - destroy_conditionally!(runner) + destroy_conditionally!(runner) { ::Ci::UnregisterRunnerService.new(runner).execute } end desc 'List jobs running on a runner' do diff --git a/lib/api/lint.rb b/lib/api/lint.rb index 886fca07b96..6de78c81cac 100644 --- a/lib/api/lint.rb +++ b/lib/api/lint.rb @@ -42,6 +42,7 @@ module API params do optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.' optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response' + optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true' end get ':id/ci/lint', urgency: :low do authorize! :download_code, user_project @@ -52,7 +53,7 @@ module API result = Gitlab::Ci::Lint .new(project: user_project, current_user: current_user) - .validate(content, dry_run: params[:dry_run]) + .validate(content, dry_run: params[:dry_run], ref: params[:ref] || user_project.default_branch) present result, with: Entities::Ci::Lint::Result, current_user: current_user, include_jobs: params[:include_jobs] end @@ -66,13 +67,14 @@ module API requires :content, type: String, desc: 'Content of .gitlab-ci.yml' optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.' optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response' + optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true' end post ':id/ci/lint', urgency: :low do authorize! :create_pipeline, user_project result = Gitlab::Ci::Lint .new(project: user_project, current_user: current_user) - .validate(params[:content], dry_run: params[:dry_run]) + .validate(params[:content], dry_run: params[:dry_run], ref: params[:ref] || user_project.default_branch) status 200 present result, with: Entities::Ci::Lint::Result, current_user: current_user, include_jobs: params[:include_jobs] diff --git a/lib/gitlab/ci/lint.rb b/lib/gitlab/ci/lint.rb index 8c1067b9bc6..c93dfe3f202 100644 --- a/lib/gitlab/ci/lint.rb +++ b/lib/gitlab/ci/lint.rb @@ -24,9 +24,9 @@ module Gitlab @sha = sha || project&.repository&.commit&.sha end - def validate(content, dry_run: false) + def validate(content, dry_run: false, ref: @project&.default_branch) if dry_run - simulate_pipeline_creation(content) + simulate_pipeline_creation(content, ref) else static_validation(content) end @@ -34,9 +34,9 @@ module Gitlab private - def simulate_pipeline_creation(content) + def simulate_pipeline_creation(content, ref) pipeline = ::Ci::CreatePipelineService - .new(@project, @current_user, ref: @project.default_branch) + .new(@project, @current_user, ref: ref) .execute(:push, dry_run: true, content: content) .payload diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 76ce6fc67c9..ef2825c9a26 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2091,6 +2091,9 @@ msgstr "" msgid "Add a numbered list" msgstr "" +msgid "Add a related epic" +msgstr "" + msgid "Add a related issue" msgstr "" @@ -5158,6 +5161,12 @@ msgstr "" msgid "Authorized applications (%{size})" msgstr "" +msgid "AuthorizedApplication|Are you sure you want to revoke this application?" +msgstr "" + +msgid "AuthorizedApplication|Revoke application" +msgstr "" + msgid "Authors: %{authors}" msgstr "" @@ -21755,6 +21764,9 @@ msgstr "" msgid "Linked emails (%{email_count})" msgstr "" +msgid "Linked epics" +msgstr "" + msgid "Linked issues" msgstr "" @@ -29685,6 +29697,9 @@ msgstr "" msgid "Read more about project permissions %{help_link_open}here%{help_link_close}" msgstr "" +msgid "Read more about related epics" +msgstr "" + msgid "Read more about related issues" msgstr "" @@ -36091,6 +36106,9 @@ msgstr "" msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered." msgstr "" +msgid "The current epic" +msgstr "" + msgid "The current issue" msgstr "" @@ -44006,6 +44024,9 @@ msgstr "" msgid "the file" msgstr "" +msgid "the following epic(s)" +msgstr "" + msgid "the following issue(s)" msgstr "" diff --git a/package.json b/package.json index c98c3e9b8e4..7e20c5d223e 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js" }, "dependencies": { + "@apollo/client": "^3.3.11", "@babel/core": "^7.10.1", "@babel/plugin-proposal-class-properties": "^7.10.1", "@babel/plugin-proposal-json-strings": "^7.10.1", @@ -94,13 +95,7 @@ "@tiptap/vue-2": "^2.0.0-beta.77", "@toast-ui/editor": "^2.5.2", "@toast-ui/vue-editor": "^2.5.2", - "apollo-cache-inmemory": "^1.6.6", - "apollo-client": "^2.6.10", - "apollo-link": "^1.2.14", - "apollo-link-batch-http": "^1.2.14", - "apollo-link-error": "^1.1.13", - "apollo-link-http": "^1.5.17", - "apollo-upload-client": "^13.0.0", + "apollo-upload-client": "^14.1.3", "autosize": "^5.0.1", "aws-sdk": "^2.637.0", "axios": "^0.24.0", @@ -186,7 +181,7 @@ "uuid": "8.1.0", "visibilityjs": "^1.2.4", "vue": "^2.6.12", - "vue-apollo": "^3.0.3", + "vue-apollo": "^3.0.7", "vue-loader": "^15.9.6", "vue-observe-visibility": "^1.0.0", "vue-resize": "^1.0.1", @@ -244,7 +239,7 @@ "markdownlint-cli": "0.31.0", "md5": "^2.2.1", "miragejs": "^0.1.40", - "mock-apollo-client": "^0.7.0", + "mock-apollo-client": "1.2.0", "nodemon": "^2.0.4", "postcss": "^8.4.5", "prettier": "2.2.1", @@ -266,6 +261,7 @@ "bootstrap-vue": "https://docs.gitlab.com/ee/development/fe_guide/dependencies.html#bootstrapvue" }, "resolutions": { + "@apollo/client/subscriptions-transport-ws": "0.11.0", "chokidar": "^3.4.0", "@types/node": "14.17.5" }, diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb index 08fb12c375e..74f352e8ec2 100644 --- a/spec/controllers/admin/runners_controller_spec.rb +++ b/spec/controllers/admin/runners_controller_spec.rb @@ -4,9 +4,10 @@ require 'spec_helper' RSpec.describe Admin::RunnersController do let_it_be(:runner) { create(:ci_runner) } + let_it_be(:user) { create(:admin) } before do - sign_in(create(:admin)) + sign_in(user) end describe '#index' do @@ -104,6 +105,10 @@ RSpec.describe Admin::RunnersController do describe '#destroy' do it 'destroys the runner' do + expect_next_instance_of(Ci::UnregisterRunnerService, runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + delete :destroy, params: { id: runner.id } expect(response).to have_gitlab_http_status(:found) diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index bc4eaf029e9..710e983dfbd 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -309,7 +309,8 @@ RSpec.describe Groups::ClustersController do .to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s) allow_any_instance_of(GoogleApi::CloudPlatform::Client) .to receive(:projects_zones_clusters_create) do - OpenStruct.new( + double( + 'instance', self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', status: 'RUNNING' ) diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index a8830efe653..9f0615a96ae 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -190,6 +190,10 @@ RSpec.describe Groups::RunnersController do end it 'destroys the runner and redirects' do + expect_next_instance_of(Ci::UnregisterRunnerService, runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + delete :destroy, params: params expect(response).to have_gitlab_http_status(:found) diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 70ff77d7ff0..246a37129d7 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -37,6 +37,10 @@ RSpec.describe Projects::RunnersController do describe '#destroy' do it 'destroys the runner' do + expect_next_instance_of(Ci::UnregisterRunnerService, runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + delete :destroy, params: params expect(response).to have_gitlab_http_status(:found) diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index 6e45529c659..b0406e1f3c4 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -99,7 +99,8 @@ RSpec.describe 'Clusters', :js do allow_any_instance_of(GoogleApi::CloudPlatform::Client) .to receive(:projects_zones_clusters_create) do - OpenStruct.new( + double( + 'cluster_control', self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', status: 'RUNNING' ) diff --git a/spec/frontend/__helpers__/mock_apollo_helper.js b/spec/frontend/__helpers__/mock_apollo_helper.js index 2dff9acbc76..c07a6d8ef85 100644 --- a/spec/frontend/__helpers__/mock_apollo_helper.js +++ b/spec/frontend/__helpers__/mock_apollo_helper.js @@ -1,15 +1,14 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; +import { InMemoryCache } from '@apollo/client/core'; import { createMockClient as createMockApolloClient } from 'mock-apollo-client'; import VueApollo from 'vue-apollo'; - -const defaultCacheOptions = { - fragmentMatcher: { match: () => true }, - addTypename: false, -}; +import possibleTypes from '~/graphql_shared/possibleTypes.json'; +import { typePolicies } from '~/lib/graphql'; export function createMockClient(handlers = [], resolvers = {}, cacheOptions = {}) { const cache = new InMemoryCache({ - ...defaultCacheOptions, + possibleTypes, + typePolicies, + addTypename: false, ...cacheOptions, }); diff --git a/spec/frontend/__helpers__/test_apollo_link.js b/spec/frontend/__helpers__/test_apollo_link.js index dde3a4e99bb..eab0c2de212 100644 --- a/spec/frontend/__helpers__/test_apollo_link.js +++ b/spec/frontend/__helpers__/test_apollo_link.js @@ -1,7 +1,4 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; -import { ApolloLink } from 'apollo-link'; -import gql from 'graphql-tag'; +import { InMemoryCache, ApolloClient, ApolloLink, gql } from '@apollo/client/core'; const FOO_QUERY = gql` query { diff --git a/spec/frontend/actioncable_link_spec.js b/spec/frontend/actioncable_link_spec.js index c785151f8fd..b15b93cb11d 100644 --- a/spec/frontend/actioncable_link_spec.js +++ b/spec/frontend/actioncable_link_spec.js @@ -1,5 +1,5 @@ import { print } from 'graphql'; -import gql from 'graphql-tag'; +import { gql } from '@apollo/client/core'; import cable from '~/actioncable_consumer'; import ActionCableLink from '~/actioncable_link'; diff --git a/spec/frontend/admin/users/components/users_table_spec.js b/spec/frontend/admin/users/components/users_table_spec.js index dffe8d6893b..ad1c45495b5 100644 --- a/spec/frontend/admin/users/components/users_table_spec.js +++ b/spec/frontend/admin/users/components/users_table_spec.js @@ -135,7 +135,6 @@ describe('AdminUsersTable component', () => { }); it('creates a flash message and captures the error', () => { - expect(createFlash).toHaveBeenCalledTimes(2); expect(createFlash).toHaveBeenCalledWith({ message: 'Could not load user group counts. Please refresh the page to try again.', captureError: true, diff --git a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js index 152061790e5..6193233881d 100644 --- a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js +++ b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js @@ -1,7 +1,7 @@ import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; -import Vue, { nextTick } from 'vue'; +import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql'; import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql'; @@ -68,10 +68,7 @@ describe('AlertsSettingsWrapper', () => { const findAlertsSettingsForm = () => wrapper.findComponent(AlertsSettingsForm); const findAlert = () => wrapper.findComponent(GlAlert); - async function destroyHttpIntegration(localWrapper) { - await jest.runOnlyPendingTimers(); - await nextTick(); - + function destroyHttpIntegration(localWrapper) { localWrapper .find(IntegrationsList) .vm.$emit('delete-integration', { id: integrationToDestroy.id }); @@ -474,11 +471,11 @@ describe('AlertsSettingsWrapper', () => { it('calls a mutation with correct parameters and destroys a integration', async () => { createComponentWithApollo(); + await waitForPromises(); - await destroyHttpIntegration(wrapper); + destroyHttpIntegration(wrapper); expect(destroyIntegrationHandler).toHaveBeenCalled(); - await waitForPromises(); expect(findIntegrations()).toHaveLength(3); diff --git a/spec/frontend/alerts_settings/components/mocks/apollo_mock.js b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js index e7ad2cd1d2a..694dff56632 100644 --- a/spec/frontend/alerts_settings/components/mocks/apollo_mock.js +++ b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js @@ -38,6 +38,7 @@ export const getIntegrationsQueryResponse = { alertManagementIntegrations: { nodes: [ { + __typename: 'AlertManagementIntegration', id: '37', type: 'HTTP', active: true, @@ -48,6 +49,7 @@ export const getIntegrationsQueryResponse = { apiUrl: null, }, { + __typename: 'AlertManagementIntegration', id: '41', type: 'HTTP', active: true, @@ -58,6 +60,7 @@ export const getIntegrationsQueryResponse = { apiUrl: null, }, { + __typename: 'AlertManagementIntegration', id: '40', type: 'HTTP', active: true, @@ -68,6 +71,7 @@ export const getIntegrationsQueryResponse = { apiUrl: null, }, { + __typename: 'AlertManagementIntegration', id: '12', type: 'PROMETHEUS', active: false, @@ -83,6 +87,7 @@ export const getIntegrationsQueryResponse = { }; export const integrationToDestroy = { + __typename: 'AlertManagementIntegration', id: '37', type: 'HTTP', active: true, @@ -97,6 +102,7 @@ export const destroyIntegrationResponse = { httpIntegrationDestroy: { errors: [], integration: { + __typename: 'AlertManagementIntegration', id: '37', type: 'HTTP', active: true, diff --git a/spec/frontend/analytics/usage_trends/apollo_mock_data.js b/spec/frontend/analytics/usage_trends/apollo_mock_data.js index 98eabd577ee..934bbc63689 100644 --- a/spec/frontend/analytics/usage_trends/apollo_mock_data.js +++ b/spec/frontend/analytics/usage_trends/apollo_mock_data.js @@ -1,4 +1,5 @@ const defaultPageInfo = { + __typename: 'PageInfo', hasNextPage: false, hasPreviousPage: false, startCursor: null, diff --git a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js index 9696e069b9c..02cf7f42a0b 100644 --- a/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js +++ b/spec/frontend/analytics/usage_trends/components/usage_trends_count_chart_spec.js @@ -129,7 +129,7 @@ describe('UsageTrendsCountChart', () => { const recordedAt = '2020-08-01'; describe('when the fetchMore query returns data', () => { beforeEach(async () => { - const newData = [{ recordedAt, count: 5 }]; + const newData = [{ __typename: 'UsageTrendsMeasurement', recordedAt, count: 5 }]; queryHandler = mockQueryResponse({ key: queryResponseDataKey, data: mockCountsData1, diff --git a/spec/frontend/analytics/usage_trends/components/users_chart_spec.js b/spec/frontend/analytics/usage_trends/components/users_chart_spec.js index 0cd605ca1bf..32a664a5026 100644 --- a/spec/frontend/analytics/usage_trends/components/users_chart_spec.js +++ b/spec/frontend/analytics/usage_trends/components/users_chart_spec.js @@ -4,6 +4,7 @@ import { shallowMount } 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 UsersChart from '~/analytics/usage_trends/components/users_chart.vue'; import usersQuery from '~/analytics/usage_trends/graphql/queries/users.query.graphql'; import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue'; @@ -86,7 +87,7 @@ describe('UsersChart', () => { describe('with data', () => { beforeEach(async () => { wrapper = createComponent({ users: mockCountsData2 }); - await nextTick(); + await waitForPromises(); }); it('hides the skeleton loader', () => { @@ -156,7 +157,7 @@ describe('UsersChart', () => { jest .spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore') .mockImplementation(jest.fn().mockRejectedValue()); - await nextTick(); + await waitForPromises(); }); it('calls fetchMore', () => { diff --git a/spec/frontend/analytics/usage_trends/mock_data.js b/spec/frontend/analytics/usage_trends/mock_data.js index d96dfa26209..77bd44d17f5 100644 --- a/spec/frontend/analytics/usage_trends/mock_data.js +++ b/spec/frontend/analytics/usage_trends/mock_data.js @@ -4,11 +4,11 @@ export const mockUsageCounts = [ ]; export const mockCountsData1 = [ - { recordedAt: '2020-07-23', count: 52 }, - { recordedAt: '2020-07-22', count: 40 }, - { recordedAt: '2020-07-21', count: 31 }, - { recordedAt: '2020-06-14', count: 23 }, - { recordedAt: '2020-06-12', count: 20 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-07-23', count: 52 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-07-22', count: 40 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-07-21', count: 31 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-06-14', count: 23 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-06-12', count: 20 }, ]; export const countsMonthlyChartData1 = [ @@ -17,11 +17,11 @@ export const countsMonthlyChartData1 = [ ]; export const mockCountsData2 = [ - { recordedAt: '2020-07-28', count: 10 }, - { recordedAt: '2020-07-27', count: 9 }, - { recordedAt: '2020-06-26', count: 14 }, - { recordedAt: '2020-06-25', count: 23 }, - { recordedAt: '2020-06-24', count: 25 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-07-28', count: 10 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-07-27', count: 9 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-06-26', count: 14 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-06-25', count: 23 }, + { __typename: 'UsageTrendsMeasurement', recordedAt: '2020-06-24', count: 25 }, ]; export const countsMonthlyChartData2 = [ diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js index d07173c8411..fd9d2b6823d 100644 --- a/spec/frontend/boards/board_list_spec.js +++ b/spec/frontend/boards/board_list_spec.js @@ -106,10 +106,6 @@ describe('Board list component', () => { fetchItemsForList: jest.fn(), }; - beforeEach(() => { - wrapper = createComponent(); - }); - it('does not load issues if already loading', () => { wrapper = createComponent({ actions, @@ -143,6 +139,7 @@ describe('Board list component', () => { await nextTick(); await waitForPromises(); await nextTick(); + await nextTick(); expect(wrapper.find('.board-list-count').text()).toBe('Showing 1 of 20 issues'); }); diff --git a/spec/frontend/captcha/apollo_captcha_link_spec.js b/spec/frontend/captcha/apollo_captcha_link_spec.js index e7ff4812ee7..eab52344d1f 100644 --- a/spec/frontend/captcha/apollo_captcha_link_spec.js +++ b/spec/frontend/captcha/apollo_captcha_link_spec.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; import { apolloCaptchaLink } from '~/captcha/apollo_captcha_link'; import UnsolvedCaptchaError from '~/captcha/unsolved_captcha_error'; diff --git a/spec/frontend/clusters/agents/components/show_spec.js b/spec/frontend/clusters/agents/components/show_spec.js index c92bf634a92..f2f073544e3 100644 --- a/spec/frontend/clusters/agents/components/show_spec.js +++ b/spec/frontend/clusters/agents/components/show_spec.js @@ -137,7 +137,8 @@ describe('ClusterAgentShow', () => { await waitForPromises(); }); - it('displays agent create information with unknown user', () => { + it('displays agent create information with unknown user', async () => { + await waitForPromises(); expect(findCreatedText()).toMatchInterpolatedText('Created by Unknown user 2 days ago'); }); }); @@ -153,19 +154,25 @@ describe('ClusterAgentShow', () => { await waitForPromises(); }); - it('displays token header with no count', () => { + it('displays token header with no count', async () => { + await waitForPromises(); expect(findTokenCount()).toMatchInterpolatedText(`${ClusterAgentShow.i18n.tokens}`); }); }); describe('when the token list has additional pages', () => { - const pageInfo = { + const pageInfoResponse = { hasNextPage: true, hasPreviousPage: false, startCursor: 'prev', endCursor: 'next', }; + const pageInfo = { + ...pageInfoResponse, + __typename: 'PageInfo', + }; + const tokenPagination = { ...defaultClusterAgent, tokens: { @@ -184,7 +191,7 @@ describe('ClusterAgentShow', () => { }); it('should pass pageInfo to the pagination component', () => { - expect(findPaginationButtons().props()).toMatchObject(pageInfo); + expect(findPaginationButtons().props()).toMatchObject(pageInfoResponse); }); }); diff --git a/spec/frontend/clusters_list/components/agents_spec.js b/spec/frontend/clusters_list/components/agents_spec.js index e1bd0b1a990..3cfa4b92bc0 100644 --- a/spec/frontend/clusters_list/components/agents_spec.js +++ b/spec/frontend/clusters_list/components/agents_spec.js @@ -92,6 +92,7 @@ describe('Agents', () => { let testDate = new Date(); const agents = [ { + __typename: 'ClusterAgent', id: '1', name: 'agent-1', webPath: '/agent-1', @@ -99,6 +100,7 @@ describe('Agents', () => { tokens: null, }, { + __typename: 'ClusterAgent', id: '2', name: 'agent-2', webPath: '/agent-2', @@ -254,7 +256,10 @@ describe('Agents', () => { beforeEach(() => { return createWrapper({ agents, - pageInfo, + pageInfo: { + ...pageInfo, + __typename: 'PageInfo', + }, }); }); diff --git a/spec/frontend/clusters_list/components/install_agent_modal_spec.js b/spec/frontend/clusters_list/components/install_agent_modal_spec.js index 3530c978370..37432ed0193 100644 --- a/spec/frontend/clusters_list/components/install_agent_modal_spec.js +++ b/spec/frontend/clusters_list/components/install_agent_modal_spec.js @@ -49,7 +49,8 @@ describe('InstallAgentModal', () => { const apolloQueryResponse = { data: { project: { - id: '1', + __typename: 'Project', + id: 'project-1', clusterAgents: { nodes: [] }, agentConfigurations: { nodes: configurations }, }, diff --git a/spec/frontend/clusters_list/mocks/apollo.js b/spec/frontend/clusters_list/mocks/apollo.js index 176896215a4..b0f2978a230 100644 --- a/spec/frontend/clusters_list/mocks/apollo.js +++ b/spec/frontend/clusters_list/mocks/apollo.js @@ -70,6 +70,7 @@ export const createAgentTokenErrorResponse = { export const getAgentResponse = { data: { project: { + __typename: 'Project', id: 'project-1', clusterAgents: { nodes: [{ ...agent, connections, tokens }], pageInfo, count }, repository: { diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js index 5a2f3bdeef8..a240a41959f 100644 --- a/spec/frontend/design_management/pages/index_spec.js +++ b/spec/frontend/design_management/pages/index_spec.js @@ -757,14 +757,13 @@ describe('Design management index page', () => { expect(moveDesignHandler).toHaveBeenCalled(); - await nextTick(); + await waitForPromises(); expect(findDesigns().at(0).props('id')).toBe('2'); }); it('prevents reordering when reorderDesigns mutation is in progress', async () => { createComponentWithApollo({}); - await moveDesigns(wrapper); expect(draggableAttributes().disabled).toBe(true); @@ -780,7 +779,6 @@ describe('Design management index page', () => { }); await moveDesigns(wrapper); - await waitForPromises(); expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' }); @@ -792,7 +790,6 @@ describe('Design management index page', () => { }); await moveDesigns(wrapper); - await waitForPromises(); expect(createFlash).toHaveBeenCalledWith({ diff --git a/spec/frontend/design_management/utils/cache_update_spec.js b/spec/frontend/design_management/utils/cache_update_spec.js index fa6a666bb37..5e2c37e24a1 100644 --- a/spec/frontend/design_management/utils/cache_update_spec.js +++ b/spec/frontend/design_management/utils/cache_update_spec.js @@ -1,4 +1,4 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; +import { InMemoryCache } from '@apollo/client/core'; import { updateStoreAfterDesignsDelete, updateStoreAfterAddImageDiffNote, diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js index cf47a1cd7bb..d7acf75fc95 100644 --- a/spec/frontend/environment.js +++ b/spec/frontend/environment.js @@ -29,6 +29,9 @@ class CustomEnvironment extends JSDOMEnvironment { }, warn(...args) { + if (args[0].includes('The updateQuery callback for fetchMore is deprecated')) { + return; + } throw new ErrorWithStack( `Unexpected call of console.warn() with:\n\n${args.join(', ')}`, this.warn, diff --git a/spec/frontend/environments/new_environments_app_spec.js b/spec/frontend/environments/new_environments_app_spec.js index 3b68a23bd32..be86a202499 100644 --- a/spec/frontend/environments/new_environments_app_spec.js +++ b/spec/frontend/environments/new_environments_app_spec.js @@ -28,6 +28,8 @@ describe('~/environments/components/new_environments_app.vue', () => { folder: environmentFolderMock, pageInfo: paginationMock, environmentToStop: environmentToStopMock, + environmentToDelete: jest.fn().mockResolvedValue(resolvedEnvironment), + environmentToRollback: jest.fn().mockResolvedValue(resolvedEnvironment), }, }; @@ -80,7 +82,7 @@ describe('~/environments/components/new_environments_app.vue', () => { }); afterEach(() => { - wrapper?.destroy(); + wrapper.destroy(); }); it('should show all the folders that are fetched', async () => { @@ -150,8 +152,6 @@ describe('~/environments/components/new_environments_app.vue', () => { }, folder: resolvedFolder, }); - await waitForPromises(); - await nextTick(); const button = wrapper.findByRole('button', { name: s__('Environments|Enable review app') }); expect(button.exists()).toBe(false); diff --git a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js index c6ddce17fe4..52c868e5356 100644 --- a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js +++ b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js @@ -1,4 +1,4 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; +import { InMemoryCache } from '@apollo/client/core'; import MockAdapter from 'axios-mock-adapter'; import { createMockClient } from 'mock-apollo-client'; import waitForPromises from 'helpers/wait_for_promises'; diff --git a/spec/frontend/import_entities/import_groups/graphql/fixtures.js b/spec/frontend/import_entities/import_groups/graphql/fixtures.js index ed4e343f331..938020e03f0 100644 --- a/spec/frontend/import_entities/import_groups/graphql/fixtures.js +++ b/spec/frontend/import_entities/import_groups/graphql/fixtures.js @@ -16,6 +16,7 @@ export const generateFakeEntry = ({ id, status, message, ...rest }) => ({ status === STATUSES.NONE || status === STATUSES.PENDING ? null : { + __typename: clientTypenames.BulkImportProgress, id, status, message: message || '', diff --git a/spec/frontend/incidents/mocks/incidents.json b/spec/frontend/incidents/mocks/incidents.json index 78783a0dce5..357b94e5b6c 100644 --- a/spec/frontend/incidents/mocks/incidents.json +++ b/spec/frontend/incidents/mocks/incidents.json @@ -1,5 +1,6 @@ [ { + "id": 1, "iid": "15", "title": "New: Alert", "createdAt": "2020-06-03T15:46:08Z", @@ -9,6 +10,7 @@ "slaDueAt": "2020-06-04T12:46:08Z" }, { + "id": 2, "iid": "14", "title": "Create issue4", "createdAt": "2020-05-19T09:26:07Z", @@ -27,6 +29,7 @@ "slaDueAt": null }, { + "id": 3, "iid": "13", "title": "Create issue3", "createdAt": "2020-05-19T08:53:55Z", @@ -35,6 +38,7 @@ "severity": "LOW" }, { + "id": 4, "iid": "12", "title": "Create issue2", "createdAt": "2020-05-18T17:13:35Z", diff --git a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js index 2ae32e89605..ce98a16dbb7 100644 --- a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js +++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js @@ -1,3 +1,4 @@ +import { GlFormGroup } from '@gitlab/ui'; import { mount, shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue'; @@ -153,6 +154,30 @@ describe('AddIssuableForm', () => { }); }); + describe('categorized issuables', () => { + it.each` + issuableType | pathIdSeparator | contextHeader | contextFooter + ${issuableTypesMap.ISSUE} | ${PathIdSeparator.Issue} | ${'The current issue'} | ${'the following issue(s)'} + ${issuableTypesMap.EPIC} | ${PathIdSeparator.Epic} | ${'The current epic'} | ${'the following epic(s)'} + `( + 'show header text as "$contextHeader" and footer text as "$contextFooter" issuableType is set to $issuableType', + ({ issuableType, contextHeader, contextFooter }) => { + wrapper = shallowMount(AddIssuableForm, { + propsData: { + issuableType, + inputValue: '', + showCategorizedIssues: true, + pathIdSeparator, + pendingReferences: [], + }, + }); + + expect(wrapper.findComponent(GlFormGroup).attributes('label')).toBe(contextHeader); + expect(wrapper.find('p.bold').text()).toContain(contextFooter); + }, + ); + }); + describe('when it is a Linked Issues form', () => { beforeEach(() => { wrapper = mount(AddIssuableForm, { diff --git a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js index 608fec45bbd..c7925034eb0 100644 --- a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js +++ b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js @@ -7,6 +7,7 @@ import { } from 'jest/issuable/components/related_issuable_mock_data'; import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue'; import { + issuableTypesMap, linkedIssueTypesMap, linkedIssueTypesTextMap, PathIdSeparator, @@ -29,14 +30,34 @@ describe('RelatedIssuesBlock', () => { wrapper = mount(RelatedIssuesBlock, { propsData: { pathIdSeparator: PathIdSeparator.Issue, - issuableType: 'issue', + issuableType: issuableTypesMap.ISSUE, }, }); }); - it('displays "Linked issues" in the header', () => { - expect(wrapper.find('.card-title').text()).toContain('Linked issues'); - }); + it.each` + issuableType | pathIdSeparator | titleText | helpLinkText | addButtonText + ${'issue'} | ${PathIdSeparator.Issue} | ${'Linked issues'} | ${'Read more about related issues'} | ${'Add a related issue'} + ${'epic'} | ${PathIdSeparator.Epic} | ${'Linked epics'} | ${'Read more about related epics'} | ${'Add a related epic'} + `( + 'displays "$titleText" in the header, "$helpLinkText" aria-label for help link, and "$addButtonText" aria-label for add button when issuableType is set to "$issuableType"', + ({ issuableType, pathIdSeparator, titleText, helpLinkText, addButtonText }) => { + wrapper = mount(RelatedIssuesBlock, { + propsData: { + pathIdSeparator, + issuableType, + canAdmin: true, + helpPath: '/help/user/project/issues/related_issues', + }, + }); + + expect(wrapper.find('.card-title').text()).toContain(titleText); + expect(wrapper.find('[data-testid="help-link"]').attributes('aria-label')).toBe( + helpLinkText, + ); + expect(findIssueCountBadgeAddButton().attributes('aria-label')).toBe(addButtonText); + }, + ); it('unable to add new related issues', () => { expect(findIssueCountBadgeAddButton().exists()).toBe(false); diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js index f8eabc951d3..88652ddc3cc 100644 --- a/spec/frontend/issues/list/components/issues_list_app_spec.js +++ b/spec/frontend/issues/list/components/issues_list_app_spec.js @@ -624,7 +624,7 @@ describe('CE IssuesListApp component', () => { it('shows an error message', () => { expect(findIssuableList().props('error')).toBe(message); - expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Network error: ERROR')); + expect(Sentry.captureException).toHaveBeenCalledWith(new Error('ERROR')); }); }); @@ -717,12 +717,13 @@ describe('CE IssuesListApp component', () => { `( 'when moving issue $description', ({ issueToMove, oldIndex, newIndex, moveBeforeId, moveAfterId }) => { - beforeEach(() => { + beforeEach(async () => { wrapper = mountComponent({ provide: { isProject }, issuesQueryResponse: jest.fn().mockResolvedValue(response(isProject)), }); jest.runOnlyPendingTimers(); + await waitForPromises(); }); it('makes API call to reorder the issue', async () => { @@ -744,11 +745,12 @@ describe('CE IssuesListApp component', () => { }); describe('when unsuccessful', () => { - beforeEach(() => { + beforeEach(async () => { wrapper = mountComponent({ issuesQueryResponse: jest.fn().mockResolvedValue(response()), }); jest.runOnlyPendingTimers(); + await waitForPromises(); }); it('displays an error message', async () => { diff --git a/spec/frontend/issues/list/mock_data.js b/spec/frontend/issues/list/mock_data.js index f9a49254275..c883b20682e 100644 --- a/spec/frontend/issues/list/mock_data.js +++ b/spec/frontend/issues/list/mock_data.js @@ -7,8 +7,10 @@ export const getIssuesQueryResponse = { data: { project: { id: '1', + __typename: 'Project', issues: { pageInfo: { + __typename: 'PageInfo', hasNextPage: true, hasPreviousPage: false, startCursor: 'startcursor', @@ -16,6 +18,7 @@ export const getIssuesQueryResponse = { }, nodes: [ { + __typename: 'Issue', id: 'gid://gitlab/Issue/123456', iid: '789', closedAt: null, @@ -36,6 +39,7 @@ export const getIssuesQueryResponse = { assignees: { nodes: [ { + __typename: 'UserCore', id: 'gid://gitlab/User/234', avatarUrl: 'avatar/url', name: 'Marge Simpson', @@ -45,6 +49,7 @@ export const getIssuesQueryResponse = { ], }, author: { + __typename: 'UserCore', id: 'gid://gitlab/User/456', avatarUrl: 'avatar/url', name: 'Homer Simpson', diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js index 7808a22e1f6..5ccd38af735 100644 --- a/spec/frontend/jobs/components/table/job_table_app_spec.js +++ b/spec/frontend/jobs/components/table/job_table_app_spec.js @@ -1,6 +1,6 @@ import { GlSkeletonLoader, GlAlert, GlEmptyState, GlPagination } from '@gitlab/ui'; import { mount, shallowMount } from '@vue/test-utils'; -import Vue, { nextTick } from 'vue'; +import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -8,7 +8,12 @@ import getJobsQuery from '~/jobs/components/table/graphql/queries/get_jobs.query import JobsTable from '~/jobs/components/table/jobs_table.vue'; import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue'; import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue'; -import { mockJobsQueryResponse, mockJobsQueryEmptyResponse } from '../../mock_data'; +import { + mockJobsQueryResponse, + mockJobsQueryEmptyResponse, + mockJobsQueryResponseLastPage, + mockJobsQueryResponseFirstPage, +} from '../../mock_data'; const projectPath = 'gitlab-org/gitlab'; Vue.use(VueApollo); @@ -95,36 +100,15 @@ describe('Job table app', () => { describe('pagination', () => { it('should disable the next page button on the last page', async () => { createComponent({ - handler: successHandler, + handler: jest.fn().mockResolvedValue(mockJobsQueryResponseLastPage), mountFn: mount, data: { - pagination: { - currentPage: 3, - }, - jobs: { - pageInfo: { - hasPreviousPage: true, - startCursor: 'abc', - endCursor: 'bcd', - }, - }, + pagination: { currentPage: 3 }, }, }); await waitForPromises(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - jobs: { - pageInfo: { - hasNextPage: false, - }, - }, - }); - - await nextTick(); - expect(findPrevious().exists()).toBe(true); expect(findNext().exists()).toBe(true); expect(findNext().classes('disabled')).toBe(true); @@ -132,20 +116,12 @@ describe('Job table app', () => { it('should disable the previous page button on the first page', async () => { createComponent({ - handler: successHandler, + handler: jest.fn().mockResolvedValue(mockJobsQueryResponseFirstPage), mountFn: mount, data: { pagination: { currentPage: 1, }, - jobs: { - pageInfo: { - hasNextPage: true, - hasPreviousPage: false, - startCursor: 'abc', - endCursor: 'bcd', - }, - }, }, }); diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js index 4aabefc1f66..2be78bac8a9 100644 --- a/spec/frontend/jobs/mock_data.js +++ b/spec/frontend/jobs/mock_data.js @@ -1579,6 +1579,44 @@ export const mockJobsQueryResponse = { }, }; +export const mockJobsQueryResponseLastPage = { + data: { + project: { + id: '1', + jobs: { + ...mockJobsQueryResponse.data.project.jobs, + pageInfo: { + endCursor: 'eyJpZCI6IjIzMTcifQ', + hasNextPage: false, + hasPreviousPage: true, + startCursor: 'eyJpZCI6IjIzMzYifQ', + __typename: 'PageInfo', + }, + }, + __typename: 'Project', + }, + }, +}; + +export const mockJobsQueryResponseFirstPage = { + data: { + project: { + id: '1', + jobs: { + ...mockJobsQueryResponse.data.project.jobs, + pageInfo: { + endCursor: 'eyJpZCI6IjIzMTcifQ', + hasNextPage: true, + hasPreviousPage: false, + startCursor: 'eyJpZCI6IjIzMzYifQ', + __typename: 'PageInfo', + }, + }, + __typename: 'Project', + }, + }, +}; + export const mockJobsQueryEmptyResponse = { data: { project: { diff --git a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js index 7b604724977..971ba8b583c 100644 --- a/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js +++ b/spec/frontend/lib/apollo/suppress_network_errors_during_navigation_link_spec.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; import waitForPromises from 'helpers/wait_for_promises'; import { getSuppressNetworkErrorsDuringNavigationLink } from '~/lib/apollo/suppress_network_errors_during_navigation_link'; import { isNavigatingAway } from '~/lib/utils/is_navigating_away'; diff --git a/spec/frontend/lib/utils/apollo_startup_js_link_spec.js b/spec/frontend/lib/utils/apollo_startup_js_link_spec.js index c0e5b06651f..e58bc063004 100644 --- a/spec/frontend/lib/utils/apollo_startup_js_link_spec.js +++ b/spec/frontend/lib/utils/apollo_startup_js_link_spec.js @@ -1,4 +1,4 @@ -import { ApolloLink, Observable } from 'apollo-link'; +import { ApolloLink, Observable } from '@apollo/client/core'; import { StartupJSLink } from '~/lib/utils/apollo_startup_js_link'; describe('StartupJSLink', () => { diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js index 1e4d9f313f0..a605edc4357 100644 --- a/spec/frontend/notes/components/comment_form_spec.js +++ b/spec/frontend/notes/components/comment_form_spec.js @@ -20,7 +20,6 @@ import { loggedOutnoteableData, notesDataMock, userDataMock, noteableDataMock } jest.mock('autosize'); jest.mock('~/commons/nav/user_merge_requests'); jest.mock('~/flash'); -jest.mock('~/gl_form'); Vue.use(Vuex); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js index bda0f3616a4..bd126fe532d 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js @@ -305,15 +305,8 @@ describe('List Page', () => { await selectImageForDeletion(); findDeleteModal().vm.$emit('primary'); - await waitForApolloRequestRender(); - - expect(wrapper.vm.itemToDelete).toEqual(deletedContainerRepository); - - const updatedImage = findImageList() - .props('images') - .find((i) => i.id === deletedContainerRepository.id); - expect(updatedImage.status).toBe(deletedContainerRepository.status); + expect(mutationResolver).toHaveBeenCalledWith({ id: deletedContainerRepository.id }); }); it('should show a success alert when delete request is successful', async () => { diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js index c6a59f20998..0a4747fc9ec 100644 --- a/spec/frontend/packages_and_registries/package_registry/mock_data.js +++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js @@ -119,6 +119,7 @@ export const packageVersions = () => [ ]; export const packageData = (extend) => ({ + __typename: 'Package', id: 'gid://gitlab/Packages::Package/111', canDestroy: true, name: '@gitlab-org/package-15', diff --git a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js index b9fbaad7734..a7e31d42c9e 100644 --- a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js @@ -57,6 +57,8 @@ describe('PackagesApp', () => { breadCrumbState, }; + const { __typename, ...packageWithoutTypename } = packageData(); + function createComponent({ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()), fileDeleteMutationResolver = jest.fn().mockResolvedValue(packageDestroyFileMutation()), @@ -130,7 +132,7 @@ describe('PackagesApp', () => { expect(findPackageTitle().exists()).toBe(true); expect(findPackageTitle().props()).toMatchObject({ - packageEntity: expect.objectContaining(packageData()), + packageEntity: expect.objectContaining(packageWithoutTypename), }); }); @@ -153,7 +155,7 @@ describe('PackagesApp', () => { expect(findPackageHistory().exists()).toBe(true); expect(findPackageHistory().props()).toMatchObject({ - packageEntity: expect.objectContaining(packageData()), + packageEntity: expect.objectContaining(packageWithoutTypename), projectName: packageDetailsQuery().data.package.project.name, }); }); @@ -165,7 +167,7 @@ describe('PackagesApp', () => { expect(findAdditionalMetadata().exists()).toBe(true); expect(findAdditionalMetadata().props()).toMatchObject({ - packageEntity: expect.objectContaining(packageData()), + packageEntity: expect.objectContaining(packageWithoutTypename), }); }); @@ -176,7 +178,7 @@ describe('PackagesApp', () => { expect(findInstallationCommands().exists()).toBe(true); expect(findInstallationCommands().props()).toMatchObject({ - packageEntity: expect.objectContaining(packageData()), + packageEntity: expect.objectContaining(packageWithoutTypename), }); }); diff --git a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js index a56bb75f8ed..33406c98f4b 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/mock_data.js @@ -13,6 +13,7 @@ export const expirationPolicyPayload = (override) => ({ project: { id: '1', containerExpirationPolicy: { + __typename: 'ContainerExpirationPolicy', ...containerExpirationPolicyData(), ...override, }, diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js index 7e71622770f..f6e3a72b5e0 100644 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js +++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js @@ -1,13 +1,15 @@ import { GlProgressBar, GlAlert } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; +import Cookies from 'js-cookie'; import LearnGitlab from '~/pages/projects/learn_gitlab/components/learn_gitlab.vue'; import eventHub from '~/invite_members/event_hub'; +import { INVITE_MODAL_OPEN_COOKIE } from '~/pages/projects/learn_gitlab/constants'; import { testActions, testSections, testProject } from './mock_data'; describe('Learn GitLab', () => { let wrapper; let sidebar; - let inviteMembersOpen = false; + let inviteMembers = false; const createWrapper = () => { wrapper = mount(LearnGitlab, { @@ -15,7 +17,7 @@ describe('Learn GitLab', () => { actions: testActions, sections: testSections, project: testProject, - inviteMembersOpen, + inviteMembers, }, }); }; @@ -36,7 +38,7 @@ describe('Learn GitLab', () => { afterEach(() => { wrapper.destroy(); wrapper = null; - inviteMembersOpen = false; + inviteMembers = false; sidebar.remove(); }); @@ -59,13 +61,20 @@ describe('Learn GitLab', () => { describe('Invite Members Modal', () => { let spy; + let cookieSpy; beforeEach(() => { spy = jest.spyOn(eventHub, '$emit'); + cookieSpy = jest.spyOn(Cookies, 'remove'); + }); + + afterEach(() => { + Cookies.remove(INVITE_MODAL_OPEN_COOKIE); }); it('emits openModal', () => { - inviteMembersOpen = true; + inviteMembers = true; + Cookies.set(INVITE_MODAL_OPEN_COOKIE, true); createWrapper(); @@ -74,9 +83,19 @@ describe('Learn GitLab', () => { inviteeType: 'members', source: 'learn-gitlab', }); + expect(cookieSpy).toHaveBeenCalledWith(INVITE_MODAL_OPEN_COOKIE); + }); + + it('does not emit openModal when cookie is not set', () => { + inviteMembers = true; + + createWrapper(); + + expect(spy).not.toHaveBeenCalled(); + expect(cookieSpy).toHaveBeenCalledWith(INVITE_MODAL_OPEN_COOKIE); }); - it('does not emit openModal', () => { + it('does not emit openModal when inviteMembers is false', () => { createWrapper(); expect(spy).not.toHaveBeenCalled(); diff --git a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js index b84dad5a988..b54feea6ff7 100644 --- a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js +++ b/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js @@ -12,7 +12,9 @@ import { COMMIT_SUCCESS, COMMIT_SUCCESS_WITH_REDIRECT, } from '~/pipeline_editor/constants'; +import { resolvers } from '~/pipeline_editor/graphql/resolvers'; import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql'; +import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql'; import updatePipelineEtag from '~/pipeline_editor/graphql/mutations/client/update_pipeline_etag.mutation.graphql'; import { @@ -70,7 +72,20 @@ describe('Pipeline Editor | Commit section', () => { const createComponentWithApollo = (options) => { const handlers = [[commitCreate, mockMutateCommitData]]; Vue.use(VueApollo); - mockApollo = createMockApollo(handlers); + mockApollo = createMockApollo(handlers, resolvers); + + mockApollo.clients.defaultClient.cache.writeQuery({ + query: getCurrentBranch, + data: { + workBranches: { + __typename: 'BranchList', + current: { + __typename: 'WorkBranch', + name: mockDefaultBranch, + }, + }, + }, + }); const apolloConfig = { apolloProvider: mockApollo, @@ -198,6 +213,7 @@ describe('Pipeline Editor | Commit section', () => { const newBranch = 'new-branch'; beforeEach(async () => { + mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse); createComponentWithApollo(); mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse); await submitCommit({ diff --git a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js index ab9027a56a4..7dbacad34bf 100644 --- a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js +++ b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js @@ -12,6 +12,10 @@ import waitForPromises from 'helpers/wait_for_promises'; import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue'; import { DEFAULT_FAILURE } from '~/pipeline_editor/constants'; import getAvailableBranchesQuery from '~/pipeline_editor/graphql/queries/available_branches.query.graphql'; +import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.query.graphql'; +import getLastCommitBranch from '~/pipeline_editor/graphql/queries/client/last_commit_branch.query.graphql'; +import { resolvers } from '~/pipeline_editor/graphql/resolvers'; + import { mockBranchPaginationLimit, mockDefaultBranch, @@ -34,6 +38,7 @@ describe('Pipeline editor branch switcher', () => { const createComponent = ({ currentBranch = mockDefaultBranch, + availableBranches = ['main'], isQueryLoading = false, mountFn = shallowMount, options = {}, @@ -59,7 +64,7 @@ describe('Pipeline editor branch switcher', () => { }, data() { return { - availableBranches: ['main'], + availableBranches, currentBranch, }; }, @@ -67,13 +72,44 @@ describe('Pipeline editor branch switcher', () => { }); }; - const createComponentWithApollo = ({ mountFn = shallowMount, props = {} } = {}) => { + const createComponentWithApollo = ({ + mountFn = shallowMount, + props = {}, + availableBranches = ['main'], + } = {}) => { const handlers = [[getAvailableBranchesQuery, mockAvailableBranchQuery]]; - mockApollo = createMockApollo(handlers); + mockApollo = createMockApollo(handlers, resolvers); + + mockApollo.clients.defaultClient.cache.writeQuery({ + query: getCurrentBranch, + data: { + workBranches: { + __typename: 'BranchList', + current: { + __typename: 'WorkBranch', + name: mockDefaultBranch, + }, + }, + }, + }); + + mockApollo.clients.defaultClient.cache.writeQuery({ + query: getLastCommitBranch, + data: { + workBranches: { + __typename: 'BranchList', + lastCommit: { + __typename: 'WorkBranch', + name: '', + }, + }, + }, + }); createComponent({ mountFn, props, + availableBranches, options: { localVue, apolloProvider: mockApollo, @@ -113,7 +149,7 @@ describe('Pipeline editor branch switcher', () => { describe('when querying for the first time', () => { beforeEach(() => { - createComponentWithApollo(); + createComponentWithApollo({ availableBranches: [] }); }); it('disables the dropdown', () => { @@ -153,7 +189,7 @@ describe('Pipeline editor branch switcher', () => { describe('on fetch error', () => { beforeEach(async () => { setAvailableBranchesMock(new Error()); - createComponentWithApollo(); + createComponentWithApollo({ availableBranches: [] }); await waitForPromises(); }); diff --git a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js index aae8656b4ad..93eb18c90cf 100644 --- a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js +++ b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js @@ -96,7 +96,7 @@ describe('Pipeline Status', () => { }); it('should emit an error event when query fails', async () => { - expect(wrapper.emitted('showError')).toHaveLength(2); + expect(wrapper.emitted('showError')).toHaveLength(1); expect(wrapper.emitted('showError')[0]).toEqual([ { type: PIPELINE_FAILURE, diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js index ca283f3b4ce..1673065e09c 100644 --- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js +++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js @@ -90,11 +90,6 @@ describe('Linked Pipelines Column', () => { await waitForPromises(); }; - const clickExpandButtonAndAwaitTimers = async () => { - await clickExpandButton(); - jest.runOnlyPendingTimers(); - }; - describe('layer type rendering', () => { let layersFn; @@ -105,7 +100,7 @@ describe('Linked Pipelines Column', () => { it('calls listByLayers only once no matter how many times view is switched', async () => { expect(layersFn).not.toHaveBeenCalled(); - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); await wrapper.setProps({ viewType: LAYER_VIEW }); await nextTick(); expect(layersFn).toHaveBeenCalledTimes(1); @@ -131,7 +126,7 @@ describe('Linked Pipelines Column', () => { }); it('shows the stage view, even when the main graph view type is layers', async () => { - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); expect(findPipelineGraph().props('viewType')).toBe(STAGE_VIEW); }); }); @@ -144,7 +139,7 @@ describe('Linked Pipelines Column', () => { it('toggles the pipeline visibility', async () => { expect(findPipelineGraph().exists()).toBe(false); - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(true); await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(false); @@ -161,15 +156,12 @@ describe('Linked Pipelines Column', () => { it('emits the error', async () => { await clickExpandButton(); - expect(wrapper.emitted().error).toEqual([ - [{ type: LOAD_FAILURE, skipSentry: true }], - [{ type: LOAD_FAILURE, skipSentry: true }], - ]); + expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]); }); it('does not show the pipeline', async () => { expect(findPipelineGraph().exists()).toBe(false); - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(false); }); }); @@ -197,7 +189,7 @@ describe('Linked Pipelines Column', () => { it('toggles the pipeline visibility', async () => { expect(findPipelineGraph().exists()).toBe(false); - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(true); await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(false); @@ -215,15 +207,12 @@ describe('Linked Pipelines Column', () => { it('emits the error', async () => { await clickExpandButton(); - expect(wrapper.emitted().error).toEqual([ - [{ type: LOAD_FAILURE, skipSentry: true }], - [{ type: LOAD_FAILURE, skipSentry: true }], - ]); + expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]); }); it('does not show the pipeline', async () => { expect(findPipelineGraph().exists()).toBe(false); - await clickExpandButtonAndAwaitTimers(); + await clickExpandButton(); expect(findPipelineGraph().exists()).toBe(false); }); }); diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js index 53479e3cdb7..109e5cef49b 100644 --- a/spec/frontend/repository/components/blob_content_viewer_spec.js +++ b/spec/frontend/repository/components/blob_content_viewer_spec.js @@ -79,6 +79,8 @@ const createComponent = async (mockData = {}, mountFn = shallowMount) => { propsData: propsMock, mixins: [{ data: () => ({ ref: refMock }) }], provide: { + targetBranch: 'test', + originalBranch: 'default-ref', ...inject, glFeatures: { highlightJs, diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js index 52c68c7925c..5a6551cb94a 100644 --- a/spec/frontend/repository/mock_data.js +++ b/spec/frontend/repository/mock_data.js @@ -50,6 +50,7 @@ export const userPermissionsMock = { }; export const projectMock = { + __typename: 'Project', id: '1234', userPermissions: userPermissionsMock, pathLocks: { diff --git a/spec/frontend/runner/admin_runner_edit/admin_runner_edit_app_spec.js b/spec/frontend/runner/admin_runner_edit/admin_runner_edit_app_spec.js index e694fbf86a3..ff6a632a4f8 100644 --- a/spec/frontend/runner/admin_runner_edit/admin_runner_edit_app_spec.js +++ b/spec/frontend/runner/admin_runner_edit/admin_runner_edit_app_spec.js @@ -76,7 +76,7 @@ describe('AdminRunnerEditApp', () => { it('error is reported to sentry', () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error('Network error: Error!'), + error: new Error('Error!'), component: 'AdminRunnerEditApp', }); }); diff --git a/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js b/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js index 9a02e9057c2..031da47acb4 100644 --- a/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js +++ b/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js @@ -137,7 +137,7 @@ describe('AdminRunnerShowApp', () => { it('error is reported to sentry', () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error('Network error: Error!'), + error: new Error('Error!'), component: 'AdminRunnerShowApp', }); }); diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js index 35df27e02ea..995f0cf7ba1 100644 --- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js +++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js @@ -302,17 +302,18 @@ describe('AdminRunnersApp', () => { it('error is reported to sentry', async () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error('Network error: Error!'), + error: new Error('Error!'), component: 'AdminRunnersApp', }); }); }); describe('Pagination', () => { - beforeEach(() => { + beforeEach(async () => { mockRunnersQuery = jest.fn().mockResolvedValue(runnersDataPaginated); createComponent({ mountFn: mountExtended }); + await waitForPromises(); }); it('more pages can be selected', () => { diff --git a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js index b2c740c3f27..dcb0af67784 100644 --- a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js +++ b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js @@ -206,7 +206,8 @@ describe('RunnerTypeCell', () => { expect(getTooltip(findDeleteBtn())).toBe(''); }); - it('The toast notification is shown', () => { + it('The toast notification is shown', async () => { + await waitForPromises(); expect(mockToastShow).toHaveBeenCalledTimes(1); expect(mockToastShow).toHaveBeenCalledWith( expect.stringContaining(`#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`), @@ -227,7 +228,7 @@ describe('RunnerTypeCell', () => { it('error is reported to sentry', () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error(`Network error: ${mockErrorMsg}`), + error: new Error(mockErrorMsg), component: 'RunnerActionsCell', }); }); diff --git a/spec/frontend/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/runner/components/registration/registration_dropdown_spec.js index 26d3f852a1e..da8ef7c3af0 100644 --- a/spec/frontend/runner/components/registration/registration_dropdown_spec.js +++ b/spec/frontend/runner/components/registration/registration_dropdown_spec.js @@ -5,6 +5,7 @@ import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; import RegistrationDropdown from '~/runner/components/registration/registration_dropdown.vue'; import RegistrationTokenResetDropdownItem from '~/runner/components/registration/registration_token_reset_dropdown_item.vue'; @@ -96,6 +97,7 @@ describe('RegistrationDropdown', () => { ); await findRegistrationInstructionsDropdownItem().trigger('click'); + await waitForPromises(); }); afterEach(() => { diff --git a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js b/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js index 43b9aa9c413..d2deb49a5f7 100644 --- a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js +++ b/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js @@ -162,10 +162,10 @@ describe('RegistrationTokenResetDropdownItem', () => { await waitForPromises(); expect(createAlert).toHaveBeenLastCalledWith({ - message: `Network error: ${mockErrorMsg}`, + message: mockErrorMsg, }); expect(captureException).toHaveBeenCalledWith({ - error: new Error(`Network error: ${mockErrorMsg}`), + error: new Error(mockErrorMsg), component: 'RunnerRegistrationTokenReset', }); }); diff --git a/spec/frontend/runner/components/runner_pause_button_spec.js b/spec/frontend/runner/components/runner_pause_button_spec.js index 34510883a25..278f3dec2ee 100644 --- a/spec/frontend/runner/components/runner_pause_button_spec.js +++ b/spec/frontend/runner/components/runner_pause_button_spec.js @@ -150,7 +150,7 @@ describe('RunnerPauseButton', () => { it('error is reported to sentry', () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error(`Network error: ${mockErrorMsg}`), + error: new Error(mockErrorMsg), component: 'RunnerPauseButton', }); }); diff --git a/spec/frontend/runner/components/runner_update_form_spec.js b/spec/frontend/runner/components/runner_update_form_spec.js index f92244f41f7..36120a4c7ed 100644 --- a/spec/frontend/runner/components/runner_update_form_spec.js +++ b/spec/frontend/runner/components/runner_update_form_spec.js @@ -132,6 +132,7 @@ describe('RunnerUpdateForm', () => { userPermissions, version, groups, + __typename, ...submitted } = mockRunner; @@ -245,11 +246,11 @@ describe('RunnerUpdateForm', () => { await submitFormAndWait(); expect(createAlert).toHaveBeenLastCalledWith({ - message: `Network error: ${mockErrorMsg}`, + message: mockErrorMsg, }); expect(captureException).toHaveBeenCalledWith({ component: 'RunnerUpdateForm', - error: new Error(`Network error: ${mockErrorMsg}`), + error: new Error(mockErrorMsg), }); expect(findSubmitDisabledAttr()).toBeUndefined(); }); diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js index f1802ac78a1..7cb1f49d4f7 100644 --- a/spec/frontend/runner/group_runners/group_runners_app_spec.js +++ b/spec/frontend/runner/group_runners/group_runners_app_spec.js @@ -262,6 +262,7 @@ describe('GroupRunnersApp', () => { mockGroupRunnersQuery = jest.fn().mockResolvedValue({ data: { group: { + id: '1', runners: { nodes: [] }, }, }, @@ -288,17 +289,18 @@ describe('GroupRunnersApp', () => { it('error is reported to sentry', async () => { expect(captureException).toHaveBeenCalledWith({ - error: new Error('Network error: Error!'), + error: new Error('Error!'), component: 'GroupRunnersApp', }); }); }); describe('Pagination', () => { - beforeEach(() => { + beforeEach(async () => { mockGroupRunnersQuery = jest.fn().mockResolvedValue(groupRunnersDataPaginated); createComponent({ mountFn: mountExtended }); + await waitForPromises(); }); it('more pages can be selected', () => { diff --git a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js index 3045b8c5842..def46255994 100644 --- a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js +++ b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js @@ -137,9 +137,17 @@ describe('Sidebar assignees widget', () => { createComponent(); await waitForPromises(); - expect(findAssignees().props('users')).toEqual( - issuableQueryResponse.data.workspace.issuable.assignees.nodes, - ); + expect(findAssignees().props('users')).toEqual([ + { + id: 'gid://gitlab/User/2', + avatarUrl: + 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', + name: 'Jacki Kub', + username: 'francina.skiles', + webUrl: '/franc', + status: null, + }, + ]); }); it('renders an error when issuable query is rejected', async () => { @@ -195,7 +203,7 @@ describe('Sidebar assignees widget', () => { { assignees: [ { - __typename: 'User', + __typename: 'UserCore', avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', id: 'gid://gitlab/User/1', @@ -353,6 +361,7 @@ describe('Sidebar assignees widget', () => { describe('when making changes to participants list', () => { beforeEach(async () => { createComponent(); + await waitForPromises(); }); it('passes falsy `isDirty` prop to editable item if no changes to selected users were made', () => { diff --git a/spec/frontend/sidebar/components/mock_data.js b/spec/frontend/sidebar/components/mock_data.js index 70c3f8a3012..a9a00b3cfdf 100644 --- a/spec/frontend/sidebar/components/mock_data.js +++ b/spec/frontend/sidebar/components/mock_data.js @@ -1,6 +1,7 @@ export const getIssueCrmContactsQueryResponse = { data: { issue: { + __typename: 'Issue', id: 'gid://gitlab/Issue/123', customerRelationsContacts: { nodes: [ @@ -37,6 +38,7 @@ export const issueCrmContactsUpdateNullResponse = { export const issueCrmContactsUpdateResponse = { data: { issueCrmContactsUpdated: { + __typename: 'Issue', id: 'gid://gitlab/Issue/123', customerRelationsContacts: { nodes: [ diff --git a/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js b/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js index 859e63b3df6..338ecf944f3 100644 --- a/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js +++ b/spec/frontend/sidebar/components/participants/sidebar_participants_widget_spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; +import { stripTypenames } from 'helpers/graphql_helpers'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import Participants from '~/sidebar/components/participants/participants.vue'; @@ -66,9 +67,11 @@ describe('Sidebar Participants Widget', () => { }); it('passes participants to child component', () => { - expect(findParticipants().props('participants')).toEqual( + const participantsWithoutTypename = stripTypenames( epicParticipantsResponse().data.workspace.issuable.participants.nodes, ); + + expect(findParticipants().props('participants')).toEqual(participantsWithoutTypename); }); }); diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js index 42e89a3ba84..30972484a08 100644 --- a/spec/frontend/sidebar/mock_data.js +++ b/spec/frontend/sidebar/mock_data.js @@ -276,6 +276,7 @@ export const epicParticipantsResponse = () => ({ participants: { nodes: [ { + __typename: 'UserCore', id: 'gid://gitlab/User/2', avatarUrl: 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', @@ -332,6 +333,7 @@ export const issuableQueryResponse = { assignees: { nodes: [ { + __typename: 'UserCore', id: 'gid://gitlab/User/2', avatarUrl: 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', @@ -389,7 +391,7 @@ export const updateIssueAssigneesMutationResponse = { assignees: { nodes: [ { - __typename: 'User', + __typename: 'UserCore', id: 'gid://gitlab/User/1', avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', @@ -414,6 +416,7 @@ export const subscriptionNullResponse = { }; const mockUser1 = { + __typename: 'UserCore', id: 'gid://gitlab/User/1', avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', @@ -424,6 +427,7 @@ const mockUser1 = { }; export const mockUser2 = { + __typename: 'UserCore', id: 'gid://gitlab/User/4', avatarUrl: '/avatar2', name: 'rookie', @@ -470,6 +474,7 @@ export const projectMembersResponse = { { id: 'user-4', user: { + __typename: 'UserCore', id: 'gid://gitlab/User/2', avatarUrl: 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', @@ -503,6 +508,7 @@ export const groupMembersResponse = { { id: 'user-3', user: { + __typename: 'UserCore', id: 'gid://gitlab/User/2', avatarUrl: 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', @@ -535,6 +541,7 @@ export const participantsQueryResponse = { mockUser1, mockUser1, { + __typename: 'UserCore', id: 'gid://gitlab/User/2', avatarUrl: 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon', @@ -546,6 +553,7 @@ export const participantsQueryResponse = { }, }, { + __typename: 'UserCore', id: 'gid://gitlab/User/3', avatarUrl: '/avatar', name: 'John Doe', diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js index 9f608765183..61424fa1eb2 100644 --- a/spec/frontend/snippets/components/edit_spec.js +++ b/spec/frontend/snippets/components/edit_spec.js @@ -329,6 +329,7 @@ describe('Snippet Edit app', () => { mutateSpy.mockRejectedValue(TEST_API_ERROR); await createComponentAndSubmit(); + await nextTick(); }); it('should not redirect', () => { @@ -338,7 +339,7 @@ describe('Snippet Edit app', () => { it('should flash', () => { // Apollo automatically wraps the resolver's error in a NetworkError expect(createFlash).toHaveBeenCalledWith({ - message: `Can't update snippet: Network error: ${TEST_API_ERROR.message}`, + message: `Can't update snippet: ${TEST_API_ERROR.message}`, }); }); @@ -348,7 +349,7 @@ describe('Snippet Edit app', () => { // eslint-disable-next-line no-console expect(console.error).toHaveBeenCalledWith( '[gitlab] unexpected error while updating snippet', - expect.objectContaining({ message: `Network error: ${TEST_API_ERROR.message}` }), + expect.objectContaining({ message: `${TEST_API_ERROR.message}` }), ); }); }); diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js index 803f1723645..c8b4cd564d9 100644 --- a/spec/frontend/terraform/components/terraform_list_spec.js +++ b/spec/frontend/terraform/components/terraform_list_spec.js @@ -99,6 +99,7 @@ describe('TerraformList', () => { nodes: states, count: states.length, pageInfo: { + __typename: 'PageInfo', hasNextPage: true, hasPreviousPage: false, startCursor: 'prev', diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js index 7808bdb8db3..0da9939e97f 100644 --- a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js +++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js @@ -77,6 +77,7 @@ describe('RunnerInstructionsModal component', () => { runnerSetupInstructionsHandler = jest.fn().mockResolvedValue(mockGraphqlInstructions); createComponent(); + await waitForPromises(); }); afterEach(() => { @@ -199,7 +200,8 @@ describe('RunnerInstructionsModal component', () => { expect(findGlLoadingIcon().exists()).toBe(false); await nextTick(); - await jest.runOnlyPendingTimers(); + jest.runOnlyPendingTimers(); + await nextTick(); await nextTick(); expect(findGlLoadingIcon().exists()).toBe(true); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js index a4199bb3e27..67e1a3ce932 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js @@ -117,9 +117,15 @@ describe('LabelsSelectRoot', () => { it('renders dropdown value component when query labels is resolved', () => { expect(findDropdownValue().exists()).toBe(true); - expect(findDropdownValue().props('selectedLabels')).toEqual( - issuableLabelsQueryResponse.data.workspace.issuable.labels.nodes, - ); + expect(findDropdownValue().props('selectedLabels')).toEqual([ + { + color: '#330066', + description: null, + id: 'gid://gitlab/ProjectLabel/1', + title: 'Label1', + textColor: '#000000', + }, + ]); }); it('emits `onLabelRemove` event on dropdown value label remove event', () => { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js index 6ef54ce37ce..49224fb915c 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js @@ -96,6 +96,7 @@ export const workspaceLabelsQueryResponse = { labels: { nodes: [ { + __typename: 'Label', color: '#330066', description: null, id: 'gid://gitlab/ProjectLabel/1', @@ -103,6 +104,7 @@ export const workspaceLabelsQueryResponse = { textColor: '#000000', }, { + __typename: 'Label', color: '#2f7b2e', description: null, id: 'gid://gitlab/ProjectLabel/2', @@ -125,6 +127,7 @@ export const issuableLabelsQueryResponse = { labels: { nodes: [ { + __typename: 'Label', color: '#330066', description: null, id: 'gid://gitlab/ProjectLabel/1', diff --git a/spec/frontend/vue_shared/components/user_select_spec.js b/spec/frontend/vue_shared/components/user_select_spec.js index 8994e16e517..411a15e1c74 100644 --- a/spec/frontend/vue_shared/components/user_select_spec.js +++ b/spec/frontend/vue_shared/components/user_select_spec.js @@ -104,14 +104,14 @@ describe('User select dropdown', () => { createComponent({ participantsQueryHandler: mockError }); await waitForPromises(); - expect(wrapper.emitted('error')).toEqual([[], []]); + expect(wrapper.emitted('error')).toEqual([[]]); }); it('emits an `error` event if search query was rejected', async () => { createComponent({ searchQueryHandler: mockError }); await waitForSearch(); - expect(wrapper.emitted('error')).toEqual([[], []]); + expect(wrapper.emitted('error')).toEqual([[]]); }); it('renders current user if they are not in participants or assignees', async () => { diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js index 0585b6c55fd..65eb42ef053 100644 --- a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js +++ b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js @@ -10,7 +10,6 @@ import { mockIssuable, mockRegularLabel, mockScopedLabel } from '../mock_data'; const createComponent = ({ issuableSymbol = '#', issuable = mockIssuable, - enableLabelPermalinks = true, showCheckbox = true, slots = {}, } = {}) => @@ -18,7 +17,6 @@ const createComponent = ({ propsData: { issuableSymbol, issuable, - enableLabelPermalinks, showDiscussions: true, showCheckbox, }, @@ -212,23 +210,13 @@ describe('IssuableItem', () => { }); describe('labelTarget', () => { - it('returns target string for a provided label param when `enableLabelPermalinks` is true', () => { + it('returns target string for a provided label param', () => { wrapper = createComponent(); expect(wrapper.vm.labelTarget(mockRegularLabel)).toBe( '?label_name[]=Documentation%20Update', ); }); - - it('returns string "#" for a provided label param when `enableLabelPermalinks` is false', async () => { - wrapper = createComponent({ - enableLabelPermalinks: false, - }); - - await nextTick(); - - expect(wrapper.vm.labelTarget(mockRegularLabel)).toBe('#'); - }); }); }); diff --git a/spec/frontend/vue_shared/security_reports/mock_data.js b/spec/frontend/vue_shared/security_reports/mock_data.js index 2b1513bb0f8..dac9accbbf5 100644 --- a/spec/frontend/vue_shared/security_reports/mock_data.js +++ b/spec/frontend/vue_shared/security_reports/mock_data.js @@ -324,7 +324,9 @@ export const secretDetectionDiffSuccessMock = { export const securityReportMergeRequestDownloadPathsQueryNoArtifactsResponse = { project: { + id: 'project-1', mergeRequest: { + id: 'mr-1', headPipeline: { id: 'gid://gitlab/Ci::Pipeline/176', jobs: { diff --git a/spec/frontend/work_items/pages/work_item_root_spec.js b/spec/frontend/work_items/pages/work_item_root_spec.js index ea26b2b4fb3..d0e40680b55 100644 --- a/spec/frontend/work_items/pages/work_item_root_spec.js +++ b/spec/frontend/work_items/pages/work_item_root_spec.js @@ -23,7 +23,11 @@ describe('Work items root component', () => { const findTitle = () => wrapper.findComponent(ItemTitle); const createComponent = ({ queryResponse = workItemQueryResponse } = {}) => { - fakeApollo = createMockApollo([], resolvers); + fakeApollo = createMockApollo([], resolvers, { + possibleTypes: { + LocalWorkItemWidget: ['LocalTitleWidget'], + }, + }); fakeApollo.clients.defaultClient.cache.writeQuery({ query: workItemQuery, variables: { diff --git a/spec/graphql/mutations/ci/runner/delete_spec.rb b/spec/graphql/mutations/ci/runner/delete_spec.rb index 9f30c95edd5..b53ee30f826 100644 --- a/spec/graphql/mutations/ci/runner/delete_spec.rb +++ b/spec/graphql/mutations/ci/runner/delete_spec.rb @@ -11,9 +11,7 @@ RSpec.describe Mutations::Ci::Runner::Delete do let(:current_ctx) { { current_user: user } } let(:mutation_params) do - { - id: runner.to_global_id - } + { id: runner.to_global_id } end specify { expect(described_class).to require_graphql_authorizations(:delete_runner) } @@ -57,6 +55,10 @@ RSpec.describe Mutations::Ci::Runner::Delete do it 'deletes runner' do mutation_params[:id] = project_runner.to_global_id + expect_next_instance_of(::Ci::UnregisterRunnerService, project_runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + expect { subject }.to change { Ci::Runner.count }.by(-1) expect(subject[:errors]).to be_empty end @@ -73,6 +75,9 @@ RSpec.describe Mutations::Ci::Runner::Delete do it 'does not delete project runner' do mutation_params[:id] = two_projects_runner.to_global_id + allow_next_instance_of(::Ci::UnregisterRunnerService) do |service| + expect(service).not_to receive(:execute).once + end expect { subject }.not_to change { Ci::Runner.count } expect(subject[:errors]).to contain_exactly("Runner #{two_projects_runner.to_global_id} associated with more than one project") end @@ -84,6 +89,10 @@ RSpec.describe Mutations::Ci::Runner::Delete do let(:current_ctx) { { current_user: admin_user } } it 'deletes runner' do + expect_next_instance_of(::Ci::UnregisterRunnerService, runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + expect { subject }.to change { Ci::Runner.count }.by(-1) expect(subject[:errors]).to be_empty end diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb index 1e433d7854a..652fe0c4f94 100644 --- a/spec/lib/gitlab/ci/lint_spec.rb +++ b/spec/lib/gitlab/ci/lint_spec.rb @@ -7,9 +7,10 @@ RSpec.describe Gitlab::Ci::Lint do let_it_be(:user) { create(:user) } let(:lint) { described_class.new(project: project, current_user: user) } + let(:ref) { project.default_branch } describe '#validate' do - subject { lint.validate(content, dry_run: dry_run) } + subject { lint.validate(content, dry_run: dry_run, ref: ref) } shared_examples 'content is valid' do let(:content) do @@ -251,6 +252,29 @@ RSpec.describe Gitlab::Ci::Lint do end end + context 'when using a ref other than the default branch' do + let(:ref) { 'feature' } + let(:content) do + <<~YAML + build: + stage: build + script: echo 1 + rules: + - if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH" + test: + stage: test + script: echo 2 + rules: + - if: "$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH" + YAML + end + + it 'includes only jobs that are excluded on the default branch' do + expect(subject.jobs.size).to eq(1) + expect(subject.jobs[0][:name]).to eq('test') + end + end + it_behaves_like 'sets merged yaml' include_context 'advanced validations' do diff --git a/spec/requests/api/ci/runners_spec.rb b/spec/requests/api/ci/runners_spec.rb index 466ae29cc4c..c309140362e 100644 --- a/spec/requests/api/ci/runners_spec.rb +++ b/spec/requests/api/ci/runners_spec.rb @@ -530,6 +530,10 @@ RSpec.describe API::Ci::Runners do context 'admin user' do context 'when runner is shared' do it 'deletes runner' do + expect_next_instance_of(Ci::UnregisterRunnerService, shared_runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + expect do delete api("/runners/#{shared_runner.id}", admin) @@ -544,6 +548,10 @@ RSpec.describe API::Ci::Runners do context 'when runner is not shared' do it 'deletes used project runner' do + expect_next_instance_of(Ci::UnregisterRunnerService, project_runner) do |service| + expect(service).to receive(:execute).once.and_call_original + end + expect do delete api("/runners/#{project_runner.id}", admin) @@ -553,6 +561,10 @@ RSpec.describe API::Ci::Runners do end it 'returns 404 if runner does not exist' do + allow_next_instance_of(Ci::UnregisterRunnerService) do |service| + expect(service).not_to receive(:execute) + end + delete api('/runners/0', admin) expect(response).to have_gitlab_http_status(:not_found) @@ -634,6 +646,10 @@ RSpec.describe API::Ci::Runners do context 'unauthorized user' do it 'does not delete project runner' do + allow_next_instance_of(Ci::UnregisterRunnerService) do |service| + expect(service).not_to receive(:execute) + end + delete api("/runners/#{project_runner.id}") expect(response).to have_gitlab_http_status(:unauthorized) diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb index e7a0c7753fb..006fe03378f 100644 --- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb @@ -47,6 +47,18 @@ RSpec.describe 'Create a work item' do ) end + context 'when input is invalid' do + let(:input) { { 'title' => '', 'workItemTypeId' => WorkItems::Type.default_by_type(:task).to_global_id.to_s } } + + it 'does not create and returns validation errors' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to not_change(WorkItem, :count) + + expect(graphql_mutation_response(:work_item_create)['errors']).to contain_exactly("Title can't be blank") + end + end + it_behaves_like 'has spam protection' do let(:mutation_class) { ::Mutations::WorkItems::Create } end diff --git a/spec/services/ci/unregister_runner_service_spec.rb b/spec/services/ci/unregister_runner_service_spec.rb new file mode 100644 index 00000000000..f427e04f228 --- /dev/null +++ b/spec/services/ci/unregister_runner_service_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Ci::UnregisterRunnerService, '#execute' do + subject { described_class.new(runner).execute } + + let(:runner) { create(:ci_runner) } + + it 'destroys runner' do + expect(runner).to receive(:destroy).once.and_call_original + expect { subject }.to change { Ci::Runner.count }.by(-1) + expect(runner[:errors]).to be_nil + end +end diff --git a/spec/services/work_items/create_service_spec.rb b/spec/services/work_items/create_service_spec.rb index 2c054ae59a0..f495e967b26 100644 --- a/spec/services/work_items/create_service_spec.rb +++ b/spec/services/work_items/create_service_spec.rb @@ -5,34 +5,46 @@ require 'spec_helper' RSpec.describe WorkItems::CreateService do include AfterNextHelpers - let_it_be(:group) { create(:group) } - let_it_be_with_reload(:project) { create(:project, group: group) } - let_it_be(:user) { create(:user) } + let_it_be_with_reload(:project) { create(:project) } + let_it_be(:guest) { create(:user) } + let_it_be(:user_with_no_access) { create(:user) } let(:spam_params) { double } + let(:current_user) { guest } + let(:opts) do + { + title: 'Awesome work_item', + description: 'please fix' + } + end + + before_all do + project.add_guest(guest) + end describe '#execute' do - let(:work_item) { described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute } + subject(:service_result) { described_class.new(project: project, current_user: current_user, params: opts, spam_params: spam_params).execute } before do stub_spam_services end - context 'when params are valid' do - before_all do - project.add_guest(user) - end + context 'when user is not allowed to create a work item in the project' do + let(:current_user) { user_with_no_access } + + it { is_expected.to be_error } - let(:opts) do - { - title: 'Awesome work_item', - description: 'please fix' - } + it 'returns an access error' do + expect(service_result.errors).to contain_exactly('Operation not allowed') end + end + context 'when params are valid' do it 'created instance is a WorkItem' do expect(Issuable::CommonSystemNotesService).to receive_message_chain(:new, :execute) + work_item = service_result[:work_item] + expect(work_item).to be_persisted expect(work_item).to be_a(::WorkItem) expect(work_item.title).to eq('Awesome work_item') @@ -41,17 +53,17 @@ RSpec.describe WorkItems::CreateService do end end - context 'checking spam' do - let(:params) do - { - title: 'Spam work_item' - } - end + context 'when params are invalid' do + let(:opts) { { title: '' } } - subject do - described_class.new(project: project, current_user: user, params: params, spam_params: spam_params) + it { is_expected.to be_error } + + it 'returns validation errors' do + expect(service_result.errors).to contain_exactly("Title can't be blank") end + end + context 'checking spam' do it 'executes SpamActionService' do expect_next_instance_of( Spam::SpamActionService, @@ -65,7 +77,7 @@ RSpec.describe WorkItems::CreateService do expect(instance).to receive(:execute) end - subject.execute + service_result end end end diff --git a/yarn.lock b/yarn.lock index 22e6b2b569a..48a86fd48dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,25 @@ # yarn lockfile v1 +"@apollo/client@^3.2.5", "@apollo/client@^3.3.11": + version "3.3.11" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.3.11.tgz#125051405e83dc899d471d43b79fd6045d92a802" + integrity sha512-54+D5FB6RJlQ+g37f432gaexnyvDsG5X6L9VO5kqN54HJlbF8hCf/8CXtAQEHCWodAwZhy6kOLp2RM96829q3A== + dependencies: + "@graphql-typed-document-node/core" "^3.0.0" + "@types/zen-observable" "^0.8.0" + "@wry/context" "^0.5.2" + "@wry/equality" "^0.3.0" + fast-json-stable-stringify "^2.0.0" + graphql-tag "^2.12.0" + hoist-non-react-statics "^3.3.2" + optimism "^0.14.0" + prop-types "^15.7.2" + symbol-observable "^2.0.0" + ts-invariant "^0.6.0" + tslib "^1.10.0" + zen-observable "^0.8.14" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -810,7 +829,7 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.13.10", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.8.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== @@ -1149,6 +1168,11 @@ tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-typed-document-node/core@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.0.tgz#0eee6373e11418bfe0b5638f654df7a4ca6a3950" + integrity sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg== + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1928,7 +1952,7 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== -"@types/node@*", "@types/node@14.17.5", "@types/node@>=6": +"@types/node@*", "@types/node@14.17.5": version "14.17.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.5.tgz#b59daf6a7ffa461b5648456ca59050ba8e40ed54" integrity sha512-bjqH2cX/O33jXT/UmReo2pM7DIJREPMnarixbQ57DOOzzFaI6D2+IcwaJQaJpv0M1E9TIhPCYVxrkcityLjlqA== @@ -2090,6 +2114,11 @@ dependencies: "@types/estree" "*" +"@types/ungap__global-this@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@types/ungap__global-this/-/ungap__global-this-0.3.1.tgz#18ce9f657da556037a29d50604335614ce703f4c" + integrity sha512-+/DsiV4CxXl6ZWefwHZDXSe1Slitz21tom38qPCaG0DYCS1NnDPIQDTKcmQ/tvK/edJUKkmuIDBJbmKDiB0r/g== + "@types/websocket@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8" @@ -2144,6 +2173,11 @@ semver "^6.3.0" tsutils "^3.17.1" +"@ungap/global-this@^0.4.2": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@ungap/global-this/-/global-this-0.4.4.tgz#8a1b2cfcd3e26e079a847daba879308c924dd695" + integrity sha512-mHkm6FvepJECMNthFuIgpAEFmPOk71UyXuIxYfjytvFTnSDBIz7jmViO+LfHI/AjrazWije0PnSP3+/NlwzqtA== + "@vue/component-compiler-utils@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.1.tgz#d4ef8f80292674044ad6211e336a302e4d2a6575" @@ -2330,20 +2364,26 @@ resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== -"@wry/context@^0.4.0": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.4.4.tgz#e50f5fa1d6cfaabf2977d1fda5ae91717f8815f8" - integrity sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag== +"@wry/context@^0.5.2": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.5.4.tgz#b6c28038872e0a0e1ff14eb40b5bf4cab2ab4e06" + integrity sha512-/pktJKHUXDr4D6TJqWgudOPJW2Z+Nb+bqk40jufA3uTkLbnCRKdJPiYDIa/c7mfcPH8Hr6O8zjCERpg5Sq04Zg== dependencies: - "@types/node" ">=6" - tslib "^1.9.3" + tslib "^1.14.1" -"@wry/equality@^0.1.2": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.9.tgz#b13e18b7a8053c6858aa6c85b54911fb31e3a909" - integrity sha512-mB6ceGjpMGz1ZTza8HYnrPGos2mC6So4NhS1PtZ8s4Qt0K7fBiIGhpSxUbQmhwcSWE3no+bYxmI2OL6KuXYmoQ== +"@wry/equality@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.3.3.tgz#1ec8f9af01d40a2eb00d055d9a3173315126c648" + integrity sha512-pMrKHIgDAWxLDTGsbaVag+USmwZ2+gGrSBrtyGUxp2pxRg1Cad70lI/hd0NTPtJ4zJxN16EQ679U1Rts83AF5g== dependencies: - tslib "^1.9.3" + tslib "^1.14.1" + +"@wry/trie@^0.2.1": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.2.2.tgz#99f20f0fcbbcda17006069b155c826cbabfc402f" + integrity sha512-OxqBB39x6MfHaa2HpMiRMfhuUnQTddD32Ko020eBeJXq87ivX6xnSSnzKHVbA21p7iqBASz8n/07b6W5wW1BVQ== + dependencies: + tslib "^1.14.1" "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -2556,113 +2596,14 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-cache-inmemory@^1.6.6: - version "1.6.6" - resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.6.tgz#56d1f2a463a6b9db32e9fa990af16d2a008206fd" - integrity sha512-L8pToTW/+Xru2FFAhkZ1OA9q4V4nuvfoPecBM34DecAugUZEBhI2Hmpgnzq2hTKZ60LAMrlqiASm0aqAY6F8/A== - dependencies: - apollo-cache "^1.3.5" - apollo-utilities "^1.3.4" - optimism "^0.10.0" - ts-invariant "^0.4.0" - tslib "^1.10.0" - -apollo-cache@1.3.5, apollo-cache@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.3.5.tgz#9dbebfc8dbe8fe7f97ba568a224bca2c5d81f461" - integrity sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA== - dependencies: - apollo-utilities "^1.3.4" - tslib "^1.10.0" - -apollo-client@^2.6.10: - version "2.6.10" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.10.tgz#86637047b51d940c8eaa771a4ce1b02df16bea6a" - integrity sha512-jiPlMTN6/5CjZpJOkGeUV0mb4zxx33uXWdj/xQCfAMkuNAC3HN7CvYDyMHHEzmcQ5GV12LszWoQ/VlxET24CtA== - dependencies: - "@types/zen-observable" "^0.8.0" - apollo-cache "1.3.5" - apollo-link "^1.0.0" - apollo-utilities "1.3.4" - symbol-observable "^1.0.2" - ts-invariant "^0.4.0" - tslib "^1.10.0" - zen-observable "^0.8.0" - -apollo-link-batch-http@^1.2.14: - version "1.2.14" - resolved "https://registry.yarnpkg.com/apollo-link-batch-http/-/apollo-link-batch-http-1.2.14.tgz#4502109d3f32a94d88eabd3a89274ae3a6e2f56f" - integrity sha512-LFUmfV3OXR3Er+zSgFxPY/qUe4Wyx0HS1euJZ36RCCaDvPegr24C9OQgKFScHy91VbjRTtFUyjXXVq1xFGPMvQ== - dependencies: - apollo-link "^1.2.14" - apollo-link-batch "^1.1.15" - apollo-link-http-common "^0.2.16" - tslib "^1.9.3" - -apollo-link-batch@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/apollo-link-batch/-/apollo-link-batch-1.1.15.tgz#3a5b8c7d9cf1b7840ce630238249b95070e75e54" - integrity sha512-XbfQI/FNxJW9RSgJTfAl7RDFxxN77425yDtT7YgsImH4/2NQ+U4SWN6thWE3ZU1Wf7ktXd+XFa3KkenBRTybOQ== - dependencies: - apollo-link "^1.2.14" - tslib "^1.9.3" - -apollo-link-error@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.13.tgz#c1a1bb876ffe380802c8df0506a32c33aad284cd" - integrity sha512-jAZOOahJU6bwSqb2ZyskEK1XdgUY9nkmeclCrW7Gddh1uasHVqmoYc4CKdb0/H0Y1J9lvaXKle2Wsw/Zx1AyUg== - dependencies: - apollo-link "^1.2.14" - apollo-link-http-common "^0.2.16" - tslib "^1.9.3" - -apollo-link-http-common@^0.2.14, apollo-link-http-common@^0.2.16: - version "0.2.16" - resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz#756749dafc732792c8ca0923f9a40564b7c59ecc" - integrity sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg== - dependencies: - apollo-link "^1.2.14" - ts-invariant "^0.4.0" - tslib "^1.9.3" - -apollo-link-http@^1.5.17: - version "1.5.17" - resolved "https://registry.yarnpkg.com/apollo-link-http/-/apollo-link-http-1.5.17.tgz#499e9f1711bf694497f02c51af12d82de5d8d8ba" - integrity sha512-uWcqAotbwDEU/9+Dm9e1/clO7hTB2kQ/94JYcGouBVLjoKmTeJTUPQKcJGpPwUjZcSqgYicbFqQSoJIW0yrFvg== - dependencies: - apollo-link "^1.2.14" - apollo-link-http-common "^0.2.16" - tslib "^1.9.3" - -apollo-link@^1.0.0, apollo-link@^1.2.12, apollo-link@^1.2.14: - version "1.2.14" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.14.tgz#3feda4b47f9ebba7f4160bef8b977ba725b684d9" - integrity sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg== - dependencies: - apollo-utilities "^1.3.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - zen-observable-ts "^0.8.21" - -apollo-upload-client@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-13.0.0.tgz#146d1ddd85d711fcac8ca97a72d3ca6787f2b71b" - integrity sha512-lJ9/bk1BH1lD15WhWRha2J3+LrXrPIX5LP5EwiOUHv8PCORp4EUrcujrA3rI5hZeZygrTX8bshcuMdpqpSrvtA== +apollo-upload-client@^14.1.3: + version "14.1.3" + resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-14.1.3.tgz#91f39011897bd08e99c0de0164e77ad2f3402247" + integrity sha512-X2T+7pHk5lcaaWnvP9h2tuAAMCzOW6/9juedQ0ZuGp3Ufl81BpDISlCs0o6u29wBV0RRT/QpMU2gbP+3FCfVpQ== dependencies: - "@babel/runtime" "^7.9.2" - apollo-link "^1.2.12" - apollo-link-http-common "^0.2.14" - extract-files "^8.0.0" - -apollo-utilities@1.3.4, apollo-utilities@^1.3.0, apollo-utilities@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.4.tgz#6129e438e8be201b6c55b0f13ce49d2c7175c9cf" - integrity sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig== - dependencies: - "@wry/equality" "^0.1.2" - fast-json-stable-stringify "^2.0.0" - ts-invariant "^0.4.0" - tslib "^1.10.0" + "@apollo/client" "^3.2.5" + "@babel/runtime" "^7.12.5" + extract-files "^9.0.0" aproba@^1.1.1: version "1.2.0" @@ -5760,10 +5701,10 @@ extract-files@11.0.0: resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== -extract-files@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-8.1.0.tgz#46a0690d0fe77411a2e3804852adeaa65cd59288" - integrity sha512-PTGtfthZK79WUMk+avLmwx3NGdU8+iVFXC2NMGxKsn0MnihOG2lvumj+AZo8CTwTrwjXDgZ5tztbRlEdRjBonQ== +extract-files@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" + integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== extract-from-css@^0.4.4: version "0.4.4" @@ -6306,10 +6247,12 @@ graphql-sse@^1.0.1: resolved "https://registry.yarnpkg.com/graphql-sse/-/graphql-sse-1.0.4.tgz#051598b0e06c225327aac659f19fcc18bcaa0191" integrity sha512-oB43ifRcEdElgep9jTP9qsj5cJ7Ny/1tAFyIl1W3A0hXRRg/P71tUHzMFBrRkEsJ9IA7MTp+RKSJfh52QR6PBQ== -graphql-tag@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.11.0.tgz#1deb53a01c46a7eb401d6cb59dec86fa1cccbffd" - integrity sha512-VmsD5pJqWJnQZMUeRwrDhfgoyqcfwEkvtpANqcoUG8/tOLkwNgU9mzub/Mc78OJMhHjx7gfAMTxzdG43VGg3bA== +graphql-tag@^2.11.0, graphql-tag@^2.12.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.1.tgz#b065ef885e4800e4afd0842811b718a205f4aa58" + integrity sha512-LPewEE1vzGkHnCO8zdOGogKsHHBdtpGyihow1UuMwp6RnZa0lAS7NcbvltLOuo4pi5diQCPASAXZkQq44ffixA== + dependencies: + tslib "^1.14.1" graphql-ws@^5.4.1: version "5.5.3" @@ -6473,6 +6416,20 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" @@ -8141,7 +8098,12 @@ lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -loose-envify@^1.0.0: +loglevel@^1.6.8: + version "1.7.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" + integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== + +loose-envify@^1.0.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -8641,10 +8603,10 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mock-apollo-client@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/mock-apollo-client/-/mock-apollo-client-0.7.0.tgz#5f70e75c842a9f3b3da2252f68fd47f2d9955f77" - integrity sha512-r0ICU01m007W0MwMej0lzlg1REtepDZ15Fyj8Hz9tiW/1TPb0PyHryGykrg9YhfbB8/+ZF2ovz+88yMF75TDoA== +mock-apollo-client@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mock-apollo-client/-/mock-apollo-client-1.2.0.tgz#72543df0d74577d29be1b34cecba8898c7e71451" + integrity sha512-zCVHv3p7zvUmen9zce9l965ZrI6rMbrm2/oqGaTerVYOaYskl/cVgTG/L7iIToTIpI7onk/f6tu8hxPXZdyy/g== moment-mini@^2.24.0: version "2.24.0" @@ -8934,6 +8896,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -9042,12 +9009,20 @@ opener@^1.5.2: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optimism@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.10.3.tgz#163268fdc741dea2fb50f300bedda80356445fd7" - integrity sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw== +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== dependencies: - "@wry/context" "^0.4.0" + is-wsl "^1.1.0" + +optimism@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.14.0.tgz#256fb079a3428585b40a3a8462f907e0abd2fc49" + integrity sha512-ygbNt8n4DOCVpkwiLF+IrKKeNHOjtr9aXLWGP9HNJGoblSGsnVbJLstcH6/nE9Xy5ZQtlkSioFQNnthmENW6FQ== + dependencies: + "@wry/context" "^0.5.2" + "@wry/trie" "^0.2.1" optionator@^0.8.1: version "0.8.3" @@ -9642,6 +9617,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" +prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + prosemirror-collab@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.2.2.tgz#8d2c0e82779cfef5d051154bd0836428bd6d9c4a" @@ -9965,7 +9949,7 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-is@^16.12.0: +react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -10536,7 +10520,7 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^2.1.0, serialize-javascript@^2.1.2: +serialize-javascript@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== @@ -11161,7 +11145,7 @@ stylis@^4.0.10: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240" integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg== -subscriptions-transport-ws@^0.11.0: +subscriptions-transport-ws@0.11.0, subscriptions-transport-ws@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz#baf88f050cba51d52afe781de5e81b3c31f89883" integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== @@ -11209,11 +11193,16 @@ swagger-ui-dist@^3.52.3: resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.52.3.tgz#a09b5cdccac69e3f5f1cbd258654a110119a7f0e" integrity sha512-7QSY4milmYx5O8dbzU5tTftiaoZt+4JGxahTTBiLAnbTvhTyzum9rsjDIJjC+xeT8Tt1KfB38UuQQjmrh2THDQ== -symbol-observable@^1.0.2, symbol-observable@^1.0.4: +symbol-observable@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-observable@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-2.0.3.tgz#5b521d3d07a43c351055fa43b8355b62d33fd16a" + integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -11551,11 +11540,13 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-invariant@^0.4.0: - version "0.4.4" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" - integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== +ts-invariant@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.6.1.tgz#eb4c52b45daaca8367abbfd6cff998ea871d592d" + integrity sha512-QQgN33g8E8yrdDuH29HASveLtbzMnRRgWh0i/JNTW4+zcLsdIOnfsgEDi/NKx4UckQyuMFt9Ujm6TWLWQ58Kvg== dependencies: + "@types/ungap__global-this" "^0.3.1" + "@ungap/global-this" "^0.4.2" tslib "^1.9.3" ts-node@^9: @@ -11585,7 +11576,7 @@ tslib@2.3.0, tslib@^2, tslib@^2.2.0, tslib@~2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.14.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -12041,13 +12032,13 @@ vscode-uri@^2.1.1, vscode-uri@^2.1.2: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A== -vue-apollo@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.0.3.tgz#7f29558df76eec0f03251847eef153816a261827" - integrity sha512-WJaQ1v/i46/oIPlKv7J0Tx6tTlbuaeCdhrAbL06h+Zca2gzr5ywjUFpl8ijMTGJsQ+Ph/U4xEpBFBOMxQmL+7g== +vue-apollo@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.0.7.tgz#97a031d45641faa4888a6d5a7f71c40834359704" + integrity sha512-EUfIn4cJmoflnDJiSNP8gH4fofIEzd0I2AWnd9nhHB8mddmzIfgSNjIRihDcRB10wypYG1OG0GcU335CFgZRfA== dependencies: chalk "^2.4.2" - serialize-javascript "^2.1.0" + serialize-javascript "^4.0.0" throttle-debounce "^2.1.0" vue-eslint-parser@^7.0.0, vue-eslint-parser@^7.4.1: @@ -12667,18 +12658,10 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zen-observable-ts@^0.8.21: - version "0.8.21" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" - integrity sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - -zen-observable@^0.8.0: - version "0.8.11" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.11.tgz#d3415885eeeb42ee5abb9821c95bb518fcd6d199" - integrity sha512-N3xXQVr4L61rZvGMpWe8XoCGX8vhU35dPyQ4fm5CY/KDlG0F75un14hjbckPXTDuKUY6V0dqR2giT6xN8Y4GEQ== +zen-observable@^0.8.14: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== zrender@5.2.1: version "5.2.1" |