Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
34708e7
added a component interface and a powerpoint component with scaling c…
jeffreywallphd Dec 12, 2025
61ff7fe
fixed slideshow resizing problem
jeffreywallphd Dec 12, 2025
7121471
changed gitignore
jeffreywallphd Dec 13, 2025
fb169ce
added new gateway and main and preload functionality for neo4j graph …
jeffreywallphd Dec 13, 2025
552c2ed
changes to gitignore
jeffreywallphd Dec 13, 2025
19144d0
added new sidecar initializer to initialize neo4j graphs
jeffreywallphd Dec 14, 2025
c5d80be
added jre-win to .gitignore
jeffreywallphd Dec 14, 2025
e8ca9ff
fixed multiple neo4j write query problem. Neo4j now sets up database
jeffreywallphd Dec 14, 2025
27b4a9b
updated to check for graph exists to avoid overwriting initialized gr…
jeffreywallphd Dec 14, 2025
02df51f
added status messages to initializer and bundled slideshows into appdata
jeffreywallphd Dec 14, 2025
bbe5ec5
added default thumbnail for news when news thumbnail fails
jeffreywallphd Dec 14, 2025
559fc3d
creating new portfolio risk analysis page
jeffreywallphd Dec 15, 2025
7c49040
updating Risk Analysis page. Creating returns time series
jeffreywallphd Dec 15, 2025
6cb7336
added calculations for portfolio volatility
jeffreywallphd Dec 16, 2025
b275618
updated view to account for calculating time
jeffreywallphd Dec 16, 2025
2663288
added portfolio risk table with daily and annual volatility, max draw…
jeffreywallphd Dec 17, 2025
38b8836
updated portfolio with popover term descriptions and add sleep calls …
jeffreywallphd Dec 17, 2025
eb940c2
updated loaders and on change events. Fixed trading to disallow purch…
jeffreywallphd Dec 18, 2025
af68eb7
Merge branch 'main' into hfAdapter
jdwallMTU Jan 5, 2026
18772eb
Made changes to Main.js to make software cross platform compatible
JabobleHead Feb 11, 2026
c7ae0c5
Set up wrapper for wrapper idea
JabobleHead Mar 25, 2026
c6ef91d
Made Warpaer using tsx file and created a test file
JabobleHead Mar 25, 2026
b3aa5b9
Made a test file to test the wrapper adn made some error fixes
JabobleHead Mar 27, 2026
fe689c6
Made it so commonets are editiable by the AI
JabobleHead Apr 3, 2026
e0e9bb1
Full implementation of the Tsx wrapper for Jsx files. Wraps all .jsx …
JabobleHead Apr 8, 2026
245f879
Added the changes to added the new pictures to forcast page. Then add…
JabobleHead Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,627 changes: 1,626 additions & 1 deletion .gitignore

Large diffs are not rendered by default.

286 changes: 286 additions & 0 deletions documentation/code_related/guides/creating-a-new-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
# Creating a New Component in OpenFinAL

All UI components in OpenFinAL are wrapped with the `withViewComponent` HOC. This gives every component:

- Visibility control (`visible: false` hides it without removing it from the tree)
- Enabled/disabled state (grays out and blocks interaction)
- Automatic fixed dimensions for aspect-ratio-sensitive components (charts, slideshows)
- Auto-sizing (`height: auto`, `width: 100%`) for content-flow components (lists, forms, rows)
- Registration in the `ComponentRegistry` so the AI chatbot can find and mutate it by natural language

There are two component types:

| Type | File extension | When to use |
|---|---|---|
| JSX component | `.jsx` | Standard React component, no TypeScript prop enforcement |
| TSX component | `.tsx` | When you need TypeScript interface checking on props |

---

## Part 1: Creating a JSX Component

### Step 1 — Create the component file

Place the file in the appropriate subdirectory under `open-fin-al/src/View/`.

**Example:** `open-fin-al/src/View/Dashboard/MyWidget.jsx`

```jsx
import React from "react";

// The component receives viewConfig automatically from the HOC wrapper.
// You do not need to use viewConfig inside the component unless you need
// to read dimension or ratio values (e.g. for canvas sizing).
export function MyWidget({ viewConfig, someOtherProp }) {
return (
<div className="my-widget">
<p>{someOtherProp}</p>
</div>
);
}
```

