From 13f0851653ec3c076941239added0406f719e43b Mon Sep 17 00:00:00 2001
From: Illya Klymov <iklymov@gitlab.com>
Date: Mon, 7 Oct 2024 12:55:04 +0300
Subject: [PATCH] Add warning if graphql field is missing during fleet update

EE: true
---
 .../standards_adherence_report/base_table.vue | 10 ++++++---
 .../components/violations_report/report.vue   | 14 ++++++++++--
 .../compliance_dashboard/constants.js         |  4 ++++
 .../javascripts/compliance_dashboard/utils.js |  8 +++++++
 .../compliance_dashboard/utils_spec.js        | 22 +++++++++++++++++++
 locale/gitlab.pot                             |  3 +++
 6 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/base_table.vue b/ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/base_table.vue
index 54f853aac6f7..1442bf4df613 100644
--- a/ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/base_table.vue
+++ b/ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/base_table.vue
@@ -7,8 +7,8 @@ import getProjectComplianceStandardsGroupAdherence from 'ee/compliance_dashboard
 import getProjectComplianceStandardsProjectAdherence from 'ee/compliance_dashboard/graphql/compliance_standards_project_adherence.query.graphql';
 import FrameworksInfo from '../shared/frameworks_info.vue';
 import Pagination from '../shared/pagination.vue';
