{!profile.value ? (
-
+
) : !profile.value.preferredUsername || profile.value.preferredUsername === '' ? (
profile.value.name
) : (
diff --git a/packages/zapp/console/src/components/Navigation/test/UserInformation.test.tsx b/packages/zapp/console/src/components/Navigation/test/UserInformation.test.tsx
index 09bbf23bc..4e0eb83a0 100644
--- a/packages/zapp/console/src/components/Navigation/test/UserInformation.test.tsx
+++ b/packages/zapp/console/src/components/Navigation/test/UserInformation.test.tsx
@@ -1,42 +1,39 @@
import { render, waitFor } from '@testing-library/react';
-import { APIContext } from 'components/data/apiContext';
-import { mockAPIContextValue } from 'components/data/__mocks__/apiContext';
-import { getUserProfile } from 'models/Common/api';
+import { FetchableData } from 'components/hooks/types';
+import { useUserProfile } from 'components/hooks/useUserProfile';
+import { loadedFetchable } from 'components/hooks/__mocks__/fetchableData';
import { UserProfile } from 'models/Common/types';
import * as React from 'react';
+
import { UserInformation } from '../UserInformation';
+jest.mock('components/hooks/useUserProfile');
+
describe('UserInformation', () => {
const sampleUserProfile: UserProfile = {
preferredUsername: 'testUser@example.com',
} as UserProfile;
- let mockGetUserProfile: jest.Mock
>;
-
- const UserInformationWithContext = () => (
-
-
-
- );
-
- beforeEach(() => {
- mockGetUserProfile = jest.fn().mockResolvedValue(null);
- });
+ const mockUseUserProfile = useUserProfile as jest.Mock>;
it('Shows login link if no user profile exists', async () => {
- const { getByText } = render();
+ mockUseUserProfile.mockReturnValue(loadedFetchable(null, jest.fn()));
+ const { getByText } = render();
+
await waitFor(() => getByText('Login'));
- expect(mockGetUserProfile).toHaveBeenCalled();
+ expect(mockUseUserProfile).toHaveBeenCalled();
+
const element = getByText('Login');
expect(element).toBeInTheDocument();
expect(element.tagName).toBe('A');
});
it('Shows user preferredName if profile exists', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
- const { getByText } = render();
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
+ const { getByText } = render();
+
await waitFor(() => getByText(sampleUserProfile.preferredUsername));
- expect(mockGetUserProfile).toHaveBeenCalled();
+ expect(mockUseUserProfile).toHaveBeenCalled();
expect(getByText(sampleUserProfile.preferredUsername)).toBeInTheDocument();
});
});
diff --git a/packages/zapp/console/src/components/Project/test/ProjectDashboard.test.tsx b/packages/zapp/console/src/components/Project/test/ProjectDashboard.test.tsx
index fe4af21af..1008c4152 100644
--- a/packages/zapp/console/src/components/Project/test/ProjectDashboard.test.tsx
+++ b/packages/zapp/console/src/components/Project/test/ProjectDashboard.test.tsx
@@ -13,16 +13,16 @@ import * as React from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { MemoryRouter } from 'react-router';
import { createTestQueryClient, disableQueryLogger, enableQueryLogger } from 'test/utils';
-
-import { APIContext } from 'components/data/apiContext';
-import { mockAPIContextValue } from 'components/data/__mocks__/apiContext';
-import { getUserProfile } from 'models/Common/api';
+import { useUserProfile } from 'components/hooks/useUserProfile';
+import { FetchableData } from 'components/hooks/types';
+import { loadedFetchable } from 'components/hooks/__mocks__/fetchableData';
import { getProjectDomainAttributes } from 'models/Project/api';
import { Admin } from 'flyteidl';
import * as LocalCache from 'basics/LocalCache';
import { ProjectDashboard } from '../ProjectDashboard';
import { failedToLoadExecutionsString } from '../constants';
+jest.mock('components/hooks/useUserProfile');
jest.mock('components/Executions/Tables/WorkflowExecutionsTable');
jest.mock('notistack', () => ({
useSnackbar: () => ({ enqueueSnackbar: jest.fn() }),
@@ -48,13 +48,14 @@ jest.mock('models/Project/api', () => ({
}));
describe('ProjectDashboard', () => {
+ const mockUseUserProfile = useUserProfile as jest.Mock>;
+
let basicPythonFixture: ReturnType;
let failedTaskFixture: ReturnType;
let executions1: Execution[];
let executions2: Execution[];
let scope: DomainIdentifierScope;
let queryClient: QueryClient;
- let mockGetUserProfile: jest.Mock>;
const sampleUserProfile: UserProfile = {
subject: 'subject',
@@ -74,12 +75,13 @@ describe('ProjectDashboard', () => {
jest.spyOn(LocalCache, 'useLocalCache');
beforeEach(() => {
- mockGetUserProfile = jest.fn().mockResolvedValue(null);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(null, jest.fn()));
queryClient = createTestQueryClient();
basicPythonFixture = basicPythonWorkflow.generate();
failedTaskFixture = oneFailedTaskWorkflow.generate();
insertFixture(mockServer, basicPythonFixture);
insertFixture(mockServer, failedTaskFixture);
+
executions1 = [
basicPythonFixture.workflowExecutions.top.data,
failedTaskFixture.workflowExecutions.top.data,
@@ -94,13 +96,7 @@ describe('ProjectDashboard', () => {
const renderView = () =>
render(
-
-
-
+
,
{ wrapper: MemoryRouter },
);
@@ -114,14 +110,14 @@ describe('ProjectDashboard', () => {
});
it('should show loading spinner', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { queryByTestId } = renderView();
await waitFor(() => {});
expect(queryByTestId(/loading-spinner/i)).toBeDefined();
});
it('should display WorkflowExecutionsTable and BarChart ', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { queryByTestId } = renderView();
await waitFor(() => {});
expect(queryByTestId('workflow-table')).toBeDefined();
@@ -130,15 +126,17 @@ describe('ProjectDashboard', () => {
it('should not display checkbox if user does not login', async () => {
const { queryByTestId } = renderView();
await waitFor(() => {});
- expect(mockGetUserProfile).toHaveBeenCalled();
+ expect(mockUseUserProfile).toHaveBeenCalled();
expect(queryByTestId(/checkbox/i)).toBeNull();
});
it('should display checkboxes if user login', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getAllByRole } = renderView();
+
await waitFor(() => {});
- expect(mockGetUserProfile).toHaveBeenCalled();
+ expect(mockUseUserProfile).toHaveBeenCalled();
+
// There are 2 checkboxes on a page: 1 - onlyMyExecutions, 2 - show archived, both unchecked by default
const checkboxes = getAllByRole(/checkbox/i) as HTMLInputElement[];
expect(checkboxes).toHaveLength(2);
@@ -148,16 +146,18 @@ describe('ProjectDashboard', () => {
/** user doesn't have its own workflow */
it('should not display workflow if the user does not have one when filtered onlyMyExecutions', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getByText, queryByText, getAllByRole } = renderView();
await waitFor(() => {});
- expect(mockGetUserProfile).toHaveBeenCalled();
+ expect(mockUseUserProfile).toHaveBeenCalled();
+
// There are 2 checkboxes on a page: 1 - onlyMyExecutions, 2 - show archived, both unchecked by default
const checkboxes = getAllByRole(/checkbox/i) as HTMLInputElement[];
expect(checkboxes[0]).toBeTruthy();
expect(checkboxes[0]?.checked).toEqual(false);
await waitFor(() => expect(getByText(executions1[0].closure.workflowId.name)));
fireEvent.click(checkboxes[0]);
+
// when user selects checkbox, table should have no executions to display
await waitFor(() => expect(queryByText(executions1[0].closure.workflowId.name)).toBeNull());
});
diff --git a/packages/zapp/console/src/components/Project/test/ProjectTask.test.tsx b/packages/zapp/console/src/components/Project/test/ProjectTask.test.tsx
index 9642f01e8..b8afe58bc 100644
--- a/packages/zapp/console/src/components/Project/test/ProjectTask.test.tsx
+++ b/packages/zapp/console/src/components/Project/test/ProjectTask.test.tsx
@@ -1,8 +1,11 @@
import { fireEvent, render, waitFor } from '@testing-library/react';
import { APIContext } from 'components/data/apiContext';
+import { useUserProfile } from 'components/hooks/useUserProfile';
import { mockAPIContextValue } from 'components/data/__mocks__/apiContext';
+import { FetchableData } from 'components/hooks/types';
+import { loadedFetchable } from 'components/hooks/__mocks__/fetchableData';
import { FilterOperationName } from 'models/AdminEntity/types';
-import { getUserProfile, listNamedEntities } from 'models/Common/api';
+import { listNamedEntities } from 'models/Common/api';
import {
NamedEntity,
NamedEntityIdentifier,
@@ -27,6 +30,7 @@ const sampleUserProfile: UserProfile = {
subject: 'subject',
} as UserProfile;
+jest.mock('components/hooks/useUserProfile');
jest.mock('notistack', () => ({
useSnackbar: () => ({ enqueueSnackbar: jest.fn() }),
}));
@@ -41,10 +45,10 @@ describe('ProjectTasks', () => {
let tasks: NamedEntity[];
let queryClient: QueryClient;
let mockListNamedEntities: jest.Mock>;
- let mockGetUserProfile: jest.Mock>;
+ const mockUseUserProfile = useUserProfile as jest.Mock>;
beforeEach(() => {
- mockGetUserProfile = jest.fn().mockResolvedValue(null);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(null, jest.fn()));
queryClient = createTestQueryClient();
tasks = ['MyTask', 'MyOtherTask'].map((name) => createTask({ domain, name, project }));
mockListNamedEntities = jest.fn().mockResolvedValue({ entities: tasks });
@@ -60,10 +64,7 @@ describe('ProjectTasks', () => {
render(
@@ -91,7 +92,7 @@ describe('ProjectTasks', () => {
});
it('should display checkbox if user login', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getAllByRole } = renderComponent();
await waitFor(() => {});
const checkboxes = getAllByRole(/checkbox/i) as HTMLInputElement[];
@@ -101,7 +102,7 @@ describe('ProjectTasks', () => {
});
it('should display archive button', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getByText, getAllByTitle, findAllByText } = renderComponent();
await waitFor(() => {});
@@ -130,7 +131,7 @@ describe('ProjectTasks', () => {
});
it('clicking show archived should hide active tasks', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getByText, queryByText, getAllByRole } = renderComponent();
await waitFor(() => {});
diff --git a/packages/zapp/console/src/components/Project/test/ProjectWorkflows.test.tsx b/packages/zapp/console/src/components/Project/test/ProjectWorkflows.test.tsx
index 49a43be48..da1bd7f5b 100644
--- a/packages/zapp/console/src/components/Project/test/ProjectWorkflows.test.tsx
+++ b/packages/zapp/console/src/components/Project/test/ProjectWorkflows.test.tsx
@@ -1,8 +1,11 @@
import { fireEvent, render, waitFor } from '@testing-library/react';
import { APIContext } from 'components/data/apiContext';
import { mockAPIContextValue } from 'components/data/__mocks__/apiContext';
+import { FetchableData } from 'components/hooks/types';
+import { useUserProfile } from 'components/hooks/useUserProfile';
+import { loadedFetchable } from 'components/hooks/__mocks__/fetchableData';
import { FilterOperationName } from 'models/AdminEntity/types';
-import { getUserProfile, listNamedEntities } from 'models/Common/api';
+import { listNamedEntities } from 'models/Common/api';
import { NamedEntity, UserProfile } from 'models/Common/types';
import { NamedEntityState } from 'models/enums';
import * as React from 'react';
@@ -16,6 +19,7 @@ const sampleUserProfile: UserProfile = {
subject: 'subject',
} as UserProfile;
+jest.mock('components/hooks/useUserProfile');
jest.mock('notistack', () => ({
useSnackbar: () => ({ enqueueSnackbar: jest.fn() }),
}));
@@ -26,10 +30,11 @@ describe('ProjectWorkflows', () => {
let workflowNames: NamedEntity[];
let queryClient: QueryClient;
let mockListNamedEntities: jest.Mock>;
- let mockGetUserProfile: jest.Mock>;
+
+ const mockUseUserProfile = useUserProfile as jest.Mock>;
beforeEach(() => {
- mockGetUserProfile = jest.fn().mockResolvedValue(null);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(null, jest.fn()));
queryClient = createTestQueryClient();
workflowNames = ['MyWorkflow', 'MyOtherWorkflow'].map((name) =>
createWorkflowName({ domain, name, project }),
@@ -41,10 +46,7 @@ describe('ProjectWorkflows', () => {
render(
@@ -71,7 +73,7 @@ describe('ProjectWorkflows', () => {
});
it('should display checkbox if user login', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getAllByRole } = renderComponent();
await waitFor(() => {});
const checkboxes = getAllByRole(/checkbox/i) as HTMLInputElement[];
@@ -82,7 +84,7 @@ describe('ProjectWorkflows', () => {
/** user doesn't have its own workflow */
it('clicking show archived should hide active workflows', async () => {
- mockGetUserProfile.mockResolvedValue(sampleUserProfile);
+ mockUseUserProfile.mockReturnValue(loadedFetchable(sampleUserProfile, jest.fn()));
const { getByText, queryByText, getAllByRole } = renderComponent();
await waitFor(() => {});
const checkboxes = getAllByRole(/checkbox/i) as HTMLInputElement[];
diff --git a/packages/zapp/console/src/components/data/QueryAuthorizationObserver.tsx b/packages/zapp/console/src/components/data/QueryAuthorizationObserver.tsx
index 915112fdd..7a99851f7 100644
--- a/packages/zapp/console/src/components/data/QueryAuthorizationObserver.tsx
+++ b/packages/zapp/console/src/components/data/QueryAuthorizationObserver.tsx
@@ -1,15 +1,17 @@
import { NotAuthorizedError } from 'errors/fetchErrors';
import * as React from 'react';
import { onlineManager, Query, useQueryClient } from 'react-query';
-import { useAPIContext } from './apiContext';
+import { useFlyteApi } from '@flyteconsole/flyte-api';
/** Watches all queries to detect a NotAuthorized error, disabling future queries
* and triggering the login refresh flow.
* Note: Should be placed just below the QueryClient and ApiContext providers.
*/
+
+// TODO: narusina - move this one to flyte-api too
export const QueryAuthorizationObserver: React.FC = () => {
const queryCache = useQueryClient().getQueryCache();
- const apiContext = useAPIContext();
+ const apiContext = useFlyteApi();
React.useEffect(() => {
const unsubscribe = queryCache.subscribe((query?: Query | undefined) => {
if (!query || !query.state.error) {
diff --git a/packages/zapp/console/src/components/data/apiContext.ts b/packages/zapp/console/src/components/data/apiContext.ts
index 8378354ba..3dca31cd1 100644
--- a/packages/zapp/console/src/components/data/apiContext.ts
+++ b/packages/zapp/console/src/components/data/apiContext.ts
@@ -1,4 +1,3 @@
-import { getLoginUrl } from 'models/AdminEntity/utils';
import * as CommonAPI from 'models/Common/api';
import * as ExecutionAPI from 'models/Execution/api';
import * as LaunchAPI from 'models/Launch/api';
@@ -14,12 +13,8 @@ type APIFunctions = typeof CommonAPI &
typeof TaskAPI &
typeof WorkflowAPI;
-export interface LoginStatus {
- expired: boolean;
- setExpired(expired: boolean): void;
-}
export interface APIContextValue extends APIFunctions {
- loginStatus: LoginStatus;
+ // use API functions only, for now
}
export const defaultAPIContextValue = {
@@ -29,12 +24,6 @@ export const defaultAPIContextValue = {
...ProjectAPI,
...TaskAPI,
...WorkflowAPI,
- loginStatus: {
- expired: false,
- setExpired: () => {
- // do nothing
- },
- },
};
/** Exposes all of the model layer api functions for use by data fetching
@@ -43,26 +32,10 @@ export const defaultAPIContextValue = {
*/
export const APIContext = React.createContext(defaultAPIContextValue);
-function useLoginStatus(): LoginStatus {
- const [expired, setExpired] = React.useState(false);
-
- // Whenever we detect expired credentials, trigger a login redirect automatically
- React.useEffect(() => {
- if (expired) {
- window.location.href = getLoginUrl();
- }
- }, [expired]);
- return {
- expired,
- setExpired,
- };
-}
-
/** Creates a state object that can be used as the value for APIContext.Provider */
export function useAPIState(): APIContextValue {
return {
...defaultAPIContextValue,
- loginStatus: useLoginStatus(),
};
}
diff --git a/packages/zapp/console/src/components/hooks/useFetchableData.ts b/packages/zapp/console/src/components/hooks/useFetchableData.ts
index d4a397783..d6f1d91d2 100644
--- a/packages/zapp/console/src/components/hooks/useFetchableData.ts
+++ b/packages/zapp/console/src/components/hooks/useFetchableData.ts
@@ -1,10 +1,10 @@
import { useMachine } from '@xstate/react';
+import { FlyteApiContextState, useFlyteApi } from '@flyteconsole/flyte-api';
import { createDebugLogger } from 'common/log';
import { CacheContext } from 'components/Cache/CacheContext';
import { ValueCache } from 'components/Cache/createCache';
import { getCacheKey } from 'components/Cache/utils';
import { defaultStateMachineConfig } from 'components/common/constants';
-import { APIContextValue, useAPIContext } from 'components/data/apiContext';
import { NotAuthorizedError } from 'errors/fetchErrors';
import { useContext, useEffect, useMemo, useRef } from 'react';
import { fetchMachine } from './fetchMachine';
@@ -33,7 +33,7 @@ function isHashableInput(value: any): value is object | string {
}
interface CreateFetchFnConfig {
- apiContext: APIContextValue;
+ apiContext: FlyteApiContextState;
cache: ValueCache;
cacheKey?: string;
debugName?: string;
@@ -110,7 +110,7 @@ export function useFetchableData(
const cacheKey = isHashableInput(data) ? getCacheKey(data) : undefined;
const contextCacheKey = useRef();
const cache = useContext(CacheContext);
- const apiContext = useAPIContext();
+ const apiContext = useFlyteApi();
const fetchFn = useMemo(
() =>
createFetchFn({
diff --git a/packages/zapp/console/src/components/hooks/useUserProfile.ts b/packages/zapp/console/src/components/hooks/useUserProfile.ts
index 1259bdffe..7f68aea4f 100644
--- a/packages/zapp/console/src/components/hooks/useUserProfile.ts
+++ b/packages/zapp/console/src/components/hooks/useUserProfile.ts
@@ -1,14 +1,16 @@
-import { useAPIContext } from 'components/data/apiContext';
import { UserProfile } from 'models/Common/types';
+import { useFlyteApi, getAxiosApiCall } from '@flyteconsole/flyte-api';
import { useFetchableData } from './useFetchableData';
/** State hook that returns the user information if logged in, null otherwise */
export function useUserProfile() {
- const { getUserProfile } = useAPIContext();
+ const { getProfileUrl } = useFlyteApi();
+ const profilePath = getProfileUrl();
+
return useFetchableData({
debugName: 'UserProfile',
defaultValue: null,
- doFetch: getUserProfile,
+ doFetch: () => getAxiosApiCall(profilePath),
useCache: true,
});
}
diff --git a/packages/zapp/console/src/components/hooks/useVersion.ts b/packages/zapp/console/src/components/hooks/useVersion.ts
index 59aca5c06..c4531f233 100644
--- a/packages/zapp/console/src/components/hooks/useVersion.ts
+++ b/packages/zapp/console/src/components/hooks/useVersion.ts
@@ -1,14 +1,16 @@
-import { useAPIContext } from 'components/data/apiContext';
+import { useFlyteApi, AdminEndpoint, getAxiosApiCall } from '@flyteconsole/flyte-api';
import { GetVersionResponse } from 'models/Common/types';
import { useFetchableData } from './useFetchableData';
/** State hook that returns the version information */
function useVersion() {
- const { getVersion } = useAPIContext();
+ const { getAdminApiUrl } = useFlyteApi();
+ const versionPath = getAdminApiUrl(AdminEndpoint.Version);
+
return useFetchableData({
debugName: 'Version',
defaultValue: null,
- doFetch: getVersion,
+ doFetch: () => getAxiosApiCall(versionPath),
useCache: true,
});
}
diff --git a/packages/zapp/console/src/models/AdminEntity/transformRequestError.ts b/packages/zapp/console/src/models/AdminEntity/transformRequestError.ts
index 9df4275f3..a5d6b36ae 100644
--- a/packages/zapp/console/src/models/AdminEntity/transformRequestError.ts
+++ b/packages/zapp/console/src/models/AdminEntity/transformRequestError.ts
@@ -8,7 +8,7 @@ function decodeErrorResponseMessage(error: AxiosError) {
try {
// probablly using a wrong decode type.. is there a decode type for the error message?
const decodedErrorResponseMessage = decodeProtoResponse(
- error.response?.data,
+ error.response?.data as any,
Admin.RawOutputDataConfig,
);
if (decodedErrorResponseMessage && decodedErrorResponseMessage.outputLocationPrefix) {
diff --git a/packages/zapp/console/src/models/AdminEntity/utils.ts b/packages/zapp/console/src/models/AdminEntity/utils.ts
index 780f12b2a..8a067e3ac 100644
--- a/packages/zapp/console/src/models/AdminEntity/utils.ts
+++ b/packages/zapp/console/src/models/AdminEntity/utils.ts
@@ -10,9 +10,6 @@ import {
} from './types';
const debug = createDebugLogger('adminEntity');
-const loginEndpoint = '/login';
-const profileEndpoint = '/me';
-const redirectParam = 'redirect_url';
/** Converts a path into a full Admin API url */
export function adminApiUrl(url: string) {
@@ -23,24 +20,6 @@ export function adminApiUrl(url: string) {
return createLocalURL(`${apiPrefix}${finalUrl}`);
}
-/** Constructs a url for redirecting to the Admin login endpoint and returning
- * to the current location after completing the flow.
- */
-export function getLoginUrl(redirectUrl: string = window.location.href) {
- const baseUrl = env.ADMIN_API_URL
- ? `${env.ADMIN_API_URL}${loginEndpoint}`
- : createLocalURL(loginEndpoint);
- return `${baseUrl}?${redirectParam}=${redirectUrl}`;
-}
-
-/** Constructs a URL for fetching the current user profile. */
-export function getProfileUrl() {
- if (env.ADMIN_API_URL) {
- return `${env.ADMIN_API_URL}${profileEndpoint}`;
- }
- return createLocalURL(profileEndpoint);
-}
-
// Helper to log out the contents of a protobuf response, since the Network tab
// shows binary values :-).
export function logProtoResponse(url: string, data: T): T {
diff --git a/packages/zapp/console/src/models/Common/api.ts b/packages/zapp/console/src/models/Common/api.ts
index 1ac7ef97d..bfaefc8ee 100644
--- a/packages/zapp/console/src/models/Common/api.ts
+++ b/packages/zapp/console/src/models/Common/api.ts
@@ -1,21 +1,16 @@
-import axios from 'axios';
import { env } from 'common/env';
-import { log } from 'common/log';
import { Admin, Core } from 'flyteidl';
+import { getAxiosApiCall } from '@flyteconsole/flyte-api';
import { getAdminEntity } from 'models/AdminEntity/AdminEntity';
import { defaultPaginationConfig } from 'models/AdminEntity/constants';
-import { transformRequestError } from 'models/AdminEntity/transformRequestError';
import { PaginatedEntityResponse, RequestConfig } from 'models/AdminEntity/types';
-import { adminApiUrl, getProfileUrl } from 'models/AdminEntity/utils';
-import { defaultAxiosConfig, defaultSystemStatus, identifierPrefixes } from './constants';
+import { defaultSystemStatus, identifierPrefixes } from './constants';
import {
- GetVersionResponse,
IdentifierScope,
NamedEntity,
NamedEntityIdentifier,
ResourceType,
SystemStatus,
- UserProfile,
} from './types';
import { makeIdentifierPath, makeNamedEntityPath } from './utils';
@@ -97,37 +92,6 @@ export const listNamedEntities = (input: ListNamedEntitiesInput, requestConfig?:
);
};
-/** Fetches the current user profile. NOTE: This will *not* fail in cases
- * where the user is not logged in or the session is expired. Admin does not
- * distinguish between these cases, so the profile will be `null` in both cases.
- * A value of `null` indicates that a redirect to the login endpoint is needed.
- */
-export const getUserProfile = async () => {
- const path = getProfileUrl();
- try {
- const { data } = await axios.get(path, defaultAxiosConfig);
- return data;
- } catch (e) {
- const { message } = transformRequestError(e, path);
- log.error(`Failed to fetch user profile: ${message}`);
- return null;
- }
-};
-
-/** Fetches the current admin version.
- */
-export const getVersion = async () => {
- const path = adminApiUrl('/version');
- try {
- const { data } = await axios.get(path, defaultAxiosConfig);
- return data;
- } catch (e) {
- const { message } = transformRequestError(e, path);
- log.error(`Failed to fetch version: ${message}`);
- return null;
- }
-};
-
/** If env.STATUS_URL is set, will issue a fetch to retrieve the current system
* status. If not, will resolve immediately with a default value indicating
* normal system status.
@@ -138,11 +102,10 @@ export const getSystemStatus = async () => {
}
const path = env.STATUS_URL;
- try {
- const { data } = await axios.get(path, defaultAxiosConfig);
- return data;
- } catch (e) {
- const { message } = transformRequestError(e, path);
- throw new Error(`Failed to fetch system status: ${message}`);
+ const result = await getAxiosApiCall(path);
+ if (!result) {
+ throw new Error('Failed to fetch system status');
}
+
+ return result;
};
diff --git a/packages/zapp/console/src/models/Common/constants.ts b/packages/zapp/console/src/models/Common/constants.ts
index 6962189fe..f011b0727 100644
--- a/packages/zapp/console/src/models/Common/constants.ts
+++ b/packages/zapp/console/src/models/Common/constants.ts
@@ -1,13 +1,5 @@
-import axios, { AxiosRequestConfig, AxiosTransformer } from 'axios';
-import * as camelcaseKeys from 'camelcase-keys';
-import * as snakecaseKeys from 'snakecase-keys';
import { LiteralMapBlob, ResourceType, SystemStatus } from './types';
-// recommended util.d.ts implementation
-const isObject = (value: unknown): boolean => {
- return value !== null && typeof value === 'object';
-};
-
export const endpointPrefixes = {
execution: '/executions',
launchPlan: '/launch_plans',
@@ -36,18 +28,4 @@ export const emptyLiteralMapBlob: LiteralMapBlob = {
values: { literals: {} },
};
-/** Config object that can be used for requests that are not sent to
- * the Admin entity API (`/api/v1/...`), such as the `/me` endpoint. This config
- * ensures that requests/responses are correctly converted and that cookies are
- * included.
- */
-export const defaultAxiosConfig: AxiosRequestConfig = {
- transformRequest: [
- (data: any) => (isObject(data) ? snakecaseKeys(data) : data),
- ...(axios.defaults.transformRequest as AxiosTransformer[]),
- ],
- transformResponse: [...(axios.defaults.transformResponse as AxiosTransformer[]), camelcaseKeys],
- withCredentials: true,
-};
-
export const defaultSystemStatus: SystemStatus = { status: 'normal' };
diff --git a/yarn.lock b/yarn.lock
index 238e49d19..d37c27cdc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5409,12 +5409,13 @@ axios-mock-adapter@^1.16.0:
fast-deep-equal "^3.1.3"
is-buffer "^2.0.3"
-axios@^0.21.2:
- version "0.21.2"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017"
- integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==
+axios@^0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
+ integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
- follow-redirects "^1.14.0"
+ follow-redirects "^1.14.9"
+ form-data "^4.0.0"
axobject-query@^2.2.0:
version "2.2.0"
@@ -6256,7 +6257,7 @@ camelcase-keys@^4.0.0:
map-obj "^2.0.0"
quick-lru "^1.0.0"
-camelcase-keys@^6.1.1, camelcase-keys@^6.2.2:
+camelcase-keys@^6.2.2:
version "6.2.2"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
@@ -6265,6 +6266,16 @@ camelcase-keys@^6.1.1, camelcase-keys@^6.2.2:
map-obj "^4.0.0"
quick-lru "^4.0.1"
+camelcase-keys@^7.0.2:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252"
+ integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==
+ dependencies:
+ camelcase "^6.3.0"
+ map-obj "^4.1.0"
+ quick-lru "^5.1.1"
+ type-fest "^1.2.1"
+
camelcase@^4.0.0, camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -6280,7 +6291,7 @@ camelcase@^6.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
-camelcase@^6.2.0:
+camelcase@^6.2.0, camelcase@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
@@ -9607,11 +9618,16 @@ flux@^4.0.1:
fbemitter "^3.0.0"
fbjs "^3.0.1"
-follow-redirects@^1.0.0, follow-redirects@^1.14.0:
+follow-redirects@^1.0.0:
version "1.14.8"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
+follow-redirects@^1.14.9:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4"
+ integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==
+
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -9688,6 +9704,15 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@@ -15744,6 +15769,11 @@ quick-lru@^4.0.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
qw@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4"
@@ -17355,13 +17385,22 @@ smart-buffer@^4.1.0:
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba"
integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==
-snakecase-keys@^3.1.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/snakecase-keys/-/snakecase-keys-3.2.1.tgz#ce5d1a2de8a93c939d7992f76f2743aa59f3d5ad"
- integrity sha512-CjU5pyRfwOtaOITYv5C8DzpZ8XA/ieRsDpr93HI2r6e3YInC6moZpSQbmUtg8cTk58tq2x3jcG2gv+p1IZGmMA==
+snake-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
+ integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
+ dependencies:
+ dot-case "^3.0.4"
+ tslib "^2.0.3"
+
+snakecase-keys@^5.4.2:
+ version "5.4.2"
+ resolved "https://registry.yarnpkg.com/snakecase-keys/-/snakecase-keys-5.4.2.tgz#b886f77c9a5fc347b04bd0ad1a05213190e60b9e"
+ integrity sha512-6mzBNP9t1ghArxcaCxZNGIJewE9qyH+eUQIGba9I7MJcZoV4WX4fM2Y+/K9+BGHCFB94ZASfoC3F44UxLXce+A==
dependencies:
map-obj "^4.1.0"
- to-snake-case "^1.0.0"
+ snake-case "^3.0.4"
+ type-fest "^2.5.2"
snapdragon-node@^2.0.1:
version "2.1.1"
@@ -18347,11 +18386,6 @@ to-ico@^1.1.5:
parse-png "^1.0.0"
resize-img "^1.1.0"
-to-no-case@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
- integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=
-
to-object-path@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
@@ -18384,20 +18418,6 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
-to-snake-case@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-snake-case/-/to-snake-case-1.0.0.tgz#ce746913897946019a87e62edfaeaea4c608ab8c"
- integrity sha1-znRpE4l5RgGah+Yu366upMYIq4w=
- dependencies:
- to-space-case "^1.0.0"
-
-to-space-case@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
- integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=
- dependencies:
- to-no-case "^1.0.0"
-
toggle-selection@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
@@ -18618,6 +18638,16 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+type-fest@^1.2.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
+ integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
+
+type-fest@^2.5.2:
+ version "2.12.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.2.tgz#80a53614e6b9b475eb9077472fb7498dc7aa51d0"
+ integrity sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==
+
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"