From a65192c8d15f402d275b11ac200b1fff4efa0c6c Mon Sep 17 00:00:00 2001 From: Zhen Date: Mon, 12 Aug 2024 08:40:54 -0400 Subject: [PATCH] add static features to featuresProvider --- .../src/feature-list/FeatureList.tsx | 40 +++++++-- .../src/feature-provider/FeatureProvider.tsx | 64 +++++++++----- .../vuu-shell/src/feature-provider/index.ts | 2 +- .../src/feature-provider/useVuuFeatures.ts | 85 ++++++++++--------- .../vuu-shell/src/left-nav/LeftNav.tsx | 4 +- .../packages/vuu-utils/src/feature-utils.ts | 42 +++++---- .../sample-apps/app-vuu-example/src/App.tsx | 9 +- .../Shell/FeatureProvider.examples.tsx | 41 +++++++++ vuu-ui/showcase/src/examples/Shell/index.ts | 1 + 9 files changed, 200 insertions(+), 88 deletions(-) create mode 100644 vuu-ui/showcase/src/examples/Shell/FeatureProvider.examples.tsx diff --git a/vuu-ui/packages/vuu-shell/src/feature-list/FeatureList.tsx b/vuu-ui/packages/vuu-shell/src/feature-list/FeatureList.tsx index b41e42b5e..2427ea654 100644 --- a/vuu-ui/packages/vuu-shell/src/feature-list/FeatureList.tsx +++ b/vuu-ui/packages/vuu-shell/src/feature-list/FeatureList.tsx @@ -1,10 +1,14 @@ import { Palette, PaletteItem } from "@finos/vuu-layout"; import { Icon, ListProps } from "@finos/vuu-ui-controls"; -import { FeatureProps } from "@finos/vuu-utils"; +import { + FeatureProps, + StaticFeatures, + featureFromJson, +} from "@finos/vuu-utils"; import { useComponentCssInjection } from "@salt-ds/styles"; import { useWindow } from "@salt-ds/window"; import cx from "clsx"; -import { HTMLAttributes, useMemo } from "react"; +import { HTMLAttributes, Key, useMemo } from "react"; import { Feature } from "../feature/Feature"; import featureListCss from "./FeatureList.css"; @@ -18,7 +22,8 @@ export type GroupedFeatureProps

= Record< export interface FeatureListProps