> **Note:** Do not call `withViewComponent` inside this file if this component will be exported from `WrappedComponents.ts`. Doing so creates a circular dependency. See the circular dependency warning below.

---

### Step 2 — Add to `WrappedComponents.ts`

Open `open-fin-al/src/hoc/WrappedComponents.ts` and add an import and a wrapped export under the appropriate section comment.

```ts
// Dashboard
import { MyWidget } from "../View/Dashboard/MyWidget";

export const WrappedMyWidget = withViewComponent(MyWidget);
```

---

### Step 3 — Register in `registerComponents.ts`

Open `open-fin-al/src/hoc/registerComponents.ts` and add an entry to the `componentConfigs` array. This registers the component in the `ComponentRegistry` so the AI chatbot can find it.

```ts
{
id: "my-widget",
config: {
label: "My Widget",
description: "Short description of what the widget does — used by AI search",
tags: ["widget", "dashboard", "relevant-keyword"],
height: 200,
width: 400,
isContainer: false,
resizable: true,
maintainAspectRatio: false, // true = fixed pixel dims; false = auto/100%
widthRatio: 2,
heightRatio: 1,
heightWidthRatioMultiplier: 0,
visible: true,
enabled: true,
minimumProficiencyRequirements: {},
requiresInternet: false,
},
},
```

**`maintainAspectRatio` guide:**
- `true` — the HOC sets explicit `height` and `width` in pixels. Use this for charts, slideshows, and any component where pixel dimensions matter.
- `false` — the HOC sets `height: "auto"` and `width: "100%"`. Use this for lists, rows, forms, and anything that should flow with its content.

---

### Step 4 — Use the wrapped component

Import the wrapped version from `WrappedComponents.ts` in any page file that is **not itself exported from `WrappedComponents.ts`**.

```jsx
import { WrappedMyWidget } from "../hoc/WrappedComponents";
import { useMemo } from "react";
import { ViewComponent } from "../types/ViewComponent";

function SomePage() {
const myWidgetConfig = useMemo(() => new ViewComponent({
height: 200, width: 400, isContainer: false, resizable: true,
maintainAspectRatio: false, widthRatio: 2, heightRatio: 1,
heightWidthRatioMultiplier: 0, visible: true, enabled: true,
label: "My Widget", description: "...",
tags: ["widget"], minimumProficiencyRequirements: {}, requiresInternet: false,
}), []);

return <WrappedMyWidget someOtherProp="hello" viewConfig={myWidgetConfig} />;
}
```

> Use `useMemo` for the config in functional components so a new `ViewComponent` instance is not created on every render. For class components, define the config as a class property instead (see the circular dependency section below).

---

## Part 2: Creating a TSX Component

TSX components work exactly the same way as JSX, but you define a TypeScript interface for the props. This ensures callers pass the correct props at compile time.

### Step 1 — Create the component file

Place it under `open-fin-al/src/View/Component/<Section>/` for sub-components, or directly in `open-fin-al/src/View/<Section>/` for page-level components.

**Example:** `open-fin-al/src/View/Component/Dashboard/MyChart.tsx`

```tsx
import React from "react";
import { withViewComponent, WithViewComponentProps } from "../../../hoc/withViewComponent";

// 1. Declare your own props and extend WithViewComponentProps.
// WithViewComponentProps contributes: viewConfig: ViewComponent
interface MyChartProps extends WithViewComponentProps {
data: number[];
label: string;
}

// 2. Write the inner component (not exported directly).
function MyChartInner({ data, label, viewConfig }: MyChartProps) {
return (
<div>
<h4>{label}</h4>
{/* use data to render chart */}
</div>
);
}

// 3. Export the wrapped version.
export const MyChart = withViewComponent(MyChartInner);
```

> The inner function is **not** exported. Only the wrapped export is public. This prevents accidental use of the unwrapped version.

---

### Step 2 — Add to `WrappedComponents.ts`

```ts
// Dashboard
import { MyChart } from "../View/Component/Dashboard/MyChart";

export const WrappedMyChart = withViewComponent(MyChart);
```

Wait — `MyChart` is already wrapped inside its `.tsx` file. **Do not double-wrap it.** Instead, just re-export it with the `Wrapped` naming convention for consistency:

