Skip to content

Commit

Permalink
Basket tidy (#1029)
Browse files Browse the repository at this point in the history
* remove old table code

* first cut at responsive basket toolbar

* finalise basket toolbar responsive layout

* responsive basket toolbar

* docs on features
  • Loading branch information
heswell authored Nov 29, 2023
1 parent 80342d7 commit 6f33d21
Show file tree
Hide file tree
Showing 170 changed files with 1,045 additions and 11,664 deletions.
61 changes: 61 additions & 0 deletions docs/ui/vuu_ui_features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# How Features currently work in Vuu

# Vuu Application = Vuu Shell + Feature(s)

A Vuu ui is an instance of the Vuu Shell, which loads content dynamically at runtime. The Shell renders the outermost chrome of the application:

- the App Header
- the left nav
- the Context panel
- a container for the main content

The shell creates the WebWorker from which all communication with the server will be handled. It provides the layout system, a persistence service and other application level features. COmponents implementing the business functionality of a Vuu application will be loaded dymanically (by the Shell) and rendered within the main content area.

Feature is the term used in Vuu to describe a UI component that can be loaded into the application to provide some specific functionality. This can be as simple as a single data table that displays data from a remote Vuu server. Equally, it can be a complex component with multiple tabbed pages that orchestrates data from multiple Vuu data tables. The Feature might occupy the full content area of the app, or it may be one of multiple features assembled within a `layout`. These are decisions that can be enforced by the application developer or made available to the end user.

## Loading Features at runtime

Technically, a feature is an ES module with a default export which must be a React component. The module will be loaded at runtime, using standard ES module loading. In other words, the module is known to the application by a url, which will be used to load it via a dynamic import statement.

The component that actually implements the dynamic loading is `Feature`, which can be found in the `vuu-shell` package.

Here are props expected/supported by `Feature`

```TypeScript
export interface FeatureProps<P extends object | undefined = any> {
ComponentProps?: P;
css?: string;
height?: number;
title?: string;
url: string;
width?: number;
}
```

The only required prop is `url`. That is the url for the JavaScript bundle that exports the featured component. Most features will also ship a css bundle. By default, features will be rendered within the Vuu UI with a header. This will dsplay the feature `title`, if provided. `ComponentProps` will be passed to the component actually rendered (i.e. the component exported by the feature bundle), so these should appropriate to that component. Vuu provide a mechanism for features to persist state between sessions. This can include props, which will be injected back into a loaded feature at construction time.

## How are Feature bundles built - current state

Right now, both the bundle exporting the Vuu Shell and all feature bundles are built together in a single build task. ESBuild is used for this and the code splitting features of ESBuild determine the exact breakdown of code into multiple bundles. The main application will output a bundle. Each feature is defined as an entrypoint to the build, so each feature will also output a bundle. These are the feature bundles that will be loaded dynamically. Any number of additional bundles may be created as dependencies, as ESBuild identifies opportunities for code sharing across bundles.

## How will Feature bundles be built - future state

It is not ideal that all bundles must be created, together with the runtime shell, in a single build. If one feature gets an update, the entire app must be rebuilt and redeployed to make this update available. Vuu is going to move to a more dynamic module system, whereby feature bundles can be built and published independently. The challenge here is managing shared depedencies. The current plan is to use Vite based `Module Federation` to achieve this. It is a system designed for exactly this scenario. This will be implemented alongside a runtime discovery mechanism, so that newly published or republished feature bundles can be indentified and surfaced in a running application.

## What is a Vuu `View` and what is the relationship between a `View` and a `Feature`

## How does a Feature manage data communication with the Vuu Server ?

## How does a Vuu app know which Feature(s) to load ?

## Getting started - how do I create a Feature ?

## Does the Vuu Showcase support Features ?

Yes it does. The Vuu showcase is a developer tool that allows components to be rendered in isolation, with hot module reloading for a convenient developer experience. Features are a little more complex to render here because of the injection of props by the Vuu Shell
and the fact that many features will create Vuu datasources. When running in the Showcase, we might want to use local datasources with no requirement to have a Vuu server instance running. All of this can be achieved and existing Showcase examples demonstrate how this is done.

### dataSource creation/injection in Showcase features

Most features will create Vuu dataSource(s) internally. However there is a pattern for dataSource creation, descibed above. Features should use the session state service provided by the Vuu shell to manage any dataSources created. The Showcase can take advantage of this pattern by pre-populating the session store with dataSources. The Feature, when loaded will then use these dataSources rather than creating.
In the existing Showcase examples, there is a `features` folder. The components in here are wrappers round actual VuuFeatures implemented in sample-apps. These render the actual underlying feature but only after creating local versions of the dataSource(s) required by those features and storing them in session state. WHen these features are rendered in SHowcase examples, they will be using the local test data.
File renamed without changes.
22 changes: 22 additions & 0 deletions vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DataSourceRow } from "@finos/vuu-data-types";
import {
ClientToServerEditRpc,
ClientToServerMenuRPC,
ClientToServerViewportRpcCall,
VuuMenu,
VuuRange,
VuuRowDataItemType,
Expand All @@ -28,18 +29,21 @@ export interface TickingArrayDataSourceConstructorProps
extends Omit<ArrayDataSourceConstructorProps, "data"> {
data?: Array<VuuRowDataItemType[]>;
menu?: VuuMenu;
menuRpcServices?: RpcService[];
rpcServices?: RpcService[];
table?: Table;
updateGenerator?: UpdateGenerator;
}

export class TickingArrayDataSource extends ArrayDataSource {
#menuRpcServices: RpcService[] | undefined;
#rpcServices: RpcService[] | undefined;
#updateGenerator: UpdateGenerator | undefined;
#table?: Table;

constructor({
data,
menuRpcServices,
rpcServices,
table,
updateGenerator,
Expand All @@ -54,6 +58,7 @@ export class TickingArrayDataSource extends ArrayDataSource {
data: data ?? table?.data ?? [],
});
this._menu = menu;
this.#menuRpcServices = menuRpcServices;
this.#rpcServices = rpcServices;
this.#updateGenerator = updateGenerator;
this.#table = table;
Expand Down Expand Up @@ -153,6 +158,23 @@ export class TickingArrayDataSource extends ArrayDataSource {
return Promise.resolve(true);
}

async rpcCall<T extends RpcResponse = RpcResponse>(
rpcRequest: Omit<ClientToServerViewportRpcCall, "vpId">
) {
const rpcService = this.#rpcServices?.find(
(service) =>
service.rpcName ===
(rpcRequest as ClientToServerViewportRpcCall).rpcName
);
if (rpcService) {
return rpcService.service({
...rpcRequest,
});
} else {
console.log(`no implementation for PRC service ${rpcRequest.rpcName}`);
}
}

async menuRpcCall(
rpcRequest: Omit<ClientToServerMenuRPC, "vpId"> | ClientToServerEditRpc
): Promise<
Expand Down
20 changes: 11 additions & 9 deletions vuu-ui/packages/vuu-data-test/src/basket/basket-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import ftse from "./reference-data/ftse100";
import nasdaq from "./reference-data/nasdaq100";
import sp500 from "./reference-data/sp500";
import hsi from "./reference-data/hsi";
import { VuuMenu, VuuRowDataItemType } from "@finos/vuu-protocol-types";
import {
ClientToServerViewportRpcCall,
VuuMenu,
VuuRowDataItemType,
} from "@finos/vuu-protocol-types";
import { Table } from "../Table";

// This is a 'local' columnMap
Expand Down Expand Up @@ -220,13 +224,11 @@ function createTradingBasket(basketId: string, basketName: string) {
});
}

