Skip to content

Commit

Permalink
feat: Integrate FastHTML replacing FastAPI and React
Browse files Browse the repository at this point in the history
This introduces a major change by replacing the FastAPI backend and
React frontend with FastHTML. The integration involves reusing existing
code where possible, but also includes significant rewrites that affect
the application's behavior. This update aims to enhance performance and
streamline the development process.

This commit also introduces project management tool which replaces the
Makefile with a Python CLI tool. The tool manages the project, including
building the Docker image, running the app in a container, and running
the app locally. The tool also builds the Tailwind CSS stylesheet.

The app always runs with hot template reloading enabled.
In development mode, it also runs with hot code reloading.

After cloning the project, one can get further information by running:

```bash
cme -h
cme run -h
cme build -h
```

Co-authored-by: Martin Lehmann <[email protected]>
  • Loading branch information
jamilraichouni and Wuestengecko committed Feb 10, 2025
1 parent 649ef5f commit 2173540
Show file tree
Hide file tree
Showing 136 changed files with 8,863 additions and 12,462 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: CC0-1.0

static/css/main*.css
32 changes: 18 additions & 14 deletions .github/workflows/build-test-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,21 @@ jobs:
- os: windows-latest
python_version: "3.11"
steps:
- name: Set env var `SKIP_LONG_RUNNING_TESTS=1` (draft PR) to skip long running tests
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }}
run: echo "SKIP_LONG_RUNNING_TESTS=1" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
- name: Set up Python ${{matrix.python_version}}
uses: actions/setup-python@v5
with:
cache: pip
cache-dependency-path: pyproject.toml
fetch-depth: 0
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: "**/pyproject.toml"
python-version: ${{matrix.python_version}}
- name: Upgrade Pip
run: |-
python -m pip install -U pip
- name: Install test dependencies
run: |-
python -m pip install '.[test]'
- name: Install dependencies
run: uv pip install ".[test]"
- name: Run unit tests
run: |-
python -m pytest --cov-report=term --cov=capella_model_explorer --rootdir=.
run: uv run coverage run

pre-commit:
runs-on: ubuntu-latest
Expand All @@ -51,7 +50,7 @@ jobs:
with:
cache: pip
cache-dependency-path: pyproject.toml
python-version: "3.11"
python-version: "3.12"
- name: Upgrade pip
run: python -m pip install -U pip
- name: Install pre-commit
Expand All @@ -63,6 +62,11 @@ jobs:
https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
chmod +x /usr/local/bin/hadolint
hadolint --version
- name: Install self
run: python -m pip install .
- name: Install prettier and prettier plugins
run: |-
python -m capella_model_explorer pre-commit-setup
- name: Run Pre-Commit
run: pre-commit run --all-files

Expand All @@ -74,7 +78,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
python-version: "3.12"
- name: Install dependencies
run: |-
python -m pip install -U pip
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,8 @@ node_modules/

# IntelliJ project files
.idea/

# stylesheet generated by tailwindcss cli
static/css/main-*.css

