diff --git a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx index 7ebc9ce8e0..225cfffcb9 100644 --- a/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx +++ b/src/containers/Tenant/ObjectSummary/SchemaTree/SchemaTree.tsx @@ -13,11 +13,13 @@ import { import {useClusterBaseInfo} from '../../../../store/reducers/cluster/cluster'; import {selectIsDirty, selectUserInput} from '../../../../store/reducers/query/query'; import {schemaApi} from '../../../../store/reducers/schema/schema'; +import {showCreateTableApi} from '../../../../store/reducers/showCreateTable/showCreateTable'; import {streamingQueriesApi} from '../../../../store/reducers/streamingQuery/streamingQuery'; import {tableSchemaDataApi} from '../../../../store/reducers/tableSchemaData'; import {useTenantBaseInfo} from '../../../../store/reducers/tenant/tenant'; import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema'; import {valueIsDefined} from '../../../../utils'; +import {getStringifiedData} from '../../../../utils/dataFormatters/dataFormatters'; import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks'; import {getConfirmation} from '../../../../utils/hooks/withConfirmation/useChangeInputWithConfirmation'; import {canShowTenantMonitoringTab} from '../../../../utils/monitoringVisibility'; @@ -28,12 +30,13 @@ import { mapPathTypeToNavigationTreeType, nodeStreamingQueryTypeToPathType, nodeTableTypeToPathType, + tableTypeToPathType, } from '../../utils/schema'; import {getActions} from '../../utils/schemaActions'; import type {DropdownItem, TreeNodeMeta} from '../../utils/types'; import {CreateDirectoryDialog} from '../CreateDirectoryDialog/CreateDirectoryDialog'; import {useDispatchTreeKey, useTreeKey} from '../UpdateTreeContext'; -import {isDomain} from '../transformPath'; +import {isDomain, transformPath} from '../transformPath'; interface SchemaTreeProps { rootName: string; @@ -58,6 +61,10 @@ export function SchemaTree(props: SchemaTreeProps) { getStreamingQueryInfo, {currentData: streamingSysData, isFetching: isStreamingInfoFetching}, ] = streamingQueriesApi.useLazyGetStreamingQueryInfoQuery(); + const [ + getShowCreateTable, + {currentData: showCreateTableData, isFetching: isShowCreateTableFetching}, + ] = showCreateTableApi.useLazyGetShowCreateTableQuery(); const isTopicPreviewAvailable = useTopicDataAvailable(); @@ -162,6 +169,8 @@ export function SchemaTree(props: SchemaTreeProps) { isSchemaDataLoading: isActionsDataFetching, hasMonitoring, streamingQueryData: streamingSysData, + showCreateTableData: getStringifiedData(showCreateTableData), + isShowCreateTableLoading: isShowCreateTableFetching, isStreamingQueryTextLoading: isStreamingInfoFetching, }, databaseFullPath, @@ -181,6 +190,9 @@ export function SchemaTree(props: SchemaTreeProps) { databaseFullPath, controlPlane, clusterMonitoring, + showCreateTableData, + isShowCreateTableFetching, + handleTenantPageChange, ]); return ( @@ -208,6 +220,12 @@ export function SchemaTree(props: SchemaTreeProps) { if (isOpen && pathType) { getTableSchemaDataQuery({path, database, type: pathType, databaseFullPath}); } + const tableType = tableTypeToPathType[type]; + + if (isOpen && tableType) { + const relativePath = transformPath(path, databaseFullPath); + getShowCreateTable({path: relativePath, database}); + } const streamingPathType = nodeStreamingQueryTypeToPathType[type]; if (isOpen && streamingPathType) { diff --git a/src/containers/Tenant/utils/schema.ts b/src/containers/Tenant/utils/schema.ts index 54a822fa1b..dd1df9c59b 100644 --- a/src/containers/Tenant/utils/schema.ts +++ b/src/containers/Tenant/utils/schema.ts @@ -57,6 +57,11 @@ export const nodeTableTypeToPathType: Partial> = { + table: EPathType.EPathTypeTable, + column_table: EPathType.EPathTypeColumnTable, +}; + export const nodeStreamingQueryTypeToPathType: Partial> = { streaming_query: EPathType.EPathTypeStreamingQuery, diff --git a/src/containers/Tenant/utils/schemaActions.tsx b/src/containers/Tenant/utils/schemaActions.tsx index 4d790250d4..0be1df5af5 100644 --- a/src/containers/Tenant/utils/schemaActions.tsx +++ b/src/containers/Tenant/utils/schemaActions.tsx @@ -62,7 +62,9 @@ interface ActionsAdditionalParams { isSchemaDataLoading?: boolean; hasMonitoring?: boolean; streamingQueryData?: IQueryResult; + showCreateTableData?: string; isStreamingQueryTextLoading?: boolean; + isShowCreateTableLoading?: boolean; } interface BindActionParams { @@ -86,6 +88,7 @@ const bindActions = ( getConnectToDBDialog, schemaData, streamingQueryData, + showCreateTableData, } = additionalEffects; const inputQuery = (tmpl: TemplateFn) => () => { @@ -94,7 +97,9 @@ const bindActions = ( setTenantPage(TENANT_PAGES_IDS.query); dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery)); setActivePath(params.path); - insertSnippetToEditor(tmpl({...params, schemaData, streamingQueryData})); + insertSnippetToEditor( + tmpl({...params, schemaData, streamingQueryData, showCreateTableData}), + ); }; if (getConfirmation) { const confirmedPromise = getConfirmation(); @@ -174,9 +179,10 @@ interface ActionConfig { text: string; action: () => void; isLoading?: boolean; + iconStart?: React.ReactNode; } -const getActionWithLoader = ({text, action, isLoading}: ActionConfig) => ({ +const getActionWithLoader = ({text, action, isLoading, iconStart}: ActionConfig) => ({ text: ( {text} @@ -185,6 +191,7 @@ const getActionWithLoader = ({text, action, isLoading}: ActionConfig) => ({ ), action, disabled: isLoading, + iconStart, }); export const getActions = @@ -269,11 +276,12 @@ export const getActions = DIR_SET.splice(1, 0, [createDirectoryItem]); } - const showCreateTableItem = { + const showCreateTableItem = getActionWithLoader({ text: i18n('actions.showCreateTable'), action: actions.showCreateTable, + isLoading: additionalEffects.isShowCreateTableLoading, iconStart: , - }; + }); const ROW_TABLE_SET: ActionsSet = [ [copyItem], diff --git a/src/containers/Tenant/utils/schemaQueryTemplates.ts b/src/containers/Tenant/utils/schemaQueryTemplates.ts index 6f80ed51c6..521d28027d 100644 --- a/src/containers/Tenant/utils/schemaQueryTemplates.ts +++ b/src/containers/Tenant/utils/schemaQueryTemplates.ts @@ -11,6 +11,7 @@ export interface SchemaQueryParams { relativePath: string; schemaData?: SchemaData[]; streamingQueryData?: IQueryResult; + showCreateTableData?: string; } export type TemplateFn = (params?: SchemaQueryParams) => string; @@ -161,6 +162,9 @@ ${filters}LIMIT \${5:10};`; }; export const showCreateTableTemplate = (params?: SchemaQueryParams) => { + if (params?.showCreateTableData) { + return params.showCreateTableData; + } const tablePath = params?.relativePath ? `\`${normalizeParameter(params.relativePath)}\`` : '${2:}'; diff --git a/src/store/reducers/showCreateTable/showCreateTable.ts b/src/store/reducers/showCreateTable/showCreateTable.ts new file mode 100644 index 0000000000..ae4b1cf3ae --- /dev/null +++ b/src/store/reducers/showCreateTable/showCreateTable.ts @@ -0,0 +1,44 @@ +import {QUERY_TECHNICAL_MARK} from '../../../utils/constants'; +import {isQueryErrorResponse, parseQueryAPIResponse} from '../../../utils/query'; +import {api} from '../api'; + +function getShowCreateTableSQL(path: string) { + const safePath = path.replace(/`/g, '``'); + return `${QUERY_TECHNICAL_MARK} +SHOW CREATE TABLE \`${safePath}\``; +} + +export const showCreateTableApi = api.injectEndpoints({ + endpoints: (build) => ({ + getShowCreateTable: build.query({ + queryFn: async ({database, path}: {database: string; path: string}, {signal}) => { + try { + const response = await window.api.viewer.sendQuery( + { + query: getShowCreateTableSQL(path), + database, + action: 'execute-query', + }, + {signal, withRetries: true}, + ); + + if (isQueryErrorResponse(response)) { + return {error: response}; + } + + const data = parseQueryAPIResponse(response); + + const result = data?.resultSets?.[0]?.result || []; + + const showCreateTableQuery = result[0]?.CreateQuery; + + return {data: showCreateTableQuery}; + } catch (error) { + return {error}; + } + }, + providesTags: ['All'], + }), + }), + overrideExisting: 'throw', +});