This is an automated email from the ASF dual-hosted git repository.

kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new a498d6d10f refactor: Move fetchTimeRange to core package (#27852)
a498d6d10f is described below

commit a498d6d10f2819ca40f0ab846b337f55906e0424
Author: Kamil Gabryjelski <[email protected]>
AuthorDate: Wed Apr 3 18:34:23 2024 +0200

    refactor: Move fetchTimeRange to core package (#27852)
---
 .../superset-ui-core/src/connection/constants.ts   |   5 +
 .../superset-ui-core/src/connection/index.ts       |   1 +
 .../src/query}/getClientErrorObject.ts             |  54 ++---
 .../packages/superset-ui-core/src/query/index.ts   |   1 +
 .../superset-ui-core/src/query/types/Query.ts      |  21 +-
 .../src/time-comparison/fetchTimeRange.ts}         |  34 +--
 .../superset-ui-core/src/time-comparison/index.ts  |   1 +
 .../chart/components/ChartDataProvider.test.tsx    |  13 +-
 .../test/color/SharedLabelColorSingleton.test.ts   |  14 +-
 .../test/query/getClientErrorObject.test.ts        | 233 +++++++++++++++++++++
 .../test/time-comparison/fetchTimeRange.test.ts    | 118 +++++++++++
 superset-frontend/src/SqlLab/actions/sqlLab.js     |   4 +-
 .../AceEditorWrapper/useAnnotations.test.ts        |   2 +-
 .../components/AceEditorWrapper/useAnnotations.ts  |   4 +-
 .../SqlLab/components/ShareSqlLabQuery/index.tsx   |   2 +-
 .../src/components/Chart/ChartErrorMessage.tsx     |   2 +-
 .../src/components/Chart/chartAction.js            |   2 +-
 .../Datasource/ChangeDatasourceModal.tsx           |   8 +-
 .../src/components/Datasource/DatasourceEditor.jsx |   2 +-
 .../src/components/Datasource/DatasourceModal.tsx  |   4 +-
 .../ErrorMessage/BasicErrorAlert.test.tsx          |   3 +-
 .../components/ErrorMessage/BasicErrorAlert.tsx    |   3 +-
 .../ErrorMessage/DatabaseErrorMessage.test.tsx     |   2 +-
 .../DatasetNotFoundErrorMessage.test.tsx           |   2 +-
 .../components/ErrorMessage/ErrorAlert.test.tsx    |   3 +-
 .../src/components/ErrorMessage/ErrorAlert.tsx     |   9 +-
 .../ErrorMessageWithStackTrace.test.tsx            |   2 +-
 .../ErrorMessage/ErrorMessageWithStackTrace.tsx    |   3 +-
 .../ErrorMessage/MarshmallowErrorMessage.test.tsx  |   8 +-
 .../ErrorMessage/OAuth2RedirectMessage.test.tsx    |   7 +-
 .../ErrorMessage/ParameterErrorMessage.test.tsx    |   2 +-
 .../ErrorMessage/TimeoutErrorMessage.test.tsx      |   2 +-
 .../src/components/ErrorMessage/types.ts           |  89 +-------
 .../src/components/Select/AsyncSelect.tsx          |   8 +-
 .../src/components/TableSelector/index.tsx         |  11 +-
 superset-frontend/src/components/Tags/utils.tsx    |  11 +-
 .../src/dashboard/actions/dashboardInfo.ts         |   8 +-
 .../src/dashboard/actions/dashboardState.js        |   2 +-
 .../src/dashboard/actions/sliceEntities.ts         |   8 +-
 .../dashboard/components/PropertiesModal/index.tsx |   2 +-
 .../components/URLShortLinkButton/index.tsx        |   3 +-
 .../FilterBar/FilterControls/FilterValue.tsx       |   6 +-
 .../FiltersConfigForm/ColumnSelect.test.tsx        |   4 +-
 .../FiltersConfigForm/ColumnSelect.tsx             |   9 +-
 .../FiltersConfigForm/DatasetSelect.tsx            |   7 +-
 .../FiltersConfigForm/FiltersConfigForm.tsx        |   6 +-
 .../src/explore/actions/datasourcesActions.test.ts |   4 +-
 .../src/explore/actions/datasourcesActions.ts      |   3 +-
 .../DataTablesPane/components/useResultsPane.tsx   |   2 +-
 .../explore/components/PropertiesModal/index.tsx   |   2 +-
 .../controls/DateFilterControl/DateFilterLabel.tsx |   2 +-
 .../DateFilterControl/components/AdvancedFrame.tsx |   3 +-
 .../controls/DateFilterControl/tests/utils.test.ts |  33 ---
 .../DateFilterControl/utils/dateFilterUtils.ts     |  47 +----
 .../controls/DateFilterControl/utils/dateParser.ts |   2 +-
 .../utils/useGetTimeRangeLabel.test.ts             |   6 +-
 .../FilterControl/utils/useGetTimeRangeLabel.tsx   |   3 +-
 .../controls/SelectAsyncControl/index.tsx          |   3 +-
 .../explore/components/controls/ViewQueryModal.tsx |   8 +-
 .../src/features/reports/ReportModal/index.tsx     |   3 +-
 .../src/hooks/apiResources/queryApi.ts             |   4 +-
 .../src/middleware/asyncEvent.test.ts              |   5 +-
 superset-frontend/src/middleware/asyncEvent.ts     |   8 +-
 .../src/pages/AnnotationList/index.tsx             |   9 +-
 superset-frontend/src/pages/Chart/index.tsx        |   2 +-
 superset-frontend/src/setup/setupApp.ts            |   4 +-
 superset-frontend/src/setup/setupErrorMessages.ts  |   2 +-
 superset-frontend/src/utils/errorMessages.ts       |  26 ---
 .../src/utils/getClientErrorObject.test.ts         |  83 --------
 superset-frontend/src/views/CRUD/hooks.ts          |   9 +-
 superset-frontend/src/views/CRUD/utils.tsx         |   2 +-
 superset/errors.py                                 |   4 +-
 72 files changed, 561 insertions(+), 463 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-core/src/connection/constants.ts 
b/superset-frontend/packages/superset-ui-core/src/connection/constants.ts
index 370c1a50ed..98a8c38574 100644
--- a/superset-frontend/packages/superset-ui-core/src/connection/constants.ts
+++ b/superset-frontend/packages/superset-ui-core/src/connection/constants.ts
@@ -34,3 +34,8 @@ export const DEFAULT_FETCH_RETRY_OPTIONS: FetchRetryOptions = 
{
   retryDelay: 1000,
   retryOn: [503],
 };
+
+export const COMMON_ERR_MESSAGES = {
+  SESSION_TIMED_OUT:
+    'Your session timed out, please refresh your page and try again.',
+};
diff --git 
a/superset-frontend/packages/superset-ui-core/src/connection/index.ts 
b/superset-frontend/packages/superset-ui-core/src/connection/index.ts
index 594bbcedef..3ac9806a05 100644
--- a/superset-frontend/packages/superset-ui-core/src/connection/index.ts
+++ b/superset-frontend/packages/superset-ui-core/src/connection/index.ts
@@ -22,4 +22,5 @@ export { default as SupersetClient } from './SupersetClient';
 export { default as SupersetClientClass } from './SupersetClientClass';
 
 export * from './types';
+export * from './constants';
 export { default as __hack_reexport_connection } from './types';
diff --git a/superset-frontend/src/utils/getClientErrorObject.ts 
b/superset-frontend/packages/superset-ui-core/src/query/getClientErrorObject.ts
similarity index 97%
rename from superset-frontend/src/utils/getClientErrorObject.ts
rename to 
superset-frontend/packages/superset-ui-core/src/query/getClientErrorObject.ts
index a5f2871872..8b4b62cf76 100644
--- a/superset-frontend/src/utils/getClientErrorObject.ts
+++ 
b/superset-frontend/packages/superset-ui-core/src/query/getClientErrorObject.ts
@@ -16,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { JsonObject, SupersetClientResponse, t } from '@superset-ui/core';
 import {
+  COMMON_ERR_MESSAGES,
+  JsonObject,
+  SupersetClientResponse,
+  t,
   SupersetError,
   ErrorTypeEnum,
-} from 'src/components/ErrorMessage/types';
-import COMMON_ERR_MESSAGES from './errorMessages';
+} from '@superset-ui/core';
 
 // The response always contains an error attribute, can contain anything from 
the
 // SupersetClientResponse object, and can contain a spread JSON blob
@@ -86,29 +88,6 @@ export function parseErrorJson(responseObject: JsonObject): 
ClientErrorObject {
   return { ...error, error: error.error }; // explicit ClientErrorObject
 }
 
-/*
- * Utility to get standardized error text for generic update failures
- */
-export async function getErrorText(
-  errorObject: ErrorType,
-  source: ErrorTextSource,
-) {
-  const { error, message } = await getClientErrorObject(errorObject);
-  let errorText = t('Sorry, an unknown error occurred.');
-
-  if (error) {
-    errorText = t(
-      'Sorry, there was an error saving this %s: %s',
-      source,
-      error,
-    );
-  }
-  if (typeof message === 'string' && message === 'Forbidden') {
-    errorText = t('You do not have permission to edit this %s', source);
-  }
-  return errorText;
-}
-
 export function getClientErrorObject(
   response:
     | SupersetClientResponse
@@ -203,6 +182,29 @@ export function getClientErrorObject(
   });
 }
 