extends HTMLAttributes { - features: FeatureProps

[] | GroupedFeatureProps

; + features: FeatureProps

[] | GroupedFeatureProps

| StaticFeatures; + isStatic?: boolean; } const listPropsFullHeight: Partial = { @@ -34,6 +39,7 @@ const listPropsAutoHeight: Partial = { export const FeatureList = ({ features, title = "VUU TABLES", + isStatic = false, ...htmlAttributes }: FeatureListProps) => { const targetWindow = useWindow(); @@ -44,6 +50,30 @@ export const FeatureList = ({ }); const content = useMemo(() => { + if (isStatic) { + return Object.entries(features).map(([heading, feature], index) => { + return ( +

+
{heading}
+ + + {feature.title} + +
+ ); + }); + } if (Array.isArray(features)) { return [
@@ -76,7 +106,7 @@ export const FeatureList = ({
{heading}
- {featureList.map((featureProps, i) => ( + {featureList.map((featureProps: FeatureProps, i: Key) => ( } @@ -96,7 +126,7 @@ export const FeatureList = ({ )); } - }, [features]); + }, [features, isStatic]); return (
diff --git a/vuu-ui/packages/vuu-shell/src/feature-provider/FeatureProvider.tsx b/vuu-ui/packages/vuu-shell/src/feature-provider/FeatureProvider.tsx index 9f8813648..2fc8ccdd9 100644 --- a/vuu-ui/packages/vuu-shell/src/feature-provider/FeatureProvider.tsx +++ b/vuu-ui/packages/vuu-shell/src/feature-provider/FeatureProvider.tsx @@ -2,51 +2,68 @@ import { DynamicFeatures, FeatureProps, FilterTableFeatureProps, - StaticFeatureDescriptor, + StaticFeatures, + getCustomAndTableFeatures, } from "@finos/vuu-utils"; -import { ReactElement, ReactNode, createContext, useContext } from "react"; -import { useVuuFeatures } from "./useVuuFeatures"; +import { + ReactElement, + ReactNode, + createContext, + useContext, + useMemo, +} from "react"; +import { useVuuTables } from "@finos/vuu-data-react"; export interface FeatureContextProps { - features: FeatureProps[]; + dynamicFeatures: FeatureProps[]; tableFeatures: FeatureProps[]; - staticFeatures: StaticFeatureDescriptor[] | undefined; + staticFeatures?: StaticFeatures; } -const NO_FEATURES: FeatureContextProps["features"] = []; +const NO_FEATURES: FeatureContextProps["dynamicFeatures"] = []; const NO_TABLES: FeatureContextProps["tableFeatures"] = []; -const NO_STATICFEATURES: FeatureContextProps["staticFeatures"] = []; +const NO_STATICFEATURES: FeatureContextProps["staticFeatures"] = {}; + +const NO_FEATURES_VUU: { + dynamicFeatures: FeatureProps[]; + tableFeatures: FeatureProps[]; +} = { dynamicFeatures: [], tableFeatures: [] }; const FeatureContext = createContext({ - features: NO_FEATURES, + dynamicFeatures: NO_FEATURES, tableFeatures: NO_TABLES, staticFeatures: NO_STATICFEATURES, }); export interface FeatureProviderProps extends Partial { children: ReactNode; - dynamicFeatures: DynamicFeatures; - staticFeatures?: StaticFeatureDescriptor[]; + features: DynamicFeatures; + staticFeatures?: StaticFeatures; } export const FeatureProvider = ({ children, - dynamicFeatures, - features: featuresProp, - tableFeatures: tableFeaturesProp, + features, staticFeatures, }: FeatureProviderProps): ReactElement => { - const [vuuFeatures, vuuTableFeatures, staticVuuFeatures] = useVuuFeatures({ - staticFeatures, - features: dynamicFeatures, - }); + const vuuTables = useVuuTables(); + const { dynamicFeatures, tableFeatures } = useMemo<{ + dynamicFeatures: FeatureProps[]; + tableFeatures: FeatureProps[]; + }>( + () => + vuuTables + ? getCustomAndTableFeatures(features, vuuTables) + : NO_FEATURES_VUU, + [features, vuuTables] + ); return ( {children} @@ -57,18 +74,19 @@ export const FeatureProvider = ({ export type FeaturesHook = ( props?: Partial ) => FeatureContextProps; -export const useFeatures: FeaturesHook = (localFeatures) => { +export const useFeatures: FeaturesHook = (localFeatures?) => { const contextFeatures = useContext(FeatureContext); if ( localFeatures === undefined || - (localFeatures.features === undefined && + (localFeatures.dynamicFeatures === undefined && localFeatures.tableFeatures === undefined && localFeatures.staticFeatures === undefined) ) { return contextFeatures; } else { return { - features: localFeatures.features ?? contextFeatures.features, + dynamicFeatures: + localFeatures.dynamicFeatures ?? contextFeatures.dynamicFeatures, tableFeatures: localFeatures.tableFeatures ?? contextFeatures.tableFeatures, staticFeatures: diff --git a/vuu-ui/packages/vuu-shell/src/feature-provider/index.ts b/vuu-ui/packages/vuu-shell/src/feature-provider/index.ts index 5b3f04ecb..d6aba1400 100644 --- a/vuu-ui/packages/vuu-shell/src/feature-provider/index.ts +++ b/vuu-ui/packages/vuu-shell/src/feature-provider/index.ts @@ -1,2 +1,2 @@ export * from "./FeatureProvider"; -export * from "./useVuuFeatures"; +// export * from "./useVuuFeatures"; diff --git a/vuu-ui/packages/vuu-shell/src/feature-provider/useVuuFeatures.ts b/vuu-ui/packages/vuu-shell/src/feature-provider/useVuuFeatures.ts index 22d98fbf6..11f065460 100644 --- a/vuu-ui/packages/vuu-shell/src/feature-provider/useVuuFeatures.ts +++ b/vuu-ui/packages/vuu-shell/src/feature-provider/useVuuFeatures.ts @@ -1,42 +1,51 @@ -import { useVuuTables } from "@finos/vuu-data-react"; -import { - DynamicFeatures, - FeatureProps, - FilterTableFeatureProps, - StaticFeatureDescriptor, - getCustomAndTableFeatures, -} from "@finos/vuu-utils"; -import { useMemo } from "react"; +// import { useVuuTables } from "@finos/vuu-data-react"; +// import { +// DynamicFeatures, +// FeatureProps, +// FilterTableFeatureProps, +// getCustomAndTableFeatures, +// } from "@finos/vuu-utils"; +// import { useMemo } from "react"; +// import { FeatureContextProps } from "./FeatureProvider"; -export interface FeaturesHookProps { - features: DynamicFeatures; - staticFeatures?: StaticFeatureDescriptor[]; -} +// export interface FeaturesHookProps { +// dynamicFeatures: DynamicFeatures; +// } -const NO_FEATURES: ReturnType = [[], [], []]; +// const NO_FEATURES: { +// vuuFeatures: FeatureProps[]; +// vuuTableFeatures: FeatureProps[]; +// } = { vuuFeatures: [], vuuTableFeatures: [] }; -export const useVuuFeatures = ({ - features, - staticFeatures, -}: FeaturesHookProps): [ - FeatureProps[], - FeatureProps[], - StaticFeatureDescriptor[] | undefined -] => { - const tables = useVuuTables(); - const [customFeatures, tableFeatures, staticCustomFeatures] = useMemo< - [ - FeatureProps[], - FeatureProps[], - StaticFeatureDescriptor[] | undefined - ] - >( - () => - tables - ? getCustomAndTableFeatures(features, tables, staticFeatures) - : NO_FEATURES, - [features, staticFeatures, tables] - ); +// export const useVuuFeatures = ({ +// dynamicFeatures: features, +// }: FeaturesHookProps): FeatureContextProps => { +// const tables = useVuuTables(); +// const { vuuFeatures, vuuTableFeatures } = useMemo<{ +// vuuFeatures: FeatureProps[]; +// vuuTableFeatures: FeatureProps[]; +// }>( +// () => (tables ? getCustomAndTableFeatures(features, tables) : NO_FEATURES), +// [features, tables] +// ); - return [customFeatures, tableFeatures, staticCustomFeatures]; -}; +// return { +// dynamicFeatures: vuuFeatures, +// tableFeatures: vuuTableFeatures, +// }; +// }; + +// const vuuTables = useVuuTables(); +// console.log("vuutable: ", vuuTables); +// const { vuuFeatures, vuuTableFeatures } = useMemo<{ +// vuuFeatures: FeatureProps[]; +// vuuTableFeatures: FeatureProps[]; +// }>(() => { +// console.log("vuutable"); +// const a = vuuTables +// ? getCustomAndTableFeatures(features, vuuTables) +// : NO_FEATURES_VUU; +// return a; +// }, [features, vuuTables]); +// console.log("vuuFeature: ", vuuFeatures); +// console.log("table: ", vuuTableFeatures); diff --git a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx index 777e5f765..701323478 100644 --- a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx +++ b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx @@ -114,8 +114,8 @@ export const LeftNav = (props: LeftNavProps) => { window: targetWindow, }); - const { features, tableFeatures } = useFeatures({ - features: featuresProp, + const { dynamicFeatures: features, tableFeatures } = useFeatures({ + dynamicFeatures: featuresProp, tableFeatures: tableFeaturesProp, }); diff --git a/vuu-ui/packages/vuu-utils/src/feature-utils.ts b/vuu-ui/packages/vuu-utils/src/feature-utils.ts index 9be20b43a..3b4511d2d 100644 --- a/vuu-ui/packages/vuu-utils/src/feature-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/feature-utils.ts @@ -3,9 +3,11 @@ import type { VuuTable } from "@finos/vuu-protocol-types"; import { ListOption } from "@finos/vuu-table-types"; import { partition } from "./array-utils"; import { wordify } from "./text-utils"; +import React, { ReactElement } from "react"; +import { getLayoutComponent } from "./component-registry"; export type PathMap = { - [key: string]: Pick; + [key: string]: Pick; }; export type Environment = "development" | "production"; export const env = process.env.NODE_ENV as Environment; @@ -39,7 +41,7 @@ declare global { const vuuConfig: Promise; } -export interface DynamicFeatureConfig { +export interface DynamicFeatureDescriptor { name: string; title: string; url: string; @@ -63,13 +65,26 @@ export interface FilterTableFeatureProps { } export type DynamicFeatures = { - [key: string]: DynamicFeatureConfig; + [key: string]: DynamicFeatureDescriptor; }; export type StaticFeatures = { [key: string]: StaticFeatureDescriptor; }; +export function featureFromJson({ + type, + label, +}: StaticFeatureDescriptor): ReactElement { + const componentType = type.match(/^[a-z]/) ? type : getLayoutComponent(type); + if (componentType === undefined) { + throw Error( + `layoutUtils unable to create component from JSON, unknown type ${type}` + ); + } + return React.createElement(componentType, { id: label, key: label }); +} + export interface VuuConfig { features: DynamicFeatures; authUrl?: string; @@ -77,7 +92,7 @@ export interface VuuConfig { ssl: boolean; } -export const isCustomFeature = (feature: DynamicFeatureConfig) => +export const isCustomFeature = (feature: DynamicFeatureDescriptor) => feature.leftNavLocation === "vuu-features"; export const isWildcardSchema = (schema?: "*" | VuuTable): schema is "*" => @@ -163,26 +178,19 @@ export const assertComponentsRegistered = (componentList: Component[]) => { export const getCustomAndTableFeatures = ( features: DynamicFeatures, - vuuTables: Map, - staticFeatures?: StaticFeatureDescriptor[] -): [ - FeatureProps[], - FeatureProps[], - StaticFeatureDescriptor[] | undefined -] => { + vuuTables: Map +): { + dynamicFeatures: FeatureProps[]; + tableFeatures: FeatureProps[]; +} => { const [customFeatureConfig, tableFeaturesConfig] = partition( Object.values(features), isCustomFeature ); - // const staticFeatureDescriptors: StaticFeatureDescriptor[] = []; const customFeatures: FeatureProps[] = []; const tableFeatures: FeatureProps[] = []; - // for (const descriptor of staticFeatures) { - // staticFeatureDescriptors.push(descriptor); - // } - for (const { featureProps = {}, viewProps, @@ -252,5 +260,5 @@ export const getCustomAndTableFeatures = ( customFeatures.push(feature); } } - return [customFeatures, tableFeatures, staticFeatures]; + return { dynamicFeatures: customFeatures, tableFeatures: tableFeatures }; }; diff --git a/vuu-ui/sample-apps/app-vuu-example/src/App.tsx b/vuu-ui/sample-apps/app-vuu-example/src/App.tsx index de08fee9c..000911aab 100644 --- a/vuu-ui/sample-apps/app-vuu-example/src/App.tsx +++ b/vuu-ui/sample-apps/app-vuu-example/src/App.tsx @@ -12,7 +12,7 @@ import { TableSettingsPanel, } from "@finos/vuu-table-extras"; import { DragDropProvider } from "@finos/vuu-ui-controls"; -import type { VuuUser } from "@finos/vuu-utils"; +import type { StaticFeatures, VuuUser } from "@finos/vuu-utils"; import { assertComponentsRegistered, registerComponent, @@ -65,13 +65,18 @@ export const App = ({ user }: { user: VuuUser }) => { [] ); console.log(`render App`); + + const staticFeatures: StaticFeatures = { + feature1: { label: "label", type: "type" }, + }; + return ( - + { + const features = useFeatures(); + if (features.staticFeatures) + return ( + <> + + + + + ); + else + return ( + <> + + + + ); +}; + +export const DefaultStaticFeatures = () => { + return ( + + + + ); +}; +DefaultStaticFeatures.displaySequence = displaySequence++; diff --git a/vuu-ui/showcase/src/examples/Shell/index.ts b/vuu-ui/showcase/src/examples/Shell/index.ts index f4cc8311b..b38e42412 100644 --- a/vuu-ui/showcase/src/examples/Shell/index.ts +++ b/vuu-ui/showcase/src/examples/Shell/index.ts @@ -3,6 +3,7 @@ export * as ConnectionStatus from "./ConnectionStatus.examples"; export * as ConnectionMetrics from "./ConnectionMetrics.examples"; export * as Feature from "./Feature.examples"; export * as FeatureList from "./FeatureList.examples"; +export * as FeatureProvider from "./FeatureProvider.examples"; export * as LayoutList from "./LayoutList.examples"; export * as LeftNav from "./LeftNav.examples"; export * as LoginPanel from "./LoginPanel.examples";