mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
console: refactor modify tab metadata hooks [GDC-666]
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7165 GitOrigin-RevId: b46408b3395198ac84f62eeae31a6bde3133c65f
This commit is contained in:
parent
ed190d6cb6
commit
bffdc2f930
@ -16,7 +16,7 @@ import {
|
||||
} from './LegacyRunQueryContainer.utils';
|
||||
import { LegacyRunQuery } from './LegacyRunQuery';
|
||||
import { FiltersAndSortFormValues, UserQuery } from '../types';
|
||||
import { useTableColumns } from '../hooks/useTableColumns';
|
||||
import { useLegacyTableColumns } from '../hooks/useLegacyTableColumns';
|
||||
import { useTableName } from '../hooks/useTableName';
|
||||
import { useDatabaseOperators } from '../hooks/useDatabaseOperators';
|
||||
import { useTableSchema } from '../hooks/useTableSchema';
|
||||
@ -69,7 +69,7 @@ export const LegacyRunQueryContainer = ({
|
||||
const curFilter = useAppSelector(state => state.tables.view.curFilter);
|
||||
const limit = curFilter.limit;
|
||||
|
||||
const tableColumns = useTableColumns({ dataSourceName, table });
|
||||
const tableColumns = useLegacyTableColumns({ dataSourceName, table });
|
||||
const tableOperators = useDatabaseOperators({ dataSourceName });
|
||||
const tableSchema = useTableSchema(table);
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useIsUnmounted } from '@/components/Services/Data';
|
||||
import { DataSource, TableColumn } from '@/features/DataSource';
|
||||
import { useHttpClient } from '@/features/Network';
|
||||
import { useIsUnmounted } from '@/components/Services/Data';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
type UseTableColumnsProps = {
|
||||
dataSourceName: string;
|
||||
table: unknown;
|
||||
};
|
||||
|
||||
export const useTableColumns = ({
|
||||
export const useLegacyTableColumns = ({
|
||||
dataSourceName,
|
||||
table,
|
||||
}: UseTableColumnsProps) => {
|
@ -10,4 +10,4 @@ export {
|
||||
convertUserQueryToFiltersAndSortFormValues,
|
||||
} from './components/RunQuery/LegacyRunQueryContainer/LegacyRunQueryContainer.utils';
|
||||
export { UserQuery } from './components/RunQuery/types';
|
||||
export { useTableColumns } from './components/RunQuery/hooks/useTableColumns';
|
||||
export { useTableColumns } from './hooks';
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { MetadataSelectors, useMetadata } from '@/features/hasura-metadata-api';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { Dialog } from '@/new-components/Dialog';
|
||||
import { InputField, UpdatedForm } from '@/new-components/Form';
|
||||
import { sanitizeGraphQLFieldNames } from '@/utils';
|
||||
import { SanitizeTips } from '@/utils/sanitizeGraphQLFieldNames';
|
||||
import React from 'react';
|
||||
import {
|
||||
useMetadataTable,
|
||||
useUpdateTableConfiguration,
|
||||
} from '../../../ModifyTable/hooks';
|
||||
import { useUpdateTableConfiguration } from '../../../ModifyTable/hooks';
|
||||
import { ModifyTableProps } from '../../ModifyTable';
|
||||
import { ModifyTableColumn } from '../../types';
|
||||
import { schema, Schema } from './schema';
|
||||
@ -20,7 +18,9 @@ interface EditTableColumnDialogProps extends ModifyTableProps {
|
||||
export const EditTableColumnDialog = (props: EditTableColumnDialogProps) => {
|
||||
const { onClose, column, table, dataSourceName } = props;
|
||||
|
||||
const { metadataTable } = useMetadataTable(dataSourceName, table);
|
||||
const { data: metadataTable } = useMetadata(
|
||||
MetadataSelectors.findTable(dataSourceName, table)
|
||||
);
|
||||
|
||||
const { isLoading: isSaveInProgress, updateTableConfiguration } =
|
||||
useUpdateTableConfiguration(dataSourceName, table);
|
||||
|
@ -10,11 +10,10 @@ import { ModifyTableProps } from '../ModifyTable';
|
||||
interface TableColumnProps extends ModifyTableProps {}
|
||||
export const TableColumns: React.VFC<TableColumnProps> = props => {
|
||||
const { dataSourceName, table } = props;
|
||||
const {
|
||||
data: columns,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useListAllTableColumns(dataSourceName, table);
|
||||
const { columns, isLoading, isError } = useListAllTableColumns(
|
||||
dataSourceName,
|
||||
table
|
||||
);
|
||||
|
||||
const [isEditColumnFormActive, setIsEditColumnFormActive] = useState(false);
|
||||
const [selectedColumn, setSelectedColumn] = useState<ModifyTableColumn>();
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { MetadataUtils, useMetadata } from '@/features/hasura-metadata-api';
|
||||
import { Table } from '@/features/hasura-metadata-types';
|
||||
import useUpdateEffect from '@/hooks/useUpdateEffect';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { IndicatorCard } from '@/new-components/IndicatorCard';
|
||||
import { Nullable } from '@/types';
|
||||
import clsx from 'clsx';
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import TextareaAutosize from 'react-autosize-textarea';
|
||||
import { FaEdit, FaRegComment } from 'react-icons/fa';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { useUpdateTableConfiguration } from '../hooks';
|
||||
|
||||
import { ModifyTableProps } from '../ModifyTable';
|
||||
@ -19,7 +21,11 @@ export interface TableCommentsProps extends ModifyTableProps {
|
||||
export const TableComments: React.VFC<TableCommentsProps> = props => {
|
||||
const { dataSourceName, table } = props;
|
||||
|
||||
const { isLoading, data: savedComment } = useMetadata(
|
||||
const {
|
||||
isLoading,
|
||||
data: savedComment,
|
||||
isError,
|
||||
} = useMetadata(
|
||||
m =>
|
||||
MetadataUtils.findMetadataTable(dataSourceName, table, m)?.configuration
|
||||
?.comment
|
||||
@ -27,15 +33,25 @@ export const TableComments: React.VFC<TableCommentsProps> = props => {
|
||||
|
||||
const [comment, setComment] = React.useState<Nullable<string>>(null);
|
||||
|
||||
const saveNeeded = useMemo(
|
||||
() => comment != null && comment !== savedComment,
|
||||
[comment, savedComment]
|
||||
);
|
||||
useUpdateEffect(() => {
|
||||
// this resets the state so we aren't carrying over the comment from a previous table
|
||||
// prevents the saveNeeded from becoming inaccurate
|
||||
setComment(null);
|
||||
}, [table]);
|
||||
|
||||
const saveNeeded = comment != null && comment !== savedComment;
|
||||
|
||||
const { updateTableConfiguration, isLoading: savingComment } =
|
||||
useUpdateTableConfiguration(dataSourceName, table);
|
||||
|
||||
if (isLoading) return <IndicatorCard status="info">Loading...</IndicatorCard>;
|
||||
if (isLoading) return <Skeleton count={5} height={20} />;
|
||||
|
||||
if (isError)
|
||||
return (
|
||||
<IndicatorCard status="negative" headline="Error">
|
||||
Unable to fetch table comments.
|
||||
</IndicatorCard>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mb-lg flex items-center">
|
||||
@ -43,11 +59,11 @@ export const TableComments: React.VFC<TableCommentsProps> = props => {
|
||||
<TextareaAutosize
|
||||
style={{ minWidth: '24rem', outline: 'none' }}
|
||||
rows={1}
|
||||
key={savedComment}
|
||||
className={clsx(
|
||||
'bg-secondary-light border border-gray-300 border-l-4 border-l-secondary p-sm peer',
|
||||
'focus:bg-white rounded focus:[box-shadow:none] focus:border-secondary',
|
||||
'placeholder-shown:italic pl-9',
|
||||
saveNeeded && 'border-l-red-500 '
|
||||
'placeholder-shown:italic pl-9'
|
||||
)}
|
||||
name="comments"
|
||||
defaultValue={savedComment}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { TableTrackingCustomizationModal } from '@/components/Services/Data/Schema/tableTrackCustomization/TableTrackingCustomizationModal';
|
||||
import { MetadataSelectors, useMetadata } from '@/features/hasura-metadata-api';
|
||||
import { Button } from '@/new-components/Button';
|
||||
import { IndicatorCard } from '@/new-components/IndicatorCard';
|
||||
import React from 'react';
|
||||
import { useMetadataTable, useUpdateTableConfiguration } from '../hooks';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { useUpdateTableConfiguration } from '../hooks';
|
||||
import { ModifyTableProps } from '../ModifyTable';
|
||||
|
||||
const RootField: React.VFC<{ property: string; value: string }> = ({
|
||||
@ -18,14 +21,24 @@ const RootField: React.VFC<{ property: string; value: string }> = ({
|
||||
export const TableRootFields: React.VFC<ModifyTableProps> = props => {
|
||||
const { dataSourceName, table, tableName } = props;
|
||||
const [showCustomModal, setShowCustomModal] = React.useState(false);
|
||||
const { metadataTable, isLoading } = useMetadataTable(dataSourceName, table);
|
||||
|
||||
const {
|
||||
data: metadataTable,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useMetadata(MetadataSelectors.findTable(dataSourceName, table));
|
||||
|
||||
const { updateCustomRootFields, isLoading: saving } =
|
||||
useUpdateTableConfiguration(dataSourceName, table);
|
||||
|
||||
if (isLoading) {
|
||||
return null;
|
||||
}
|
||||
if (isLoading) return <Skeleton count={5} height={20} />;
|
||||
|
||||
if (isError)
|
||||
return (
|
||||
<IndicatorCard status="negative" headline="Error">
|
||||
Unable to fetch table data.
|
||||
</IndicatorCard>
|
||||
);
|
||||
|
||||
const isEmpty =
|
||||
!metadataTable?.configuration?.custom_name &&
|
||||
|
@ -1,7 +1,2 @@
|
||||
export {
|
||||
getTableFromMetadata,
|
||||
manageTableMetadataQueryKey,
|
||||
useMetadataTable,
|
||||
useListAllTableColumns,
|
||||
} from './useMetadataForManageTable';
|
||||
export { useListAllTableColumns } from './useListAllTableColumns';
|
||||
export { useUpdateTableConfiguration } from './useUpdateTableConfiguration';
|
||||
|
@ -0,0 +1,26 @@
|
||||
import { useTableColumns } from '@/features/BrowseRows';
|
||||
import { MetadataSelectors, useMetadata } from '@/features/hasura-metadata-api';
|
||||
|
||||
export const useListAllTableColumns = (
|
||||
dataSourceName: string,
|
||||
table: unknown
|
||||
) => {
|
||||
const { data: tableColumns } = useTableColumns({
|
||||
table,
|
||||
dataSourceName,
|
||||
});
|
||||
|
||||
const { data: metadataTable, ...rest } = useMetadata(
|
||||
MetadataSelectors.findTable(dataSourceName, table)
|
||||
);
|
||||
|
||||
const tableConfig = metadataTable?.configuration?.column_config;
|
||||
|
||||
return {
|
||||
columns: (tableColumns?.columns ?? []).map(tableColumn => ({
|
||||
...tableColumn,
|
||||
config: tableConfig?.[tableColumn.name],
|
||||
})),
|
||||
...rest,
|
||||
};
|
||||
};
|
@ -1,106 +0,0 @@
|
||||
import { exportMetadata } from '@/features/DataSource';
|
||||
import { Source } from '@/features/hasura-metadata-types';
|
||||
import { useHttpClient } from '@/features/Network';
|
||||
import { AxiosError } from 'axios';
|
||||
import isEqual from 'lodash.isequal';
|
||||
import React from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useTableColumns } from '@/features/BrowseRows/hooks/useTableColumns';
|
||||
|
||||
export const getTableFromMetadata = (
|
||||
metadata: Source | undefined,
|
||||
table: unknown
|
||||
) => {
|
||||
if (!table) return null;
|
||||
return metadata?.tables.find(t => isEqual(t.table, table));
|
||||
};
|
||||
|
||||
export const manageTableMetadataQueryKey = (dataSourceName: string) => [
|
||||
'manage-table-metadata',
|
||||
dataSourceName,
|
||||
];
|
||||
|
||||
// adding underscore to prevent conflicts or confusion as this is only mean to be for this scope
|
||||
export const useMetadataForManageTable = (
|
||||
dataSourceName: string,
|
||||
queryEnabled = true
|
||||
) => {
|
||||
const httpClient = useHttpClient();
|
||||
|
||||
return useQuery<
|
||||
{ metadata: Source; resource_version: number } | undefined,
|
||||
AxiosError
|
||||
>({
|
||||
queryKey: manageTableMetadataQueryKey(dataSourceName),
|
||||
queryFn: async () => {
|
||||
const { metadata, resource_version } = await exportMetadata({
|
||||
httpClient,
|
||||
});
|
||||
|
||||
if (!metadata) throw Error('Unable to fetch sources from metadata');
|
||||
|
||||
const metadataSource = metadata.sources.find(
|
||||
source => source.name === dataSourceName
|
||||
);
|
||||
|
||||
if (!metadataSource) throw Error('Unable to find the source in metadata');
|
||||
|
||||
const data = {
|
||||
metadata: metadataSource,
|
||||
resource_version,
|
||||
};
|
||||
|
||||
return data;
|
||||
},
|
||||
enabled: queryEnabled,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const useMetadataTable = (dataSourceName: string, table: unknown) => {
|
||||
const { data, ...rest } = useMetadataForManageTable(dataSourceName);
|
||||
|
||||
const metadataTable = React.useMemo(
|
||||
() => getTableFromMetadata(data?.metadata, table),
|
||||
[table, data?.metadata]
|
||||
);
|
||||
|
||||
return {
|
||||
metadata: data?.metadata,
|
||||
resource_version: data?.resource_version,
|
||||
metadataTable,
|
||||
...rest,
|
||||
};
|
||||
};
|
||||
|
||||
export const useListAllTableColumns = (
|
||||
dataSourceName: string,
|
||||
table: unknown
|
||||
) => {
|
||||
const { data: tableColumns, isFetching: isIntrospectionReady } =
|
||||
useTableColumns({
|
||||
table,
|
||||
dataSourceName,
|
||||
});
|
||||
|
||||
const { data, ...rest } = useMetadataForManageTable(
|
||||
dataSourceName,
|
||||
!isIntrospectionReady
|
||||
);
|
||||
|
||||
const metadataTable = React.useMemo(
|
||||
() => getTableFromMetadata(data?.metadata, table),
|
||||
[table, data?.metadata]
|
||||
);
|
||||
|
||||
const tableConfig = metadataTable?.configuration?.column_config;
|
||||
|
||||
return {
|
||||
data: (tableColumns?.columns ?? []).map(tableColumn => ({
|
||||
...tableColumn,
|
||||
config: tableConfig?.[tableColumn.name],
|
||||
})),
|
||||
...rest,
|
||||
};
|
||||
};
|
@ -1,9 +1,12 @@
|
||||
import {
|
||||
MetadataUtils,
|
||||
useInvalidateMetata,
|
||||
useMetadata,
|
||||
} from '@/features/hasura-metadata-api';
|
||||
import { MetadataTable } from '@/features/hasura-metadata-types';
|
||||
import { useMetadataMigration } from '@/features/MetadataAPI';
|
||||
import { useFireNotification } from '@/new-components/Notifications';
|
||||
import { useCallback } from 'react';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { manageTableMetadataQueryKey, useMetadataTable } from '.';
|
||||
|
||||
export const useUpdateTableConfiguration = (
|
||||
dataSourceName: string,
|
||||
@ -13,20 +16,23 @@ export const useUpdateTableConfiguration = (
|
||||
|
||||
const { fireNotification } = useFireNotification();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const invalidateMetadata = useInvalidateMetata();
|
||||
|
||||
const { metadata, resource_version, metadataTable } = useMetadataTable(
|
||||
dataSourceName,
|
||||
table
|
||||
);
|
||||
const { data } = useMetadata(m => ({
|
||||
source: MetadataUtils.findMetadataSource(dataSourceName, m),
|
||||
resource_version: m.resource_version,
|
||||
metadataTable: MetadataUtils.findMetadataTable(dataSourceName, table, m),
|
||||
}));
|
||||
|
||||
const { source, metadataTable, resource_version } = data || {};
|
||||
|
||||
const updateTableConfiguration = useCallback(
|
||||
(config: MetadataTable['configuration']) => {
|
||||
const driver = metadata?.kind;
|
||||
const driver = source?.kind;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (!metadata) {
|
||||
throw Error('Metadata not found!');
|
||||
if (!source) {
|
||||
throw Error('Data Source not found!');
|
||||
}
|
||||
|
||||
mutate(
|
||||
@ -46,10 +52,8 @@ export const useUpdateTableConfiguration = (
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(
|
||||
manageTableMetadataQueryKey(dataSourceName)
|
||||
);
|
||||
queryClient.invalidateQueries('export_metadata');
|
||||
invalidateMetadata();
|
||||
|
||||
fireNotification({
|
||||
type: 'success',
|
||||
title: 'Success!',
|
||||
@ -72,10 +76,11 @@ export const useUpdateTableConfiguration = (
|
||||
[
|
||||
dataSourceName,
|
||||
fireNotification,
|
||||
metadata,
|
||||
mutate,
|
||||
queryClient,
|
||||
invalidateMetadata,
|
||||
metadataTable,
|
||||
resource_version,
|
||||
source,
|
||||
table,
|
||||
]
|
||||
);
|
||||
@ -98,7 +103,7 @@ export const useUpdateTableConfiguration = (
|
||||
return {
|
||||
updateTableConfiguration,
|
||||
updateCustomRootFields,
|
||||
metadata,
|
||||
source,
|
||||
resource_version,
|
||||
...rest,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as MetadataSelectors from './selectors';
|
||||
import * as MetadataUtils from './utils';
|
||||
|
||||
export { useMetadata } from './useMetadata';
|
||||
export { useMetadata, useInvalidateMetata } from './useMetadata';
|
||||
export { areTablesEqual } from './areTablesEqual';
|
||||
export { MetadataSelectors };
|
||||
export { MetadataUtils };
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { exportMetadata } from '@/features/DataSource';
|
||||
import { Metadata } from '@/features/hasura-metadata-types';
|
||||
import { useHttpClient } from '@/features/Network';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useCallback } from 'react';
|
||||
import { useQuery, useQueryClient } from 'react-query';
|
||||
|
||||
export const DEFAULT_STALE_TIME = 5 * 60000; // 5 minutes as default stale time
|
||||
|
||||
@ -11,13 +12,27 @@ 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
|
||||
*/
|
||||
|
||||
const METADATA_QUERY_KEY = 'export_metadata';
|
||||
|
||||
export const useInvalidateMetata = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const invalidate = useCallback(
|
||||
() => queryClient.invalidateQueries([METADATA_QUERY_KEY]),
|
||||
[queryClient]
|
||||
);
|
||||
|
||||
return invalidate;
|
||||
};
|
||||
|
||||
export const useMetadata = <T = Metadata>(
|
||||
selector?: (m: Metadata) => T,
|
||||
staleTime: number = DEFAULT_STALE_TIME
|
||||
) => {
|
||||
const httpClient = useHttpClient();
|
||||
return useQuery({
|
||||
queryKey: ['export_metadata'],
|
||||
const invalidateMetadata = useInvalidateMetata();
|
||||
|
||||
const queryReturn = useQuery({
|
||||
queryKey: [METADATA_QUERY_KEY],
|
||||
queryFn: async () => {
|
||||
const result = await exportMetadata({ httpClient });
|
||||
return result;
|
||||
@ -26,4 +41,9 @@ export const useMetadata = <T = Metadata>(
|
||||
refetchOnWindowFocus: false,
|
||||
select: selector,
|
||||
});
|
||||
|
||||
return {
|
||||
...queryReturn,
|
||||
invalidateMetadata,
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user