diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts index f61bc490f..1409d38ae 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts @@ -3,14 +3,15 @@ import { useDataSource } from "@finos/vuu-utils"; import { useCallback, useEffect, useState } from "react"; export const useVuuTables = () => { - const [tables, setTables] = useState | undefined>(); + const [tableSchemas, setTableSchemas] = useState(); const { getServerAPI } = useDataSource(); const buildTables = useCallback((schemas: TableSchema[]) => { const vuuTables = new Map(); schemas.forEach((schema) => { - vuuTables.set(schema.table.table, schema); + const { module, table } = schema.table; + vuuTables.set(`${module}:${table}`, schema); }); return vuuTables; }, []); @@ -20,12 +21,10 @@ export const useVuuTables = () => { try { const server = await getServerAPI(); const { tables } = await server.getTableList(); - const tableSchemas = buildTables( - await Promise.all( - tables.map((vuuTable) => server.getTableSchema(vuuTable)), - ), + const tableSchemas = await Promise.all( + tables.map((vuuTable) => server.getTableSchema(vuuTable)), ); - setTables(tableSchemas); + setTableSchemas(tableSchemas); } catch (err) { console.warn( `useVuuTables: error fetching table metadata ${String(err)}`, @@ -36,5 +35,5 @@ export const useVuuTables = () => { fetchTableMetadata(); }, [buildTables, getServerAPI]); - return tables; + return tableSchemas; }; diff --git a/vuu-ui/packages/vuu-shell/src/feature-and-layout-provider/FeatureAndLayoutProvider.tsx b/vuu-ui/packages/vuu-shell/src/feature-and-layout-provider/FeatureAndLayoutProvider.tsx index e55097f92..94e48778b 100644 --- a/vuu-ui/packages/vuu-shell/src/feature-and-layout-provider/FeatureAndLayoutProvider.tsx +++ b/vuu-ui/packages/vuu-shell/src/feature-and-layout-provider/FeatureAndLayoutProvider.tsx @@ -58,16 +58,16 @@ export const FeatureAndLayoutProvider = ({ staticFeatures, systemLayouts, }: FeatureAndLayoutProviderProps): ReactElement => { - const vuuTables = useVuuTables(); + const tableSchemas = useVuuTables(); const { dynamicFeatures, tableFeatures } = useMemo<{ dynamicFeatures: DynamicFeatureProps[]; tableFeatures: DynamicFeatureProps[]; }>( () => - vuuTables - ? getCustomAndTableFeatures(dynamicFeaturesProp, vuuTables) + tableSchemas + ? getCustomAndTableFeatures(dynamicFeaturesProp, tableSchemas) : NO_FEATURES_VUU, - [dynamicFeaturesProp, vuuTables], + [dynamicFeaturesProp, tableSchemas], ); return ( diff --git a/vuu-ui/packages/vuu-utils/src/feature-utils.ts b/vuu-ui/packages/vuu-utils/src/feature-utils.ts index e8bafad72..b380df86c 100644 --- a/vuu-ui/packages/vuu-utils/src/feature-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/feature-utils.ts @@ -61,12 +61,12 @@ export interface StaticFeatureDescriptor { } const isStaticFeature = ( - feature: unknown + feature: unknown, ): feature is StaticFeatureDescriptor => feature !== null && typeof feature === "object" && "type" in feature; export const isStaticFeatures = ( - features: unknown + features: unknown, ): features is StaticFeatureDescriptor[] => Array.isArray(features) && features.every(isStaticFeature); @@ -82,7 +82,7 @@ export function featureFromJson({ type }: { type: string }): ReactElement { const componentType = type.match(/^[a-z]/) ? type : getLayoutComponent(type); if (componentType === undefined) { throw Error( - `layoutUtils unable to create feature component from JSON, unknown type ${type}` + `layoutUtils unable to create feature component from JSON, unknown type ${type}`, ); } return React.createElement(componentType); @@ -100,10 +100,10 @@ export const isCustomFeature = (feature: DynamicFeatureDescriptor) => export const isWildcardSchema = (schema?: "*" | VuuTable): schema is "*" => schema === "*"; -export const isTableSchema = (schema?: "*" | VuuTable): schema is VuuTable => - typeof schema === "object" && - typeof schema.module === "string" && - typeof schema.table === "string"; +export const isVuuTable = (vuuTable?: "*" | VuuTable): vuuTable is VuuTable => + typeof vuuTable === "object" && + typeof vuuTable.module === "string" && + typeof vuuTable.table === "string"; export interface FeaturePropsWithFilterTableFeature extends Omit { @@ -111,12 +111,16 @@ export interface FeaturePropsWithFilterTableFeature } export const hasFilterTableFeatureProps = ( - props: DynamicFeatureProps + props: DynamicFeatureProps, ): props is FeaturePropsWithFilterTableFeature => typeof props.ComponentProps === "object" && props.ComponentProps !== null && "tableSchema" in props.ComponentProps; +export const isSameTable = (t1: VuuTable, t2: VuuTable) => { + t1.module === t2.module && t1.table == t2.table; +}; + // Sort TableScheas by module export const byModule = (schema1: TableSchema, schema2: TableSchema) => { const m1 = schema1.table.module.toLowerCase(); @@ -142,19 +146,19 @@ export type GetFeaturePaths = (params: { export const getFilterTableFeatures = ( schemas: TableSchema[], - getFeaturePath: GetFeaturePaths + getFeaturePath: GetFeaturePaths, ) => schemas .sort(byModule) .map>((schema) => ({ ...getFeaturePath({ env, fileName: "FilterTable" }), ComponentProps: { - tableSchema: schema + tableSchema: schema, }, ViewProps: { - allowRename: true + allowRename: true, }, - title: `${schema.table.module} ${schema.table.table}` + title: `${schema.table.module} ${schema.table.table}`, })); export type Component = { @@ -164,11 +168,11 @@ export type Component = { export const assertComponentRegistered = ( componentName: string, - component: unknown + component: unknown, ) => { if (typeof component !== "function") { console.warn( - `${componentName} module not loaded, will be unabale to deserialize from layout JSON` + `${componentName} module not loaded, will be unabale to deserialize from layout JSON`, ); } }; @@ -181,14 +185,14 @@ export const assertComponentsRegistered = (componentList: Component[]) => { export const getCustomAndTableFeatures = ( dynamicFeatures: DynamicFeatureDescriptor[], - vuuTables: Map + tableSchemas: TableSchema[], ): { dynamicFeatures: DynamicFeatureProps[]; tableFeatures: DynamicFeatureProps[]; } => { const [customFeatureConfig, tableFeaturesConfig] = partition( dynamicFeatures, - isCustomFeature + isCustomFeature, ); const customFeatures: DynamicFeatureProps[] = []; @@ -199,32 +203,34 @@ export const getCustomAndTableFeatures = ( viewProps, ...feature } of tableFeaturesConfig) { - const { schema } = featureProps; - if (isWildcardSchema(schema) && vuuTables) { - for (const tableSchema of vuuTables.values()) { + const { schema: vuuTable } = featureProps; + if (isWildcardSchema(vuuTable) && tableSchemas) { + for (const tableSchema of tableSchemas) { tableFeatures.push({ ...feature, ComponentProps: { - tableSchema + tableSchema, }, title: `${tableSchema.table.module} ${wordify( - tableSchema.table.table + tableSchema.table.table, )}`, ViewProps: { ...viewProps, - allowRename: true - } + allowRename: true, + }, }); } - } else if (isTableSchema(schema) && vuuTables) { - const tableSchema = vuuTables.get(schema.table); + } else if (isVuuTable(vuuTable) && tableSchemas) { + const tableSchema = tableSchemas.find((tableSchema) => + isSameTable(vuuTable, tableSchema.table), + ); if (tableSchema) { tableFeatures.push({ ...feature, ComponentProps: { - tableSchema + tableSchema, }, - ViewProps: viewProps + ViewProps: viewProps, }); } } @@ -235,29 +241,31 @@ export const getCustomAndTableFeatures = ( viewProps, ...feature } of customFeatureConfig) { - const { schema, schemas } = featureProps; - if (isTableSchema(schema) && vuuTables) { - const tableSchema = vuuTables.get(schema.table); + const { schema: vuuTable, schemas } = featureProps; + if (isVuuTable(vuuTable) && tableSchemas) { + const tableSchema = tableSchemas.find((tableSchema) => + isSameTable(vuuTable, tableSchema.table), + ); customFeatures.push({ ...feature, ComponentProps: { - tableSchema + tableSchema, }, - ViewProps: viewProps + ViewProps: viewProps, }); - } else if (Array.isArray(schemas) && vuuTables) { + } else if (Array.isArray(schemas) && tableSchemas) { customFeatures.push({ ...feature, ComponentProps: schemas.reduce>( - (map, schema) => { - map[`${schema.table}Schema`] = vuuTables.get( - schema.table + (map, vuuTable) => { + map[`${vuuTable.table}Schema`] = tableSchemas.find((tableSchema) => + isSameTable(vuuTable, tableSchema.table), ) as TableSchema; return map; }, - {} + {}, ), - ViewProps: viewProps + ViewProps: viewProps, }); } else { customFeatures.push(feature); diff --git a/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx b/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx index bb6240c63..e63fe1191 100644 --- a/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx +++ b/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx @@ -3,7 +3,7 @@ import { RpcResponseHandler } from "@finos/vuu-data-types"; import { useDialog } from "@finos/vuu-popups"; import { VuuTable } from "@finos/vuu-protocol-types"; import { Feature } from "@finos/vuu-shell"; -import { isActionMessage } from "@finos/vuu-utils"; +import { isActionMessage, isSameTable } from "@finos/vuu-utils"; import { useCallback } from "react"; const withTable = (action: unknown): action is { table: VuuTable } => @@ -12,7 +12,7 @@ const withTable = (action: unknown): action is { table: VuuTable } => const vuuFilterTableFeatureUrl = "../feature-filter-table/index.js"; export const useRpcResponseHandler = () => { - const tables = useVuuTables(); + const tableSchemas = useVuuTables(); const { setDialogState } = useDialog(); const handleRpcResponse = useCallback( @@ -26,10 +26,13 @@ export const useRpcResponseHandler = () => { ) { if ( withTable(rpcResponse.action) && - tables && + tableSchemas && rpcResponse.action.table ) { - const schema = tables.get(rpcResponse.action.table.table); + const { table } = rpcResponse.action; + const schema = tableSchemas.find((tableSchema) => + isSameTable(tableSchema.table, table), + ); if (schema) { // If we already have this table open in this viewport, ignore setDialogState({ @@ -49,7 +52,7 @@ export const useRpcResponseHandler = () => { } return false; }, - [setDialogState, tables], + [setDialogState, tableSchemas], ); return { diff --git a/vuu-ui/showcase/src/examples/VUU/Vuu.examples.tsx b/vuu-ui/showcase/src/examples/VUU/Vuu.examples.tsx index d3220e77a..2c688ac61 100644 --- a/vuu-ui/showcase/src/examples/VUU/Vuu.examples.tsx +++ b/vuu-ui/showcase/src/examples/VUU/Vuu.examples.tsx @@ -1,24 +1,30 @@ import { List, ListItem } from "@finos/vuu-ui-controls"; -import { useVuuTables } from "@finos/vuu-data-react"; +import { useVuuTables, VuuDataSourceProvider } from "@finos/vuu-data-react"; import { useAutoLoginToVuuServer } from "../utils"; let displaySequence = 1; -export const VuuTables = () => { - const tables = useVuuTables(); +const VuuTablesTemplate = () => { + const tableSchemas = useVuuTables(); + + useAutoLoginToVuuServer({ authenticate: false }); - useAutoLoginToVuuServer(); + return ( + + + {tableSchemas?.map(({ table: { module, table } }, i) => ( + {`[${module}] ${table}`} + )) ?? null} + + + ); +}; +export const VuuTables = () => { return ( - - {tables - ? Array.from(tables.entries()).map(([tableName, schema]) => ( - {`[${schema.table.module}] ${schema.table.table}`} - )) - : null} - + + + ); };