async function createNewBasket(rpcRequest: any) {
const { basketName, selectedRows } = rpcRequest;
if (selectedRows.length === 1) {
const [row] = selectedRows;
const basketId = row[KEY];
createTradingBasket(basketId, basketName);
}
async function createNewBasket(rpcRequest: ClientToServerViewportRpcCall) {
const {
params: [basketId, basketName],
} = rpcRequest;
createTradingBasket(basketId, basketName);
}

//-------------------
Expand Down Expand Up @@ -298,7 +300,7 @@ const services: Record<BasketsTableName, RpcService[] | undefined> = {
algoType: undefined,
basket: [
{
rpcName: "CREATE_NEW_BASKET",
rpcName: "createBasket",
service: createNewBasket,
},
],
Expand Down
1 change: 0 additions & 1 deletion vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const schemas: Readonly<
columns: [
{ name: "basketId", serverDataType: "string" },
{ name: "change", serverDataType: "string" },
// this column doesn't exist on Vuu server
{ name: "description", serverDataType: "string" },
{ name: "lastTrade", serverDataType: "string" },
{ name: "ric", serverDataType: "string" },
Expand Down
6 changes: 5 additions & 1 deletion vuu-ui/packages/vuu-data-test/src/simul/simul-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ export const populateArray = (tableName: SimulTableName, count: number) => {

const getColumnDescriptors = (tableName: SimulTableName) => {
const schema = schemas[tableName];
return schema.columns;
if (schema) {
return schema.columns;
} else {
console.error(`simul-module no schema found for table SIMUL ${tableName}`);
}
};

const createDataSource = (tableName: SimulTableName) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ export class ArrayDataSource
private groupMap: undefined | GroupMap;
/** the index of key field within raw data row */
private key: number;
private tableSchema: TableSchema;
private lastRangeServed: VuuRange = { from: 0, to: 0 };
private rangeChangeRowset: "delta" | "full";
private openTreeNodes: string[] = [];
Expand All @@ -120,6 +119,7 @@ export class ArrayDataSource
protected _menu: VuuMenu | undefined;
protected selectedRows: Selection = [];

public tableSchema: TableSchema;
public viewport: string;

private keys = new KeySet(this.#range);
Expand Down
Loading

0 comments on commit 6f33d21

Please sign in to comment.