+/*
+ * Utility to get standardized error text for generic update failures
+ */
+export async function getErrorText(
+  errorObject: ErrorType,
+  source: ErrorTextSource,
+) {
+  const { error, message } = await getClientErrorObject(errorObject);
+  let errorText = t('Sorry, an unknown error occurred.');
+
+  if (error) {
+    errorText = t(
+      'Sorry, there was an error saving this %s: %s',
+      source,
+      error,
+    );
+  }
+  if (typeof message === 'string' && message === 'Forbidden') {
+    errorText = t('You do not have permission to edit this %s', source);
+  }
+  return errorText;
+}
+
 export function getClientErrorMessage(
   message: string,
   clientError?: ClientErrorObject,
diff --git a/superset-frontend/packages/superset-ui-core/src/query/index.ts 
b/superset-frontend/packages/superset-ui-core/src/query/index.ts
index bb83e3d340..434fe95798 100644
--- a/superset-frontend/packages/superset-ui-core/src/query/index.ts
+++ b/superset-frontend/packages/superset-ui-core/src/query/index.ts
@@ -31,6 +31,7 @@ export { default as normalizeOrderBy } from 
'./normalizeOrderBy';
 export { normalizeTimeColumn } from './normalizeTimeColumn';
 export { default as extractQueryFields } from './extractQueryFields';
 export * from './getXAxis';
+export * from './getClientErrorObject';
 
 export * from './types/AnnotationLayer';
 export * from './types/QueryFormData';
diff --git 
a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts 
b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts
index 718f10514c..4d5ccaf6f0 100644
--- a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts
+++ b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts
@@ -166,6 +166,7 @@ export interface QueryContext {
   form_data?: QueryFormData;
 }
 
+// Keep in sync with superset/errors.py
 export const ErrorTypeEnum = {
   // Frontend errors
   FRONTEND_CSRF_ERROR: 'FRONTEND_CSRF_ERROR',
@@ -187,9 +188,10 @@ export const ErrorTypeEnum = {
   CONNECTION_UNKNOWN_DATABASE_ERROR: 'CONNECTION_UNKNOWN_DATABASE_ERROR',
   CONNECTION_DATABASE_PERMISSIONS_ERROR:
     'CONNECTION_DATABASE_PERMISSIONS_ERROR',
-  CONNECTION_MISSING_PARAMETERS_ERRORS: 'CONNECTION_MISSING_PARAMETERS_ERRORS',
+  CONNECTION_MISSING_PARAMETERS_ERROR: 'CONNECTION_MISSING_PARAMETERS_ERROR',
   OBJECT_DOES_NOT_EXIST_ERROR: 'OBJECT_DOES_NOT_EXIST_ERROR',
   SYNTAX_ERROR: 'SYNTAX_ERROR',
+  CONNECTION_DATABASE_TIMEOUT: 'CONNECTION_DATABASE_TIMEOUT',
 
   // Viz errors
   VIZ_GET_DF_ERROR: 'VIZ_GET_DF_ERROR',
@@ -203,12 +205,17 @@ export const ErrorTypeEnum = {
   DATABASE_SECURITY_ACCESS_ERROR: 'DATABASE_SECURITY_ACCESS_ERROR',
   QUERY_SECURITY_ACCESS_ERROR: 'QUERY_SECURITY_ACCESS_ERROR',
   MISSING_OWNERSHIP_ERROR: 'MISSING_OWNERSHIP_ERROR',
+  USER_ACTIVITY_SECURITY_ACCESS_ERROR: 'USER_ACTIVITY_SECURITY_ACCESS_ERROR',
+  DASHBOARD_SECURITY_ACCESS_ERROR: 'DASHBOARD_SECURITY_ACCESS_ERROR',
+  CHART_SECURITY_ACCESS_ERROR: 'CHART_SECURITY_ACCESS_ERROR',
+  OAUTH2_REDIRECT: 'OAUTH2_REDIRECT',
+  OAUTH2_REDIRECT_ERROR: 'OAUTH2_REDIRECT_ERROR',
 
   // Other errors
   BACKEND_TIMEOUT_ERROR: 'BACKEND_TIMEOUT_ERROR',
   DATABASE_NOT_FOUND_ERROR: 'DATABASE_NOT_FOUND_ERROR',
 
-  // Sqllab error
+  // Sql Lab errors
   MISSING_TEMPLATE_PARAMS_ERROR: 'MISSING_TEMPLATE_PARAMS_ERROR',
   INVALID_TEMPLATE_PARAMS_ERROR: 'INVALID_TEMPLATE_PARAMS_ERROR',
   RESULTS_BACKEND_NOT_CONFIGURED_ERROR: 'RESULTS_BACKEND_NOT_CONFIGURED_ERROR',
@@ -218,6 +225,8 @@ export const ErrorTypeEnum = {
   SQLLAB_TIMEOUT_ERROR: 'SQLLAB_TIMEOUT_ERROR',
   RESULTS_BACKEND_ERROR: 'RESULTS_BACKEND_ERROR',
   ASYNC_WORKERS_ERROR: 'ASYNC_WORKERS_ERROR',
+  ADHOC_SUBQUERY_NOT_ALLOWED_ERROR: 'ADHOC_SUBQUERY_NOT_ALLOWED_ERROR',
+  INVALID_SQL_ERROR: 'INVALID_SQL_ERROR',
 
   // Generic errors
   GENERIC_COMMAND_ERROR: 'GENERIC_COMMAND_ERROR',
@@ -226,16 +235,20 @@ export const ErrorTypeEnum = {
   // API errors
   INVALID_PAYLOAD_FORMAT_ERROR: 'INVALID_PAYLOAD_FORMAT_ERROR',
   INVALID_PAYLOAD_SCHEMA_ERROR: 'INVALID_PAYLOAD_SCHEMA_ERROR',
+  MARSHMALLOW_ERROR: 'MARSHMALLOW_ERROR',
+
+  // Report errors
+  REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR',
 } as const;
 
 type ValueOf<T> = T[keyof T];
 
 export type ErrorType = ValueOf<typeof ErrorTypeEnum>;
 
-// Keep in sync with superset/views/errors.py
+// Keep in sync with superset/errors.py
 export type ErrorLevel = 'info' | 'warning' | 'error';
 
-export type ErrorSource = 'dashboard' | 'explore' | 'sqllab';
+export type ErrorSource = 'dashboard' | 'explore' | 'sqllab' | 'crud';
 
 export type SupersetError<ExtraType = Record<string, any> | null> = {
   error_type: ErrorType;
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
 
b/superset-frontend/packages/superset-ui-core/src/time-comparison/fetchTimeRange.ts
similarity index 70%
copy from 
superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
copy to 
superset-frontend/packages/superset-ui-core/src/time-comparison/fetchTimeRange.ts
index aad2f9984d..50509af52b 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
+++ 
b/superset-frontend/packages/superset-ui-core/src/time-comparison/fetchTimeRange.ts
@@ -17,15 +17,7 @@
  * under the License.
  */
 import rison from 'rison';
-import { SupersetClient, NO_TIME_RANGE, JsonObject } from '@superset-ui/core';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
-import { useSelector } from 'react-redux';
-import {
-  COMMON_RANGE_VALUES_SET,
-  CALENDAR_RANGE_VALUES_SET,
-  customTimeRangeDecode,
-} from '.';
-import { FrameType } from '../types';
+import { SupersetClient, getClientErrorObject } from '@superset-ui/core';
 
 export const SEPARATOR = ' : ';
 
@@ -47,22 +39,6 @@ export const formatTimeRange = (
   )} ≤ ${columnPlaceholder} < ${formatDateEndpoint(splitDateRange[1])}`;
 };
 
-export const guessFrame = (timeRange: string): FrameType => {
-  if (COMMON_RANGE_VALUES_SET.has(timeRange)) {
-    return 'Common';
-  }
-  if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) {
-    return 'Calendar';
-  }
-  if (timeRange === NO_TIME_RANGE) {
-    return 'No filter';
-  }
-  if (customTimeRangeDecode(timeRange).matchedFlag) {
-    return 'Custom';
-  }
-  return 'Advanced';
-};
-
 export const fetchTimeRange = async (
   timeRange: string,
   columnPlaceholder = 'col',
@@ -85,11 +61,3 @@ export const fetchTimeRange = async (
     };
   }
 };
-
-export function useDefaultTimeFilter() {
-  return (
-    useSelector(
-      (state: JsonObject) => state?.common?.conf?.DEFAULT_TIME_FILTER,
-    ) ?? NO_TIME_RANGE
-  );
-}
diff --git 
a/superset-frontend/packages/superset-ui-core/src/time-comparison/index.ts 
b/superset-frontend/packages/superset-ui-core/src/time-comparison/index.ts
index 4b9fb361fd..ad5b5f5918 100644
--- a/superset-frontend/packages/superset-ui-core/src/time-comparison/index.ts
+++ b/superset-frontend/packages/superset-ui-core/src/time-comparison/index.ts
@@ -21,3 +21,4 @@ export * from './types';
 
 export { default as getComparisonInfo } from './getComparisonInfo';
 export { default as getComparisonFilters } from './getComparisonFilters';
+export { SEPARATOR, fetchTimeRange } from './fetchTimeRange';
diff --git 
a/superset-frontend/packages/superset-ui-core/test/chart/components/ChartDataProvider.test.tsx
 
b/superset-frontend/packages/superset-ui-core/test/chart/components/ChartDataProvider.test.tsx
index 2947fd9f94..8423ee99ad 100644
--- 
a/superset-frontend/packages/superset-ui-core/test/chart/components/ChartDataProvider.test.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/test/chart/components/ChartDataProvider.test.tsx
@@ -49,14 +49,13 @@ const mockLoadQueryData = jest.fn<Promise<unknown>, 
unknown[]>(
   createArrayPromise,
 );
 
+const actual = jest.requireActual('../../../src/chart/clients/ChartClient');
 // ChartClient is now a mock
-jest.mock('../../../src/chart/clients/ChartClient', () =>
-  jest.fn().mockImplementation(() => ({
-    loadDatasource: mockLoadDatasource,
-    loadFormData: mockLoadFormData,
-    loadQueryData: mockLoadQueryData,
-  })),
-);
+jest.spyOn(actual, 'default').mockImplementation(() => ({
+  loadDatasource: mockLoadDatasource,
+  loadFormData: mockLoadFormData,
+  loadQueryData: mockLoadQueryData,
+}));
 
 const ChartClientMock = ChartClient as jest.Mock<ChartClient>;
 
diff --git 
a/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts
 
b/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts
index 8f89ae8a69..ca3f89a523 100644
--- 
a/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts
+++ 
b/superset-frontend/packages/superset-ui-core/test/color/SharedLabelColorSingleton.test.ts
@@ -25,13 +25,11 @@ import {
   SharedLabelColor,
   SharedLabelColorSource,
 } from '@superset-ui/core';
-import { getAnalogousColors } from '../../src/color/utils';
 
-jest.mock('../../src/color/utils', () => ({
-  getAnalogousColors: jest
-    .fn()
-    .mockImplementation(() => ['red', 'green', 'blue']),
-}));
+const actual = jest.requireActual('../../src/color/utils');
+const getAnalogousColorsSpy = jest
+  .spyOn(actual, 'getAnalogousColors')
+  .mockImplementation(() => ['red', 'green', 'blue']);
 
 describe('SharedLabelColor', () => {
   beforeAll(() => {
@@ -161,7 +159,7 @@ describe('SharedLabelColor', () => {
       sharedLabelColor.updateColorMap('', 'testColors');
       const colorMap = sharedLabelColor.getColorMap();
       expect(Object.fromEntries(colorMap)).not.toEqual({});
-      expect(getAnalogousColors).not.toBeCalled();
+      expect(getAnalogousColorsSpy).not.toBeCalled();
     });
 
     it('should use analagous colors', () => {
@@ -176,7 +174,7 @@ describe('SharedLabelColor', () => {
       sharedLabelColor.updateColorMap('', 'testColors');
       const colorMap = sharedLabelColor.getColorMap();
       expect(Object.fromEntries(colorMap)).not.toEqual({});
-      expect(getAnalogousColors).toBeCalled();
+      expect(getAnalogousColorsSpy).toBeCalled();
     });
   });
 
diff --git 
a/superset-frontend/packages/superset-ui-core/test/query/getClientErrorObject.test.ts
 
b/superset-frontend/packages/superset-ui-core/test/query/getClientErrorObject.test.ts
new file mode 100644
index 0000000000..c37e6fbe93
--- /dev/null
+++ 
b/superset-frontend/packages/superset-ui-core/test/query/getClientErrorObject.test.ts
@@ -0,0 +1,233 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {
+  COMMON_ERR_MESSAGES,
+  getClientErrorMessage,
+  getClientErrorObject,
+  getErrorText,
+  parseErrorJson,
+  ErrorTypeEnum,
+} from '@superset-ui/core';
+
+it('Returns a Promise', () => {
+  const response = getClientErrorObject('error');
+  expect(response instanceof Promise).toBe(true);
+});
+
+it('Returns a Promise that resolves to an object with an error key', async () 
=> {
+  const error = 'error';
+
+  const errorObj = await getClientErrorObject(error);
+  expect(errorObj).toMatchObject({ error });
+});
+
+it('Handles Response that can be parsed as json', async () => {
+  const jsonError = { something: 'something', error: 'Error message' };
+  const jsonErrorString = JSON.stringify(jsonError);
+
+  const errorObj = await getClientErrorObject(new Response(jsonErrorString));
+  expect(errorObj).toMatchObject(jsonError);
+});
+
+it('Handles backwards compatibility between old error messages and the new 
SIP-40 errors format', async () => {
+  const jsonError = {
+    errors: [
+      {
+        error_type: ErrorTypeEnum.GENERIC_DB_ENGINE_ERROR,
+        extra: { engine: 'presto', link: 'https://www.google.com' },
+        level: 'error',
+        message: 'presto error: test error',
+      },
+    ],
+  };
+  const jsonErrorString = JSON.stringify(jsonError);
+
+  const errorObj = await getClientErrorObject(new Response(jsonErrorString));
+  expect(errorObj.error).toEqual(jsonError.errors[0].message);
+  expect(errorObj.link).toEqual(jsonError.errors[0].extra.link);
+});
+
+it('Handles Response that can be parsed as text', async () => {
+  const textError = 'Hello I am a text error';
+
+  const errorObj = await getClientErrorObject(new Response(textError));
+  expect(errorObj).toMatchObject({ error: textError });
+});
+
+it('Handles TypeError Response', async () => {
+  const error = new TypeError('Failed to fetch');
+
+  // @ts-ignore
+  const errorObj = await getClientErrorObject(error);
+  expect(errorObj).toMatchObject({ error: 'Network error' });
+});
+
+it('Handles timeout error', async () => {
+  const errorObj = await getClientErrorObject({
+    timeout: 1000,
+    statusText: 'timeout',
+  });
+  expect(errorObj).toMatchObject({
+    timeout: 1000,
+    statusText: 'timeout',
+    error: 'Request timed out',
+    errors: [
+      {
+        error_type: ErrorTypeEnum.FRONTEND_TIMEOUT_ERROR,
+        extra: {
+          timeout: 1,
+          issue_codes: [
+            {
+              code: 1000,
+              message: 'Issue 1000 - The dataset is too large to query.',
+            },
+            {
+              code: 1001,
+              message: 'Issue 1001 - The database is under an unusual load.',
+            },
+          ],
+        },
+        level: 'error',
+        message: 'Request timed out',
+      },
+    ],
+  });
+});
+
+it('Handles plain text as input', async () => {
+  const error = 'error';
+
+  const errorObj = await getClientErrorObject(error);
+  expect(errorObj).toMatchObject({ error });
+});
+
+it('Handles error with status text and message', async () => {
+  const statusText = 'status';
+  const message = 'message';
+
+  // @ts-ignore
+  expect(await getClientErrorObject({ statusText, message })).toMatchObject({
+    error: statusText,
+  });
+  // @ts-ignore
+  expect(await getClientErrorObject({ message })).toMatchObject({
+    error: message,
+  });
+  // @ts-ignore
+  expect(await getClientErrorObject({})).toMatchObject({
+    error: 'An error occurred',
+  });
+});
+
+it('getClientErrorMessage', () => {
+  expect(getClientErrorMessage('error')).toEqual('error');
+  expect(
+    getClientErrorMessage('error', {
+      error: 'client error',
+      message: 'client error message',
+    }),
+  ).toEqual('error:\nclient error message');
+  expect(
+    getClientErrorMessage('error', {
+      error: 'client error',
+    }),
+  ).toEqual('error:\nclient error');
+});
+
+it('parseErrorJson with message', () => {
+  expect(parseErrorJson({ message: 'error message' })).toEqual({
+    message: 'error message',
+    error: 'error message',
+  });
+
+  expect(
+    parseErrorJson({
+      message: {
+        key1: ['error message1', 'error message2'],
+        key2: ['error message3', 'error message4'],
+      },
+    }),
+  ).toEqual({
+    message: {
+      key1: ['error message1', 'error message2'],
+      key2: ['error message3', 'error message4'],
+    },
+    error: 'error message1',
+  });
+
+  expect(
+    parseErrorJson({
+      message: {},
+    }),
+  ).toEqual({
+    message: {},
+    error: 'Invalid input',
+  });
+});
+
+it('parseErrorJson with stacktrace', () => {
+  expect(
+    parseErrorJson({ error: 'error message', stack: 'stacktrace' }),
+  ).toEqual({
+    error: 'Unexpected error: (no description, click to see stack trace)',
+    stacktrace: 'stacktrace',
+    stack: 'stacktrace',
+  });
+
+  expect(
+    parseErrorJson({
+      error: 'error message',
+      description: 'error description',
+      stack: 'stacktrace',
+    }),
+  ).toEqual({
+    error: 'Unexpected error: error description',
+    stacktrace: 'stacktrace',
+    description: 'error description',
+    stack: 'stacktrace',
+  });
+});
+
+it('parseErrorJson with CSRF', () => {
+  expect(
+    parseErrorJson({
+      responseText: 'CSRF',
+    }),
+  ).toEqual({
+    error: COMMON_ERR_MESSAGES.SESSION_TIMED_OUT,
+    responseText: 'CSRF',
+  });
+});
+
+it('getErrorText', async () => {
+  expect(await getErrorText('error', 'dashboard')).toEqual(
+    'Sorry, there was an error saving this dashboard: error',
+  );
+
+  const error = JSON.stringify({ message: 'Forbidden' });
+  expect(await getErrorText(new Response(error), 'dashboard')).toEqual(
+    'You do not have permission to edit this dashboard',
+  );
+  expect(
+    await getErrorText(
+      new Response(JSON.stringify({ status: 'error' })),
+      'dashboard',
+    ),
+  ).toEqual('Sorry, an unknown error occurred.');
+});
diff --git 
a/superset-frontend/packages/superset-ui-core/test/time-comparison/fetchTimeRange.test.ts
 
b/superset-frontend/packages/superset-ui-core/test/time-comparison/fetchTimeRange.test.ts
new file mode 100644
index 0000000000..e07fa8617f
--- /dev/null
+++ 
b/superset-frontend/packages/superset-ui-core/test/time-comparison/fetchTimeRange.test.ts
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import fetchMock from 'fetch-mock';
+import { fetchTimeRange } from '@superset-ui/core';
+import {
+  buildTimeRangeString,
+  formatTimeRange,
+} from '../../src/time-comparison/fetchTimeRange';
+
+afterEach(fetchMock.restore);
+
+it('generates proper time range string', () => {
+  expect(
+    buildTimeRangeString('2010-07-30T00:00:00', '2020-07-30T00:00:00'),
+  ).toBe('2010-07-30T00:00:00 : 2020-07-30T00:00:00');
+  expect(buildTimeRangeString('', '2020-07-30T00:00:00')).toBe(
+    ' : 2020-07-30T00:00:00',
+  );
+  expect(buildTimeRangeString('', '')).toBe(' : ');
+});
+
+it('generates a readable time range', () => {
+  expect(formatTimeRange('Last 7 days')).toBe('Last 7 days');
+  expect(formatTimeRange('No filter')).toBe('No filter');
+  expect(formatTimeRange('Yesterday : Tomorrow')).toBe(
+    'Yesterday ≤ col < Tomorrow',
+  );
+  expect(formatTimeRange('2010-07-30T00:00:00 : 2020-07-30T00:00:00')).toBe(
+    '2010-07-30 ≤ col < 2020-07-30',
+  );
+  expect(formatTimeRange('2010-07-30T01:00:00 : ')).toBe(
+    '2010-07-30T01:00:00 ≤ col < ∞',
+  );
+  expect(formatTimeRange(' : 2020-07-30T00:00:00')).toBe(
+    '-∞ ≤ col < 2020-07-30',
+  );
+});
+
+it('returns a formatted time range from response', async () => {
+  fetchMock.get("glob:*/api/v1/time_range/?q='Last+day'", {
+    result: [
+      {
+        since: '2021-04-13T00:00:00',
+        until: '2021-04-14T00:00:00',
+        timeRange: 'Last day',
+      },
+    ],
+  });
+
+  const timeRange = await fetchTimeRange('Last day', 'temporal_col');
+  expect(timeRange).toEqual({
+    value: '2021-04-13 ≤ temporal_col < 2021-04-14',
+  });
+});
+
+it('returns a formatted time range from empty response', async () => {
+  fetchMock.get("glob:*/api/v1/time_range/?q='Last+day'", {
+    result: [],
+  });
+
+  const timeRange = await fetchTimeRange('Last day');
+  expect(timeRange).toEqual({
+    value: '-∞ ≤ col < ∞',
+  });
+});
+
+it('returns a formatted error message from response', async () => {
+  fetchMock.getOnce("glob:*/api/v1/time_range/?q='Last+day'", {
+    throws: new Response(JSON.stringify({ message: 'Network error' })),
+  });
+  let timeRange = await fetchTimeRange('Last day');
+  expect(timeRange).toEqual({
+    error: 'Network error',
+  });
+
+  fetchMock.getOnce(
+    "glob:*/api/v1/time_range/?q='Last+day'",
+    {
+      throws: new Error('Internal Server Error'),
+    },
+    { overwriteRoutes: true },
+  );
+  timeRange = await fetchTimeRange('Last day');
+  expect(timeRange).toEqual({
+    error: 'Internal Server Error',
+  });
+
+  fetchMock.getOnce(
+    "glob:*/api/v1/time_range/?q='Last+day'",
+    {
+      throws: new Response(JSON.stringify({ statusText: 'Network error' }), {
+        statusText: 'Network error',
+      }),
+    },
+    { overwriteRoutes: true },
+  );
+  timeRange = await fetchTimeRange('Last day');
+  expect(timeRange).toEqual({
+    error: 'Network error',
+  });
+});
diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js 
b/superset-frontend/src/SqlLab/actions/sqlLab.js
index fa5198e532..6befa17ac1 100644
--- a/superset-frontend/src/SqlLab/actions/sqlLab.js
+++ b/superset-frontend/src/SqlLab/actions/sqlLab.js
@@ -23,6 +23,8 @@ import {
   SupersetClient,
   t,
   isFeatureEnabled,
+  COMMON_ERR_MESSAGES,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import { invert, mapKeys } from 'lodash';
 
@@ -33,8 +35,6 @@ import {
   addSuccessToast as addSuccessToastAction,
   addWarningToast as addWarningToastAction,
 } from 'src/components/MessageToasts/actions';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
-import COMMON_ERR_MESSAGES from 'src/utils/errorMessages';
 import { LOG_ACTIONS_SQLLAB_FETCH_FAILED_QUERY } from 'src/logger/LogUtils';
 import getBootstrapData from 'src/utils/getBootstrapData';
 import { logEvent } from 'src/logger/actions';
diff --git 
a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.test.ts
 
b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.test.ts
index ddabbea55b..0f17fdafcb 100644
--- 
a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.test.ts
+++ 
b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.test.ts
@@ -18,13 +18,13 @@
  */
 import fetchMock from 'fetch-mock';
 import { act, renderHook } from '@testing-library/react-hooks';
+import { COMMON_ERR_MESSAGES } from '@superset-ui/core';
 import {
   createWrapper,
   defaultStore as store,
 } from 'spec/helpers/testing-library';
 import { api } from 'src/hooks/apiResources/queryApi';
 import { initialState } from 'src/SqlLab/fixtures';
-import COMMON_ERR_MESSAGES from 'src/utils/errorMessages';
 import { useAnnotations } from './useAnnotations';
 
 const fakeApiResult = {
diff --git 
a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.ts 
b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.ts
index f6924a243f..f640e30779 100644
--- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.ts
+++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useAnnotations.ts
@@ -18,16 +18,14 @@
  */
 import { useSelector } from 'react-redux';
 
+import { COMMON_ERR_MESSAGES, ClientErrorObject, t } from '@superset-ui/core';
 import { SqlLabRootState } from 'src/SqlLab/types';
-import COMMON_ERR_MESSAGES from 'src/utils/errorMessages';
 import { VALIDATION_DEBOUNCE_MS } from 'src/SqlLab/constants';
 import {
   FetchValidationQueryParams,
   useQueryValidationsQuery,
 } from 'src/hooks/apiResources';
 import { useDebounceValue } from 'src/hooks/useDebounceValue';
-import { ClientErrorObject } from 'src/utils/getClientErrorObject';
-import { t } from '@superset-ui/core';
 
 export function useAnnotations(params: FetchValidationQueryParams) {
   const { sql, dbId, schema, templateParams } = params;
diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx 
b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx
index 8f4cde1a66..9309ce7c05 100644
--- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx
+++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/index.tsx
@@ -23,13 +23,13 @@ import {
   t,
   useTheme,
   isFeatureEnabled,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import Button from 'src/components/Button';
 import Icons from 'src/components/Icons';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import CopyToClipboard from 'src/components/CopyToClipboard';
 import { storeQuery } from 'src/utils/common';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor';
 
 interface ShareSqlLabQueryProps {
diff --git a/superset-frontend/src/components/Chart/ChartErrorMessage.tsx 
b/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
index 077ca2282a..b15a20ea67 100644
--- a/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
+++ b/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
@@ -18,9 +18,9 @@
  */
 
 import React from 'react';
+import { SupersetError } from '@superset-ui/core';
 import { useChartOwnerNames } from 'src/hooks/apiResources';
 import ErrorMessageWithStackTrace from 
'src/components/ErrorMessage/ErrorMessageWithStackTrace';
-import { SupersetError } from 'src/components/ErrorMessage/types';
 
 interface Props {
   chartId: string;
diff --git a/superset-frontend/src/components/Chart/chartAction.js 
b/superset-frontend/src/components/Chart/chartAction.js
index 9597a3cbb3..d4657988ca 100644
--- a/superset-frontend/src/components/Chart/chartAction.js
+++ b/superset-frontend/src/components/Chart/chartAction.js
@@ -25,6 +25,7 @@ import {
   SupersetClient,
   t,
   isFeatureEnabled,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import { getControlsState } from 'src/explore/store';
 import {
@@ -38,7 +39,6 @@ import {
 import { addDangerToast } from 'src/components/MessageToasts/actions';
 import { logEvent } from 'src/logger/actions';
 import { Logger, LOG_ACTIONS_LOAD_CHART } from 'src/logger/LogUtils';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { allowCrossDomain as domainShardingEnabled } from 
'src/utils/hostNamesConfig';
 import { updateDataMask } from 'src/dataMask/actions';
 import { waitForAsyncData } from 'src/middleware/asyncEvent';
diff --git 
a/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx 
b/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx
index 5e837f0a26..7fde5645a1 100644
--- a/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx
+++ b/superset-frontend/src/components/Datasource/ChangeDatasourceModal.tsx
@@ -24,7 +24,12 @@ import React, {
   useCallback,
 } from 'react';
 import Alert from 'src/components/Alert';
-import { SupersetClient, t, styled } from '@superset-ui/core';
+import {
+  SupersetClient,
+  t,
+  styled,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import TableView, { EmptyWrapperType } from 'src/components/TableView';
 import { ServerPagination, SortByType } from 'src/components/TableView/types';
 import StyledModal from 'src/components/Modal';
@@ -33,7 +38,6 @@ import { useListViewResource } from 'src/views/CRUD/hooks';
 import Dataset from 'src/types/Dataset';
 import { useDebouncedEffect } from 'src/explore/exploreUtils';
 import { SLOW_DEBOUNCE } from 'src/constants';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import Loading from 'src/components/Loading';
 import { AntdInput } from 'src/components';
 import { Input } from 'src/components/Input';
diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx 
b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
index cc18ec0fe4..b9af27d2af 100644
--- a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
+++ b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx
@@ -34,6 +34,7 @@ import {
   SupersetClient,
   t,
   withTheme,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import { Select, AsyncSelect, Row, Col } from 'src/components';
 import { FormLabel } from 'src/components/Form';
@@ -46,7 +47,6 @@ import Label from 'src/components/Label';
 import Loading from 'src/components/Loading';
 import TableSelector from 'src/components/TableSelector';
 import EditableTitle from 'src/components/EditableTitle';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
 import TextControl from 'src/explore/components/controls/TextControl';
 import TextAreaControl from 'src/explore/components/controls/TextAreaControl';
diff --git a/superset-frontend/src/components/Datasource/DatasourceModal.tsx 
b/superset-frontend/src/components/Datasource/DatasourceModal.tsx
index e318821a5b..f4cdecc1c3 100644
--- a/superset-frontend/src/components/Datasource/DatasourceModal.tsx
+++ b/superset-frontend/src/components/Datasource/DatasourceModal.tsx
@@ -26,16 +26,16 @@ import {
   Metric,
   styled,
   SupersetClient,
+  getClientErrorObject,
   t,
+  SupersetError,
 } from '@superset-ui/core';
 
 import Modal from 'src/components/Modal';
 import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
-import { SupersetError } from 'src/components/ErrorMessage/types';
 import ErrorMessageWithStackTrace from 
'src/components/ErrorMessage/ErrorMessageWithStackTrace';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import { useSelector } from 'react-redux';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 
 const DatasourceEditor = AsyncEsmComponent(() => import('./DatasourceEditor'));
 
diff --git 
a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx 
b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx
index a82f3583cd..e39f5079b6 100644
--- a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx
+++ b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.test.tsx
@@ -19,9 +19,8 @@
 
 import React from 'react';
 import { render, screen } from 'spec/helpers/testing-library';
-import { supersetTheme } from '@superset-ui/core';
+import { ErrorLevel, supersetTheme } from '@superset-ui/core';
 import BasicErrorAlert from './BasicErrorAlert';
-import { ErrorLevel } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.tsx 
b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.tsx
index 918aee5f24..db61656b83 100644
--- a/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.tsx
+++ b/superset-frontend/src/components/ErrorMessage/BasicErrorAlert.tsx
@@ -17,9 +17,8 @@
  * under the License.
  */
 import React from 'react';
-import { styled, useTheme } from '@superset-ui/core';
+import { ErrorLevel, styled, useTheme } from '@superset-ui/core';
 import Icons from 'src/components/Icons';
-import { ErrorLevel } from './types';
 
 const StyledContainer = styled.div<{ level: ErrorLevel }>`
   display: flex;
diff --git 
a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx 
b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx
index 0a1ad27299..1ddcb67aca 100644
--- 
a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.test.tsx
@@ -18,10 +18,10 @@
  */
 
 import React from 'react';
+import { ErrorLevel, ErrorSource, ErrorTypeEnum } from '@superset-ui/core';
 import { render, screen } from 'spec/helpers/testing-library';
 import userEvent from '@testing-library/user-event';
 import DatabaseErrorMessage from './DatabaseErrorMessage';
-import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git 
a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx
 
b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx
index 60883ae9a0..c258d9128c 100644
--- 
a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.test.tsx
@@ -18,9 +18,9 @@
  */
 
 import React from 'react';
+import { ErrorLevel, ErrorSource, ErrorTypeEnum } from '@superset-ui/core';
 import { render, screen } from 'spec/helpers/testing-library';
 import DatasetNotFoundErrorMessage from './DatasetNotFoundErrorMessage';
-import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx 
b/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx
index d6f2ebe25e..65530ff91f 100644
--- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx
@@ -20,10 +20,9 @@
 import React from 'react';
 import userEvent from '@testing-library/user-event';
 import { render, screen } from 'spec/helpers/testing-library';
-import { supersetTheme } from '@superset-ui/core';
+import { ErrorLevel, ErrorSource, supersetTheme } from '@superset-ui/core';
 import { isCurrentUserBot } from 'src/utils/isBot';
 import ErrorAlert from './ErrorAlert';
-import { ErrorLevel, ErrorSource } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx 
b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
index da5894e887..c80d78d926 100644
--- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
@@ -17,14 +17,19 @@
  * under the License.
  */
 import React, { useState, ReactNode } from 'react';
-import { styled, useTheme, t } from '@superset-ui/core';
+import {
+  ErrorLevel,
+  ErrorSource,
+  styled,
+  useTheme,
+  t,
+} from '@superset-ui/core';
 import { noOp } from 'src/utils/common';
 import Modal from 'src/components/Modal';
 import Button from 'src/components/Button';
 import { isCurrentUserBot } from 'src/utils/isBot';
 
 import Icons from 'src/components/Icons';
-import { ErrorLevel, ErrorSource } from './types';
 import CopyToClipboard from '../CopyToClipboard';
 
 const ErrorAlertDiv = styled.div<{ level: ErrorLevel }>`
diff --git 
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
 
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
index 7583983e43..ef505e4ab2 100644
--- 
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
@@ -18,11 +18,11 @@
  */
 
 import React from 'react';
+import { ErrorLevel, ErrorSource, ErrorTypeEnum } from '@superset-ui/core';
 import { render, screen } from 'spec/helpers/testing-library';
 import userEvent from '@testing-library/user-event';
 import ErrorMessageWithStackTrace from './ErrorMessageWithStackTrace';
 import BasicErrorAlert from './BasicErrorAlert';
-import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git 
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx 
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
index b9e7e5c053..5197ea72ef 100644
--- 
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
@@ -17,9 +17,8 @@
  * under the License.
  */
 import React from 'react';
-import { t } from '@superset-ui/core';
+import { ErrorSource, t, SupersetError } from '@superset-ui/core';
 import getErrorMessageComponentRegistry from 
'./getErrorMessageComponentRegistry';
-import { SupersetError, ErrorSource } from './types';
 import ErrorAlert from './ErrorAlert';
 
 const DEFAULT_TITLE = t('Unexpected error');
diff --git 
a/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.test.tsx
 
b/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.test.tsx
index 5fd6ee7bfb..5a35f93068 100644
--- 
a/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.test.tsx
@@ -20,8 +20,12 @@
 import React from 'react';
 import { render, screen, fireEvent } from '@testing-library/react';
 import '@testing-library/jest-dom/extend-expect';
-import { ThemeProvider, supersetTheme } from '@superset-ui/core';
-import { ErrorLevel, ErrorTypeEnum } from 'src/components/ErrorMessage/types';
+import {
+  ErrorLevel,
+  ErrorTypeEnum,
+  ThemeProvider,
+  supersetTheme,
+} from '@superset-ui/core';
 import MarshmallowErrorMessage from './MarshmallowErrorMessage';
 
 describe('MarshmallowErrorMessage', () => {
diff --git 
a/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.test.tsx 
b/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.test.tsx
index c0930ee41b..f9c6872f00 100644
--- 
a/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.test.tsx
@@ -23,13 +23,14 @@ import { Provider } from 'react-redux';
 import { createStore } from 'redux';
 import { render, fireEvent, waitFor } from '@testing-library/react';
 import '@testing-library/jest-dom';
-import { ThemeProvider, supersetTheme } from '@superset-ui/core';
-import OAuth2RedirectMessage from 
'src/components/ErrorMessage/OAuth2RedirectMessage';
 import {
   ErrorLevel,
   ErrorSource,
   ErrorTypeEnum,
-} from 'src/components/ErrorMessage/types';
+  ThemeProvider,
+  supersetTheme,
+} from '@superset-ui/core';
+import OAuth2RedirectMessage from 
'src/components/ErrorMessage/OAuth2RedirectMessage';
 import { reRunQuery } from 'src/SqlLab/actions/sqlLab';
 import { triggerQuery } from 'src/components/Chart/chartAction';
 import { onRefresh } from 'src/dashboard/actions/dashboardState';
diff --git 
a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx 
b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx
index 0b9518b4fc..5d7b949267 100644
--- 
a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx
+++ 
b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.test.tsx
@@ -18,10 +18,10 @@
  */
 
 import userEvent from '@testing-library/user-event';
+import { ErrorLevel, ErrorSource, ErrorTypeEnum } from '@superset-ui/core';
 import React from 'react';
 import { render, screen } from 'spec/helpers/testing-library';
 import ParameterErrorMessage from './ParameterErrorMessage';
-import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git 
a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx 
b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx
index a82b4d3f76..a99afed906 100644
--- a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx
+++ b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.test.tsx
@@ -19,9 +19,9 @@
 
 import userEvent from '@testing-library/user-event';
 import React from 'react';
+import { ErrorSource, ErrorTypeEnum, ErrorLevel } from '@superset-ui/core';
 import { render, screen } from 'spec/helpers/testing-library';
 import TimeoutErrorMessage from './TimeoutErrorMessage';
-import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
 
 jest.mock(
   'src/components/Icons/Icon',
diff --git a/superset-frontend/src/components/ErrorMessage/types.ts 
b/superset-frontend/src/components/ErrorMessage/types.ts
index a27c4aff45..ed05ef4481 100644
--- a/superset-frontend/src/components/ErrorMessage/types.ts
+++ b/superset-frontend/src/components/ErrorMessage/types.ts
@@ -17,95 +17,14 @@
  * under the License.
  */
 
-// Keep in sync with superset/views/errors.py
-export const ErrorTypeEnum = {
-  // Frontend errors
-  FRONTEND_CSRF_ERROR: 'FRONTEND_CSRF_ERROR',
-  FRONTEND_NETWORK_ERROR: 'FRONTEND_NETWORK_ERROR',
-  FRONTEND_TIMEOUT_ERROR: 'FRONTEND_TIMEOUT_ERROR',
-
-  // DB Engine errors
-  GENERIC_DB_ENGINE_ERROR: 'GENERIC_DB_ENGINE_ERROR',
-  COLUMN_DOES_NOT_EXIST_ERROR: 'COLUMN_DOES_NOT_EXIST_ERROR',
-  TABLE_DOES_NOT_EXIST_ERROR: 'TABLE_DOES_NOT_EXIST_ERROR',
-  SCHEMA_DOES_NOT_EXIST_ERROR: 'SCHEMA_DOES_NOT_EXIST_ERROR',
-  CONNECTION_INVALID_USERNAME_ERROR: 'CONNECTION_INVALID_USERNAME_ERROR',
-  CONNECTION_INVALID_PASSWORD_ERROR: 'CONNECTION_INVALID_PASSWORD_ERROR',
-  CONNECTION_INVALID_HOSTNAME_ERROR: 'CONNECTION_INVALID_HOSTNAME_ERROR',
-  CONNECTION_PORT_CLOSED_ERROR: 'CONNECTION_PORT_CLOSED_ERROR',
-  CONNECTION_INVALID_PORT_ERROR: 'CONNECTION_INVALID_PORT_ERROR',
-  CONNECTION_HOST_DOWN_ERROR: 'CONNECTION_HOST_DOWN_ERROR',
-  CONNECTION_ACCESS_DENIED_ERROR: 'CONNECTION_ACCESS_DENIED_ERROR',
-  CONNECTION_UNKNOWN_DATABASE_ERROR: 'CONNECTION_UNKNOWN_DATABASE_ERROR',
-  CONNECTION_DATABASE_PERMISSIONS_ERROR:
-    'CONNECTION_DATABASE_PERMISSIONS_ERROR',
-  CONNECTION_MISSING_PARAMETERS_ERRORS: 'CONNECTION_MISSING_PARAMETERS_ERRORS',
-  OBJECT_DOES_NOT_EXIST_ERROR: 'OBJECT_DOES_NOT_EXIST_ERROR',
-  SYNTAX_ERROR: 'SYNTAX_ERROR',
-
-  // Viz errors
-  VIZ_GET_DF_ERROR: 'VIZ_GET_DF_ERROR',
-  UNKNOWN_DATASOURCE_TYPE_ERROR: 'UNKNOWN_DATASOURCE_TYPE_ERROR',
-  FAILED_FETCHING_DATASOURCE_INFO_ERROR:
-    'FAILED_FETCHING_DATASOURCE_INFO_ERROR',
-
-  // Security access errors
-  TABLE_SECURITY_ACCESS_ERROR: 'TABLE_SECURITY_ACCESS_ERROR',
-  DATASOURCE_SECURITY_ACCESS_ERROR: 'DATASOURCE_SECURITY_ACCESS_ERROR',
-  DATABASE_SECURITY_ACCESS_ERROR: 'DATABASE_SECURITY_ACCESS_ERROR',
-  QUERY_SECURITY_ACCESS_ERROR: 'QUERY_SECURITY_ACCESS_ERROR',
-  MISSING_OWNERSHIP_ERROR: 'MISSING_OWNERSHIP_ERROR',
-  DASHBOARD_SECURITY_ACCESS_ERROR: 'DASHBOARD_SECURITY_ACCESS_ERROR',
-  OAUTH2_REDIRECT: 'OAUTH2_REDIRECT',
-  OAUTH2_REDIRECT_ERROR: 'OAUTH2_REDIRECT_ERROR',
-
-  // Other errors
-  BACKEND_TIMEOUT_ERROR: 'BACKEND_TIMEOUT_ERROR',
-  DATABASE_NOT_FOUND_ERROR: 'DATABASE_NOT_FOUND_ERROR',
-
-  // Sqllab error
-  MISSING_TEMPLATE_PARAMS_ERROR: 'MISSING_TEMPLATE_PARAMS_ERROR',
-  INVALID_TEMPLATE_PARAMS_ERROR: 'INVALID_TEMPLATE_PARAMS_ERROR',
-  RESULTS_BACKEND_NOT_CONFIGURED_ERROR: 'RESULTS_BACKEND_NOT_CONFIGURED_ERROR',
-  DML_NOT_ALLOWED_ERROR: 'DML_NOT_ALLOWED_ERROR',
-  INVALID_CTAS_QUERY_ERROR: 'INVALID_CTAS_QUERY_ERROR',
-  INVALID_CVAS_QUERY_ERROR: 'INVALID_CVAS_QUERY_ERROR',
-  SQLLAB_TIMEOUT_ERROR: 'SQLLAB_TIMEOUT_ERROR',
-  RESULTS_BACKEND_ERROR: 'RESULTS_BACKEND_ERROR',
-  ASYNC_WORKERS_ERROR: 'ASYNC_WORKERS_ERROR',
-
-  // Generic errors
-  GENERIC_COMMAND_ERROR: 'GENERIC_COMMAND_ERROR',
-  GENERIC_BACKEND_ERROR: 'GENERIC_BACKEND_ERROR',
-
-  // API errors
-  INVALID_PAYLOAD_FORMAT_ERROR: 'INVALID_PAYLOAD_FORMAT_ERROR',
-  INVALID_PAYLOAD_SCHEMA_ERROR: 'INVALID_PAYLOAD_SCHEMA_ERROR',
-  MARSHMALLOW_ERROR: 'MARSHMALLOW_ERROR',
-} as const;
-
-type ValueOf<T> = T[keyof T];
-
-export type ErrorType = ValueOf<typeof ErrorTypeEnum>;
-
-// Keep in sync with superset/views/errors.py
-export type ErrorLevel = 'info' | 'warning' | 'error';
-
-export type ErrorSource = 'dashboard' | 'explore' | 'sqllab' | 'crud';
-
-export type SupersetError<ExtraType = Record<string, any> | null> = {
-  error_type: ErrorType;
-  extra: ExtraType;
-  level: ErrorLevel;
-  message: string;
-};
+import { ReactNode, ComponentType } from 'react';
+import { ErrorSource, SupersetError } from '@superset-ui/core';
 
 export type ErrorMessageComponentProps<ExtraType = Record<string, any> | null> 
=
   {
     error: SupersetError<ExtraType>;
     source?: ErrorSource;
-    subtitle?: React.ReactNode;
+    subtitle?: ReactNode;
   };
 
-export type ErrorMessageComponent =
-  React.ComponentType<ErrorMessageComponentProps>;
+export type ErrorMessageComponent = ComponentType<ErrorMessageComponentProps>;
diff --git a/superset-frontend/src/components/Select/AsyncSelect.tsx 
b/superset-frontend/src/components/Select/AsyncSelect.tsx
index 3fb8bceaf4..4f7a69784d 100644
--- a/superset-frontend/src/components/Select/AsyncSelect.tsx
+++ b/superset-frontend/src/components/Select/AsyncSelect.tsx
@@ -29,11 +29,15 @@ import React, {
   useImperativeHandle,
   ClipboardEvent,
 } from 'react';
-import { ensureIsArray, t, usePrevious } from '@superset-ui/core';
+import {
+  ensureIsArray,
+  t,
+  usePrevious,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import { LabeledValue as AntdLabeledValue } from 'antd/lib/select';
 import { debounce, isEqual, uniq } from 'lodash';
 import Icons from 'src/components/Icons';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { FAST_DEBOUNCE, SLOW_DEBOUNCE } from 'src/constants';
 import {
   getValue,
diff --git a/superset-frontend/src/components/TableSelector/index.tsx 
b/superset-frontend/src/components/TableSelector/index.tsx
index 2598d4df23..b7c92a978a 100644
--- a/superset-frontend/src/components/TableSelector/index.tsx
+++ b/superset-frontend/src/components/TableSelector/index.tsx
@@ -25,7 +25,12 @@ import React, {
 } from 'react';
 import { SelectValue } from 'antd/lib/select';
 
-import { styled, t } from '@superset-ui/core';
+import {
+  styled,
+  t,
+  getClientErrorMessage,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import { Select } from 'src/components';
 import { FormLabel } from 'src/components/Form';
 import Icons from 'src/components/Icons';
@@ -37,10 +42,6 @@ import CertifiedBadge from 'src/components/CertifiedBadge';
 import WarningIconWithTooltip from 'src/components/WarningIconWithTooltip';
 import { useToasts } from 'src/components/MessageToasts/withToasts';
 import { useTables, Table } from 'src/hooks/apiResources';
-import {
-  getClientErrorMessage,
-  getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
 
 const REFRESH_WIDTH = 30;
 
diff --git a/superset-frontend/src/components/Tags/utils.tsx 
b/superset-frontend/src/components/Tags/utils.tsx
index ec08a3b126..f0dd4c46f6 100644
--- a/superset-frontend/src/components/Tags/utils.tsx
+++ b/superset-frontend/src/components/Tags/utils.tsx
@@ -17,15 +17,16 @@
  * under the License.
  */
 
-import { SupersetClient, t } from '@superset-ui/core';
+import {
+  ClientErrorObject,
+  getClientErrorObject,
+  SupersetClient,
+  t,
+} from '@superset-ui/core';
 import Tag from 'src/types/TagType';
 
 import rison from 'rison';
 import { cacheWrapper } from 'src/utils/cacheWrapper';
-import {
-  ClientErrorObject,
-  getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
 
 const localCache = new Map<string, any>();
 
diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.ts 
b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
index 472f945b54..d1029203c7 100644
--- a/superset-frontend/src/dashboard/actions/dashboardInfo.ts
+++ b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
@@ -17,9 +17,13 @@
  * under the License.
  */
 import { Dispatch } from 'redux';
-import { makeApi, CategoricalColorNamespace, t } from '@superset-ui/core';
+import {
+  makeApi,
+  CategoricalColorNamespace,
+  t,
+  getErrorText,
+} from '@superset-ui/core';
 import { isString } from 'lodash';
-import { getErrorText } from 'src/utils/getClientErrorObject';
 import { addDangerToast } from 'src/components/MessageToasts/actions';
 import {
   ChartConfiguration,
diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js 
b/superset-frontend/src/dashboard/actions/dashboardState.js
index bdbf430903..d6c7109a4c 100644
--- a/superset-frontend/src/dashboard/actions/dashboardState.js
+++ b/superset-frontend/src/dashboard/actions/dashboardState.js
@@ -26,6 +26,7 @@ import {
   getSharedLabelColor,
   SupersetClient,
   t,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import {
   addChart,
@@ -34,7 +35,6 @@ import {
 } from 'src/components/Chart/chartAction';
 import { chart as initChart } from 'src/components/Chart/chartReducer';
 import { applyDefaultFormData } from 'src/explore/store';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import {
   SAVE_TYPE_OVERWRITE,
   SAVE_TYPE_OVERWRITE_CONFIRMED,
diff --git a/superset-frontend/src/dashboard/actions/sliceEntities.ts 
b/superset-frontend/src/dashboard/actions/sliceEntities.ts
index 9d85e57a6a..91b5faf6f0 100644
--- a/superset-frontend/src/dashboard/actions/sliceEntities.ts
+++ b/superset-frontend/src/dashboard/actions/sliceEntities.ts
@@ -17,9 +17,13 @@
  * under the License.
  */
 import rison from 'rison';
-import { DatasourceType, SupersetClient, t } from '@superset-ui/core';
+import {
+  DatasourceType,
+  SupersetClient,
+  t,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import { addDangerToast } from 'src/components/MessageToasts/actions';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { Dispatch } from 'redux';
 import { Slice } from '../types';
 
diff --git 
a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx 
b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
index 1b5ef5fceb..8613a8db6f 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
@@ -34,6 +34,7 @@ import {
   styled,
   SupersetClient,
   t,
+  getClientErrorObject,
 } from '@superset-ui/core';
 
 import Modal from 'src/components/Modal';
@@ -41,7 +42,6 @@ import { JsonEditor } from 'src/components/AsyncAceEditor';
 
 import ColorSchemeControlWrapper from 
'src/dashboard/components/ColorSchemeControlWrapper';
 import FilterScopeModal from 
'src/dashboard/components/filterscope/FilterScopeModal';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import TagType from 'src/types/TagType';
 import {
diff --git 
a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx 
b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
index 2d13cedcd6..f91790e814 100644
--- a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
+++ b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
@@ -17,14 +17,13 @@
  * under the License.
  */
 import React, { useState } from 'react';
-import { t } from '@superset-ui/core';
+import { getClientErrorObject, t } from '@superset-ui/core';
 import Popover, { PopoverProps } from 'src/components/Popover';
 import CopyToClipboard from 'src/components/CopyToClipboard';
 import { getDashboardPermalink } from 'src/utils/urlUtils';
 import { useToasts } from 'src/components/MessageToasts/withToasts';
 import { useSelector } from 'react-redux';
 import { RootState } from 'src/dashboard/types';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 
 export type URLShortLinkButtonProps = {
   dashboardId: number;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx
index 5041fa3c97..f8f4f6174e 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx
@@ -35,6 +35,8 @@ import {
   styled,
   SuperChart,
   t,
+  ClientErrorObject,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import { useDispatch, useSelector } from 'react-redux';
 import { isEqual, isEqualWith } from 'lodash';
@@ -43,10 +45,6 @@ import Loading from 'src/components/Loading';
 import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
 import ErrorMessageWithStackTrace from 
'src/components/ErrorMessage/ErrorMessageWithStackTrace';
 import { waitForAsyncData } from 'src/middleware/asyncEvent';
-import {
-  ClientErrorObject,
-  getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
 import { FilterBarOrientation, RootState } from 'src/dashboard/types';
 import {
   onFiltersRefreshSuccess,
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx
index 096771e44d..07e1432733 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx
@@ -19,7 +19,7 @@
 import React from 'react';
 import { render, screen, waitFor } from 'spec/helpers/testing-library';
 import fetchMock from 'fetch-mock';
-import * as utils from 'src/utils/getClientErrorObject';
+import * as uiCore from '@superset-ui/core';
 import { Column, JsonObject } from '@superset-ui/core';
 import userEvent from '@testing-library/user-event';
 import { ColumnSelect } from './ColumnSelect';
@@ -97,7 +97,7 @@ test('Should call "getClientErrorObject" when api returns an 
error', async () =>
   const props = createProps();
 
   props.datasetId = 789;
-  const spy = jest.spyOn(utils, 'getClientErrorObject');
+  const spy = jest.spyOn(uiCore, 'getClientErrorObject');
 
   expect(spy).not.toBeCalled();
   render(<ColumnSelect {...(props as any)} />, {
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
index d167a9be8c..243f3d2135 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.tsx
@@ -18,10 +18,15 @@
  */
 import React, { useCallback, useState, useMemo, useEffect } from 'react';
 import rison from 'rison';
-import { Column, ensureIsArray, t, useChangeEffect } from '@superset-ui/core';
+import {
+  Column,
+  ensureIsArray,
+  t,
+  useChangeEffect,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import { Select, FormInstance } from 'src/components';
 import { useToasts } from 'src/components/MessageToasts/withToasts';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { cachedSupersetGet } from 'src/utils/cachedSupersetGet';
 import { NativeFiltersForm } from '../types';
 
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
index 532547e58a..a27d6d089a 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
@@ -18,12 +18,13 @@
  */
 import React, { useCallback, useMemo, ReactNode } from 'react';
 import rison from 'rison';
-import { t, JsonResponse } from '@superset-ui/core';
-import { AsyncSelect } from 'src/components';
 import {
+  t,
+  JsonResponse,
   ClientErrorObject,
   getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
+} from '@superset-ui/core';
+import { AsyncSelect } from 'src/components';
 import { cachedSupersetGet } from 'src/utils/cachedSupersetGet';
 import {
   Dataset,
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index 029a95f3ab..be8311b913 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -37,6 +37,8 @@ import {
   styled,
   SupersetApiError,
   t,
+  ClientErrorObject,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import { isEqual } from 'lodash';
 import React, {
@@ -73,10 +75,6 @@ import {
 import DateFilterControl from 
'src/explore/components/controls/DateFilterControl';
 import AdhocFilterControl from 
'src/explore/components/controls/FilterControl/AdhocFilterControl';
 import { waitForAsyncData } from 'src/middleware/asyncEvent';
-import {
-  ClientErrorObject,
-  getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
 import { SingleValueType } from 'src/filters/components/Range/SingleValueType';
 import {
   getFormData,
diff --git a/superset-frontend/src/explore/actions/datasourcesActions.test.ts 
b/superset-frontend/src/explore/actions/datasourcesActions.test.ts
index a844ff4789..71a92cfd21 100644
--- a/superset-frontend/src/explore/actions/datasourcesActions.test.ts
+++ b/superset-frontend/src/explore/actions/datasourcesActions.test.ts
@@ -18,13 +18,13 @@
  */
 import { DatasourceType } from '@superset-ui/core';
 import fetchMock from 'fetch-mock';
+import * as uiCore from '@superset-ui/core';
 import {
   setDatasource,
   changeDatasource,
   saveDataset,
 } from 'src/explore/actions/datasourcesActions';
 import sinon from 'sinon';
-import * as ClientError from 'src/utils/getClientErrorObject';
 import datasourcesReducer from '../reducers/datasourcesReducer';
 import { updateFormDataByDatasource } from './exploreActions';
 
@@ -126,7 +126,7 @@ test('updateSlice with add to existing dashboard handles 
failure', async () => {
   const sampleError = new Error('sampleError');
   fetchMock.post(saveDatasetEndpoint, { throws: sampleError });
   const dispatch = sinon.spy();
-  const errorSpy = jest.spyOn(ClientError, 'getClientErrorObject');
+  const errorSpy = jest.spyOn(uiCore, 'getClientErrorObject');
 
   let caughtError;
   try {
diff --git a/superset-frontend/src/explore/actions/datasourcesActions.ts 
b/superset-frontend/src/explore/actions/datasourcesActions.ts
index c11be07be3..54990c6f38 100644
--- a/superset-frontend/src/explore/actions/datasourcesActions.ts
+++ b/superset-frontend/src/explore/actions/datasourcesActions.ts
@@ -20,9 +20,8 @@
 import { Dispatch, AnyAction } from 'redux';
 import { ThunkDispatch } from 'redux-thunk';
 import { Dataset } from '@superset-ui/chart-controls';
-import { SupersetClient } from '@superset-ui/core';
+import { SupersetClient, getClientErrorObject } from '@superset-ui/core';
 import { addDangerToast } from 'src/components/MessageToasts/actions';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { updateFormDataByDatasource } from './exploreActions';
 import { ExplorePageState } from '../types';
 
diff --git 
a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
 
b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
index bae6b6fd7b..bab7b78957 100644
--- 
a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
+++ 
b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
@@ -22,11 +22,11 @@ import {
   styled,
   t,
   getChartMetadataRegistry,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import Loading from 'src/components/Loading';
 import { EmptyStateMedium } from 'src/components/EmptyState';
 import { getChartDataRequest } from 'src/components/Chart/chartAction';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { ResultsPaneProps, QueryResultInterface } from '../types';
 import { SingleQueryResultPane } from './SingleQueryResultPane';
 import { TableControls } from './DataTableControls';
diff --git a/superset-frontend/src/explore/components/PropertiesModal/index.tsx 
b/superset-frontend/src/explore/components/PropertiesModal/index.tsx
index ba78dfa037..45af79a54b 100644
--- a/superset-frontend/src/explore/components/PropertiesModal/index.tsx
+++ b/superset-frontend/src/explore/components/PropertiesModal/index.tsx
@@ -29,9 +29,9 @@ import {
   styled,
   isFeatureEnabled,
   FeatureFlag,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import Chart, { Slice } from 'src/types/Chart';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import { loadTags } from 'src/components/Tags/utils';
 import {
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
index a1a0a670f6..059bb35828 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
@@ -25,6 +25,7 @@ import {
   NO_TIME_RANGE,
   SupersetTheme,
   useCSSTextTruncation,
+  fetchTimeRange,
 } from '@superset-ui/core';
 import Button from 'src/components/Button';
 import ControlHeader from 'src/explore/components/ControlHeader';
@@ -41,7 +42,6 @@ import ControlPopover from '../ControlPopover/ControlPopover';
 import { DateFilterControlProps, FrameType } from './types';
 import {
   DateFilterTestKey,
-  fetchTimeRange,
   FRAME_OPTIONS,
   guessFrame,
   useDefaultTimeFilter,
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx
index 77f42598ac..88d36f23ce 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DateFilterControl/components/AdvancedFrame.tsx
@@ -17,8 +17,7 @@
  * under the License.
  */
 import React from 'react';
-import { t } from '@superset-ui/core';
-import { SEPARATOR } from 
'src/explore/components/controls/DateFilterControl/utils';
+import { SEPARATOR, t } from '@superset-ui/core';
 import { Input } from 'src/components/Input';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
 import { FrameComponentProps } from 
'src/explore/components/controls/DateFilterControl/types';
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts
index 3a0debfec8..d44b08dddd 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts
+++ 
b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/utils.test.ts
@@ -20,8 +20,6 @@
 import {
   customTimeRangeEncode,
   customTimeRangeDecode,
-  buildTimeRangeString,
-  formatTimeRange,
 } from 'src/explore/components/controls/DateFilterControl/utils';
 
 describe('Custom TimeRange', () => {
@@ -298,34 +296,3 @@ describe('Custom TimeRange', () => {
     });
   });
 });
-
-describe('buildTimeRangeString', () => {
-  it('generates proper time range string', () => {
-    expect(
-      buildTimeRangeString('2010-07-30T00:00:00', '2020-07-30T00:00:00'),
-    ).toBe('2010-07-30T00:00:00 : 2020-07-30T00:00:00');
-    expect(buildTimeRangeString('', '2020-07-30T00:00:00')).toBe(
-      ' : 2020-07-30T00:00:00',
-    );
-    expect(buildTimeRangeString('', '')).toBe(' : ');
-  });
-});
-
-describe('formatTimeRange', () => {
-  it('generates a readable time range', () => {
-    expect(formatTimeRange('Last 7 days')).toBe('Last 7 days');
-    expect(formatTimeRange('No filter')).toBe('No filter');
-    expect(formatTimeRange('Yesterday : Tomorrow')).toBe(
-      'Yesterday ≤ col < Tomorrow',
-    );
-    expect(formatTimeRange('2010-07-30T00:00:00 : 2020-07-30T00:00:00')).toBe(
-      '2010-07-30 ≤ col < 2020-07-30',
-    );
-    expect(formatTimeRange('2010-07-30T01:00:00 : ')).toBe(
-      '2010-07-30T01:00:00 ≤ col < ∞',
-    );
-    expect(formatTimeRange(' : 2020-07-30T00:00:00')).toBe(
-      '-∞ ≤ col < 2020-07-30',
-    );
-  });
-});
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
index aad2f9984d..4be932e34a 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
+++ 
b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
@@ -16,9 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import rison from 'rison';
-import { SupersetClient, NO_TIME_RANGE, JsonObject } from '@superset-ui/core';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
+import { NO_TIME_RANGE, JsonObject } from '@superset-ui/core';
 import { useSelector } from 'react-redux';
 import {
   COMMON_RANGE_VALUES_SET,
@@ -27,26 +25,6 @@ import {
 } from '.';
 import { FrameType } from '../types';
 
-export const SEPARATOR = ' : ';
-
-export const buildTimeRangeString = (since: string, until: string): string =>
-  `${since}${SEPARATOR}${until}`;
-
-const formatDateEndpoint = (dttm: string, isStart?: boolean): string =>
-  dttm.replace('T00:00:00', '') || (isStart ? '-∞' : '∞');
-
-export const formatTimeRange = (
-  timeRange: string,
-  columnPlaceholder = 'col',
-) => {
-  const splitDateRange = timeRange.split(SEPARATOR);
-  if (splitDateRange.length === 1) return timeRange;
-  return `${formatDateEndpoint(
-    splitDateRange[0],
-    true,
-  )} ≤ ${columnPlaceholder} < ${formatDateEndpoint(splitDateRange[1])}`;
-};
-
 export const guessFrame = (timeRange: string): FrameType => {
   if (COMMON_RANGE_VALUES_SET.has(timeRange)) {
     return 'Common';
@@ -63,29 +41,6 @@ export const guessFrame = (timeRange: string): FrameType => {
   return 'Advanced';
 };
 
-export const fetchTimeRange = async (
-  timeRange: string,
-  columnPlaceholder = 'col',
-) => {
-  const query = rison.encode_uri(timeRange);
-  const endpoint = `/api/v1/time_range/?q=${query}`;
-  try {
-    const response = await SupersetClient.get({ endpoint });
-    const timeRangeString = buildTimeRangeString(
-      response?.json?.result[0]?.since || '',
-      response?.json?.result[0]?.until || '',
-    );
-    return {
-      value: formatTimeRange(timeRangeString, columnPlaceholder),
-    };
-  } catch (response) {
-    const clientError = await getClientErrorObject(response);
-    return {
-      error: clientError.message || clientError.error || response.statusText,
-    };
-  }
-};
-
 export function useDefaultTimeFilter() {
   return (
     useSelector(
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateParser.ts
 
b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateParser.ts
index e4863665bf..b55cceccea 100644
--- 
a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateParser.ts
+++ 
b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateParser.ts
@@ -17,13 +17,13 @@
  * under the License.
  */
 import moment, { Moment } from 'moment';
+import { SEPARATOR } from '@superset-ui/core';
 import {
   CustomRangeDecodeType,
   CustomRangeType,
   DateTimeGrainType,
   DateTimeModeType,
 } from 'src/explore/components/controls/DateFilterControl/types';
-import { SEPARATOR } from './dateFilterUtils';
 import { SEVEN_DAYS_AGO, MIDNIGHT, MOMENT_FORMAT } from './constants';
 
 /**
diff --git 
a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts
 
b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts
index 1c3dc321a8..7c0c916109 100644
--- 
a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts
+++ 
b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts
@@ -18,8 +18,8 @@
  */
 import { renderHook } from '@testing-library/react-hooks';
 import { NO_TIME_RANGE } from '@superset-ui/core';
+import * as uiCore from '@superset-ui/core';
 import { Operators } from 'src/explore/constants';
-import * as FetchTimeRangeModule from 
'src/explore/components/controls/DateFilterControl';
 import { useGetTimeRangeLabel } from './useGetTimeRangeLabel';
 import AdhocFilter from '../AdhocFilter';
 import { Clauses, ExpressionTypes } from '../types';
@@ -65,7 +65,7 @@ test('should get "No filter" label', () => {
 
 test('should get actualTimeRange and title', async () => {
   jest
-    .spyOn(FetchTimeRangeModule, 'fetchTimeRange')
+    .spyOn(uiCore, 'fetchTimeRange')
     .mockResolvedValue({ value: 'MOCK TIME' });
 
   const adhocFilter = new AdhocFilter({
@@ -85,7 +85,7 @@ test('should get actualTimeRange and title', async () => {
 
 test('should get actualTimeRange and title when gets an error', async () => {
   jest
-    .spyOn(FetchTimeRangeModule, 'fetchTimeRange')
+    .spyOn(uiCore, 'fetchTimeRange')
     .mockResolvedValue({ error: 'MOCK ERROR' });
 
   const adhocFilter = new AdhocFilter({
diff --git 
a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx
 
b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx
index 3a0b7a45ca..d68239c709 100644
--- 
a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx
+++ 
b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx
@@ -17,8 +17,7 @@
  * under the License.
  */
 import { useEffect, useState } from 'react';
-import { NO_TIME_RANGE } from '@superset-ui/core';
-import { fetchTimeRange } from 
'src/explore/components/controls/DateFilterControl';
+import { NO_TIME_RANGE, fetchTimeRange } from '@superset-ui/core';
 import { Operators } from 'src/explore/constants';
 import AdhocFilter from '../AdhocFilter';
 import { ExpressionTypes } from '../types';
diff --git 
a/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx
 
b/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx
index ddc242a764..702abf5479 100644
--- 
a/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/SelectAsyncControl/index.tsx
@@ -17,13 +17,12 @@
  * under the License.
  */
 import React, { useEffect, useState } from 'react';
-import { t, SupersetClient } from '@superset-ui/core';
+import { t, SupersetClient, getClientErrorObject } from '@superset-ui/core';
 import ControlHeader from 'src/explore/components/ControlHeader';
 import { Select } from 'src/components';
 import { SelectOptionsType, SelectProps } from 'src/components/Select/types';
 import { SelectValue, LabeledValue } from 'antd/lib/select';
 import withToasts from 'src/components/MessageToasts/withToasts';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 
 type SelectAsyncProps = Omit<SelectProps, 'options' | 'ariaLabel' | 
'onChange'>;
 
diff --git 
a/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx 
b/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx
index 023c1e3551..bd07ff5f01 100644
--- a/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx
+++ b/superset-frontend/src/explore/components/controls/ViewQueryModal.tsx
@@ -17,9 +17,13 @@
  * under the License.
  */
 import React, { useEffect, useState } from 'react';
-import { styled, ensureIsArray, t } from '@superset-ui/core';
+import {
+  styled,
+  ensureIsArray,
+  t,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import Loading from 'src/components/Loading';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { getChartDataRequest } from 'src/components/Chart/chartAction';
 import ViewQuery from 'src/explore/components/controls/ViewQuery';
 
diff --git a/superset-frontend/src/features/reports/ReportModal/index.tsx 
b/superset-frontend/src/features/reports/ReportModal/index.tsx
index c9993c8ffa..2f79e31f59 100644
--- a/superset-frontend/src/features/reports/ReportModal/index.tsx
+++ b/superset-frontend/src/features/reports/ReportModal/index.tsx
@@ -23,9 +23,8 @@ import React, {
   useCallback,
   useMemo,
 } from 'react';
-import { t, SupersetTheme } from '@superset-ui/core';
+import { t, SupersetTheme, getClientErrorObject } from '@superset-ui/core';
 import { useDispatch, useSelector } from 'react-redux';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import {
   addReport,
   editReport,
diff --git a/superset-frontend/src/hooks/apiResources/queryApi.ts 
b/superset-frontend/src/hooks/apiResources/queryApi.ts
index ae25f3cc56..439418529f 100644
--- a/superset-frontend/src/hooks/apiResources/queryApi.ts
+++ b/superset-frontend/src/hooks/apiResources/queryApi.ts
@@ -17,12 +17,10 @@
  * under the License.
  */
 import rison from 'rison';
+import { createApi, BaseQueryFn } from '@reduxjs/toolkit/query/react';
 import {
   ClientErrorObject,
   getClientErrorObject,
-} from 'src/utils/getClientErrorObject';
-import { createApi, BaseQueryFn } from '@reduxjs/toolkit/query/react';
-import {
   SupersetClient,
   ParseMethod,
   SupersetClientResponse,
diff --git a/superset-frontend/src/middleware/asyncEvent.test.ts 
b/superset-frontend/src/middleware/asyncEvent.test.ts
index c819893580..1debb22ac0 100644
--- a/superset-frontend/src/middleware/asyncEvent.test.ts
+++ b/superset-frontend/src/middleware/asyncEvent.test.ts
@@ -20,7 +20,6 @@ import fetchMock from 'fetch-mock';
 import WS from 'jest-websocket-mock';
 import sinon from 'sinon';
 import * as uiCore from '@superset-ui/core';
-import { parseErrorJson } from 'src/utils/getClientErrorObject';
 import * as asyncEvent from 'src/middleware/asyncEvent';
 
 describe('asyncEvent middleware', () => {
@@ -129,7 +128,7 @@ describe('asyncEvent middleware', () => {
         status: 200,
         body: { result: [asyncErrorEvent] },
       });
-      const errorResponse = await parseErrorJson(asyncErrorEvent);
+      const errorResponse = await uiCore.parseErrorJson(asyncErrorEvent);
       await expect(
         asyncEvent.waitForAsyncData(asyncPendingEvent),
       ).rejects.toEqual(errorResponse);
@@ -204,7 +203,7 @@ describe('asyncEvent middleware', () => {
 
       wsServer.send(JSON.stringify(asyncErrorEvent));
 
-      const errorResponse = await parseErrorJson(asyncErrorEvent);
+      const errorResponse = await uiCore.parseErrorJson(asyncErrorEvent);
 
       await expect(promise).rejects.toEqual(errorResponse);
 
diff --git a/superset-frontend/src/middleware/asyncEvent.ts 
b/superset-frontend/src/middleware/asyncEvent.ts
index faa14229ca..0512e6817b 100644
--- a/superset-frontend/src/middleware/asyncEvent.ts
+++ b/superset-frontend/src/middleware/asyncEvent.ts
@@ -23,13 +23,11 @@ import {
   makeApi,
   SupersetClient,
   logging,
-} from '@superset-ui/core';
-import { SupersetError } from 'src/components/ErrorMessage/types';
-import getBootstrapData from 'src/utils/getBootstrapData';
-import {
   getClientErrorObject,
   parseErrorJson,
-} from '../utils/getClientErrorObject';
+  SupersetError,
+} from '@superset-ui/core';
+import getBootstrapData from 'src/utils/getBootstrapData';
 
 type AsyncEvent = {
   id?: string | null;
diff --git a/superset-frontend/src/pages/AnnotationList/index.tsx 
b/superset-frontend/src/pages/AnnotationList/index.tsx
index e04b48080f..344b7104ed 100644
--- a/superset-frontend/src/pages/AnnotationList/index.tsx
+++ b/superset-frontend/src/pages/AnnotationList/index.tsx
@@ -19,7 +19,13 @@
 
 import React, { useMemo, useState, useEffect, useCallback } from 'react';
 import { useParams, Link, useHistory } from 'react-router-dom';
-import { css, t, styled, SupersetClient } from '@superset-ui/core';
+import {
+  css,
+  t,
+  styled,
+  SupersetClient,
+  getClientErrorObject,
+} from '@superset-ui/core';
 import moment from 'moment';
 import rison from 'rison';
 
@@ -28,7 +34,6 @@ import ConfirmStatusChange from 
'src/components/ConfirmStatusChange';
 import DeleteModal from 'src/components/DeleteModal';
 import ListView, { ListViewProps } from 'src/components/ListView';
 import SubMenu, { SubMenuProps } from 'src/features/home/SubMenu';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import withToasts from 'src/components/MessageToasts/withToasts';
 import { useListViewResource } from 'src/views/CRUD/hooks';
 import { createErrorHandler } from 'src/views/CRUD/utils';
diff --git a/superset-frontend/src/pages/Chart/index.tsx 
b/superset-frontend/src/pages/Chart/index.tsx
index c679e0e628..8cf47f0e3f 100644
--- a/superset-frontend/src/pages/Chart/index.tsx
+++ b/superset-frontend/src/pages/Chart/index.tsx
@@ -26,12 +26,12 @@ import {
   makeApi,
   SharedLabelColorSource,
   t,
+  getClientErrorObject,
 } from '@superset-ui/core';
 import Loading from 'src/components/Loading';
 import { addDangerToast } from 'src/components/MessageToasts/actions';
 import { getUrlParam } from 'src/utils/urlUtils';
 import { URL_PARAMS } from 'src/constants';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import getFormDataWithExtraFilters from 
'src/dashboard/util/charts/getFormDataWithExtraFilters';
 import { getAppliedFilterValues } from 
'src/dashboard/util/activeDashboardFilters';
 import { getParsedExploreURLParams } from 
'src/explore/exploreUtils/getParsedExploreURLParams';
diff --git a/superset-frontend/src/setup/setupApp.ts 
b/superset-frontend/src/setup/setupApp.ts
index 227aad3a68..0f31024cda 100644
--- a/superset-frontend/src/setup/setupApp.ts
+++ b/superset-frontend/src/setup/setupApp.ts
@@ -18,11 +18,11 @@
  */
 /* eslint global-require: 0 */
 import $ from 'jquery';
-import { SupersetClient } from '@superset-ui/core';
 import {
+  SupersetClient,
   getClientErrorObject,
   ClientErrorObject,
-} from 'src/utils/getClientErrorObject';
+} from '@superset-ui/core';
 import setupErrorMessages from 'src/setup/setupErrorMessages';
 
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/superset-frontend/src/setup/setupErrorMessages.ts 
b/superset-frontend/src/setup/setupErrorMessages.ts
index f393a36f1c..4d731cb4e3 100644
--- a/superset-frontend/src/setup/setupErrorMessages.ts
+++ b/superset-frontend/src/setup/setupErrorMessages.ts
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { ErrorTypeEnum } from '@superset-ui/core';
 import getErrorMessageComponentRegistry from 
'src/components/ErrorMessage/getErrorMessageComponentRegistry';
-import { ErrorTypeEnum } from 'src/components/ErrorMessage/types';
 import TimeoutErrorMessage from 
'src/components/ErrorMessage/TimeoutErrorMessage';
 import DatabaseErrorMessage from 
'src/components/ErrorMessage/DatabaseErrorMessage';
 import MarshmallowErrorMessage from 
'src/components/ErrorMessage/MarshmallowErrorMessage';
diff --git a/superset-frontend/src/utils/errorMessages.ts 
b/superset-frontend/src/utils/errorMessages.ts
deleted file mode 100644
index d5bfbdc17b..0000000000
--- a/superset-frontend/src/utils/errorMessages.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// Error messages used in many places across applications
-const COMMON_ERR_MESSAGES = {
-  SESSION_TIMED_OUT:
-    'Your session timed out, please refresh your page and try again.',
-};
-
-export default COMMON_ERR_MESSAGES;
diff --git a/superset-frontend/src/utils/getClientErrorObject.test.ts 
b/superset-frontend/src/utils/getClientErrorObject.test.ts
deleted file mode 100644
index 8e89fec284..0000000000
--- a/superset-frontend/src/utils/getClientErrorObject.test.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import { ErrorTypeEnum } from 'src/components/ErrorMessage/types';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
-
-describe('getClientErrorObject()', () => {
-  it('Returns a Promise', () => {
-    const response = getClientErrorObject('error');
-    expect(response instanceof Promise).toBe(true);
-  });
-
-  it('Returns a Promise that resolves to an object with an error key', () => {
-    const error = 'error';
-
-    return getClientErrorObject(error).then(errorObj => {
-      expect(errorObj).toMatchObject({ error });
-    });
-  });
-
-  it('Handles Response that can be parsed as json', () => {
-    const jsonError = { something: 'something', error: 'Error message' };
-    const jsonErrorString = JSON.stringify(jsonError);
-
-    return getClientErrorObject(new Response(jsonErrorString)).then(
-      errorObj => {
-        expect(errorObj).toMatchObject(jsonError);
-      },
-    );
-  });
-
-  it('Handles backwards compatibility between old error messages and the new 
SIP-40 errors format', () => {
-    const jsonError = {
-      errors: [
-        {
-          error_type: ErrorTypeEnum.GENERIC_DB_ENGINE_ERROR,
-          extra: { engine: 'presto', link: 'https://www.google.com' },
-          level: 'error',
-          message: 'presto error: test error',
-        },
-      ],
-    };
-    const jsonErrorString = JSON.stringify(jsonError);
-
-    return getClientErrorObject(new Response(jsonErrorString)).then(
-      errorObj => {
-        expect(errorObj.error).toEqual(jsonError.errors[0].message);
-        expect(errorObj.link).toEqual(jsonError.errors[0].extra.link);
-      },
-    );
-  });
-
-  it('Handles Response that can be parsed as text', () => {
-    const textError = 'Hello I am a text error';
-
-    return getClientErrorObject(new Response(textError)).then(errorObj => {
-      expect(errorObj).toMatchObject({ error: textError });
-    });
-  });
-
-  it('Handles plain text as input', () => {
-    const error = 'error';
-
-    return getClientErrorObject(error).then(errorObj => {
-      expect(errorObj).toMatchObject({ error });
-    });
-  });
-});
diff --git a/superset-frontend/src/views/CRUD/hooks.ts 
b/superset-frontend/src/views/CRUD/hooks.ts
index 8f31f2fcdd..129734fc8b 100644
--- a/superset-frontend/src/views/CRUD/hooks.ts
+++ b/superset-frontend/src/views/CRUD/hooks.ts
@@ -18,7 +18,13 @@
  */
 import rison from 'rison';
 import { useState, useEffect, useCallback } from 'react';
-import { makeApi, SupersetClient, t, JsonObject } from '@superset-ui/core';
+import {
+  makeApi,
+  SupersetClient,
+  t,
+  JsonObject,
+  getClientErrorObject,
+} from '@superset-ui/core';
 
 import {
   createErrorHandler,
@@ -33,7 +39,6 @@ import { FetchDataConfig } from 'src/components/ListView';
 import { FilterValue } from 'src/components/ListView/types';
 import Chart, { Slice } from 'src/types/Chart';
 import copyTextToClipboard from 'src/utils/copy';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import SupersetText from 'src/utils/textUtils';
 import { DatabaseObject } from 'src/features/databases/types';
 import { FavoriteStatus, ImportResourceName } from './types';
diff --git a/superset-frontend/src/views/CRUD/utils.tsx 
b/superset-frontend/src/views/CRUD/utils.tsx
index 514a39964e..96b8b0161d 100644
--- a/superset-frontend/src/views/CRUD/utils.tsx
+++ b/superset-frontend/src/views/CRUD/utils.tsx
@@ -24,12 +24,12 @@ import {
   SupersetClient,
   SupersetClientResponse,
   SupersetTheme,
+  getClientErrorObject,
   t,
 } from '@superset-ui/core';
 import Chart from 'src/types/Chart';
 import { intersection } from 'lodash';
 import rison from 'rison';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
 import { FetchDataConfig, FilterValue } from 'src/components/ListView';
 import SupersetText from 'src/utils/textUtils';
 import { findPermission } from 'src/utils/findPermission';
diff --git a/superset/errors.py b/superset/errors.py
index b792a120da..612977ad65 100644
--- a/superset/errors.py
+++ b/superset/errors.py
@@ -26,7 +26,7 @@ class SupersetErrorType(StrEnum):
     """
     Types of errors that can exist within Superset.
 
-    Keep in sync with superset-frontend/src/components/ErrorMessage/types.ts
+    Keep in sync with 
superset-frontend/packages/superset-ui-core/src/query/types/Query.ts
     """
 
     # Frontend errors
@@ -196,7 +196,7 @@ class ErrorLevel(StrEnum):
     """
     Levels of errors that can exist within Superset.
 
-    Keep in sync with superset-frontend/src/components/ErrorMessage/types.ts
+    Keep in sync with 
superset-frontend/packages/superset-ui-core/src/query/types/Query.ts
     """
 
     INFO = "info"


Reply via email to