Skip to content

Commit cda7382

Browse files
Merge branch 'finos:main' into feat/add-deployment-decorator-standard
2 parents 13d71c8 + 5a163d0 commit cda7382

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3428
-523
lines changed

calm-hub-ui/README.md

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,114 @@
1-
# Getting Started with Create React App
1+
# 🏛️ CALM Hub UI
22

3-
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
43

5-
## Available Scripts
4+
https://github.com/user-attachments/assets/931cca52-6dff-4895-8de4-88a291acd41a
65

7-
In the project directory, you can run:
86

9-
### `npm start`
7+
Explore, visualize, and manage CALM architecture models through an interactive web interface. Features graph-based visualization, pattern decision exploration.
108

11-
Runs the app in the development mode.\
12-
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
9+
## ✨ Features
1310

14-
The page will reload when you make changes.\
15-
You may also see any lint errors in the console.
11+
### 🎯 Interactive Architecture Visualization
12+
- **Graph-Based Rendering**: ReactFlow-powered diagrams with automatic layout via Dagre
13+
- **Smart Node Rendering**: Type-specific icons for Actors, Systems, Services, Databases, Networks, and more
14+
- **Group Nodes**: Automatic container grouping for `deployed-in` and `composed-of` relationships
15+
- **Floating Edges**: Bezier-curved edges with labels and badges that avoid node overlap
16+
- **Pan, Zoom & Minimap**: Full interactive controls with fit-to-view
1617

17-
### `npm test`
18+
### 🧩 Pattern Visualization with Decision Support
19+
- **JSON Schema Patterns**: Render architecture patterns with automatic layout
20+
- **Decision Points**: Extract and display `oneOf`/`anyOf` constraints as interactive decision selectors
21+
- **Dynamic Filtering**: Select decision paths to see how the architecture changes
22+
- **Decision Group Nodes**: Visual grouping highlights pattern variants
1823

19-
Launches the test runner in the interactive watch mode.\
20-
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
24+
### 🌳 Hub Navigation
25+
- **Tree-Based Browsing**: Collapsible sidebar to explore Namespaces, Architectures, Patterns, Flows, and ADRs
26+
- **Diagram & JSON Views**: Toggle between interactive visualization and raw JSON with syntax highlighting
27+
- **Version Selection**: Browse and switch between architecture revisions
28+
- **Quick Visualize**: Jump from any document into the full Visualizer workspace
2129

22-
### `npm run start-cypress`
30+
### 🔍 Search & Filtering
31+
- **Node Search**: Find nodes by name, unique-id, or node-type
32+
- **Type-Based Filtering**: Filter by node type via dropdown
33+
- **Opacity Dimming**: Matching nodes at full opacity, non-matching dimmed to 15%
34+
- **Edge Filtering**: Edges follow connected node visibility
2335

