console (refactor): remove redundant metadata invalidations

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9675
GitOrigin-RevId: 4a34f9f4ba09e8437824573dd3522fb4737a89d6
This commit is contained in:
Matthew Goodwin 2023-07-10 10:25:35 -05:00 committed by hasura-bot
parent 216f6a8f30
commit f238e7a28a
55 changed files with 530 additions and 446 deletions

View File

@ -177,6 +177,6 @@ export {
removeLSItem,
} from './lib/utils/localStorage';
export { listenForStoreMetadataChanges } from './lib/store.utils';
export { reduxStoreListener } from './lib/store/utils/';
export { default as App } from './lib/components/App/App';

View File

@ -1,14 +1,17 @@
import { Dispatch } from '../../../../../../types';
import {
useInvalidateMetadata,
useMetadata,
} from '../../../../../../features/hasura-metadata-api';
import { reactQueryClient } from '../../../../../../lib/reactQuery';
import { Dispatch } from '../../../../../../types';
import _push from '../../../push';
import { NeonBanner } from './components/Neon/NeonBanner';
import { FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY } from './components/NeonDashboardLink';
import { useNeonIntegration } from './useNeonIntegration';
import {
getNeonDBName,
transformNeonIntegrationStatusToNeonBannerProps,
} from './utils';
import { useNeonIntegration } from './useNeonIntegration';
import _push from '../../../push';
import { FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY } from './components/NeonDashboardLink';
import { useMetadata } from '../../../../../../features/hasura-metadata-api';
type NeonConnectProps = {
dispatch: Dispatch;
@ -19,7 +22,8 @@ export function NeonConnect({
dispatch,
connectDbUrl = '/data/manage/connect',
}: NeonConnectProps) {
const { data, invalidateMetadata } = useMetadata();
const { data } = useMetadata();
const invalidateMetadata = useInvalidateMetadata();
const allDatabases = data?.metadata.sources.map(source => source.name) ?? [];
// success callback
@ -29,7 +33,10 @@ export function NeonConnect({
reactQueryClient.refetchQueries(FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY);
// invalidate react query metadata on success
invalidateMetadata();
invalidateMetadata({
componentName: 'NeonConnect',
reasons: ['Successfully adding neon source.'],
});
dispatch(_push(`/data/${dataSourceName}/schema/public`));
};

View File

@ -1,5 +1,4 @@
import { getDriverPrefix } from '../../../../../../../features/DataSource';
import { useInvalidateMetadata } from '../../../../../../../features/hasura-metadata-api';
import {
QualifiedFunction,
SupportedDrivers,
@ -40,11 +39,8 @@ type Props = {
export const useSetFunctionCustomization = ({ onSuccess, onError }: Props) => {
const dispatch = useAppDispatch();
const invalidateMetadata = useInvalidateMetadata();
const mutation = useMetadataMigration({
onSuccess: () => {
invalidateMetadata();
dispatch(updateSchemaInfo()).then(() => {
if (onSuccess) {
onSuccess();

View File

@ -1,11 +1,10 @@
import React from 'react';
import { FaExclamationTriangle } from 'react-icons/fa';
import { Source } from '../../../../../features/hasura-metadata-types';
import { exportMetadata } from '../../../../../metadata/actions';
import { Button } from '../../../../../new-components/Button';
import { Tooltip } from '../../../../../new-components/Tooltip';
import { Dispatch } from '../../../../../types';
import React from 'react';
import { FaExclamationTriangle } from 'react-icons/fa';
import { useQueryClient } from 'react-query';
import _push from '../../push';
import { isInconsistentSource } from '../../utils';
import { useDropSource } from '../hooks/useDropSource';
@ -17,16 +16,15 @@ type GDCDatabaseListItemItemProps = {
dispatch: Dispatch;
};
// This appears to be dead code that's not referenced or implemented anywhere:
export const GDCDatabaseListItem: React.FC<GDCDatabaseListItemItemProps> = ({
dataSource,
inconsistentObjects,
dispatch,
}) => {
const queryClient = useQueryClient();
const { dropSource, isLoading: isDropSourceInProgress } = useDropSource({
customOnSuccess: () => {
dispatch(exportMetadata());
queryClient.invalidateQueries(['export_metadata']);
},
});

View File

@ -1,18 +1,18 @@
import React, { useReducer } from 'react';
import { useQueryClient } from 'react-query';
import { RemoteDBRelationship } from '../../../../../metadata/types';
import { useReducer } from 'react';
import { NormalizedTable } from '../../../../../dataSources/types';
import { useInvalidateMetadata } from '../../../../../features/hasura-metadata-api';
import { RemoteDBRelationship } from '../../../../../metadata/types';
import { Dispatch } from '../../../../../types';
import ExpandableEditor from '../../../../Common/Layout/ExpandableEditor/Editor';
import { ordinalColSort } from '../../utils';
import { addDbToDbRelationship, dropDbToDbRelationship } from '../Actions';
import {
relResetState,
dbToDbRelDefaultState,
dbToDbRelReducer,
} from './state';
import ExpandableEditor from '../../../../Common/Layout/ExpandableEditor/Editor';
import ManualRelationshipSelector from './ManualRelationshipSelector';
import { RemoteRelCollapsedLabel } from './RemoteRelCollapsedLabel';
import {
dbToDbRelDefaultState,
dbToDbRelReducer,
relResetState,
} from './state';
import { parseDbToDbRemoteRel } from './utils';
const AddManualRelationship = ({
@ -32,7 +32,7 @@ const AddManualRelationship = ({
);
const columns = tableSchema.columns.sort(ordinalColSort);
const isNew = relationship === null;
const queryClient = useQueryClient();
const invalidate = useInvalidateMetadata();
// columns in the right order with their indices
const orderedColumns = columns.map((c, i) => ({
@ -51,7 +51,10 @@ const AddManualRelationship = ({
reduxDispatch(
dropDbToDbRelationship(state, tableSchema, () => {
toggleEditor();
queryClient.refetchQueries(['metadata'], { active: true });
invalidate({
componentName: 'AddManualRelationship',
reasons: ['Dropped db-to-db relationship'],
});
})
);
}
@ -60,10 +63,12 @@ const AddManualRelationship = ({
const saveFk = (toggleEditor: unknown) => {
reduxDispatch(
addDbToDbRelationship(state, tableSchema, toggleEditor, isNew, () => {
queryClient.refetchQueries(['metadata'], { active: true });
invalidate({
componentName: 'AddManualRelationship',
reasons: ['Added db-to-db relationship'],
});
})
);
// queryClient.refetchQueries(['metadata'], { active: true });
};
const expandedContent = () => (

View File

@ -1,22 +1,22 @@
import { useDispatch, useStore } from 'react-redux';
import { Link } from 'react-router';
import {
createActionMigration,
deleteAction,
executeActionCreation,
} from '../../../../components/Services/Actions/ServerIO';
import { Link } from 'react-router';
import { useMetadata } from '../../../MetadataAPI';
import { useDispatch, useStore } from 'react-redux';
import { GeneratedAction } from './types';
import { parseCustomTypes } from '../../../../shared/utils/hasuraCustomTypeUtils';
import { useMetadata } from '../../../MetadataAPI';
import { generatedActionToHasuraAction } from '../OASGenerator/utils';
import { GeneratedAction } from './types';
import React from 'react';
import { FaAngleRight, FaFileImport, FaHome } from 'react-icons/fa';
import { z } from 'zod';
import { useQueryClient } from 'react-query';
import { SimpleForm } from '../../../../new-components/Form';
import { OasGeneratorForm } from './OASGeneratorForm';
import React from 'react';
import { useLocalStorage } from '../../../../hooks';
import { SimpleForm } from '../../../../new-components/Form';
import { useInvalidateMetadata } from '../../../hasura-metadata-api';
import { OasGeneratorForm } from './OASGeneratorForm';
export const formSchema = z.object({
oas: z.string(),
@ -49,7 +49,7 @@ export const Breadcrumbs = () => (
export const OASGeneratorPage = () => {
const dispatch = useDispatch();
const store = useStore();
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
const [savedOas, setSavedOas] = useLocalStorage<string>('oas', '');
@ -77,7 +77,10 @@ export const OASGeneratorPage = () => {
state,
false,
() => {
queryClient.invalidateQueries(['metadata']);
invalidateMetadata({
componentName: 'OASGeneratorPage',
reasons: ['onGenerate action migration occurred'],
});
setBusy(false);
},
() => {
@ -99,7 +102,10 @@ export const OASGeneratorPage = () => {
store.getState,
false,
() => {
queryClient.invalidateQueries(['metadata']);
invalidateMetadata({
componentName: 'OASGeneratorPage',
reasons: ['onDelete delete action occurred'],
});
setBusy(false);
},
() => {

View File

@ -1,13 +1,13 @@
import { useQueryClient } from 'react-query';
import { useDispatch } from 'react-redux';
import { push } from 'react-router-redux';
import { SupportedDrivers } from '../../hasura-metadata-types';
import { allowedMetadataTypes, useMetadataMigration } from '../../MetadataAPI';
import { APIError } from '../../../hooks/error';
import { exportMetadata } from '../../../metadata/actions';
import { useFireNotification } from '../../../new-components/Notifications';
import { getDriverPrefix } from '../../DataSource';
import { exportMetadata } from '../../../metadata/actions';
import { allowedMetadataTypes, useMetadataMigration } from '../../MetadataAPI';
import { SupportedDrivers } from '../../hasura-metadata-types';
import { useAvailableDrivers } from './useAvailableDrivers';
import { useDispatch } from 'react-redux';
type UseRedirectArgs = {
redirectWithLatencyCheck: boolean;
@ -48,7 +48,6 @@ export const useSubmit = () => {
const drivers = useAvailableDrivers();
const { fireNotification } = useFireNotification();
const redirect = useRedirect({ redirectWithLatencyCheck: false });
const queryClient = useQueryClient();
const { mutate, ...rest } = useMetadataMigration({
onError: (error: APIError) => {
@ -59,8 +58,6 @@ export const useSubmit = () => {
});
},
onSuccess: () => {
queryClient.invalidateQueries(['export_metadata']);
fireNotification({
type: 'success',
title: 'Success',

View File

@ -6,7 +6,6 @@ import Skeleton from 'react-loading-skeleton';
import globals from '../../../../Globals';
import _push from '../../../../components/Services/Data/push';
import { exportMetadata } from '../../../../metadata/actions';
import { MetadataDataSource } from '../../../../metadata/types';
import { useDestructiveAlert } from '../../../../new-components/Alert';
import { Button } from '../../../../new-components/Button';
import { CardedTable } from '../../../../new-components/CardedTable';
@ -14,7 +13,9 @@ import { IndicatorCard } from '../../../../new-components/IndicatorCard';
import { hasuraToast } from '../../../../new-components/Toasts';
import { useAppDispatch } from '../../../../storeHooks';
import { getProjectId, isCloudConsole } from '../../../../utils/cloudConsole';
import { useMetadata } from '../../../MetadataAPI';
import { useMetadata } from '../../../hasura-metadata-api';
import { Source } from '../../../hasura-metadata-types';
import { useDatabaseLatencyCheck } from '../../hooks/useDatabaseLatencyCheck';
import { useDatabaseVersion } from '../../hooks/useDatabaseVersion';
import { useDropSource } from '../../hooks/useDropSource';
@ -25,8 +26,8 @@ import { Latency } from '../../types';
import { AccelerateProject, Details, LatencyBadge } from './parts';
type DatabaseItem = {
dataSourceName: MetadataDataSource['name'];
driver: MetadataDataSource['kind'];
dataSourceName: Source['name'];
driver: Source['kind'];
};
export const ListConnectedDatabases = (props?: { className?: string }) => {
@ -88,7 +89,10 @@ export const ListConnectedDatabases = (props?: { className?: string }) => {
!isFetching
);
const isCurrentRow = (rowIndex: number) => rowIndex === activeRow;
const isCurrentRow = React.useCallback(
(rowIndex: number) => rowIndex === activeRow,
[activeRow]
);
const columns = ['database', 'driver', '', ''];
@ -128,7 +132,7 @@ export const ListConnectedDatabases = (props?: { className?: string }) => {
},
});
},
[dropSource]
[destructivePrompt, dropSource]
);
const rowData = React.useMemo(
@ -193,6 +197,8 @@ export const ListConnectedDatabases = (props?: { className?: string }) => {
[
databaseList,
databaseVersions,
handleEdit,
handleRemove,
inconsistentSources,
isCurrentRow,
isDatabaseVersionLoading,
@ -209,7 +215,8 @@ export const ListConnectedDatabases = (props?: { className?: string }) => {
// isLoading: isUpdatingProjectRegion,
} = useUpdateProjectRegion();
const openUpdateProjectRegionPage = React.useCallback((_rowId?: string) => {
const openUpdateProjectRegionPage = React.useCallback(
(_rowId?: string) => {
if (!_rowId) {
hasuraToast({
type: 'error',
@ -231,7 +238,9 @@ export const ListConnectedDatabases = (props?: { className?: string }) => {
const cloudDetailsPage = `${window.location.protocol}//${window.location.host}/project/${projectId}/details?open_update_region_drawer=true`;
window.open(cloudDetailsPage, '_blank');
}, []);
},
[updateProjectRegionForRowId]
);
if (isLoading) return <>Loading...</>;

View File

@ -1,19 +1,18 @@
import { useInvalidateMetadata } from '../../hasura-metadata-api';
import { useMetadataMigration } from '../../MetadataAPI';
import { hasuraToast } from '../../../new-components/Toasts';
import { useCallback } from 'react';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { useAppDispatch } from '../../../storeHooks';
import { UPDATE_CURRENT_DATA_SOURCE } from '../../../components/Services/Data/DataActions';
import { hasuraToast } from '../../../new-components/Toasts';
import { useAppDispatch } from '../../../storeHooks';
import { useMetadataMigration } from '../../MetadataAPI';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
export const useDropSource = (props?: MetadataMigrationOptions) => {
const { ...globalMutateOptions } = props;
const dispatch = useAppDispatch();
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
onSuccess: (data, variables, ctx) => {
hasuraToast({ type: 'success', title: 'Source dropped from metadata!' });
invalidateMetadata();
dispatch({
type: UPDATE_CURRENT_DATA_SOURCE,
source: '',

View File

@ -1,18 +1,16 @@
import { useCallback, useMemo } from 'react';
import { useQueryClient } from 'react-query';
import { Driver } from '../../../dataSources';
import { exportMetadata } from '../../../metadata/actions';
import { useAppDispatch } from '../../../storeHooks';
import { generateQueryKeys } from '../../DatabaseRelationships/utils/queryClientUtils';
import { useMetadataMigration } from '../../MetadataAPI';
import { useHttpClient } from '../../Network';
import { useMetadata } from '../../hasura-metadata-api';
import { DatabaseConnection } from '../types';
import { usePushRoute } from './usePushRoute';
import {
sendConnectDatabaseTelemetryEvent,
transformErrorResponse,
} from '../utils';
import { useHttpClient } from '../../Network';
import { Driver } from '../../../dataSources';
import { useMetadata } from '../../hasura-metadata-api';
import { usePushRoute } from './usePushRoute';
export const useManageDatabaseConnection = ({
onSuccess,
@ -21,7 +19,6 @@ export const useManageDatabaseConnection = ({
onSuccess?: () => void;
onError?: (err: Error) => void;
}) => {
const queryClient = useQueryClient();
const { mutateAsync, ...rest } = useMetadataMigration({
errorTransform: transformErrorResponse,
});
@ -33,7 +30,6 @@ export const useManageDatabaseConnection = ({
const mutationOptions = useMemo(
() => ({
onSuccess: () => {
queryClient.invalidateQueries(generateQueryKeys.metadata());
onSuccess?.();
// this code is only for the demo
@ -45,7 +41,7 @@ export const useManageDatabaseConnection = ({
onError?.(err);
},
}),
[dispatch, onError, onSuccess, push, queryClient]
[dispatch, onError, onSuccess, push]
);
const createConnection = useCallback(

View File

@ -1,15 +1,11 @@
import { useMetadataMigration } from '../../MetadataAPI';
import { useInvalidateMetadata } from '../../hasura-metadata-api';
import { hasuraToast } from '../../../new-components/Toasts';
import { useCallback } from 'react';
import { hasuraToast } from '../../../new-components/Toasts';
import { useMetadataMigration } from '../../MetadataAPI';
export const useReloadSource = () => {
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
onSuccess: () => {
hasuraToast({ type: 'success', title: 'Reload successful!' });
invalidateMetadata();
},
onError: () => {
hasuraToast({ type: 'error', title: 'Failed to reload source.' });

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import { useState } from 'react';
import { InjectedRouter, Link, withRouter } from 'react-router';
import { useDestructiveAlert } from '../../../../new-components/Alert';
import { Button } from '../../../../new-components/Button';
@ -8,22 +8,20 @@ import {
useEnvironmentState,
usePushRoute,
} from '../../../ConnectDBRedesign/hooks';
import {
useInvalidateMetadata,
useMetadata,
} from '../../../hasura-metadata-api';
import { useMetadata } from '../../../hasura-metadata-api';
import { useTrackLogicalModel } from '../../hooks/useTrackLogicalModel';
import { useTrackNativeQuery } from '../../hooks/useTrackNativeQuery';
import { LogicalModelWidget } from '../LogicalModelWidget/LogicalModelWidget';
import { LimitedFeatureWrapper } from '../../../ConnectDBRedesign/components/LimitedFeatureWrapper/LimitedFeatureWrapper';
import { extractModelsAndQueriesFromMetadata } from '../../../hasura-metadata-api/selectors';
import { useSyncResourceVersionOnMount } from '../../../hasura-metadata-api';
import { RouteWrapper } from '../components/RouteWrapper';
import { NATIVE_QUERY_ROUTES } from '../constants';
import { LogicalModelWithSource, NativeQueryWithSource } from '../types';
import { ListLogicalModels } from './components/ListLogicalModels';
import { ListNativeQueries } from './components/ListNativeQueries';
import { ListStoredProcedures } from './components/ListStoredProcedures';
import { NATIVE_QUERY_ROUTES } from '../constants';
import { extractModelsAndQueriesFromMetadata } from '../../../hasura-metadata-api/selectors';
import { RouteWrapper } from '../components/RouteWrapper';
import { LimitedFeatureWrapper } from '../../../ConnectDBRedesign/components/LimitedFeatureWrapper/LimitedFeatureWrapper';
export const LandingPage = ({ pathname }: { pathname: string }) => {
const push = usePushRoute();
@ -41,15 +39,7 @@ export const LandingPage = ({ pathname }: { pathname: string }) => {
.flat()
);
const invalidateMetadata = useInvalidateMetadata();
useEffect(() => {
/**
* Workaround to avoid that a metadata migration that happened in the legacy part of the Console (i.e. Run SQL)
* might affect the metadata migrations in the child components of this page,
* resulting in the error "metadata resource version referenced (x) did not match current version"
*/
invalidateMetadata();
}, []);
useSyncResourceVersionOnMount({ componentName: 'LandingPage' });
const nativeQueries = data?.queries ?? [];
const logicalModels = data?.models ?? [];

View File

@ -1,13 +1,11 @@
import { useCallback } from 'react';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { exportMetadata } from '../../../../DataSource';
import { useHttpClient } from '../../../../Network';
import { getCreateLogicalModelBody } from './utils/getCreateLogicalModelBody';
import { LogicalModel, Source } from '../../../../hasura-metadata-types';
import { useQueryClient } from 'react-query';
import { useFireNotification } from '../../../../../new-components/Notifications/index';
import { METADATA_QUERY_KEY } from '../../../../hasura-metadata-api/useMetadata';
import { exportMetadata } from '../../../../DataSource';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { useHttpClient } from '../../../../Network';
import { LogicalModel, Source } from '../../../../hasura-metadata-types';
import { errorTransform } from './utils/errorTransform';
import { getCreateLogicalModelBody } from './utils/getCreateLogicalModelBody';
const useCreateLogicalModelsPermissions = ({
logicalModels,
@ -21,7 +19,6 @@ const useCreateLogicalModelsPermissions = ({
});
const { fireNotification } = useFireNotification();
const httpClient = useHttpClient();
const queryClient = useQueryClient();
const create = useCallback(
async ({ permission, logicalModelName, onSuccess }) => {
@ -60,7 +57,6 @@ const useCreateLogicalModelsPermissions = ({
});
},
onSettled: async () => {
await queryClient.invalidateQueries([METADATA_QUERY_KEY]);
onSuccess?.();
},
}

View File

@ -1,13 +1,11 @@
import { useCallback } from 'react';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { useFireNotification } from '../../../../../new-components/Notifications/index';
import { exportMetadata } from '../../../../DataSource';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { useHttpClient } from '../../../../Network';
import { LogicalModel, Source } from '../../../../hasura-metadata-types';
import { useQueryClient } from 'react-query';
import { useFireNotification } from '../../../../../new-components/Notifications/index';
import { METADATA_QUERY_KEY } from '../../../../hasura-metadata-api/useMetadata';
import { errorTransform } from './utils/errorTransform';
import { Permission } from '../components/types';
import { errorTransform } from './utils/errorTransform';
import { getDeleteLogicalModelBody } from './utils/getDeleteLogicalModelBody';
const useRemoveLogicalModelsPermissions = ({
@ -22,7 +20,6 @@ const useRemoveLogicalModelsPermissions = ({
});
const { fireNotification } = useFireNotification();
const httpClient = useHttpClient();
const queryClient = useQueryClient();
const remove = useCallback(
async ({
@ -68,7 +65,6 @@ const useRemoveLogicalModelsPermissions = ({
});
},
onSettled: async () => {
await queryClient.invalidateQueries([METADATA_QUERY_KEY]);
onSuccess?.();
},
}

View File

@ -1,17 +1,13 @@
import { useCallback } from 'react';
import {
useInvalidateMetadata,
useMetadata,
} from '../../../hasura-metadata-api';
import { Table } from '../../../hasura-metadata-types';
import { useMetadataMigration } from '../../../MetadataAPI';
import { useMetadata } from '../../../hasura-metadata-api';
import { Table } from '../../../hasura-metadata-types';
export const useUntrackTable = (props?: {
onSuccess?: () => void;
onError?: (err: Error) => void;
}) => {
const { mutate, ...rest } = useMetadataMigration();
const invalidateMetadata = useInvalidateMetadata();
const { onSuccess, onError } = props ?? {};
@ -37,7 +33,6 @@ export const useUntrackTable = (props?: {
},
{
onSuccess: () => {
invalidateMetadata();
onSuccess?.();
},
onError: err => {

View File

@ -1,12 +1,8 @@
import {
MetadataUtils,
useInvalidateMetadata,
useMetadata,
} from '../../../hasura-metadata-api';
import { MetadataTable } from '../../../hasura-metadata-types';
import { useMetadataMigration } from '../../../MetadataAPI';
import { useFireNotification } from '../../../../new-components/Notifications';
import { useCallback } from 'react';
import { useFireNotification } from '../../../../new-components/Notifications';
import { useMetadataMigration } from '../../../MetadataAPI';
import { MetadataUtils, useMetadata } from '../../../hasura-metadata-api';
import { MetadataTable } from '../../../hasura-metadata-types';
export const useUpdateTableConfiguration = (
dataSourceName: string,
@ -16,8 +12,6 @@ export const useUpdateTableConfiguration = (
const { fireNotification } = useFireNotification();
const invalidateMetadata = useInvalidateMetadata();
const { data } = useMetadata(m => ({
source: MetadataUtils.findMetadataSource(dataSourceName, m),
resource_version: m.resource_version,
@ -52,8 +46,6 @@ export const useUpdateTableConfiguration = (
},
{
onSuccess: () => {
invalidateMetadata();
fireNotification({
type: 'success',
title: 'Success!',
@ -77,7 +69,6 @@ export const useUpdateTableConfiguration = (
dataSourceName,
fireNotification,
mutate,
invalidateMetadata,
metadataTable,
resource_version,
source,

View File

@ -118,7 +118,14 @@ export const TrackedFunctions = (props: TrackedFunctionsProps) => {
[
<span
className="py-2"
onClick={() => invalidateMetadata()}
onClick={() =>
invalidateMetadata({
componentName: 'TrackedFunctions',
reasons: [
'Refreshing tracked functions on dropdown menu item click.',
],
})
}
>
Refresh
</span>,

View File

@ -163,7 +163,14 @@ export const UntrackedFunctions = (props: UntrackedFunctionsProps) => {
[
<span
className="py-2"
onClick={() => invalidateMetadata()}
onClick={() =>
invalidateMetadata({
componentName: 'UntrackedFunctions',
reasons: [
'Refreshing untracked functions on Dropdown Menu item click.',
],
})
}
>
Refresh
</span>,

View File

@ -1,38 +1,35 @@
import React, { useEffect, useState } from 'react';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import Skeleton from 'react-loading-skeleton';
import { APIError } from '../../../../hooks/error';
import { Badge } from '../../../../new-components/Badge';
import { Button } from '../../../../new-components/Button';
import { CardedTable } from '../../../../new-components/CardedTable';
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
import { useFireNotification } from '../../../../new-components/Notifications';
import { hasuraToast } from '../../../../new-components/Toasts';
import { exportMetadata } from '../../../DataSource';
import { RelationshipMapping } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/RelationshipMapping';
import { RowActions } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/RowActions';
import { TargetName } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/TargetName';
import { RenderWidget } from '../../../DatabaseRelationships/components/RenderWidget/RenderWidget';
import { NOTIFICATIONS } from '../../../DatabaseRelationships/components/constants';
import { useCheckRows } from '../../../DatabaseRelationships/hooks/useCheckRows';
import { MODE, Relationship } from '../../../DatabaseRelationships/types';
import {
generateDeleteLocalRelationshipRequest,
generateRemoteRelationshipDeleteRequest,
} from '../../../DatabaseRelationships/utils/generateRequest';
import { useMetadataMigration } from '../../../MetadataAPI';
import { useHttpClient } from '../../../Network';
import { BulkKeepGoingResponse, Source } from '../../../hasura-metadata-types';
import {
DEFAULT_PAGE_NUMBER,
DEFAULT_PAGE_SIZE,
DEFAULT_PAGE_SIZES,
} from '../constants';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import { paginate } from '../utils';
import { SearchBar } from './SearchBar';
import { Badge } from '../../../../new-components/Badge';
import { hasuraToast } from '../../../../new-components/Toasts';
import { TargetName } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/TargetName';
import { RelationshipMapping } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/RelationshipMapping';
import { RowActions } from '../../../DatabaseRelationships/components/AvailableRelationshipsList/parts/RowActions';
import { MODE, Relationship } from '../../../DatabaseRelationships/types';
import { RenderWidget } from '../../../DatabaseRelationships/components/RenderWidget/RenderWidget';
import { NOTIFICATIONS } from '../../../DatabaseRelationships/components/constants';
import { useFireNotification } from '../../../../new-components/Notifications';
import { useMetadataMigration } from '../../../MetadataAPI';
import {
generateDeleteLocalRelationshipRequest,
generateRemoteRelationshipDeleteRequest,
} from '../../../DatabaseRelationships/utils/generateRequest';
import { exportMetadata } from '../../../DataSource';
import { useHttpClient } from '../../../Network';
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
import { MetadataDataSource } from '../../../../metadata/types';
import Skeleton from 'react-loading-skeleton';
import { generateQueryKeys } from '../../../DatabaseRelationships/utils/queryClientUtils';
import { useQueryClient } from 'react-query';
import { useCheckRows } from '../../../DatabaseRelationships/hooks/useCheckRows';
import { APIError } from '../../../../hooks/error';
import { BulkKeepGoingResponse } from '../../../hasura-metadata-types';
const getQueryFunction = (relationship: Relationship) => {
if (relationship.type === 'localRelationship') {
@ -58,7 +55,7 @@ type RelationshipAction = {
interface TrackedRelationshipsProps {
dataSourceName: string;
driver?: MetadataDataSource['kind'];
driver?: Source['kind'];
isLoading: boolean;
onUpdate: () => void;
relationships: Relationship[];
@ -73,7 +70,6 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
}) => {
const httpClient = useHttpClient();
const { mutateAsync } = useMetadataMigration<BulkKeepGoingResponse>();
const queryClient = useQueryClient();
const [isTrackingSelectedRelationships, setTrackingSelectedRelationships] =
useState(false);
@ -161,6 +157,8 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
).length;
const plural = successfullyTrackedCounter > 1 ? 's' : '';
onUpdate();
hasuraToast({
type: 'success',
title: 'Successfully untracked',
@ -174,13 +172,8 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
message: (err as APIError).message,
});
},
onSettled: () => {
queryClient.invalidateQueries(generateQueryKeys.metadata());
},
}
);
onUpdate();
}
} catch (err) {
console.error(err);

View File

@ -1,18 +1,12 @@
import React, { useEffect } from 'react';
import { useTrackedRelationships } from './hooks/useTrackedRelationships';
import { useInvalidateMetadata } from '../../../hasura-metadata-api';
import { useMetadata } from '../../../MetadataAPI';
import React from 'react';
import {
MetadataSelectors,
useMetadata,
useSyncResourceVersionOnMount,
} from '../../../hasura-metadata-api';
import { TrackedRelationships } from './TrackedRelationships';
const useInvalidateMetadataOnLoad = () => {
const invalidateMetadata = useInvalidateMetadata();
// just invalidate metadata when this screen loads for the first time
// why? because the user might be coming from a redux based paged and the resource_version might gone out of sync
useEffect(() => {
invalidateMetadata();
}, [invalidateMetadata]);
};
import { useTrackedRelationships } from './hooks/useTrackedRelationships';
interface TrackedRelationshipsContainerProps {
dataSourceName: string;
@ -21,7 +15,9 @@ interface TrackedRelationshipsContainerProps {
export const TrackedRelationshipsContainer: React.VFC<
TrackedRelationshipsContainerProps
> = ({ dataSourceName }) => {
useInvalidateMetadataOnLoad();
useSyncResourceVersionOnMount({
componentName: 'TrackedRelationshipsContainer',
});
const {
data: relationships,
@ -29,18 +25,9 @@ export const TrackedRelationshipsContainer: React.VFC<
refetchRelationships,
} = useTrackedRelationships(dataSourceName);
const {
data: metadataDataSource,
refetch: refetchMetadata,
isLoading: isLoadingMetadata,
} = useMetadata(m => {
return {
resource_version: m.resource_version,
source: m.metadata.sources.find(s => s.name === dataSourceName),
};
});
const metadataSource = metadataDataSource?.source;
const driver = metadataSource?.kind;
const { data: metadataSource, isLoading: isLoadingMetadata } = useMetadata(
MetadataSelectors.findSource(dataSourceName)
);
return (
<TrackedRelationships
@ -49,9 +36,8 @@ export const TrackedRelationshipsContainer: React.VFC<
relationships={relationships}
onUpdate={async () => {
await refetchRelationships();
await refetchMetadata();
}}
driver={driver}
driver={metadataSource?.kind}
/>
);
};

View File

@ -1,8 +1,10 @@
import { useQuery } from 'react-query';
import { useAllSuggestedRelationships } from '../../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
import { getTableLocalRelationships } from '../../../../DatabaseRelationships/utils/tableRelationships';
import { exportMetadata } from '../../../../hasura-metadata-api';
import { useHttpClient } from '../../../../Network';
import {
MetadataSelectors,
useMetadata,
} from '../../../../hasura-metadata-api';
export const getTrackedRelationshipsCacheKey = (dataSourceName: string) => [
'tracked_relationships',
@ -10,21 +12,16 @@ export const getTrackedRelationshipsCacheKey = (dataSourceName: string) => [
];
export const useTrackedRelationships = (dataSourceName: string) => {
const httpClient = useHttpClient();
const { suggestedRelationships } = useAllSuggestedRelationships({
dataSourceName,
isEnabled: true,
omitTracked: false,
});
const fetchLocalRelationships = async () => {
const { metadata } = await exportMetadata({
httpClient,
});
const currentMetadataSource = metadata?.sources?.find(
source => source.name === dataSourceName
const { data: currentMetadataSource } = useMetadata(
MetadataSelectors.findSource(dataSourceName)
);
const fetchLocalRelationships = async () => {
const metadataTables = currentMetadataSource?.tables || [];
const _tableRelationships = [];

View File

@ -1,3 +1,2 @@
export { useCheckRows } from './useCheckRows';
export { useMetadataSource } from './useMetadataSource';
export { usePaginatedSearchableList } from './usePaginatedSearchableList';

View File

@ -1,24 +0,0 @@
import { exportMetadata } from '../../../DataSource';
import { useHttpClient } from '../../../Network';
import { useQuery } from 'react-query';
export const useMetadataSource = (dataSourceName: string) => {
const httpClient = useHttpClient();
return useQuery(
['export_metadata', 'trackTables', 'metadataSource'],
async () => {
const result = await exportMetadata({ httpClient });
if (!result) throw Error('useMetadataSource: cannot export metadata');
const driver = result.metadata.sources.find(
source => source.name === dataSourceName
)?.kind;
if (!driver)
throw Error('useMetadataSource: cannot find source in metadata');
return { metadata: result, driver };
}
);
};

View File

@ -1,8 +1,4 @@
import { useCallback } from 'react';
import {
MetadataFunction,
QualifiedFunction,
} from '../../hasura-metadata-types';
import {
MetadataMigrationOptions,
useMetadataMigration,
@ -10,9 +6,12 @@ import {
import {
MetadataSelectors,
areTablesEqual,
useInvalidateMetadata,
useMetadata,
} from '../../hasura-metadata-api';
import {
MetadataFunction,
QualifiedFunction,
} from '../../hasura-metadata-types';
import { transformErrorResponse } from '../errorUtils';
export type MetadataFunctionPayload = {
@ -26,12 +25,9 @@ export const useSetFunctionConfiguration = ({
dataSourceName,
...globalMutateOptions
}: { dataSourceName: string } & MetadataMigrationOptions) => {
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
...globalMutateOptions,
onSuccess: (data, variables, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variables, ctx);
},
errorTransform: transformErrorResponse,

View File

@ -1,17 +1,13 @@
import { useCallback } from 'react';
import {
MetadataFunction,
QualifiedFunction,
} from '../../hasura-metadata-types';
import {
MetadataMigrationOptions,
useMetadataMigration,
} from '../../MetadataAPI/hooks/useMetadataMigration';
import { MetadataSelectors, useMetadata } from '../../hasura-metadata-api';
import {
MetadataSelectors,
useInvalidateMetadata,
useMetadata,
} from '../../hasura-metadata-api';
MetadataFunction,
QualifiedFunction,
} from '../../hasura-metadata-types';
import { transformErrorResponse } from '../errorUtils';
export type MetadataFunctionPayload = {
@ -25,12 +21,9 @@ export const useTrackFunction = ({
dataSourceName,
...globalMutateOptions
}: { dataSourceName: string } & MetadataMigrationOptions) => {
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
...globalMutateOptions,
onSuccess: (data, variables, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variables, ctx);
},
errorTransform: transformErrorResponse,

View File

@ -1,7 +1,7 @@
import { transformErrorResponse } from '../../ConnectDBRedesign/utils';
import { useMetadataMigration } from '../../MetadataAPI';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { useInvalidateMetadata, useMetadata } from '../../hasura-metadata-api';
import { useMetadata } from '../../hasura-metadata-api';
import { LogicalModel } from '../../hasura-metadata-types';
import { getSourceDriver } from './utils';
@ -20,13 +20,10 @@ export const useTrackLogicalModel = (
resource_version: m.resource_version,
}));
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
...globalMutateOptions,
errorTransform: transformErrorResponse,
onSuccess: (data, variable, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variable, ctx);
},
});

View File

@ -1,7 +1,7 @@
import { transformErrorResponse } from '../../ConnectDBRedesign/utils';
import { useMetadataMigration } from '../../MetadataAPI';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { useInvalidateMetadata, useMetadata } from '../../hasura-metadata-api';
import { useMetadata } from '../../hasura-metadata-api';
import { NativeQuery, Source } from '../../hasura-metadata-types';
import { getSourceDriver } from './utils';
@ -25,13 +25,10 @@ export const useTrackNativeQuery = (
resource_version: m.resource_version,
}));
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
...globalMutateOptions,
errorTransform: transformErrorResponse,
onSuccess: (data, variable, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variable, ctx);
},
});

View File

@ -1,7 +1,7 @@
import { transformErrorResponse } from '../../ConnectDBRedesign/utils';
import { useMetadataMigration } from '../../MetadataAPI';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { useInvalidateMetadata, useMetadata } from '../../hasura-metadata-api';
import { useMetadata } from '../../hasura-metadata-api';
import {
QualifiedStoredProcedure,
StoredProcedure,
@ -23,13 +23,10 @@ export const useTrackStoredProcedure = (
resource_version: m.resource_version,
}));
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration({
...globalMutateOptions,
errorTransform: transformErrorResponse,
onSuccess: (data, variable, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variable, ctx);
},
});

View File

@ -1,14 +1,10 @@
import { useMetadataMigration } from '../../MetadataAPI';
import { useCallback } from 'react';
import {
MetadataSelectors,
useInvalidateMetadata,
useMetadata,
} from '../../hasura-metadata-api';
import type { TrackableTable } from '../TrackResources/types';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { transformErrorResponse } from '../../ConnectDBRedesign/utils';
import { useMetadataMigration } from '../../MetadataAPI';
import { MetadataMigrationOptions } from '../../MetadataAPI/hooks/useMetadataMigration';
import { MetadataSelectors, useMetadata } from '../../hasura-metadata-api';
import { BulkKeepGoingResponse } from '../../hasura-metadata-types';
import type { TrackableTable } from '../TrackResources/types';
export const useTrackTables = ({
dataSourceName,
@ -19,12 +15,9 @@ export const useTrackTables = ({
resource_version: m.resource_version,
}));
const invalidateMetadata = useInvalidateMetadata();
const { mutate, ...rest } = useMetadataMigration<BulkKeepGoingResponse>({
...globalMutateOptions,
onSuccess: (data, variables, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variables, ctx);
},
errorTransform: transformErrorResponse,

View File

@ -2,7 +2,6 @@ export * from './ManageDatabase/ManageDatabase.Route';
export * from './components';
export * from './hooks';
export { useTrackTables } from './hooks/useTrackTables';
export { useMetadataSource } from './TrackResources/hooks/useMetadataSource';
export * from './CustomFieldNames';
export * from '../../utils/getDataRoute';
export * from './mocks/metadata.mocks';

View File

@ -1,15 +1,15 @@
import { useState, useEffect } from 'react';
import { Table } from '../hasura-metadata-types';
import { useState } from 'react';
import { FaPlusCircle } from 'react-icons/fa';
import { Button } from '../../new-components/Button';
import { useFireNotification } from '../../new-components/Notifications';
import { FaPlusCircle } from 'react-icons/fa';
import Legend from './components/Legend';
import { SuggestedRelationships } from './components/SuggestedRelationships/SuggestedRelationships';
import { MODE, Relationship } from './types';
import { useSyncResourceVersionOnMount } from '../hasura-metadata-api';
import { Table } from '../hasura-metadata-types';
import { AvailableRelationshipsList } from './components/AvailableRelationshipsList/AvailableRelationshipsList';
import { NOTIFICATIONS } from './components/constants';
import Legend from './components/Legend';
import { RenderWidget } from './components/RenderWidget/RenderWidget';
import { useInvalidateMetadata } from '../hasura-metadata-api';
import { SuggestedRelationships } from './components/SuggestedRelationships/SuggestedRelationships';
import { NOTIFICATIONS } from './components/constants';
import { MODE, Relationship } from './types';
export interface DatabaseRelationshipsProps {
dataSourceName: string;
@ -29,8 +29,6 @@ export const DatabaseRelationships = ({
});
const { fireNotification } = useFireNotification();
const invalidateMetadata = useInvalidateMetadata();
const onCancel = () => {
setTabState({
mode: undefined,
@ -38,11 +36,9 @@ export const DatabaseRelationships = ({
});
};
// just invalidate metadata when this screen loads for the first time
// why? because the user might be coming from a redux based paged and the resource_version might gone out of sync
useEffect(() => {
invalidateMetadata();
}, [invalidateMetadata]);
useSyncResourceVersionOnMount({
componentName: 'DatabaseRelationships',
});
const onError = (err: Error) => {
if (mode)

View File

@ -1,13 +1,11 @@
import React from 'react';
import { Table } from '../../../hasura-metadata-types';
import { CardedTable } from '../../../../new-components/CardedTable';
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
import { FiRefreshCcw } from 'react-icons/fi';
import Skeleton from 'react-loading-skeleton';
import { QueryClient, useQueryClient } from 'react-query';
import { CardedTable } from '../../../../new-components/CardedTable';
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
import { useInvalidateMetadata } from '../../../hasura-metadata-api';
import { Table } from '../../../hasura-metadata-types';
import { useListAllDatabaseRelationships } from '../../hooks/useListAllDatabaseRelationships';
import { MODE, Relationship } from '../../types';
import { generateQueryKeys } from '../../utils/queryClientUtils';
import { RelationshipMapping } from './parts/RelationshipMapping';
import { RowActions } from './parts/RowActions';
import { TargetName } from './parts/TargetName';
@ -18,10 +16,6 @@ export interface AvailableRelationshipsListProps {
table: Table;
}
const refreshMetadata = (client: QueryClient) => {
client.invalidateQueries(generateQueryKeys.metadata());
};
export const AvailableRelationshipsList = ({
dataSourceName,
onAction,
@ -32,7 +26,14 @@ export const AvailableRelationshipsList = ({
table,
});
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
const refreshMetadata = () => {
invalidateMetadata({
componentName: 'AvailableRelationshipList',
reasons: ['User clicked button to refresh metadata.'],
});
};
if (!relationships) return <Skeleton count={7} height={30} />;
@ -55,7 +56,7 @@ export const AvailableRelationshipsList = ({
'TYPE',
'RELATIONSHIP',
<div className="flex justify-end hidden">
<FiRefreshCcw onClick={() => refreshMetadata(queryClient)} />
<FiRefreshCcw onClick={() => refreshMetadata()} />
</div>,
]}
/>

View File

@ -5,19 +5,12 @@ import { transformErrorResponse } from '../../../Data/errorUtils';
// useAllDriverCapabilities,
// useDriverCapabilities,
// } from '../../../Data/hooks/useDriverCapabilities';
import { useAllDriverCapabilities } from '../../../Data/hooks/useAllDriverCapabilities';
import { Feature } from '../../../DataSource';
import { useMetadataMigration } from '../../../MetadataAPI';
import { MetadataMigrationOptions } from '../../../MetadataAPI/hooks/useMetadataMigration';
import {
areTablesEqual,
useInvalidateMetadata,
useMetadata,
} from '../../../hasura-metadata-api';
import {
createTableRelationshipRequestBody,
deleteTableRelationshipRequestBody,
renameRelationshipRequestBody,
} from './utils';
import { areTablesEqual, useMetadata } from '../../../hasura-metadata-api';
import { Table } from '../../../hasura-metadata-types';
import {
DeleteRelationshipProps,
LocalTableRelationshipDefinition,
@ -26,8 +19,11 @@ import {
RenameRelationshipProps,
TableRelationshipBasicDetails,
} from './types';
import { Table } from '../../../hasura-metadata-types';
import { useAllDriverCapabilities } from '../../../Data/hooks/useAllDriverCapabilities';
import {
createTableRelationshipRequestBody,
deleteTableRelationshipRequestBody,
renameRelationshipRequestBody,
} from './utils';
type AllowedRelationshipDefinitions =
| Omit<LocalTableRelationshipDefinition, 'capabilities'>
@ -66,8 +62,6 @@ export const useCreateTableRelationships = (
dataSourceName: string,
globalMutateOptions?: MetadataMigrationOptions
) => {
const invalidateMetadata = useInvalidateMetadata();
// get these capabilities
const { data: driverCapabilties = [] } = useAllDriverCapabilities({
@ -152,7 +146,6 @@ export const useCreateTableRelationships = (
...globalMutateOptions,
errorTransform: transformErrorResponse,
onSuccess: (data, variable, ctx) => {
invalidateMetadata();
globalMutateOptions?.onSuccess?.(data, variable, ctx);
},
});

View File

@ -34,8 +34,6 @@ export const useManageLocalRelationship = ({
const mutationOptions = useMemo(
() => ({
onSuccess: () => {
queryClient.invalidateQueries(generateQueryKeys.metadata());
queryClient.invalidateQueries(
generateQueryKeys.suggestedRelationships({ dataSourceName, table })
);

View File

@ -1,14 +1,13 @@
import { useMetadataMigration } from '../../MetadataAPI';
import { useCallback, useMemo } from 'react';
import { useQueryClient } from 'react-query';
import { useMetadataMigration } from '../../MetadataAPI';
import { useMetadata } from '../../hasura-metadata-api';
import { RemoteDatabaseRelationship } from '../types';
import {
generateRemoteRelationshipCreateRequest,
generateRemoteRelationshipEditRequest,
generateRemoteRelationshipDeleteRequest,
generateRemoteRelationshipEditRequest,
} from '../utils/generateRequest';
import { generateQueryKeys } from '../utils/queryClientUtils';
export const useManageRemoteDatabaseRelationship = ({
dataSourceName,
@ -31,7 +30,6 @@ export const useManageRemoteDatabaseRelationship = ({
const mutationOptions = useMemo(
() => ({
onSuccess: () => {
queryClient.invalidateQueries(generateQueryKeys.metadata());
onSuccess?.();
},
onError: (err: Error) => {

View File

@ -1,14 +1,13 @@
import { useMetadataMigration } from '../../MetadataAPI';
import { useCallback, useMemo } from 'react';
import { useQueryClient } from 'react-query';
import { useMetadataMigration } from '../../MetadataAPI';
import { useMetadata } from '../../hasura-metadata-api';
import { RemoteSchemaRelationship } from '../types';
import {
generateRemoteRelationshipCreateRequest,
generateRemoteRelationshipEditRequest,
generateRemoteRelationshipDeleteRequest,
generateRemoteRelationshipEditRequest,
} from '../utils/generateRequest';
import { generateQueryKeys } from '../utils/queryClientUtils';
export const useManageRemoteSchemaRelationship = ({
dataSourceName,
@ -31,7 +30,6 @@ export const useManageRemoteSchemaRelationship = ({
const mutationOptions = useMemo(
() => ({
onSuccess: () => {
queryClient.invalidateQueries(generateQueryKeys.metadata());
onSuccess?.();
},
onError: (err: Error) => {

View File

@ -11,7 +11,6 @@ interface ManyTablesParams {
}
export const generateQueryKeys = {
metadata: () => ['export_metadata'],
fkConstraints: (params: BaseParams) =>
[
'dal-introspection',

View File

@ -3,12 +3,34 @@ import { Api } from '../../../hooks/apiUtils';
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
import { useSelector } from 'react-redux';
import type { MetadataResponse } from '../types';
import {
METADATA_QUERY_KEY,
MetadataQueryKey,
} from '../../hasura-metadata-api/useMetadata';
// overloads
/**
*
* @deprecated
* this metadata library function is no longer recommended.
* Please use the `useMetadata` from the features/hasura-metadata-api
*/
export function useMetadata(): UseQueryResult<MetadataResponse, Error>;
/**
*
* @deprecated
* this metadta library function is no longer recommended.
* Please use the `useMetadata` from the features/hasura-metadata-api
*/
export function useMetadata<T extends (d: MetadataResponse) => any>(
select: T
): UseQueryResult<ReturnType<T>, Error>;
/**
*
* @deprecated
* this metadta library function is no longer recommended.
* Please use the `useMetadata` from the features/hasura-metadata-api
*/
export function useMetadata<
T extends (d: MetadataResponse) => any,
D extends (d: ReturnType<T>) => any
@ -16,16 +38,21 @@ export function useMetadata<
select: T,
transformFn: D,
queryOptions?: Omit<
UseQueryOptions<MetadataResponse, Error, ReturnType<T>, 'metadata'>,
UseQueryOptions<MetadataResponse, Error, ReturnType<T>, MetadataQueryKey>,
'queryKey' | 'queryFn'
>
): UseQueryResult<ReturnType<D>, Error>;
/**
*
* @deprecated
* this metadta library function is no longer recommended.
* Please use the `useMetadata` from the features/hasura-metadata-api
*/
export function useMetadata(
select = (d: MetadataResponse) => d,
transformFn = (d: unknown) => d,
queryOptions?: Omit<
UseQueryOptions<MetadataResponse, Error, unknown, 'metadata'>,
UseQueryOptions<MetadataResponse, Error, unknown, MetadataQueryKey>,
'queryKey' | 'queryFn'
>
) {
@ -49,7 +76,7 @@ export function useMetadata(
};
return useQuery({
queryKey: 'metadata',
queryKey: METADATA_QUERY_KEY,
queryFn,
...queryOptions,
select: d => transformFn(select(d)),

View File

@ -5,6 +5,7 @@ import Endpoints from '../../../Endpoints';
import { Api } from '../../../hooks/apiUtils';
import { useConsoleConfig } from '../../../hooks/useEnvVars';
import { allowedMetadataTypes, MetadataResponse } from '../types';
import { useInvalidateMetadata } from '../../hasura-metadata-api';
const maxAllowedLength = 255;
const unixEpochLength = 14;
@ -46,7 +47,8 @@ export function useMetadataMigration<
metadataMigrationOptions: MetadataMigrationOptions<
ResponseType,
ArgsType
> = {}
> = {},
additionalQueryKeysToInvalidate?: string[]
) {
const { errorTransform, ...mutationOptions } = metadataMigrationOptions;
@ -57,11 +59,14 @@ export function useMetadataMigration<
string
>;
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
let lastBody: any = null;
return useMutation(
async props => {
const { query } = props;
const body = query;
lastBody = body;
const result = await Api.post<ResponseType>(
{
url: Endpoints.metadata,
@ -94,10 +99,20 @@ export function useMetadataMigration<
});
}
/*
Get the latest metadata from server (this will NOT update metadata that is in the redux state, to do that please pass a custom onSuccess)
*/
queryClient.refetchQueries(['metadata'], { active: true });
invalidateMetadata({
componentName: 'useMetadataMigration()',
reasons: [
'Metadata migration occurred',
`Migration Type: ${lastBody.type}`,
`Migration Body:`,
JSON.stringify(lastBody, null, 2),
],
additionalQueryKeys:
additionalQueryKeysToInvalidate &&
additionalQueryKeysToInvalidate?.length > 0
? additionalQueryKeysToInvalidate
: undefined,
});
const { onSuccess } = mutationOptions ?? {};
if (onSuccess) {

View File

@ -1,9 +1,8 @@
import type { SetOpenTelemetryQuery } from '../../../hasura-metadata-types';
import { useMetadataVersion, useMetadataMigration } from '../../../MetadataAPI';
import { useMetadataMigration, useMetadataVersion } from '../../../MetadataAPI';
import { useFireNotification } from '../../../../new-components/Notifications';
import { useInvalidateMetadata } from '../../../hasura-metadata-api';
import type { FormValues } from '../../OpenTelemetry/components/Form/schema';
@ -22,7 +21,6 @@ function errorTransform(error: unknown) {
export function useSetOpenTelemetry() {
const mutation = useMetadataMigration({ errorTransform });
const { data: version } = useMetadataVersion();
const invalidateMetadata = useInvalidateMetadata();
const { fireNotification } = useFireNotification();
@ -45,7 +43,6 @@ export function useSetOpenTelemetry() {
{
onSuccess: () => {
resolve();
invalidateMetadata();
fireNotification({
title: 'Success!',

View File

@ -1,15 +1,15 @@
import { useQueryClient } from 'react-query';
import { AxiosInstance } from 'axios';
import { useQueryClient } from 'react-query';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { exportMetadata } from '../../../../DataSource';
import { useHttpClient } from '../../../../Network';
import { useFireNotification } from '../../../../../new-components/Notifications';
import { AccessType, QueryType } from '../../../types';
import { api } from '../../api';
import { isPermission, keyToPermission } from '../../../utils';
import { PermissionsSchema } from '../../../schema';
import { exportMetadata } from '../../../../DataSource';
import { useMetadataMigration } from '../../../../MetadataAPI';
import { useHttpClient } from '../../../../Network';
import { Table } from '../../../../hasura-metadata-types';
import { PermissionsSchema } from '../../../schema';
import { AccessType, QueryType } from '../../../types';
import { isPermission, keyToPermission } from '../../../utils';
import { api } from '../../api';
export interface UseSubmitFormArgs {
dataSourceName: string;
@ -68,11 +68,12 @@ export const useSubmitForm = (args: UseSubmitFormArgs) => {
args;
const queryClient = useQueryClient();
const httpClient = useHttpClient();
const { fireNotification } = useFireNotification();
const mutate = useMetadataMigration();
const mutate = useMetadataMigration(undefined, ['roles']);
const submit = async (formData: PermissionsSchema) => {
const { metadata, resource_version } = await exportMetadata({
@ -129,7 +130,6 @@ export const useSubmitForm = (args: UseSubmitFormArgs) => {
});
},
onSettled: () => {
queryClient.invalidateQueries(['export_metadata', 'roles']);
queryClient.invalidateQueries([
dataSourceName,
'permissionFormData',

View File

@ -1,10 +1,11 @@
import { useMutation } from 'react-query';
import Endpoints from '../../../../Endpoints';
import { Api } from '../../../../hooks/apiUtils';
import { useAppSelector } from '../../../../storeHooks';
import { useMutation, useQueryClient } from 'react-query';
import { useInvalidateMetadata } from '../../../hasura-metadata-api';
export const useAddRemoteSchemaRelationship = () => {
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
const headers = useAppSelector(state => state.tables.dataHeaders);
return useMutation(
@ -19,13 +20,16 @@ export const useAddRemoteSchemaRelationship = () => {
}),
{
onSuccess: () => {
queryClient.refetchQueries(['metadata'], { active: true });
invalidateMetadata({
componentName: 'useAddRemoteSchemaRelationship',
reasons: ['added a remote schema relationship'],
});
},
}
);
};
export const useDropRemoteSchemaRelationship = () => {
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
const headers = useAppSelector(state => state.tables.dataHeaders);
return useMutation(
@ -40,7 +44,10 @@ export const useDropRemoteSchemaRelationship = () => {
}),
{
onSuccess: () => {
queryClient.refetchQueries(['metadata'], { active: true });
invalidateMetadata({
componentName: 'useDropRemoteSchemaRelationship',
reasons: ['dropped a remote schema relationship'],
});
},
onError: () => {},
}
@ -48,7 +55,7 @@ export const useDropRemoteSchemaRelationship = () => {
};
export const useUpdateRemoteSchemaRelationship = () => {
const queryClient = useQueryClient();
const invalidateMetadata = useInvalidateMetadata();
const headers = useAppSelector(state => state.tables.dataHeaders);
return useMutation(
@ -63,7 +70,10 @@ export const useUpdateRemoteSchemaRelationship = () => {
}),
{
onSuccess: () => {
queryClient.refetchQueries(['metadata'], { active: true });
invalidateMetadata({
componentName: 'useUpdateRemoteSchemaRelationship',
reasons: ['updated a remote schema relationship'],
});
},
onError: () => {},
}

View File

@ -4,7 +4,10 @@ export {
useInconsistentMetadata,
useInvalidateInconsistentMetadata,
} from './useInconsistentMetadata';
export { useMetadata, useInvalidateMetadata } from './useMetadata';
export { useMetadata } from './useMetadata';
export type { MetadataQueryKey } from './useMetadata';
export { useInvalidateMetadata } from './useInvalidateMetadata';
export { useSyncResourceVersionOnMount } from './useSyncResourceVersionOnMount';
export { areTablesEqual } from './areTablesEqual';
export { MetadataSelectors };
export { MetadataUtils };

View File

@ -0,0 +1,16 @@
import { Metadata } from '../hasura-metadata-types';
import { reactQueryClient } from '../../lib/reactQuery';
import { METADATA_QUERY_KEY } from './useMetadata';
/**
*
* You only want to use these in helper libraries, and not in React Components.
*
* NEVER use these in React Components as it could produce unexpected results.
*
*/
export const MetadataHelpers = {
getQueryData: () =>
reactQueryClient.getQueryData<Metadata>(METADATA_QUERY_KEY),
invalidate: () => reactQueryClient.invalidateQueries(METADATA_QUERY_KEY),
};

View File

@ -0,0 +1,40 @@
import { useCallback } from 'react';
import { useQueryClient } from 'react-query';
import globals from '../../Globals';
import { METADATA_QUERY_KEY } from './useMetadata';
export type LogMetadataInvalidationProps = {
componentName: string;
reasons: string[];
};
export const logMetadataInvalidation = ({
componentName,
reasons,
}: LogMetadataInvalidationProps) => {
if (!globals.isProduction) {
const logLabel = 'Invalidating Metadata...';
console.groupCollapsed(logLabel);
console.info(`Component: ${componentName}`);
console.info(`Reasons:`);
reasons.forEach(reason => console.info(`\t${reason}`));
console.groupEnd();
}
};
export const useInvalidateMetadata = () => {
const queryClient = useQueryClient();
const invalidate = useCallback(
(
props: LogMetadataInvalidationProps & { additionalQueryKeys?: string[] }
) => {
logMetadataInvalidation(props);
queryClient.invalidateQueries([
METADATA_QUERY_KEY,
...(props?.additionalQueryKeys ?? []),
]);
},
[queryClient]
);
return invalidate;
};

View File

@ -1,10 +1,10 @@
import { exportMetadata } from './exportMetadata';
import { Metadata } from '../hasura-metadata-types';
import { useHttpClient } from '../Network';
import { useCallback } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import { useQuery } from 'react-query';
import { APIError } from '../../hooks/error';
import { useAppDispatch } from '../../storeHooks';
import { useHttpClient } from '../Network';
import { Metadata } from '../hasura-metadata-types';
import { exportMetadata } from './exportMetadata';
import { getCurrentReduxResourceVersion } from '../../store/utils/';
export const DEFAULT_STALE_TIME = 5 * 60000; // 5 minutes as default stale time
@ -14,17 +14,9 @@ export const DEFAULT_STALE_TIME = 5 * 60000; // 5 minutes as default stale time
Default stale time is 5 minutes, but can be adjusted using the staleTime arg
*/
export const METADATA_QUERY_KEY = 'export_metadata';
export type MetadataQueryKey = 'export_metadata';
export const useInvalidateMetadata = () => {
const queryClient = useQueryClient();
const invalidate = useCallback(
() => queryClient.invalidateQueries([METADATA_QUERY_KEY]),
[queryClient]
);
return invalidate;
};
export const METADATA_QUERY_KEY: MetadataQueryKey = 'export_metadata';
type Options = {
staleTime?: number;
@ -39,7 +31,7 @@ export const useMetadata = <FinalResult = Metadata>(
}
) => {
const httpClient = useHttpClient();
const invalidateMetadata = useInvalidateMetadata();
const dispatch = useAppDispatch();
const queryReturn = useQuery<Metadata, APIError, FinalResult>({
@ -47,10 +39,12 @@ export const useMetadata = <FinalResult = Metadata>(
queryFn: async () => {
const result = await exportMetadata({ httpClient });
if (result.resource_version !== getCurrentReduxResourceVersion()) {
dispatch({
type: 'Metadata/EXPORT_METADATA_SUCCESS',
data: result,
});
}
return result;
},
@ -62,6 +56,5 @@ export const useMetadata = <FinalResult = Metadata>(
return {
...queryReturn,
invalidateMetadata,
};
};

View File

@ -0,0 +1,41 @@
import { useEffect } from 'react';
import { getCurrentReduxResourceVersion } from '../../store/utils';
import { useInvalidateMetadata } from './useInvalidateMetadata';
import { useMetadata } from './useMetadata';
/**
*
* This hook checks if the react-query resource_version is out of sync with the redux store on component mount
* If it is, it performs a react-query invalidation of the metadata key and logs the action.
*
*/
export const useSyncResourceVersionOnMount = ({
componentName,
}: {
componentName: string;
}) => {
const { data: reactQueryResourceVersion } = useMetadata(
m => m.resource_version
);
const reduxResourceVersion = getCurrentReduxResourceVersion();
const invalidateMetadata = useInvalidateMetadata();
useEffect(() => {
if (
reduxResourceVersion &&
reactQueryResourceVersion &&
reduxResourceVersion > reactQueryResourceVersion
) {
invalidateMetadata({
componentName,
reasons: [
`(useSyncResourceVersionOnMount)`,
`Resource versions detected to be out of sync on component mount...`,
`redux: ${reduxResourceVersion}`,
`react-query: ${reactQueryResourceVersion}`,
],
});
}
}, []);
};

View File

@ -1,6 +1,6 @@
import { routerMiddleware } from 'react-router-redux';
import { browserHistory } from 'react-router';
import { listenForStoreMetadataChanges } from './store.utils';
import { reduxStoreListener } from './store/utils/';
// Since we only use it in dev, this warning doesn't make sense.
// eslint-disable-next-line import/no-extraneous-dependencies
@ -25,7 +25,7 @@ export const store = configureStore({
devTools: __DEVELOPMENT__,
});
listenForStoreMetadataChanges(store);
reduxStoreListener(store);
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;

View File

@ -1,47 +0,0 @@
import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import { reactQueryClient } from './lib/reactQuery';
import { Metadata } from './features/hasura-metadata-types';
import { METADATA_QUERY_KEY } from './features/hasura-metadata-api/useMetadata';
export const listenForStoreMetadataChanges = (store: ToolkitStore) => {
let previousStore: any = null;
store.subscribe(() => {
if (!previousStore || previousStore?.metadata?.metadataObject == null) {
previousStore = store.getState();
return;
}
const currentStore = store.getState();
const reactQueryResourceVersion =
reactQueryClient.getQueryData<Metadata>(
METADATA_QUERY_KEY
)?.resource_version;
if (
currentStore?.metadata?.resourceVersion >
previousStore?.metadata?.resourceVersion &&
currentStore?.metadata?.resourceVersion !== reactQueryResourceVersion
) {
console.groupCollapsed(
'Metadata change occurred in redux, and is no longer in sync with react-query:'
);
console.info(
`current redux store rv: ${currentStore?.metadata?.resourceVersion}`
);
console.info(
`previous redux store rv: ${previousStore?.metadata?.resourceVersion}`
);
console.info(`react query rv: ${reactQueryResourceVersion}`);
console.info(
`Triggering react-query invalidation of query key: ${METADATA_QUERY_KEY}`
);
console.groupEnd();
reactQueryClient.invalidateQueries(METADATA_QUERY_KEY);
}
previousStore = currentStore;
});
};

View File

@ -0,0 +1,2 @@
export { reduxStoreListener } from './reduxStoreListener';
export { getCurrentReduxResourceVersion } from './store-change-handlers/currentReduxResourceVersion';

View File

@ -0,0 +1,10 @@
import { updateReduxResourceVersion } from './store-change-handlers/currentReduxResourceVersion';
import { syncResourceVersions } from './store-change-handlers/syncResourceVersions';
export type OnStoreChangeProps = { currentStore: any; previousStore: any };
export const onStoreChange = (props: OnStoreChangeProps) => {
// execute functions here....
syncResourceVersions(props);
updateReduxResourceVersion(props);
};

View File

@ -0,0 +1,21 @@
import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import { onStoreChange } from './onStoreChange';
// listens for any redux store changes:
export const reduxStoreListener = (store: ToolkitStore) => {
let previousStore: any = null;
store.subscribe(() => {
if (!previousStore) {
previousStore = store.getState();
return;
}
const currentStore = store.getState();
// execute code on store change:
onStoreChange({ currentStore, previousStore });
previousStore = currentStore;
});
};

View File

@ -0,0 +1,19 @@
import type { OnStoreChangeProps } from '../onStoreChange';
// private module variable
let CURRENT_REDUX_RESOURCE_VERSION = 0;
/**
* Public exported function to read private variable
*
* This is intended to get the current resourceVersion from redux. Will NOT react to new changes so don't use it as a reactive value
*/
export const getCurrentReduxResourceVersion = () => {
return CURRENT_REDUX_RESOURCE_VERSION;
};
export const updateReduxResourceVersion = ({
currentStore,
}: OnStoreChangeProps) => {
CURRENT_REDUX_RESOURCE_VERSION = currentStore?.metadata?.resourceVersion;
};

View File

@ -0,0 +1,40 @@
import { MetadataHelpers } from '../../../features/hasura-metadata-api/metadataHelpers';
import { logMetadataInvalidation } from '../../../features/hasura-metadata-api/useInvalidateMetadata';
import { OnStoreChangeProps } from '../onStoreChange';
export const syncResourceVersions = ({
currentStore,
previousStore,
}: OnStoreChangeProps) => {
if (previousStore.metadata?.metadataObject == null) {
// if this is true, then no actual metadata change occurred.
// metadata just changed from default state to initial actual metadata
return;
}
const redux = {
previousResourceVersion: previousStore?.metadata?.resourceVersion,
resourceVersion: currentStore?.metadata?.resourceVersion,
};
const reactQueryResourceVersion =
MetadataHelpers.getQueryData()?.resource_version ?? 0;
if (
redux.resourceVersion > redux.previousResourceVersion &&
redux.resourceVersion > reactQueryResourceVersion
) {
// log the invalidation:
logMetadataInvalidation({
componentName: 'syncResourceVersions() in reduxStoreListener()',
reasons: [
`Inconsistent resourse version detected between redux and react-query after redux changes:`,
`previous redux version: ${redux.previousResourceVersion}`,
`current redux version: ${redux.resourceVersion}`,
`current react-query version: ${reactQueryResourceVersion}`,
],
});
// invalidate react-query's metadata key:
MetadataHelpers.invalidate();
}
};

View File

@ -2,7 +2,7 @@ import { compose, createStore, applyMiddleware } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import { browserHistory } from 'react-router';
import thunk from 'redux-thunk';
import { listenForStoreMetadataChanges } from '@hasura/console-legacy-ce';
import { reduxStoreListener } from '@hasura/console-legacy-ce';
import reducer from './reducer';
@ -27,6 +27,6 @@ if (__DEVELOPMENT__) {
const store = _finalCreateStore(reducer);
listenForStoreMetadataChanges(store);
reduxStoreListener(store);
export default store;