```ts
// Dashboard
export { MyChart as WrappedMyChart } from "../View/Component/Dashboard/MyChart";
```

Or skip `WrappedComponents.ts` entirely for TSX components and import directly from the source file:

```tsx
import { MyChart } from "../View/Component/Dashboard/MyChart";
```

---

### Step 3 — Register in `registerComponents.ts`

Same as JSX — add an entry to `componentConfigs` in `open-fin-al/src/hoc/registerComponents.ts`.

```ts
{
id: "my-chart",
config: {
label: "My Chart",
description: "Displays data as a chart",
tags: ["chart", "dashboard", "data"],
height: 300,
width: 700,
isContainer: false,
resizable: true,
maintainAspectRatio: true,
widthRatio: 16,
heightRatio: 9,
heightWidthRatioMultiplier: 0,
visible: true,
enabled: true,
minimumProficiencyRequirements: {},
requiresInternet: false,
},
},
```

---

### Step 4 — Use the component

```tsx
import { MyChart } from "../View/Component/Dashboard/MyChart";
import { useMemo } from "react";
import { ViewComponent } from "../types/ViewComponent";

function SomePage() {
const chartConfig = useMemo(() => new ViewComponent({
height: 300, width: 700, isContainer: false, resizable: true,
maintainAspectRatio: true, widthRatio: 16, heightRatio: 9,
heightWidthRatioMultiplier: 0, visible: true, enabled: true,
label: "My Chart", description: "...",
tags: ["chart"], minimumProficiencyRequirements: {}, requiresInternet: false,
}), []);

return <MyChart data={[1, 2, 3]} label="Revenue" viewConfig={chartConfig} />;
}
```

TypeScript will error at compile time if you forget `data`, `label`, or `viewConfig`, or if you pass the wrong type.

---

## Circular Dependency Warning

**Rule:** Any file that is exported from `WrappedComponents.ts` must NOT import from `WrappedComponents.ts`.

If a page-level component (e.g. `Home.jsx`, `Settings.jsx`) is listed in `WrappedComponents.ts` AND also needs to render a wrapped sub-component, it cannot use `WrappedComponents.ts` as the import source. Instead, wrap locally inside that file:

```jsx
// At the top of Home.jsx — wrap locally instead of importing from WrappedComponents
import { withViewComponent } from "../hoc/withViewComponent";
import { NewsBrowser } from "./News/Browser";

const WrappedNewsBrowser = withViewComponent(NewsBrowser);
```

For class components that cannot use `useMemo`, define the config as a class property:

```jsx
class Home extends Component {
newsBrowserConfig = new ViewComponent({
height: 300, width: 400, isContainer: false, resizable: true,
maintainAspectRatio: false, widthRatio: 4, heightRatio: 3,
heightWidthRatioMultiplier: 0, visible: true, enabled: true,
label: "News Browser", description: "...",
tags: ["news"], minimumProficiencyRequirements: {}, requiresInternet: true,
});

render() {
return <WrappedNewsBrowser viewConfig={this.newsBrowserConfig} />;
}
}
```

---

## Summary Checklist

### JSX component
- [ ] Create `open-fin-al/src/View/<Section>/MyComponent.jsx` and export a named function
- [ ] Add import + `withViewComponent` export to `open-fin-al/src/hoc/WrappedComponents.ts`
- [ ] Add a config entry to `open-fin-al/src/hoc/registerComponents.ts`
- [ ] Use `WrappedMyComponent` with a `viewConfig` prop at the call site

### TSX component
- [ ] Create `open-fin-al/src/View/Component/<Section>/MyComponent.tsx`
- [ ] Define `interface MyComponentProps extends WithViewComponentProps { ... }`
- [ ] Write the inner function (unexported), call `withViewComponent(Inner)` and export the result
- [ ] Add a config entry to `open-fin-al/src/hoc/registerComponents.ts`
- [ ] Use the exported component directly with a `viewConfig` prop at the call site