uv.lock
29 changes: 11 additions & 18 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ default_stages: [pre-commit, pre-merge-commit]
minimum_pre_commit_version: 4.0.0
repos:
- repo: https://github.com/gitleaks/gitleaks.git
rev: v8.23.2
rev: v8.23.3
hooks:
- id: gitleaks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
args: ['--maxkb=10000']
- id: check-ast
- id: check-builtin-literals
- id: check-case-conflict
Expand All @@ -28,8 +29,10 @@ repos:
- id: debug-statements
- id: destroyed-symlinks
- id: end-of-file-fixer
exclude: 'static/js/plotly.*\.min\.js'
- id: fix-byte-order-marker
- id: trailing-whitespace
exclude: 'static/js/plotly.*\.min\.js'
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
Expand Down Expand Up @@ -65,7 +68,7 @@ repos:
- id: insert-license
name: Insert Apache license headers (C-style comments)
files: '\.(?:s?css|js|ts)$'
exclude: '(?:^|/)\..+'
exclude: '(?:^|/)\..+|static/js/plotly.*\.min\.js'
args:
- --detect-license-in-X-top-lines=15
- --license-filepath
Expand Down Expand Up @@ -99,7 +102,7 @@ repos:
additional_dependencies:
- docformatter[tomli]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.3
rev: v0.9.5
hooks:
- id: ruff
args: [--extend-ignore=FIX, --fix]
Expand All @@ -109,7 +112,7 @@ repos:
hooks:
- id: actionlint
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1
rev: v1.15.0
hooks:
- id: mypy
additional_dependencies:
Expand Down Expand Up @@ -137,35 +140,25 @@ repos:
- id: prettier-css
name: prettier-css
language: system
entry: sh -c 'make frontend/node_modules && ./frontend/node_modules/.bin/prettier --write --tab-width 2 --print-width 79 --parser css "$@"' --
entry: sh -c 'node_modules/.bin/prettier --write --parser css "$@"' --
require_serial: true
files: '\.css$'
- id: prettier-jinja
name: prettier-jinja
language: system
entry: sh -c 'make frontend/node_modules && ./frontend/node_modules/.bin/prettier --write --tab-width 2 --print-width 79 --parser jinja-template --plugin "$(npm root -g)/prettier-plugin-jinja-template/lib/index.js" "$@"' --
entry: sh -c 'node_modules/.bin/prettier --write --parser jinja-template --plugin "$(pwd)/node_modules/prettier-plugin-jinja-template/lib/index.js" "$@"' --
require_serial: true
files: '\.(j2|jinja)$'
- id: prettier-js
name: prettier-js
language: system
entry: sh -c 'make frontend/node_modules && ./frontend/node_modules/.bin/prettier --write --tab-width 2 --print-width 79 --parser babel "$@"' --
entry: sh -c 'node_modules/.bin/prettier --write --parser babel "$@"' --
require_serial: true
files: '\.js$'
- id: prettier-md
# depends on https://github.com/remarkjs/remark/tree/main/packages/remark-parse
name: prettier-md
language: system
entry: sh -c 'make frontend/node_modules && ./frontend/node_modules/.bin/prettier --write --tab-width 2 --print-width 79 --parser markdown "$@"' --
entry: sh -c 'node_modules/.bin/prettier --write --parser markdown "$@"' --
require_serial: true
files: '\.md$'
- repo: local
hooks:
- id: eslint
name: eslint
language: system
entry: sh -c 'make frontend/node_modules && ./frontend/node_modules/.bin/eslint "$@"' --
require_serial: true
args: ['--fix', '--config', 'frontend/eslint.config.js']
types: []
files: '^frontend/.*\.(js|jsx)$'
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: CC0-1.0

static/css/main*.min.js
static/js/plotly*.min.js
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"printWidth": 79,
"tabWidth": 2
}
File renamed without changes.
70 changes: 63 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,10 @@ our style guidelines outlined below.

## Developing

