From 323f69f2b8ad0070217ea76a42bce396f9b20a27 Mon Sep 17 00:00:00 2001 From: heswell Date: Sun, 7 May 2023 17:17:20 +0100 Subject: [PATCH] add progress cell renderer (#683) --- .../background-cell/BackgroundCell.tsx | 6 +- .../progress-cell/ProgressCell.css | 39 +++++++++++ .../progress-cell/ProgressCell.tsx | 66 +++++++++++++++++++ .../src/cell-renderers/progress-cell/index.ts | 1 + .../feature-vuu-blotter/src/VuuBlotter.css | 1 + .../showcase/src/examples/utils/useSchemas.ts | 36 +++++++++- 6 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.css create mode 100644 vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx create mode 100644 vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/index.ts diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCell.tsx index 514ca1a1e9..5b8bb681c1 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCell.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCell.tsx @@ -1,8 +1,4 @@ -import { - ColumnType, - ColumnTypeRenderer, - TableCellProps, -} from "@finos/vuu-datagrid-types"; +import { ColumnType, TableCellProps } from "@finos/vuu-datagrid-types"; import { DOWN1, DOWN2, diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.css b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.css new file mode 100644 index 0000000000..c2fb1aa026 --- /dev/null +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.css @@ -0,0 +1,39 @@ +.vuuProgressCell { + align-items: center; + display: flex; +} + +.vuuProgressCell-track { + display: inline-block; + flex: auto 1 1; + height: 4px; + overflow: hidden; + position: relative; +} + +.vuuProgressCell-bg { + background-color: var(--salt-measured-background); + display: inline-block; + height: 2px; + left: 0; + position: absolute; + top: 1px; + width: 100%; +} + + +.vuuProgressCell-bar { + background-color: var(--salt-measured-fill); + display: inline-block; + height: 100%; + left: 0; + position: absolute; + top:0; + transform: translateX(var(--progress-bar-pct, -100%)); + width: 100%; +} + +.vuuProgressCell-text { + flex: 35px 0 0; + text-align: right; +} \ No newline at end of file diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx new file mode 100644 index 0000000000..3497a41938 --- /dev/null +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx @@ -0,0 +1,66 @@ +import { TableCellProps } from "@finos/vuu-datagrid-types"; +import { + isColumnTypeRenderer, + isTypeDescriptor, + registerComponent, +} from "@finos/vuu-utils"; +import cx from "classnames"; +import { CSSProperties } from "react"; + +import "./ProgressCell.css"; + +const classBase = "vuuProgressCell"; + +const ProgressCell = ({ column, columnMap, row }: TableCellProps) => { + //TODO what about click handling + + const { type } = column; + const value = row[column.key]; + let showProgress = false; + let percentage = 0; + + if (isTypeDescriptor(type) && isColumnTypeRenderer(type.renderer)) { + const { associatedField } = type.renderer; + const associatedValue = row[columnMap[associatedField]]; + if (typeof value === "number" && typeof associatedValue === "number") { + percentage = Math.min(Math.round((value / associatedValue) * 100), 100); + showProgress = isFinite(percentage); + } else { + // Temp workaround for bug on server that sends aggregated values as strings + const floatValue = parseFloat(value as string); + if (Number.isFinite(floatValue)) { + const floatOtherValue = parseFloat(associatedValue as string); + if (Number.isFinite(floatOtherValue)) { + percentage = Math.min( + Math.round((floatValue / floatOtherValue) * 100), + 100 + ); + showProgress = isFinite(percentage); + } + } + } + } + + const className = cx(classBase, {}); + + return ( +
+ {showProgress ? ( + + + + + ) : null} + {`${percentage} %`} +
+ ); +}; + +registerComponent("vuu.progress", ProgressCell, "cell-renderer", { + serverDataType: ["long", "int", "double"], +}); diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/index.ts b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/index.ts new file mode 100644 index 0000000000..8a7b876161 --- /dev/null +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/index.ts @@ -0,0 +1 @@ +export * from "./ProgressCell"; diff --git a/vuu-ui/sample-apps/feature-vuu-blotter/src/VuuBlotter.css b/vuu-ui/sample-apps/feature-vuu-blotter/src/VuuBlotter.css index 0e91f9e7c6..ba9ccedce1 100644 --- a/vuu-ui/sample-apps/feature-vuu-blotter/src/VuuBlotter.css +++ b/vuu-ui/sample-apps/feature-vuu-blotter/src/VuuBlotter.css @@ -10,6 +10,7 @@ --vuuDataGrid-font-size: 10px; --vuuDataGridCell-border-style: none; --vuuDataGridRow-background-odd: var(--salt-palette-neutral-background-high); + max-height: 100%; } .vuuBlotter-gridContainer { diff --git a/vuu-ui/showcase/src/examples/utils/useSchemas.ts b/vuu-ui/showcase/src/examples/utils/useSchemas.ts index ae7d55e3e7..0a3a396f6a 100644 --- a/vuu-ui/showcase/src/examples/utils/useSchemas.ts +++ b/vuu-ui/showcase/src/examples/utils/useSchemas.ts @@ -1,7 +1,15 @@ +import { TableSchema } from "@finos/vuu-data"; import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; import { VuuTable } from "@finos/vuu-protocol-types"; import { Reducer, useReducer } from "react"; +export type VuuTableName = + | "instruments" + | "orders" + | "childOrders" + | "parentOrders" + | "prices"; + export type Schema = { table: VuuTable; columns: ColumnDescriptor[] }; const schemas: { [key: string]: Schema } = { instruments: { @@ -22,11 +30,11 @@ const schemas: { [key: string]: Schema } = { { name: "created", type: "date" }, { name: "filledQuantity", - label: "Filled Quantity %", + label: "Fill Progress", type: { name: "number", - renderer: { name: "progress", associatedField: "quantity" }, + renderer: { name: "vuu.progress", associatedField: "quantity" }, formatting: { decimals: 0 }, }, width: 120, @@ -37,6 +45,11 @@ const schemas: { [key: string]: Schema } = { { name: "ric" }, { name: "side" }, { name: "trader" }, + // { + // name: "filledQtyPct", + // expression: "=if(quantity=0, 0, min(1, filledQuantity / quantity))", + // serverDataType: "double", + // }, ], table: { module: "SIMUL", table: "orders" }, }, @@ -147,3 +160,22 @@ export const useSchemas = () => { dispatch, }; }; + +export const useSchema = (tableName: VuuTableName) => { + const { schemas } = useSchemas(); + if (schemas[tableName]) { + return schemas[tableName]; + } + throw Error(`useSchema no schema for table ${tableName}`); +}; + +export const useTableSchema = (tableName: VuuTableName): TableSchema => { + const { table, columns } = useSchema(tableName); + return { + table, + columns: columns.map(({ name, serverDataType = "string" }) => ({ + name, + serverDataType, + })), + }; +};