### Both
- [ ] Set `maintainAspectRatio: true` only for components that need fixed pixel dimensions (charts, slideshows)
- [ ] Never import from `WrappedComponents.ts` inside a file that is itself exported from `WrappedComponents.ts`
3 changes: 3 additions & 0 deletions open-fin-al/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/jest": "^30.0.0",
"@types/react": "^19.2.7",
"@vercel/webpack-asset-relocator-loader": "^1.7.3",
"babel-loader": "^10.0.0",
"browserify-fs": "^1.0.0",
Expand Down Expand Up @@ -72,6 +73,7 @@
"cors": "^2.8.5",
"crypto": "^1.0.1",
"crypto-browserify": "^3.12.1",
"danfojs": "^1.2.0",
"electron-squirrel-startup": "^1.0.1",
"events": "^3.3.0",
"express": "^5.1.0",
Expand All @@ -80,6 +82,7 @@
"http": "^0.0.1-security",
"https": "^1.0.0",
"keytar": "^7.9.0",
"neo4j-driver": "^6.0.1",
"node-html-parser": "^7.0.1",
"os-browserify": "^0.3.0",
"pptx-preview": "^1.0.7",
Expand Down
3 changes: 3 additions & 0 deletions open-fin-al/resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Purpose of this Folder
The resources folder should contain the following folders:
neo4j-win - this folder should include binaries for neo4j community for Windows
Binary file not shown.
Binary file added open-fin-al/src/Asset/Image/ai_header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added open-fin-al/src/Asset/Image/binary_header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ export class AlphaVantageEconomicGateway implements IKeyedDataGateway {
throw new Error("This gateway does not have the ability to post content");
}

async read(entity: IEntity, action: string): Promise<Array<IEntity>> {
async read(entity: IEntity, action: string): Promise<Array<IEntity>> {
const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms));
await sleep(1001);

var url = `${this.baseURL}?`;

if(action==="getGDP") {
Expand Down
14 changes: 14 additions & 0 deletions open-fin-al/src/Gateway/Data/ICredentialedDataGateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {IEntity} from "../../Entity/IEntity";
import { IDataGateway } from "./IDataGateway";

export interface ICredentialedDataGateway extends IDataGateway {
user: string;
key: string;
sourceName: string;
connect(): void;
disconnect(): void;
create(entity: IEntity, action?: string): Promise<Boolean>;
read(entity: IEntity, action?: string): Promise<Array<IEntity>>;
update(entity: IEntity, action?: string): Promise<number>;
delete(entity: IEntity, action?: string): Promise<number>;
}
1 change: 1 addition & 0 deletions open-fin-al/src/Gateway/Data/IDataGateway.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {IEntity} from "../../Entity/IEntity";

export interface IDataGateway {
user?: string;
key?: string;
sourceName: string;
connect(): void;
Expand Down
4 changes: 2 additions & 2 deletions open-fin-al/src/Gateway/Data/IKeylessDataGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { IDataGateway } from "./IDataGateway";

export interface IKeylessDataGateway extends IDataGateway {
sourceName: string;
connect(): void;
disconnect(): void;
connect(): void | Promise<void> | Promise<boolean>;
disconnect(): void | Promise<void> | Promise<boolean>;
create(entity: IEntity, action?: string): Promise<Boolean>;
read(entity: IEntity, action?: string): Promise<Array<IEntity>>;
update(entity: IEntity, action?: string): Promise<number>;
Expand Down
17 changes: 17 additions & 0 deletions open-fin-al/src/Gateway/Data/INeo4JGraphGateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {IEntity} from "../../Entity/IEntity";
import { IDataGateway } from "./IDataGateway";

export interface INeo4JGraphGateway extends IDataGateway {
user: string;
key: string;
sourceName: string;
connect(): Promise<boolean>;
disconnect(): Promise<boolean>;
create(entity: IEntity, action?: string): Promise<Boolean>;
read(entity: IEntity, action?: string): Promise<Array<IEntity>>;
update(entity: IEntity, action?: string): Promise<number>;
delete(entity: IEntity, action?: string): Promise<number>;
checkGraphConnected(): Promise<Boolean>;
checkGraphExists(): Promise<Boolean>;
checkLastGraphUpdate() : Promise<Date>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export class AlphaVantageMarketGateway implements IKeyedDataGateway {
}

async read(entity: IEntity, action: string): Promise<Array<IEntity>> {
const sleep = (ms:number) => new Promise(resolve => setTimeout(resolve, ms));
await sleep(1001);

var url = `${this.baseURL}?function=MARKET_STATUS&apikey=${entity.getFieldValue("key")}`;
const urlObject = new URL(url);

Expand Down
Loading