24-
End to End tests are written with cypress. Cypress can be run in headless and headed modes.
25-
The above command runs in headed mode and allows the developer to locally run through the spec
26-
files and observe the test runs. [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) queries and paradigm for testing feature
27-
heavily in these tests as these help maintainability by organising tests around how the UI is used
28-
and not how its implemented. [Cypress and its best practices](https://docs.cypress.io/app/core-concepts/best-practices) are also used in writing and updating
29-
these tests.
36+
### 📋 Metadata Panel
37+
- **Flows Panel**: View business and data flows with step-by-step transitions
38+
- **Controls Panel**: Hierarchical security and compliance controls
39+
- **Flow Highlighting**: Click a transition to highlight the corresponding relationship in the graph
40+
- **Control Deep-Linking**: Jump from a control to the affected node
3041

31-
You need to set an environment variable VITE_BASE_URL which should be the address where the vite server is being run
32-
A default in .env.example has been added. This can also be set in CI to whatever the intended vite port should be
42+
### 🛡️ Risk & Control Integration
43+
- **Risk-Aware Borders**: Node border color indicates risk level (red, yellow, green)
44+
- **Hover Details**: Tooltips show associated risks and mitigations
45+
- **Control Badges**: Quick visibility into control coverage per node
3346

34-
#### Test Stubbing
35-
The tests are all stubbed to return desired responses. These will need to be maintained in tandem with
36-
calm-hub API. This section can be updated when a different and more reliable integration strategy is devised
47+
### 📝 ADR Rendering
48+
- **Rich Display**: Context, decision drivers, considered options, outcome, and links
49+
- **Markdown Support**: Full markdown rendering within ADR sections
50+
- **Revision Browsing**: Switch between ADR versions
51+
- **Status Badges**: Visual indicators for approved, deprecated, and other statuses
3752

53+
### 🔎 Inspector Sidebar
54+
- **Selection Details**: Click any node or edge to inspect its raw JSON
55+
- **Drag & Drop Upload**: Load CALM JSON files directly into the visualizer
3856

39-
### `npm run build`
57+
## 🚀 Getting Started
4058

41-
Builds the app for production to the `build` folder.\
42-
It correctly bundles React in production mode and optimizes the build for the best performance.
59+
### Prerequisites
60+
- Node.js (see `.nvmrc` for the recommended version)
61+
- A running instance of CALM Hub (the backend API)
4362

44-
The build is minified and the filenames include the hashes.\
45-
Your app is ready to be deployed!
63+
### Development
4664

47-
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
65+
```bash
66+
npm install
67+
npm start
68+
```
4869

49-
### `npm run eject`
70+
Open [http://localhost:3000](http://localhost:3000) to view the app in your browser. The page will reload when you make changes.
5071

51-
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
72+
### 🧪 Running Tests
5273

53-
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
74+
```bash
75+
# Unit tests
76+
npm test
5477

55-
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
78+
# End-to-end tests (headed mode)
79+
npm run start-cypress
80+
```
5681

57-
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
82+
E2E tests use [Cypress](https://docs.cypress.io/) with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) queries. All tests are stubbed against the CALM Hub API.
5883

59-
## Learn More
84+
You need to set the environment variable `VITE_BASE_URL` to the address where the Vite dev server is running (see `.env.example` for defaults).
6085

61-
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
86+
### 📦 Production Build
6287

63-
To learn React, check out the [React documentation](https://reactjs.org/).
88+
```bash
89+
npm run build
90+
```
6491

65-
### Code Splitting
92+
Outputs an optimized production bundle to the `build` folder.
6693

67-
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
94+
## 🛠️ Tech Stack
6895

69-
### Analyzing the Bundle Size
96+
| Category | Libraries |
97+
|---|---|
98+
| UI Framework | React 19, React Router, TypeScript |
99+
| Visualization | ReactFlow, Dagre, D3 |
100+
| Styling | TailwindCSS, DaisyUI |
101+
| Code Display | Monaco Editor, react-json-view-lite |
102+
| Auth | OpenID Connect (oidc-client) |
103+
| Testing | Vitest, Cypress |
104+
| Build | Vite |
70105

71-
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
106+
## 🤝 Getting Involved
72107

73-
### Making a Progressive Web App
108+
Architecture as Code was developed as part of the [DevOps Automation Special Interest Group](https://devops.finos.org/) before graduating as a top level project in its own right. Our community Zoom meetups take place on the fourth Tuesday of every month, see [here](https://github.com/finos/architecture-as-code/issues?q=label%3Ameeting) for upcoming and previous meetings. For active contributors we have Office Hours every Thursday, see the [FINOS Event Calendar](http://calendar.finos.org) for meeting details.
74109

75-
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
110+
Have an idea or feedback? [Raise an issue](https://github.com/finos/architecture-as-code/issues/new/choose) in this repository.
76111

77-
### Advanced Configuration
112+
---
78113

79-
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
80-
81-
### Deployment
82-
83-
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
84-
85-
### `npm run build` fails to minify
86-
87-
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
114+
**Contributing**: Issues and PRs welcome! 🎉

calm-hub-ui/cypress/e2e/adrs.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const expectedNamespace = "finos"
1+
const expectedNamespace = { name: "finos", description: "FINOS namespace" };
22
const expectedAdrId = 1;
33
const expectedAdrRevision = 2;
44

@@ -14,7 +14,7 @@ describe('ADR Tests', () => {
1414

1515
it("Displays ADR JSON successfully", () => {
1616
cy.visit("/");
17-
cy.findByText(expectedNamespace).click();
17+
cy.findByText(expectedNamespace.name).click();
1818
cy.findByText(/adrs/i).click();
1919
cy.findByText(/1/i).click();
2020
cy.findByText(expectedAdrRevision).click();

calm-hub-ui/cypress/e2e/architectures.cy.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const expectedNamespace = "finos"
1+
const expectedNamespace = { name: "finos", description: "FINOS namespace" };
22
const expectedArchitectureId = 1;
33
const expectedArchitectureVersion = "1.0.0";
44

@@ -12,15 +12,24 @@ describe('Architecture Tests', () => {
1212
});
1313
})
1414

15-
it("Displays architecture JSON successfully", () => {
15+
it("Displays architecture diagram by default", () => {
1616
cy.visit("/");
17-
cy.findByText(expectedNamespace).click();
17+
cy.findByText(expectedNamespace.name).click();
1818
cy.findByText(/architectures/i).click();
1919
cy.findByText(/1/i).click();
2020
cy.findByText(/1.0.0/i).click();
2121

22-
cy.findByText(/relationship descriptions/i).should("exist");
23-
cy.findByText(/node descriptions/i).should("exist");
22+
cy.get('canvas').should("exist");
23+
cy.findByRole("tab", { name: /diagram/i }).should("exist");
24+
cy.findByRole("tab", { name: /json/i }).should("exist");
25+
})
26+
27+
it("Displays architecture JSON successfully", () => {
28+
cy.visit("/");
29+
cy.findByText(expectedNamespace.name).click();
30+
cy.findByText(/architectures/i).click();
31+
cy.findByText(/1/i).click();
32+
cy.findByText(/1.0.0/i).click();
2433

2534
cy.findByRole("tab", { name: /json/i}).click();
2635

calm-hub-ui/cypress/e2e/flows.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const expectedNamespace = "finos"
1+
const expectedNamespace = { name: "finos", description: "FINOS namespace" };
22
const expectedFlowId = 1;
33
const expectedFlowVersion = "1.0.0";
44

@@ -14,7 +14,7 @@ describe('Flow Tests', () => {
1414

1515
it("Displays flow JSON successfully", () => {
1616
cy.visit("/");
17-
cy.findByText(expectedNamespace).click();
17+
cy.findByText(expectedNamespace.name).click();
1818
cy.findByText(/flows/i).click();
1919
cy.findByText(/1/i).click();
2020
cy.findByText(/1.0.0/i).click();

calm-hub-ui/cypress/e2e/home.cy.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {namespaces, resourceTypes} from "../fixtures/constants.js";
1+
import {namespaceInfos, namespaces, resourceTypes} from "../fixtures/constants.js";
22

33
describe('Home page tests', () => {
44
beforeEach(() => {
5-
cy.intercept("/calm/namespaces", {"values": namespaces})
5+
cy.intercept("/calm/namespaces", {"values": namespaceInfos})
66
})
77

88
it('Loads initial screen successfully', () => {
@@ -14,14 +14,26 @@ describe('Home page tests', () => {
1414
resourceTypes.forEach(resourceType => { cy.findByText(resourceType).should("exist"); });
1515
})
1616

17+
context("Sidebar collapse", () => {
18+
it("Collapses and expands the sidebar", () => {
19+
cy.visit('/');
20+
cy.findByText("Explore").should("exist");
21+
22+
cy.findByLabelText("Collapse sidebar").click();
23+
cy.findByText("Explore").should("not.exist");
24+
25+
cy.findByLabelText("Expand sidebar").click();
26+
cy.findByText("Explore").should("exist");
27+
})
28+
})
29+
1730
context("Wide screen tests", () => {
1831
it("Finds navigation items", () => {
1932
cy.viewport('macbook-16')
2033
cy.visit('/');
2134
cy.findByRole("link", { name: "Hub" })
2235
cy.findByRole("link", { name: "Visualizer" })
2336
})
24-
2537
})
2638

2739
context("Collapsed screen tests", () => {

calm-hub-ui/cypress/e2e/patterns.cy.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const expectedNamespace = "finos"
1+
const expectedNamespace = { name: "finos", description: "FINOS namespace" };
22
const expectedPatternId = 1;
33
const expectedPatternVersion = "1.0.0";
44

@@ -12,13 +12,27 @@ describe('Pattern Tests', () => {
1212
});
1313
})
1414

15-
it("Displays pattern JSON successfully", () => {
15+
it("Displays pattern diagram by default", () => {
1616
cy.visit("/");
17-
cy.findByText(expectedNamespace).click();
17+
cy.findByText(expectedNamespace.name).click();
1818
cy.findByText(/patterns/i).click();
1919
cy.findByText(/1/i).click();
2020
cy.findByText(/1.0.0/i).click();
2121

22+
cy.findByRole("tab", { name: /diagram/i }).should("exist");
23+
cy.findByRole("tab", { name: /json/i }).should("exist");
24+
cy.get('canvas').should("exist");
25+
})
26+
27+
it("Switches to JSON tab and displays pattern content", () => {
28+
cy.visit("/");
29+
cy.findByText(expectedNamespace.name).click();
30+
cy.findByText(/patterns/i).click();
31+
cy.findByText(/1/i).click();
32+
cy.findByText(/1.0.0/i).click();
33+
34+
cy.findByRole("tab", { name: /json/i }).click();
35+
2236
cy.fixture('conference-signup-pattern').then(data => {
2337
cy.contains(/\$schema/i).should("exist");
2438
cy.contains(data.$schema).should("exist");
@@ -32,11 +46,6 @@ describe('Pattern Tests', () => {
3246
cy.contains(/description/i).should("exist");
3347
cy.contains(data.description).should("exist");
3448

35-
cy.contains(/minItems/i).should("exist");
36-
cy.contains(data.properties.nodes.minItems).should("exist");
37-
38-
cy.contains(data.properties.nodes.minItems).should("exist");
39-
4049
cy.contains(/prefixItems/i).should("exist");
4150
});
4251
})

calm-hub-ui/cypress/e2e/visualizer.cy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ describe("Visualizer page tests", () => {
1515
cy.findByText(/relationship descriptions/i).should("exist");
1616
cy.findByText(/node descriptions/i).should("exist");
1717
})
18+
19+
it("Displays pattern visualization on file upload", () => {
20+
cy.viewport('macbook-16')
21+
cy.visit("/");
22+
23+
cy.findByRole("link", { name: "Visualizer" }).click();
24+
25+
cy.fixture("conference-signup-pattern", null).as('pattern');
26+
cy.get('input[type=file]').selectFile("@pattern", {force: true})
27+
28+
cy.get('canvas').should("exist");
29+
})
1830
})
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1-
export const namespaces = ["finos","workshop","traderx","osff2025", "e2e"];
1+
export const namespaceInfos = [
2+
{ name: "finos", description: "FINOS namespace" },
3+
{ name: "workshop", description: "Workshop namespace" },
4+
{ name: "traderx", description: "TraderX namespace" },
5+
{ name: "osff2025", description: "OSFF 2025 namespace" },
6+
{ name: "e2e", description: "E2E namespace" },
7+
];
8+
export const namespaces = namespaceInfos.map(ns => ns.name);
29
export const resourceTypes = ['Architectures', 'Patterns', 'Flows', 'ADRs'];

0 commit comments

Comments
 (0)