diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/ManageDatabase/ManageDatabase.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/ManageDatabase/ManageDatabase.tsx index 71adc66ab76..2408707dcce 100644 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/ManageDatabase/ManageDatabase.tsx +++ b/frontend/libs/console/legacy-ce/src/lib/features/Data/ManageDatabase/ManageDatabase.tsx @@ -2,7 +2,7 @@ import get from 'lodash/get'; import { Analytics, REDACT_EVERYTHING } from '../../Analytics'; import { ManageTrackedTables } from '../ManageTable/components/ManageTrackedTables'; import { ManageTrackedFunctions } from '../TrackResources/TrackFunctions/components/ManageTrackedFunctions'; -import { ManageTrackedRelationshipsContainer } from '../TrackResources/components/ManageTrackedRelationshipsContainer'; +import { ManageSuggestedRelationships } from '../TrackResources/TrackRelationships/ManageSuggestedRelationships'; import { useDriverCapabilities } from '../hooks/useDriverCapabilities'; import { BreadCrumbs, CollapsibleResource, SourceName } from './parts'; @@ -11,7 +11,6 @@ export interface ManageDatabaseProps { schema?: string; } -//This component has the code for template gallery but is currently commented out until further notice. export const ManageDatabase = ({ dataSourceName }: ManageDatabaseProps) => { const { data: { @@ -55,9 +54,7 @@ export const ManageDatabase = ({ dataSourceName }: ManageDatabaseProps) => { title="Foreign Key Relationships" tooltip="Track foreign key relationships in your database in your GraphQL API" > - + )} diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.stories.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.stories.tsx deleted file mode 100644 index b02690f0220..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { expect } from '@storybook/jest'; -import { StoryObj, Meta } from '@storybook/react'; -import { within } from '@storybook/testing-library'; -import { ReactQueryDecorator } from '../../../../storybook/decorators/react-query'; - -import { Relationship } from '../../../DatabaseRelationships'; -import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships'; -import { ManageTrackedRelationships } from '../components/ManageTrackedRelationships'; - -export default { - title: 'Data/Components/ManageTrackedRelationships', - component: ManageTrackedRelationships, - decorators: [ReactQueryDecorator()], -} as Meta; - -const suggestedRelationships: SuggestedRelationshipWithName[] = []; - -const trackedFKRelationships: Relationship[] = []; - -export const Base: StoryObj = { - render: () => ( - - ), - - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await expect( - canvas.getByText('No untracked relationships found') - ).toBeInTheDocument(); - }, -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.tsx deleted file mode 100644 index bf197dc03b2..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationships.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships'; -import { Relationship } from '../../../DatabaseRelationships/types'; -import { TrackableResourceTabs } from '../../ManageDatabase/components/TrackableResourceTabs'; -import { TrackedRelationshipsContainer } from './TrackedRelationshipsContainer'; -import { UntrackedRelationships } from './UntrackedRelationships'; - -type ManageTrackedRelationshipsProps = { - dataSourceName: string; - suggestedRelationships: SuggestedRelationshipWithName[]; - trackedFKRelationships: Relationship[]; - isLoading: boolean; -}; - -export const ManageTrackedRelationships: React.VFC< - ManageTrackedRelationshipsProps -> = ({ - dataSourceName, - isLoading, - suggestedRelationships, - trackedFKRelationships, -}) => { - const [tab, setTab] = React.useState<'tracked' | 'untracked'>('untracked'); - - if (!suggestedRelationships) - return
Something went wrong
; - - return ( - setTab(value)} - isLoading={isLoading} - items={{ - tracked: { - amount: trackedFKRelationships.length, - content: ( - - ), - }, - untracked: { - amount: suggestedRelationships.length, - content: , - }, - }} - /> - ); -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationshipsContainer.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationshipsContainer.tsx deleted file mode 100644 index f862b46f9e4..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/ManageTrackedRelationshipsContainer.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useAllSuggestedRelationships } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships'; -import { useTrackedRelationships } from './hooks/useTrackedRelationships'; -import { ManageTrackedRelationships } from './ManageTrackedRelationships'; - -export const ManageTrackedRelationshipsContainer = ({ - dataSourceName, -}: { - dataSourceName: string; -}) => { - const { - data: trackedFKRelationships, - isLoading: isLoadingTrackedRelationships, - } = useTrackedRelationships(dataSourceName); - - const { suggestedRelationships, isLoadingSuggestedRelationships } = - useAllSuggestedRelationships({ - dataSourceName, - omitTracked: true, - isEnabled: true, - }); - - if (!suggestedRelationships) - return
Something went wrong
; - - return ( - - ); -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.stories.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.stories.tsx deleted file mode 100644 index d5ee290d9cd..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.stories.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { StoryFn, Meta } from '@storybook/react'; -import { ReactQueryDecorator } from '../../../../storybook/decorators/react-query'; -import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships'; -import { RelationshipRow, RelationshipRowProps } from './RelationshipRow'; -import { action } from '@storybook/addon-actions'; - -export default { - component: RelationshipRow, - decorators: [ReactQueryDecorator()], -} as Meta; - -const relationship: SuggestedRelationshipWithName = { - constraintName: 'Album_Artist', - type: 'object', - from: { - table: 'Album', - columns: ['id'], - }, - to: { - table: 'Artist', - columns: ['albumId'], - }, -}; - -const baseProps: RelationshipRowProps = { - relationship: relationship, - dataSourceName: 'Chinook', - isChecked: false, - isLoading: false, - onCustomize: () => action('onCustomize')(), - onToggle: () => action('onToggle')(), - onTrack: async () => action('onTrack')(), -}; - -export const Base: StoryFn = () => ( - -); - -export const Checked: StoryFn = () => ( - -); diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.tsx deleted file mode 100644 index 0f378f6f177..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/RelationshipRow.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { ChangeEvent, useState } from 'react'; -import { Button } from '../../../../new-components/Button'; -import { CardedTable } from '../../../../new-components/CardedTable'; -import { FaArrowRight, FaColumns, FaDatabase, FaTable } from 'react-icons/fa'; -import { capitaliseFirstLetter } from '../../../../components/Common/ConfigureTransformation/utils'; -import { getTableDisplayName } from '../../../DatabaseRelationships'; -import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships'; - -export type RelationshipRowProps = { - dataSourceName: string; - isChecked: boolean; - isLoading: boolean; - onCustomize: () => void; - onToggle: (e: ChangeEvent) => void; - onTrack: () => Promise; - relationship: SuggestedRelationshipWithName; -}; - -export const RelationshipRow: React.VFC = ({ - dataSourceName, - isChecked, - isLoading, - onCustomize, - onToggle, - onTrack, - relationship, -}) => { - const [isLoadingState, setLoading] = useState(false); - const onTrackHandler = () => { - setLoading(true); - onTrack().finally(() => setLoading(false)); - }; - return ( - - - - - - {relationship.constraintName} - - -
- {dataSourceName} -
-
- - {capitaliseFirstLetter(relationship.type)} - - -
- - {getTableDisplayName(relationship.from.table)} - / - - {relationship.from.columns.join(' ')} - - - {getTableDisplayName(relationship.to.table)} - / - - {relationship.to.columns.join(' ')} -
-
- -
- - -
-
-
- ); -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.stories.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.stories.tsx deleted file mode 100644 index df6c86fcb29..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.stories.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { StoryFn, StoryObj, Meta } from '@storybook/react'; -import { within } from '@storybook/testing-library'; -import { ReactQueryDecorator } from '../../../../storybook/decorators/react-query'; -import { expect } from '@storybook/jest'; -import { TrackedRelationships } from './TrackedRelationships'; -import { action } from '@storybook/addon-actions'; -import { Relationship } from '../../../DatabaseRelationships'; - -export default { - title: 'Data/Components/TrackedRelationships', - component: TrackedRelationships, - decorators: [ReactQueryDecorator()], -} as Meta; - -const relationships: Relationship[] = [ - { - name: 'CUSTOMER_INVOICEs', - fromSource: 'Snow', - fromTable: ['CUSTOMER'], - relationshipType: 'Array', - type: 'localRelationship', - definition: { mapping: {}, toTable: 'INVOICE' }, - }, - { - name: 'INVOICE_CUSTOMER', - fromSource: 'Snow', - fromTable: ['INVOICE'], - relationshipType: 'Object', - type: 'localRelationship', - definition: { - toTable: ['CUSTOMER'], - mapping: { CUSTOMERID: 'CUSTOMERID' }, - }, - }, -]; - -export const Base: StoryObj = { - render: () => ( - action('onRefetchMetadata')()} - relationships={relationships} - /> - ), - - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await expect(canvas.getByText('Untrack Selected (0)')).toBeInTheDocument(); - await expect(canvas.getByText('Show 10 relationships')).toBeInTheDocument(); - await expect(canvas.getByText('RELATIONSHIP NAME')).toBeInTheDocument(); - await expect(canvas.getByText('SOURCE')).toBeInTheDocument(); - await expect(canvas.getByText('TYPE')).toBeInTheDocument(); - await expect(canvas.getByText('RELATIONSHIP')).toBeInTheDocument(); - - await expect(canvas.getByText('CUSTOMER_INVOICEs')).toBeInTheDocument(); - await expect(canvas.getByText('INVOICE_CUSTOMER')).toBeInTheDocument(); - - await expect(canvas.getByText('Array')).toBeInTheDocument(); - await expect(canvas.getByText('Object')).toBeInTheDocument(); - - await expect(canvas.getAllByText('Snow')).toHaveLength(2); - await expect(canvas.getAllByText('Rename')).toHaveLength(2); - await expect(canvas.getAllByText('Remove')).toHaveLength(2); - }, -}; - -export const Loading: StoryFn = () => ( - action('onRefetchMetadata')()} - relationships={relationships} - /> -); - -export const NoRelationships: StoryFn = () => ( - action('onRefetchMetadata')()} - relationships={[]} - /> -); diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.tsx deleted file mode 100644 index 063b364f784..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationships.tsx +++ /dev/null @@ -1,378 +0,0 @@ -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 { paginate } from '../utils'; -import { SearchBar } from './SearchBar'; - -const getQueryFunction = (relationship: Relationship) => { - if (relationship.type === 'localRelationship') { - return generateDeleteLocalRelationshipRequest; - } - if ( - relationship.type === 'remoteDatabaseRelationship' || - relationship.type === 'remoteSchemaRelationship' - ) { - return generateRemoteRelationshipDeleteRequest; - } - - return undefined; -}; - -const getSerializedRelationshipNames = (relationships: Relationship[]) => - relationships.map(rel => rel.name).join('-'); - -type RelationshipAction = { - mode?: MODE; - relationship?: Relationship; -}; - -interface TrackedRelationshipsProps { - dataSourceName: string; - driver?: Source['kind']; - isLoading: boolean; - onUpdate: () => void; - relationships: Relationship[]; -} - -export const TrackedRelationships: React.VFC = ({ - dataSourceName, - driver, - isLoading, - onUpdate, - relationships, -}) => { - const httpClient = useHttpClient(); - const { mutateAsync } = useMetadataMigration(); - - const [isTrackingSelectedRelationships, setTrackingSelectedRelationships] = - useState(false); - - const [pageNumber, setPageNumber] = useState(DEFAULT_PAGE_NUMBER); - const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); - const [searchText, setSearchText] = useState(''); - - const checkboxRef = React.useRef(null); - const { checkedIds, onCheck, allChecked, toggleAll, reset, inputStatus } = - useCheckRows(relationships.map(rel => ({ id: rel.name }))); - - useEffect(() => { - if (!checkboxRef.current) return; - checkboxRef.current.indeterminate = inputStatus === 'indeterminate'; - }, [inputStatus]); - - const [filteredRelationships, setFilteredRelationships] = - useState(relationships); - - const serializedRelationshipNames = - getSerializedRelationshipNames(relationships); - // apply the search text to the relationships - useEffect(() => { - reset(); - - if (!searchText) { - setFilteredRelationships(relationships); - return; - } - - setFilteredRelationships( - relationships.filter(rel => - rel.name.toLowerCase().includes(searchText.toLowerCase()) - ) - ); - }, [serializedRelationshipNames, searchText]); - - const onUntrackSelected = async () => { - setTrackingSelectedRelationships(true); - try { - const selectedRelationships = relationships.filter(rel => - checkedIds.includes(rel.name) - ); - - if (driver) { - const recentMetadata = await exportMetadata({ httpClient }); - - const queries = selectedRelationships.map(relationship => { - const queryFunction = getQueryFunction(relationship); - - const query = queryFunction - ? queryFunction({ - driver, - resource_version: recentMetadata.resource_version, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - relationship, - }) - : {}; - return query; - }); - - await mutateAsync( - { - query: { - type: 'bulk_keep_going', - args: queries, - }, - }, - { - onSuccess: response => { - response.forEach(result => { - if ('error' in result) { - hasuraToast({ - type: 'error', - title: 'Error while tracking table', - children: result.error, - }); - } - }); - - const successfullyTrackedCounter = response.filter( - result => 'message' in result && result.message === 'success' - ).length; - const plural = successfullyTrackedCounter > 1 ? 's' : ''; - - onUpdate(); - - hasuraToast({ - type: 'success', - title: 'Successfully untracked', - message: `${successfullyTrackedCounter} object${plural} tracked`, - }); - }, - onError: err => { - hasuraToast({ - type: 'error', - title: 'Unable to perform operation', - message: (err as APIError).message, - }); - }, - } - ); - } - } catch (err) { - console.error(err); - setTrackingSelectedRelationships(false); - } - reset(); - setTrackingSelectedRelationships(false); - }; - - const { fireNotification } = useFireNotification(); - const [{ mode, relationship }, setRelationshipAction] = - useState({ - mode: undefined, - relationship: undefined, - }); - - const onRelationshipActionCancel = () => { - setRelationshipAction({ - mode: undefined, - relationship: undefined, - }); - }; - - const onRelationshipActionError = (err: Error) => { - if (mode) - fireNotification({ - type: 'error', - title: NOTIFICATIONS.onError[mode], - message: err?.message ?? '', - }); - }; - - const onRelationshipActionSuccess = () => { - onUpdate(); - if (mode) - fireNotification({ - type: 'success', - title: 'Success!', - message: NOTIFICATIONS.onSuccess[mode], - }); - - setRelationshipAction({ - mode: undefined, - relationship: undefined, - }); - }; - - if (isLoading) { - return ( -
- -
- ); - } - - if (!isLoading && relationships.length === 0) { - return ( -
- No tracked relationships found -
- ); - } - - return ( -
-
-
- - - - -
- setSearchText(data)} /> - {searchText.length ? ( - {filteredRelationships.length} results found - ) : null} -
-
- -
-
-
- - - - - - - - - RELATIONSHIP NAME - - SOURCE - TYPE - RELATIONSHIP - - - - - - {paginate({ - data: filteredRelationships, - pageSize, - pageNumber, - }).data.map(relationship => { - return ( - - - onCheck(relationship.name)} - /> - - - {relationship.name} - - -
- -
-
- - {relationship.relationshipType} - - - - - - - - { - setRelationshipAction({ - mode: _mode, - relationship: _relationship, - }); - }} - /> - -
- ); - })} -
-
-
- {mode && ( - - )} -
-
- ); -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationshipsContainer.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationshipsContainer.tsx deleted file mode 100644 index d3361089cb8..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/TrackedRelationshipsContainer.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; - -import { - MetadataSelectors, - useMetadata, - useSyncResourceVersionOnMount, -} from '../../../hasura-metadata-api'; -import { TrackedRelationships } from './TrackedRelationships'; -import { useTrackedRelationships } from './hooks/useTrackedRelationships'; - -interface TrackedRelationshipsContainerProps { - dataSourceName: string; -} - -export const TrackedRelationshipsContainer: React.VFC< - TrackedRelationshipsContainerProps -> = ({ dataSourceName }) => { - useSyncResourceVersionOnMount({ - componentName: 'TrackedRelationshipsContainer', - }); - - const { - data: relationships, - isLoading: isLoadingRelationships, - refetchRelationships, - } = useTrackedRelationships(dataSourceName); - - const { data: metadataSource, isLoading: isLoadingMetadata } = useMetadata( - MetadataSelectors.findSource(dataSourceName) - ); - - return ( - { - await refetchRelationships(); - }} - driver={metadataSource?.kind} - /> - ); -}; diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/UntrackedRelationships.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/UntrackedRelationships.tsx deleted file mode 100644 index 9ef5288b4df..00000000000 --- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/UntrackedRelationships.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -import { Button } from '../../../../new-components/Button'; -import { CardedTable } from '../../../../new-components/CardedTable'; -import { IndicatorCard } from '../../../../new-components/IndicatorCard'; -import { DEFAULT_PAGE_SIZES } from '../constants'; -import { FaAngleLeft, FaAngleRight, FaMagic } from 'react-icons/fa'; -import { DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE } from '../constants'; -import { paginate } from '../utils'; -import { SearchBar } from './SearchBar'; -import { Badge } from '../../../../new-components/Badge'; -import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships'; -import { RelationshipRow } from './RelationshipRow'; -import { SuggestedRelationshipTrackModal } from '../../../DatabaseRelationships/components/SuggestedRelationshipTrackModal/SuggestedRelationshipTrackModal'; -import Skeleton from 'react-loading-skeleton'; -import { useAllSuggestedRelationships } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships'; -import { useCheckRows } from '../../../DatabaseRelationships/hooks/useCheckRows'; -import { useCreateTableRelationships } from '../../../DatabaseRelationships/hooks/useCreateTableRelationships/useCreateTableRelationships'; -import { hasuraToast } from '../../../../new-components/Toasts'; -import { DisplayToastErrorMessage } from '../../components/DisplayErrorMessage'; - -interface UntrackedRelationshipsProps { - dataSourceName: string; -} - -export const UntrackedRelationships: React.VFC = ({ - dataSourceName, -}) => { - const [pageNumber, setPageNumber] = useState(DEFAULT_PAGE_NUMBER); - const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); - const [searchText, setSearchText] = useState(''); - - const [isModalVisible, setModalVisible] = useState(false); - const [selectedRelationship, setSelectedRelationship] = - useState(null); - - const { suggestedRelationships, isLoadingSuggestedRelationships } = - useAllSuggestedRelationships({ - dataSourceName, - isEnabled: true, - omitTracked: true, - }); - - const { createTableRelationships, isLoading } = - useCreateTableRelationships(dataSourceName); - - // const { data: trackedRelationships } = - // useTrackedRelationships(dataSourceName); - - const checkboxRef = React.useRef(null); - const { checkedIds, onCheck, allChecked, toggleAll, reset, inputStatus } = - useCheckRows( - suggestedRelationships.map(rel => ({ id: rel.constraintName })) - ); - - const [filteredRelationships, setFilteredRelationships] = useState< - SuggestedRelationshipWithName[] - >(suggestedRelationships); - // console.log('trackedRelationships', trackedRelationships); - // console.log('suggestedRelationships', suggestedRelationships); - const serializedRelationshipNames = suggestedRelationships - .map(rel => rel.constraintName) - .join('-'); - useEffect(() => { - reset(); - if (!searchText) { - setFilteredRelationships(suggestedRelationships); - return; - } - - setFilteredRelationships( - suggestedRelationships.filter(rel => - rel.constraintName.toLowerCase().includes(searchText.toLowerCase()) - ) - ); - }, [serializedRelationshipNames, searchText]); - - useEffect(() => { - if (!checkboxRef.current) return; - checkboxRef.current.indeterminate = inputStatus === 'indeterminate'; - }, [inputStatus]); - - const onTrackRelationship = async (rel: SuggestedRelationshipWithName) => { - await createTableRelationships({ - data: [ - { - name: rel.constraintName, - source: { - fromSource: dataSourceName, - fromTable: rel.from.table, - }, - definition: { - target: { - toSource: dataSourceName, - toTable: rel.to.table, - }, - type: rel.type, - detail: { - fkConstraintOn: - 'constraint_name' in rel.from ? 'fromTable' : 'toTable', - fromColumns: rel.from.columns, - toColumns: rel.to.columns, - }, - }, - }, - ], - }); - }; - - const onTrackSelected = async () => { - const selectedRelationships = suggestedRelationships.filter(rel => - checkedIds.includes(rel.constraintName) - ); - - createTableRelationships({ - data: selectedRelationships.map(rel => ({ - name: rel.constraintName, - source: { - fromSource: dataSourceName, - fromTable: rel.from.table, - }, - definition: { - target: { - toSource: dataSourceName, - toTable: rel.to.table, - }, - type: rel.type, - detail: { - fkConstraintOn: - 'constraint_name' in rel.from ? 'fromTable' : 'toTable', - fromColumns: rel.from.columns, - toColumns: rel.to.columns, - }, - }, - })), - onSettled: () => { - reset(); - }, - onSuccess: () => { - hasuraToast({ - type: 'success', - title: 'Successfully tracked relationships', - }); - }, - onError: err => { - hasuraToast({ - type: 'error', - title: 'Error while tracking relationships', - children: , - }); - }, - }); - }; - - if (isLoadingSuggestedRelationships) { - return ( -
- -
- ); - } - - if (!isLoadingSuggestedRelationships && suggestedRelationships.length === 0) { - return ( -
- No untracked relationships found -
- ); - } - - return ( -
-
-
- - - - -
- setSearchText(data)} /> - {searchText.length ? ( - {filteredRelationships.length} results found - ) : null} -
-
- -
-
-
- - - - - - - - -
- SUGGESTED RELATIONSHIPS -
-
- SOURCE - TYPE - RELATIONSHIP - ACTIONS -
-
- - - {paginate({ - data: filteredRelationships, - pageSize, - pageNumber, - }).data.map(relationship => ( - onCheck(relationship.constraintName)} - onTrack={() => onTrackRelationship(relationship)} - onCustomize={() => { - setSelectedRelationship(relationship); - setModalVisible(true); - }} - dataSourceName={dataSourceName} - /> - ))} - -
- {isModalVisible && selectedRelationship && ( - setModalVisible(false)} - /> - )} -
- ); -};