Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 11 additions & 6 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: Deploy to Server
on:
push:
branches: [main]
paths:
- 'flowming/**'
- '.github/workflows/deploy.yml'

jobs:
build-and-deploy:
Expand All @@ -18,18 +21,18 @@ jobs:
rm -f package-lock.json

- name: Install dependencies
run: npm install
run: npm install --workspace=flowming

- name: Run tests
run: npm test
run: npm test --workspace=flowming

- name: Build project
run: npm run build
run: npm run build --workspace=flowming

- name: Deploy files
run: |
rm -rf /var/www/flow-diagram/*
cp -a dist/* /var/www/flow-diagram/
cp -a flowming/dist/* /var/www/flow-diagram/
chown -R github-runner:www-data /var/www/flow-diagram

- name: Restart server
Expand All @@ -38,6 +41,8 @@ jobs:

- name: Clean up
run: |
rm -rf dist
rm -rf flowming/dist
rm -rf node_modules
rm package-lock.json
rm -rf flowming/node_modules
rm -rf y-webrtc-server/node_modules
rm -f package-lock.json
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ name: Test
on:
pull_request:
branches: [main]
paths:
- 'flowming/**'
- 'y-webrtc-server/**'
- '.github/workflows/test.yml'
push:
branches: [main]
paths:
- 'flowming/**'
- 'y-webrtc-server/**'
- '.github/workflows/test.yml'

jobs:
test:
Expand Down
133 changes: 130 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,130 @@
## Comment annotations
- TODO: {...}
- NOTE: {...}
<p align="center">
<a href="https://github.com/MrPoll0/flowming">
<img src="flowming/public/logo.svg" alt="Flowming Logo" width="400">
</a>
</p>

<p align="center">
<a href="https://github.com/MrPoll0/flowming/actions/workflows/test.yml"><img src="https://github.com/MrPoll0/flowming/actions/workflows/test.yml/badge.svg" alt="Build Status"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg" alt="License"></a>
</p>

Interactive web application for designing, executing and debugging algorithms using standard flowchart notation.

Flowming helps beginners focus on computational thinking before wrestling with the syntax of a textual language. Students build flowcharts visually, run them step-by-step, watch variables change in real time and export the equivalent Python code – all from their browser.

---

## ✨ Key features

* Visual editor powered by React Flow: drag-and-drop blocks, connect them and rearrange freely.
* Strongly-typed execution engine with breakpoint support, variable watch panel and execution trace.
* Automatic code generation (Python 3) showing the 1-to-1 mapping from flowchart to text.
* Exercises bank & auto-evaluation.
* Real-time collaboration (peer-to-peer WebRTC): edit the same diagram together *(experimental)*.
* Modern SPA built with React 19, TypeScript, Vite and Tailwind.

---

## 🚀 Getting started

### Prerequisites

* Node.js **>= 18** (https://nodejs.org)
* Git (to clone the repo)
*(all other dependencies are installed via **npm**)*

### 1. Clone & install

```bash
git clone https://github.com/MrPoll0/flowming.git
cd flowming
npm install # Installs dependencies for all packages
```

### 2. Run development servers

To start the Vite dev server for the main application and the WebRTC signaling server simultaneously, run:
```bash
# From the project root
npm run dev
```
This will start the `flowming` app (usually on `http://localhost:5173`) and the collaboration server.

### 3. Production build

```bash
# From the project root
npm run build # Builds the flowming app to flowming/dist/
npm run preview # Serves the production build locally
```

### 4. Test

```bash
# From the project root
npm run test # Runs Vitest unit tests for flowming
```

---

## 🗂️ Repository layout (short)

```
.
├── flowming/ # Main React application
│ └── src/
│ ├── components/ # React UI & flowchart nodes
│ ├── context/ # React context providers (state)
│ ├── models/ # Core domain classes (Variable, Expression, …)
│ └── utils/ # Execution engine, code generation, helpers
├── y-webrtc-server/ # WebSocket-based WebRTC signaling server
│ └── server.js
├── README.md # This file
├── LICENSE # CC BY-NC-SA 4.0
├── CONTRIBUTING.md
└── CLA.md
```

---

## 🤝 Contributing

We love contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow, coding style and commit conventions.
The first time you open a pull request you will be asked to sign our **Contributor License Agreement (CLA)** via CLA-Assistant.

---

## 📚 Project Thesis

This repository includes the full bachelor's thesis (Spanish) that motivated the project, detailing state-of-the-art, design decisions and user evaluation.

*Title:* "Aplicación web para el diseño y ejecución de diagramas de flujo"
*Author:* Daniel Pérez Fernández
*Advisor*: Álvaro Montero Montes
**Universidad Carlos III de Madrid**, 2025

You can find the PDF and additional assets in the `docs/` release section.

---

## 📜 License & trademarks

* **Source code**: Creative Commons **Attribution-NonCommercial-ShareAlike 4.0** International (CC BY-NC-SA 4.0).
You may study, fork and improve Flowming for non-commercial purposes, but must share derivatives under the same license.
* **Documentation** (thesis, README, etc.): Creative Commons **Attribution-NonCommercial-NoDerivatives 4.0** (CC BY-NC-ND 4.0).
* The name **"Flowming"** and the logo are **not** part of the CC license and remain protected trademarks of the author.

See [LICENSE](LICENSE) for the full text.

---

## ❤️ Acknowledgements

Built with:

* React & TypeScript
* React Flow – amazing node-based UI toolkit
* Yjs – CRDT magic for collaboration
* shadcn/ui & Lucide icons
* Vite & Vitest
Empty file added docs/TODOadd_doc
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
66 changes: 66 additions & 0 deletions flowming/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "flowming",
"version": "1.0.0",
"author": "Daniel Pérez Fernández",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest run"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-scroll-area": "^1.2.9",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-tooltip": "^1.2.7",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@xyflow/react": "^12.4.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"framer-motion": "^12.6.3",
"lucide-react": "^0.511.0",
"next-themes": "^0.4.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-resizable-panels": "^3.0.2",
"react-syntax-highlighter": "^15.6.1",
"sonner": "^2.0.5",
"tailwind-merge": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
"y-webrtc": "^10.3.0",
"yjs": "^13.6.27"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/node": "^22.15.21",
"@types/react-syntax-highlighter": "^15.5.13",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.21",
"eslint": "^9.19.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.18",
"globals": "^15.14.0",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.22.0",
"vite": "^6.1.0",
"vitest": "^3.1.1"
}
}
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { IValuedVariable, ValuedVariable } from '../../../models/ValuedVariable'
import { VariableType } from '../../../models/Variable';
import { Badge } from '@/components/ui/badge';
import BreakpointIndicator from './BreakpointIndicator';
import { ExpressionElement } from '@/models/ExpressionElement';

interface AssignVariableNode extends BaseNode {
expression?: Expression;
leftSideIndex?: string;
}

export class AssignVariableProcessor implements NodeProcessor {
Expand Down Expand Up @@ -63,7 +65,24 @@ export class AssignVariableProcessor implements NodeProcessor {
}

const AssignVariable = memo(function AssignVariableComponent({ data, id: _nodeId }: { data: AssignVariableNode; id: string }) {
const { isHovered, isSelected, isHighlighted, isCodeHighlighted, expression, width, height, visualId, isError, hasBreakpoint, isBreakpointTriggered } = data;
const { isHovered, isSelected, isHighlighted, isCodeHighlighted, expression, width, height, visualId, isError, hasBreakpoint, isBreakpointTriggered, leftSideIndex } = data as AssignVariableNode & { leftSideIndex?: string };

const buildDisplayString = () => {
if (!expression) return null;
const exprInstance = expression instanceof Expression ? expression : Expression.fromObject(expression);
// For assign variable expressions, leftSide is a Variable
if (exprInstance.leftSide instanceof Variable) {
const leftName = exprInstance.leftSide.name;
const leftDisplay = leftSideIndex ? `${leftName}[${leftSideIndex}]` : leftName;
const right = exprInstance.rightSide.map((e: any) => (e as ExpressionElement).toString()).join(' ');
return `${leftDisplay} = ${right}`;
}
// Fallback
return exprInstance.toString();
};

const displayString = buildDisplayString();

return (
<div
className={`assign-variable-node`}
Expand Down Expand Up @@ -108,7 +127,7 @@ const AssignVariable = memo(function AssignVariableComponent({ data, id: _nodeId
{expression ? (
<div className="mb-1">
<Badge variant="outline" className="font-mono text-sm w-full justify-center">
{expression instanceof Expression ? expression.toString() : Expression.fromObject(expression).toString()}
{displayString}
</Badge>
</div>
) : (
Expand Down
File renamed without changes.
Loading