Skip to content

Commit 24e802b

Browse files
authored
create example for Vuu Blotter Feature (#684)
* create example for Vuu Blotter * add column type check function * exclude showcase index from semgrep * add semgrep ignore for showcase file * fix semgrepignore
1 parent 1d70064 commit 24e802b

37 files changed

Lines changed: 756 additions & 291 deletions

File tree

.semgrepignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ vuu/src/main/resources/www/ws-example.html
44
vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala
55
vuu-ui/packages/vuu-datagrid-extras/src/column-expression-input/column-language-parser/walkExpressionTree.ts
66
vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx
7+
vuu-ui/showcase/src/index.tsx
78
vuu-ui/showcase/src/examples/Layout/Menu.examples.tsx
89
vuu-ui/tools/websocket-test.html
910
vuu/src/test/scala/org/finos/vuu/viewport/CreateViewPortScenarioTest.scala

vuu-ui/packages/vuu-datatable/src/configurable-table/ConfigurableTable.css

Whitespace-only changes.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { GridConfig } from "@finos/vuu-datagrid-types";
2+
import { Table, TableProps } from "@finos/vuu-table";
3+
import { ReactElement, useCallback, useRef, useState } from "react";
4+
import { itemsChanged, toDataSourceColumns } from "@finos/vuu-utils";
5+
import { Dialog } from "@finos/vuu-popups";
6+
import { DatagridSettingsPanel } from "@finos/vuu-table-extras";
7+
8+
export const ConfigurableTable = ({
9+
config,
10+
dataSource,
11+
...restProps
12+
}: TableProps) => {
13+
const [dialogContent, setDialogContent] = useState<ReactElement | null>(null);
14+
const configRef = useRef<Omit<GridConfig, "headings">>(config);
15+
const [tableConfig, setTableConfig] =
16+
useState<Omit<GridConfig, "headings">>(config);
17+
18+
const handleSettingsConfigChange = useCallback(
19+
(config: Omit<GridConfig, "headings">, closePanel = false) => {
20+
console.log(`Table.examples config changed`, {
21+
config,
22+
});
23+
setTableConfig((currentConfig) => {
24+
if (itemsChanged(currentConfig.columns, config.columns, "name")) {
25+
// side effect: update columns on dataSource
26+
dataSource.columns = config.columns.map(toDataSourceColumns);
27+
}
28+
return (configRef.current = config);
29+
});
30+
closePanel && setDialogContent(null);
31+
},
32+
[dataSource]
33+
);
34+
35+
const showConfigEditor = useCallback(() => {
36+
setDialogContent(
37+
<DatagridSettingsPanel
38+
availableColumns={config.columns}
39+
gridConfig={configRef.current}
40+
onConfigChange={handleSettingsConfigChange}
41+
/>
42+
);
43+
}, [config.columns, handleSettingsConfigChange]);
44+
45+
const hideSettings = useCallback(() => {
46+
setDialogContent(null);
47+
}, []);
48+
49+
return (
50+
<>
51+
<Table
52+
{...restProps}
53+
allowConfigEditing
54+
config={tableConfig}
55+
dataSource={dataSource}
56+
onShowConfigEditor={showConfigEditor}
57+
/>
58+
<Dialog
59+
className="vuuDialog-gridConfig"
60+
isOpen={dialogContent !== null}
61+
onClose={hideSettings}
62+
title="Grid and Column Settings"
63+
>
64+
{dialogContent}
65+
</Dialog>
66+
</>
67+
);
68+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./ConfigurableTable";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from "./configurable-table";
12
export * from "./json-table";

vuu-ui/packages/vuu-filter-types/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,9 @@ export interface OrFilter extends MultiClauseFilter {
6868
}
6969
*/
7070
export declare type Filter = FilterClause | MultiClauseFilter;
71+
72+
export declare type FilterState = {
73+
filter: Filter | undefined;
74+
filterQuery: string;
75+
filterName?: string;
76+
};

vuu-ui/packages/vuu-filters/src/filter-input/FilterInput.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ const classBase = "vuuFilterInput";
1414
export interface FilterInputProps
1515
extends SuggestionConsumer,
1616
HTMLAttributes<HTMLDivElement> {
17+
iconName?: string;
1718
existingFilter?: Filter;
1819
namedFilters?: Map<string, string>;
1920
onSubmitFilter?: filterSubmissionHandler;
2021
}
2122

2223
export const FilterInput = ({
2324
existingFilter,
25+
iconName = "filter",
2426
namedFilters,
2527
onSubmitFilter,
2628
suggestionProvider,
@@ -34,7 +36,11 @@ export const FilterInput = ({
3436

3537
return (
3638
<div {...props} className={classBase}>
37-
<Button className={`${classBase}-FilterButton`} data-icon="filter" />
39+
<Button
40+
className={`${classBase}-FilterButton`}
41+
data-icon={iconName}
42+
tabIndex={-1}
43+
/>
3844
<div className={`${classBase}-Editor`} ref={editorRef} />
3945
<Button
4046
className={`${classBase}-ClearButton`}

vuu-ui/packages/vuu-layout/src/flexbox/flexbox-utils.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import { ReactElement } from 'react';
2-
import { getIntrinsicSize, hasUnboundedFlexStyle } from '../layout-reducer/flexUtils';
3-
import { getProp } from '../utils';
4-
import type { BreakPoint, ContentMeta } from './flexboxTypes';
1+
import { ReactElement } from "react";
2+
import {
3+
getIntrinsicSize,
4+
hasUnboundedFlexStyle,
5+
} from "../layout-reducer/flexUtils";
6+
import { getProp } from "../utils";
7+
import type { BreakPoint, ContentMeta } from "./flexboxTypes";
58

69
const NO_INTRINSIC_SIZE: {
710
height?: number;
@@ -11,9 +14,13 @@ const NO_INTRINSIC_SIZE: {
1114
export const SPLITTER = 1;
1215
export const PLACEHOLDER = 2;
1316

14-
const isIntrinsicallySized = (item: ContentMeta) => typeof item.intrinsicSize === 'number';
17+
const isIntrinsicallySized = (item: ContentMeta) =>
18+
typeof item.intrinsicSize === "number";
1519

16-
const getBreakPointValues = (breakPoints: BreakPoint[], component: ReactElement) => {
20+
const getBreakPointValues = (
21+
breakPoints: BreakPoint[],
22+
component: ReactElement
23+
) => {
1724
const values: { [key: string]: number | undefined } = {};
1825
breakPoints.forEach((breakPoint) => {
1926
values[breakPoint] = getProp(component, breakPoint);
@@ -23,20 +30,21 @@ const getBreakPointValues = (breakPoints: BreakPoint[], component: ReactElement)
2330

2431
export const gatherChildMeta = (
2532
children: ReactElement[],
26-
dimension: 'width' | 'height',
33+
dimension: "width" | "height",
2734
breakPoints?: BreakPoint[]
2835
) => {
2936
return children.map((child, index) => {
30-
const resizeable = getProp(child, 'resizeable');
31-
const { [dimension]: intrinsicSize } = getIntrinsicSize(child) ?? NO_INTRINSIC_SIZE;
37+
const resizeable = getProp(child, "resizeable");
38+
const { [dimension]: intrinsicSize } =
39+
getIntrinsicSize(child) ?? NO_INTRINSIC_SIZE;
3240
const flexOpen = hasUnboundedFlexStyle(child);
3341
if (breakPoints) {
3442
return {
3543
index,
3644
flexOpen,
3745
intrinsicSize,
3846
resizeable,
39-
...getBreakPointValues(breakPoints, child)
47+
...getBreakPointValues(breakPoints, child),
4048
};
4149
} else {
4250
return { index, flexOpen, intrinsicSize, resizeable };
@@ -47,7 +55,9 @@ export const gatherChildMeta = (
4755
// Splitters are inserted AFTER the associated index, so
4856
// never a splitter in last position.
4957
// Placeholder goes before (first) OR after(last) index
50-
export const findSplitterAndPlaceholderPositions = (childMeta: ContentMeta[]) => {
58+
export const findSplitterAndPlaceholderPositions = (
59+
childMeta: ContentMeta[]
60+
) => {
5161
const count = childMeta.length;
5262
const allIntrinsic = childMeta.every(isIntrinsicallySized);
5363
const splitterPositions = Array(count).fill(0);
@@ -81,15 +91,21 @@ export const findSplitterAndPlaceholderPositions = (childMeta: ContentMeta[]) =>
8191
}
8292
};
8393

84-
export const identifyResizeParties = (contentMeta: ContentMeta[], idx: number) => {
94+
export const identifyResizeParties = (
95+
contentMeta: ContentMeta[],
96+
idx: number
97+
) => {
8598
const idx1 = getLeadingResizeablePos(contentMeta, idx);
8699
const idx2 = getTrailingResizeablePos(contentMeta, idx);
87100
const participants = idx1 !== -1 && idx2 !== -1 ? [idx1, idx2] : undefined;
88101
const bystanders = identifyResizeBystanders(contentMeta, participants);
89102
return [participants, bystanders];
90103
};
91104

92-
function identifyResizeBystanders(contentMeta: ContentMeta[], participants?: number[]) {
105+
function identifyResizeBystanders(
106+
contentMeta: ContentMeta[],
107+
participants?: number[]
108+
) {
93109
if (participants) {
94110
const bystanders = [];
95111
for (let i = 0; i < contentMeta.length; i++) {
@@ -115,7 +131,7 @@ function getTrailingResizeablePos(contentMeta: ContentMeta[], idx: number) {
115131
let pos = idx,
116132
resizeable = false;
117133
const count = contentMeta.length;
118-
while (pos < count && !resizeable) {
134+
while (pos < count - 1 && !resizeable) {
119135
pos = pos + 1;
120136
resizeable = isResizeable(contentMeta, pos);
121137
}

vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,21 @@ export const Header = ({
9999
};
100100

101101
const toolbarItems: ReactElement[] = [];
102-
const contributedItems: ReactElement[] = [];
102+
const postTitleContributedItems: ReactElement[] = [];
103103
const actionButtons: ReactElement[] = [];
104104

105+
contributions?.forEach((contribution, i) => {
106+
switch (contribution.location) {
107+
case "pre-title":
108+
toolbarItems.push(React.cloneElement(contribution.content, { key: i }));
109+
break;
110+
default:
111+
postTitleContributedItems.push(
112+
React.cloneElement(contribution.content, { key: i })
113+
);
114+
}
115+
});
116+
105117
title &&
106118
toolbarItems.push(
107119
<ToolbarField className="vuuHeader-title" key="title">
@@ -120,10 +132,6 @@ export const Header = ({
120132
</ToolbarField>
121133
);
122134

123-
contributions?.forEach((contribution, i) => {
124-
contributedItems.push(React.cloneElement(contribution.content, { key: i }));
125-
});
126-
127135
closeable &&
128136
actionButtons.push(
129137
<ToolbarButton
@@ -135,10 +143,10 @@ export const Header = ({
135143
</ToolbarButton>
136144
);
137145

138-
contributedItems.length > 0 &&
146+
postTitleContributedItems.length > 0 &&
139147
toolbarItems.push(
140148
<Tooltray data-align-end key="contributions">
141-
{contributedItems}
149+
{postTitleContributedItems}
142150
</Tooltray>
143151
);
144152

@@ -152,7 +160,6 @@ export const Header = ({
152160
return (
153161
<Toolbar
154162
className={className}
155-
id="stevo"
156163
orientation={orientationProp}
157164
style={style}
158165
onMouseDown={handleMouseDown}

vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ReactElement } from "react";
33
import { DragDropRect, DragInstructions } from "../drag-drop";
44
import { DropTarget } from "../drag-drop/DropTarget";
5+
import { ContributionLocation } from "../layout-view";
56

67
export interface WithProps {
78
props?: { [key: string]: any };
@@ -131,12 +132,12 @@ export type SaveAction = {
131132

132133
export type AddToolbarContributionViewAction = {
133134
content: ReactElement;
134-
location: string;
135+
location: ContributionLocation;
135136
type: "add-toolbar-contribution";
136137
};
137138

138139
export type RemoveToolbarContributionViewAction = {
139-
location: string;
140+
location: ContributionLocation;
140141
type: "remove-toolbar-contribution";
141142
};
142143

0 commit comments

Comments
 (0)