We recommend that you
[develop inside of a virtual environment](README.md#installation). After you
have set it up, simply run the unit tests to verify that everything is set up
correctly:
### Common

```sh
pytest
```
We recommend that you
[develop inside of a virtual environment](README.md#installation).

We additionally recommend that you set up your editor / IDE as follows.

Expand Down Expand Up @@ -57,6 +53,66 @@ We additionally recommend that you set up your editor / IDE as follows.
save. Language server clients are available for a wide range of editors, from
Vim/Emacs to PyCharm/IDEA.

### Preconditions

- Python 3.11 or higher
- Node package manager (npm)
- Docker (to guarantee, that the app will continue to work in a container)

### Quick start

1. Clone the project, change into the project root directory, and install in
editable mode in the virtual environment:

```bash
pip install -e ."[dev,docs,test]"
```

1. Install node packages (needed to build the CSS from TailwindCSS):

```bash
npm clean-install
```

1. Optional:

Create a `.env` file in the root of the project and define any of the
environment variables decribed in the help `cme run local-dev -h`.

Example `.env` file:

```bash
CME_MODEL={"path": "git+https://github.com/DSD-DBS/Capella-IFE-sample.git","revision": "master", "entrypoint": "In-Flight Entertainment System.aird"}
CME_PORT=5000
CME_ROUTE_PREFIX="/prefic"
```

1. Run the application in development mode with the following command executed
in the root directory of the project:

```bash
dotenv run cme run local-dev # if you want to make use of the .env file
cme run local-dev # without .env file
```

`cme run local-dev` starts the TailwindCSS CLI and the FastHTML server in watch
mode that reloads the backend and frontend on change of files with the
extensions `*.css`, `*.j2` (templates), `*.js`, and `*.py`.

The app will be available at the location printed to the terminal when
the console confirms `Application startup complete.`.

### Modifying the style of the frontend

Always modify the style via TailwindCSS classes within the Python or Jinja2
template files.

If not possible (because of collision with TailwindCSS' `prosa` class), modify
the file `static/css/input.css` directly.

Note, that it is sometimes needed to empty cache and hard reload the app in the
browser, when styles are not applied correctly.

## Code style

We base our code style on a modified version of the
Expand Down
115 changes: 69 additions & 46 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,61 +1,84 @@
# Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: Apache-2.0

# Build frontend
FROM node:20 AS build-frontend
WORKDIR /app
COPY frontend/package*.json ./
RUN npm install
COPY frontend/ ./
RUN npm run build

# Build backend
FROM python:3.12-slim-bookworm
WORKDIR /app

USER root

RUN apt-get update && \
apt-get install --yes --no-install-recommends \
git \
git-lfs \
libgirepository1.0-dev \
libcairo2-dev \
gir1.2-pango-1.0 \
graphviz \
nodejs \
npm && \
rm -rf /var/lib/apt/lists/*

COPY ./capella_model_explorer ./capella_model_explorer
COPY ./pyproject.toml ./
COPY ./.git ./.git

RUN pip install --no-cache-dir .
COPY --from=build-frontend /app/dist/ ./frontend/dist/

# Expose the port the app runs in
WORKDIR /app
ENV HOME=/home
ENV PATH=$HOME/.local/bin:$PATH
ENV MODEL_ENTRYPOINT=/model
# Expose the port the app runs on
EXPOSE 8000

COPY ./templates /views

ENV HOME=/home
# install system pkgs {{{
RUN apt-get update && \
apt-get install --yes --no-install-recommends \
curl \
git \
git-lfs \
gir1.2-pango-1.0 \
graphviz \
libcairo2-dev \
libgirepository1.0-dev \
npm && \
apt-get autoremove --yes && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# }}}

COPY entrypoint.sh /entrypoint.sh
# copy files {{{
COPY capella_model_explorer capella_model_explorer
COPY static static
COPY templates templates
COPY pyproject.toml ./
COPY .git .git
COPY package*.json ./
# copy entrypoint.sh to root:
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENV MODEL_ENTRYPOINT=/model
RUN chmod -R 777 ./frontend/dist/
# }}}

# Run script to get software version
ENV MODE=production
COPY frontend/fetch-version.py ./frontend/
RUN python frontend/fetch-version.py && \
python -c "from capellambse_context_diagrams import install_elk; install_elk()"
# misc setup {{{
RUN git config --global --add safe.directory /model && \
git config --global --add safe.directory /model/.git && \
chmod -R 777 /app && \
chmod -R 777 /home
# }}}

# Run as non-root user per default
RUN git config --global --add safe.directory /model && \
git config --global --add safe.directory /model/.git && \
chmod -R 777 /home
USER 1000

# install uv {{{
RUN curl -Lo /tmp/install.sh https://astral.sh/uv/install.sh && \
chmod +x /tmp/install.sh && \
UV_NO_MODIFY_PATH=1 sh /tmp/install.sh && \
rm /tmp/install.sh
# }}}

# install app incl. its cli and install elk.js {{{
RUN uv venv && \
# install app
uv pip install --no-cache-dir . && \
# Install elk.js automatically into a persistent local cache directory
# in order to prepare the elk.js execution environment ahead of time.
uv run python3 -c "from capellambse_context_diagrams import install_elk; install_elk()"
# }}}

# install Nodep kgs and build the CSS {{{
RUN npm clean-install && uv run python3 -m capella_model_explorer build css
# }}}

# clean up as root {{{
USER root
RUN ln -s /home/.local/bin/uv /usr/local/bin && \
apt-get purge --remove --yes curl npm && \
apt-get autoremove --yes && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* \
rm -rf node_modules
# }}}

# Back to non-root user
USER 1000

ENTRYPOINT ["/entrypoint.sh"]
Loading

0 comments on commit 2173540

Please sign in to comment.