-import { GRAPHQL_PAGE_SIZE } from '../../constants';
-import { isTopLevelGroup } from '../../utils';
+import { GRAPHQL_PAGE_SIZE, GRAPHQL_FIELD_MISSING_ERROR_MESSAGE } from '../../constants';
+import { isTopLevelGroup, isGraphqlFieldMissingError } from '../../utils';
 import {
   FAIL_STATUS,
   STANDARDS_ADHERENCE_CHECK_LABELS,
@@ -61,6 +61,7 @@ export default {
   data() {
     return {
       hasStandardsAdherenceFetchError: false,
+      customErrorText: null,
       hasFilterValueError: false,
       drawerId: null,
       drawerAdherence: {},
@@ -94,6 +95,9 @@ export default {
       error(e) {
         Sentry.captureException(e);
         this.hasStandardsAdherenceFetchError = true;
+        this.customErrorText = isGraphqlFieldMissingError(e, 'projectComplianceStandardsAdherence')
+          ? GRAPHQL_FIELD_MISSING_ERROR_MESSAGE
+          : null;
       },
     },
   },
@@ -269,7 +273,7 @@ export default {
       class="gl-mt-3"
       :dismissible="false"
     >
-      {{ $options.standardsAdherenceFetchError }}
+      {{ customErrorText || $options.standardsAdherenceFetchError }}
     </gl-alert>
     <gl-table
       :fields="fields"
diff --git a/ee/app/assets/javascripts/compliance_dashboard/components/violations_report/report.vue b/ee/app/assets/javascripts/compliance_dashboard/components/violations_report/report.vue
index 93e87dac6213..5ff5ef61d216 100644
--- a/ee/app/assets/javascripts/compliance_dashboard/components/violations_report/report.vue
+++ b/ee/app/assets/javascripts/compliance_dashboard/components/violations_report/report.vue
@@ -11,11 +11,17 @@ import { ISO_SHORT_FORMAT } from '~/vue_shared/constants';
 import getComplianceViolationsGroupQuery from '../../graphql/compliance_violations_group.query.graphql';
 import getComplianceViolationsProjectQuery from '../../graphql/compliance_violations_project.query.graphql';
 import { mapViolations } from '../../graphql/mappers';
-import { DEFAULT_PAGINATION_CURSORS, DEFAULT_SORT, GRAPHQL_PAGE_SIZE } from '../../constants';
+import {
+  DEFAULT_PAGINATION_CURSORS,
+  DEFAULT_SORT,
+  GRAPHQL_PAGE_SIZE,
+  GRAPHQL_FIELD_MISSING_ERROR_MESSAGE,
+} from '../../constants';
 import {
   buildDefaultViolationsFilterParams,
   isTopLevelGroup,
   parseViolationsQueryFilter,
+  isGraphqlFieldMissingError,
 } from '../../utils';
 import MergeRequestDrawer from './drawer.vue';
 import ViolationReason from './violations/reason.vue';
@@ -63,6 +69,7 @@ export default {
       defaultFilterParams,
       urlQuery: { ...defaultFilterParams },
       queryError: false,
+      customErrorText: false,
       violations: {
         list: [],
         pageInfo: {},
@@ -109,6 +116,9 @@ export default {
       error(e) {
         Sentry.captureException(e);
         this.queryError = true;
+        this.customErrorText = isGraphqlFieldMissingError(e, 'mergeRequestViolations')
+          ? GRAPHQL_FIELD_MISSING_ERROR_MESSAGE
+          : null;
       },
     },
   },
@@ -247,7 +257,7 @@ export default {
 <template>
   <section>
     <gl-alert v-if="queryError" variant="danger" class="gl-mt-3" :dismissible="false">
-      {{ $options.i18n.queryError }}
+      {{ customErrorText || $options.i18n.queryError }}
     </gl-alert>
     <violation-filter
       :show-project-filter="!projectPath"
diff --git a/ee/app/assets/javascripts/compliance_dashboard/constants.js b/ee/app/assets/javascripts/compliance_dashboard/constants.js
index 52350ca67221..f08286599061 100644
--- a/ee/app/assets/javascripts/compliance_dashboard/constants.js
+++ b/ee/app/assets/javascripts/compliance_dashboard/constants.js
@@ -77,3 +77,7 @@ export const POLICY_SCOPES_DOCS_URL = `${DOCS_URL_IN_EE_DIR}/user/application_se
 export const CREATE_FRAMEWORKS_DOCS_URL = `${DOCS_URL_IN_EE_DIR}/user/group/compliance_frameworks.html#prerequisites`;
 
 export const FEEDBACK_ISSUE_URL = 'https://gitlab.com/gitlab-org/gitlab/-/issues/481586';
+
+export const GRAPHQL_FIELD_MISSING_ERROR_MESSAGE = __(
+  'Your GitLab instance is currently being updated. Please try again later.',
+);
diff --git a/ee/app/assets/javascripts/compliance_dashboard/utils.js b/ee/app/assets/javascripts/compliance_dashboard/utils.js
index 7c208b374977..5eb3b2571a20 100644
--- a/ee/app/assets/javascripts/compliance_dashboard/utils.js
+++ b/ee/app/assets/javascripts/compliance_dashboard/utils.js
@@ -126,3 +126,11 @@ export function mapStandardsAdherenceQueryToFilters(filters) {
 
   return filterParams;
 }
+
+export const isGraphqlFieldMissingError = (error, field) => {
+  return Boolean(
+    error?.graphQLErrors?.some((e) =>
+      e?.message?.startsWith(`Field '${field}' doesn't exist on type`),
+    ),
+  );
+};
diff --git a/ee/spec/frontend/compliance_dashboard/utils_spec.js b/ee/spec/frontend/compliance_dashboard/utils_spec.js
index 2e24bd76bf15..7239a076096b 100644
--- a/ee/spec/frontend/compliance_dashboard/utils_spec.js
+++ b/ee/spec/frontend/compliance_dashboard/utils_spec.js
@@ -1,4 +1,5 @@
 import timezoneMock from 'timezone-mock';
+import { ApolloError } from '@apollo/client/core';
 import * as utils from 'ee/compliance_dashboard/utils';
 import {
   FRAMEWORKS_FILTER_TYPE_FRAMEWORK,
@@ -241,4 +242,25 @@ describe('compliance report utils', () => {
       expect(utils.checkFilterForChange({ currentFilters, newFilters })).toBe(false);
     });
   });
+
+  describe('isGraphqlFieldMissingError', () => {
+    const graphqlError = new ApolloError({
+      graphQLErrors: [
+        {
+          message: "Field 'foo' doesn't exist on type 'Project'",
+        },
+      ],
+    });
+
+    it('returns true when error looks like graphql one and references correct field', () => {
+      expect(utils.isGraphqlFieldMissingError(graphqlError, 'foo')).toBe(true);
+    });
+
+    it('returns false when error looks like graphql one but references other field', () => {
+      expect(utils.isGraphqlFieldMissingError(graphqlError, 'bar')).toBe(false);
+    });
+    it('returns false for other errors', () => {
+      expect(utils.isGraphqlFieldMissingError(new Error('test'), 'foo')).toBe(false);
+    });
+  });
 });
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e00417bfdfc7..bf6021136257 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -63757,6 +63757,9 @@ msgstr ""
 msgid "Your GitLab instance allows anyone to register for an account, which is a security risk on public-facing GitLab instances. You should deactivate new sign ups if public users aren't expected to register for an account."
 msgstr ""
 
+msgid "Your GitLab instance is currently being updated. Please try again later."
+msgstr ""
+
 msgid "Your GitLab version"
 msgstr ""
 
-- 
GitLab