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
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ import { getFieldErrors, handleSubmit } from '@app-builder/utils/form';

### Form Components

| Component | Props | Purpose |
|-----------|-------|---------|
| `FormInput` | `type`, `name`, `defaultValue`, `onChange`, `onBlur`, `valid` | Text/number input with error border |
| `FormLabel` | `name`, `valid` | Label linked to input via `htmlFor` |
| `FormErrorOrDescription` | `errors?`, `description?` | Shows errors or help text |
| `FormTextArea` | Same as FormInput | Multi-line input |
| `FormError` | `field`, `asString?`, `translations?` | Translates Zod error codes to i18n |
| Component | Props | Purpose |
| ------------------------ | ------------------------------------------------------------- | ----------------------------------- |
| `FormInput` | `type`, `name`, `defaultValue`, `onChange`, `onBlur`, `valid` | Text/number input with error border |
| `FormLabel` | `name`, `valid` | Label linked to input via `htmlFor` |
| `FormErrorOrDescription` | `errors?`, `description?` | Shows errors or help text |
| `FormTextArea` | Same as FormInput | Multi-line input |
| `FormError` | `field`, `asString?`, `translations?` | Translates Zod error codes to i18n |

### Number Fields

Expand Down Expand Up @@ -161,14 +161,14 @@ export function DeleteConfirmModal({ onDelete }: { onDelete: () => void }) {

### Modal Components

| Component | Purpose |
|-----------|---------|
| `Modal.Root` | Root state manager. Props: `open`, `onOpenChange` |
| `Modal.Trigger` | Opens the modal. Use `asChild` to wrap custom trigger |
| `Modal.Content` | Dialog container. Props: `size` (`small`/`medium`/`large`/`xlarge`) |
| `Modal.Title` | Dialog title (required for accessibility) |
| `Modal.Close` | Closes on click. Use `asChild` to wrap custom button |
| `Modal.Footer` | Standard buttons in the footer, asClosed for the buttons that close the modal, with optional icon and isLoading state |
| Component | Purpose |
| --------------- | --------------------------------------------------------------------------------------------------------------------- |
| `Modal.Root` | Root state manager. Props: `open`, `onOpenChange` |
| `Modal.Trigger` | Opens the modal. Use `asChild` to wrap custom trigger |
| `Modal.Content` | Dialog container. Props: `size` (`small`/`medium`/`large`/`xlarge`) |
| `Modal.Title` | Dialog title (required for accessibility) |
| `Modal.Close` | Closes on click. Use `asChild` to wrap custom button |
| `Modal.Footer` | Standard buttons in the footer, asClosed for the buttons that close the modal, with optional icon and isLoading state |

### Modal with Form

Expand Down Expand Up @@ -196,7 +196,7 @@ Wrap `<form>` around `Modal.Title`, content, and `Modal.Footer`:
Right-side sliding panel for detail views. Import from app-builder components.

```typescript
import { Panel } from '@app-builder/components/Panel';
import { Panel } from 'ui-design-system';
import { useTranslation } from 'react-i18next';

export function DetailPanel({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) {
Expand Down Expand Up @@ -225,11 +225,10 @@ export function DetailPanel({ open, onOpenChange }: { open: boolean; onOpenChang

### Panel Sizes

| Size | Max Width |
|------|-----------|
| small | 'max-w-[calc(100vw_/_3)]' |
| medium | 'max-w-[50vw]' |
| large | 'max-w-[calc(100vw_*_(2_/_3))]' |

| Size | Max Width |
| ------ | ------------------------------- |
| small | 'max-w-[calc(100vw_/_3)]' |
| medium | 'max-w-[50vw]' |
| large | 'max-w-[calc(100vw_*_(2_/_3))]' |

Features: slide animation, focus trapping, Escape to close, portal rendering.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
node_modules

# Build outputs
packages/app-builder/build
**/.output
**/.nitro
**/build
Expand Down
13 changes: 9 additions & 4 deletions .github/workflows/build_and_deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ name: Reusable build and deploy job
on:
workflow_call:
inputs:
app:
type: string
description: "Application to build and deploy (app-builder or backoffice)"
required: true
default: "app-builder"
environment:
type: string
description: "Github environment to use"
Expand Down Expand Up @@ -33,7 +38,7 @@ jobs:
environment: ${{ inputs.environment }}
env:
VERSION: ${{ inputs.version }}
IMAGE: europe-west1-docker.pkg.dev/marble-infra/marble/marble-frontend:${{ inputs.version }}
IMAGE: europe-west1-docker.pkg.dev/marble-infra/marble/${{ inputs.app }}:${{ inputs.version }}
SERVICE_ACCOUNT: marble-frontend-cloud-run@${{ vars.GCP_PROJECT_ID }}.iam.gserviceaccount.com
steps:
- name: Checkout
Expand Down Expand Up @@ -71,9 +76,9 @@ jobs:
with:
context: .
push: true
target: app-builder
target: ${{ inputs.app }}
tags: ${{ env.IMAGE }}
file: ./Dockerfile
file: ${{ inputs.dockerfile }}
build-args: |
SENTRY_PROJECT=marble-frontend
SENTRY_RELEASE=${{ inputs.SENTRY_RELEASE }}
Expand All @@ -89,7 +94,7 @@ jobs:

- name: Deploy server
run: |
gcloud run deploy marble-frontend \
gcloud run deploy ${{ inputs.app }} \
--quiet \
--region="europe-west1" \
--image="$IMAGE"
3 changes: 3 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ jobs:

- name: Build app-builder
run: bun run -F app-builder build

- name: Build backoffice
run: bun run -F backoffice build
25 changes: 22 additions & 3 deletions .github/workflows/main_push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,34 @@ jobs:
actions: read
uses: ./.github/workflows/check.yaml

build_and_deploy:
build_and_deploy_app_builder:
needs: check
permissions:
contents: read
actions: read
id-token: 'write' # needed for using open id token to authenticate with GCP
id-token: "write" # needed for using open id token to authenticate with GCP
uses: ./.github/workflows/build_and_deploy.yaml
with:
environment: 'staging'
app: "app-builder"
dockerfile: ./Dockerfile
environment: "staging"
version: latest
SENTRY_RELEASE: ${{ github.sha }}
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SEGMENT_WRITE_KEY_OPENSOURCE: ${{ secrets.SEGMENT_WRITE_KEY_OPENSOURCE }}

build_and_deploy_backoffice:
needs: check
permissions:
contents: read
actions: read
id-token: "write" # needed for using open id token to authenticate with GCP
uses: ./.github/workflows/build_and_deploy.yaml
with:
app: "backoffice"
dockerfile: ./Dockerfile.backoffice
environment: "staging"
version: latest
SENTRY_RELEASE: ${{ github.sha }}
secrets:
Expand Down
21 changes: 20 additions & 1 deletion .github/workflows/tags_push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,33 @@ jobs:
actions: read
uses: ./.github/workflows/check.yaml

build_and_deploy:
build_and_deploy_app_builder:
needs: check
permissions:
contents: read
actions: read
id-token: "write" # needed for using open id token to authenticate with GCP
uses: ./.github/workflows/build_and_deploy.yaml
with:
app: "app-builder"
dockerfile: ./Dockerfile
environment: "production"
version: ${{ github.ref_name }}
SENTRY_RELEASE: ${{ github.ref_name }}
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SEGMENT_WRITE_KEY_OPENSOURCE: ${{ secrets.SEGMENT_WRITE_KEY_OPENSOURCE }}

build_and_deploy_backoffice:
needs: check
permissions:
contents: read
actions: read
id-token: "write" # needed for using open id token to authenticate with GCP
uses: ./.github/workflows/build_and_deploy.yaml
with:
app: "backoffice"
dockerfile: ./Dockerfile.backoffice
environment: "production"
version: ${{ github.ref_name }}
SENTRY_RELEASE: ${{ github.ref_name }}
Expand Down
28 changes: 27 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ WORKDIR /usr/src/app
# Copy only workspace manifests to maximize install cache hits
COPY package.json bun.lock ./
COPY packages/app-builder/package.json ./packages/app-builder/
COPY packages/backoffice/package.json ./packages/backoffice/
COPY packages/shared/package.json ./packages/shared/
COPY packages/marble-api/package.json ./packages/marble-api/
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
Expand Down Expand Up @@ -68,9 +69,13 @@ RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN \
if [ -f /run/secrets/SENTRY_AUTH_TOKEN ]; then export SENTRY_AUTH_TOKEN=$(cat /run/secrets/SENTRY_AUTH_TOKEN); fi; \
bun run -F app-builder build

RUN bun run -F backoffice build

# Collect build artifacts and dependencies for runtime
RUN mkdir -p /prod/app-builder && \
cp -R packages/app-builder/.output /prod/app-builder/.output
cp -R packages/app-builder/.output /prod/app-builder/.output && \
mkdir -p /prod/backoffice && \
cp -R packages/backoffice/.output /prod/backoffice/.output

# ---- Production Dependencies stage ----
FROM ${BUN_IMAGE} AS deps-prod
Expand All @@ -79,6 +84,7 @@ WORKDIR /usr/src/app
# Copy only workspace manifests to maximize install cache hits
COPY package.json bun.lock ./
COPY packages/app-builder/package.json ./packages/app-builder/
COPY packages/backoffice/package.json ./packages/backoffice/
COPY packages/shared/package.json ./packages/shared/
COPY packages/marble-api/package.json ./packages/marble-api/
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
Expand Down Expand Up @@ -119,3 +125,23 @@ COPY --from=deps-prod /usr/src/app/node_modules ./node_modules

EXPOSE $PORT
CMD [".output/server/index.mjs"]

# ---- Runtime stage (backoffice) ----
FROM ${BUN_IMAGE} AS backoffice
WORKDIR /prod/backoffice

ENV NODE_ENV=production
ARG PORT=8080
ENV PORT=${PORT:-8080}

ARG APP_VERSION
ENV APP_VERSION=$APP_VERSION

# Copy build output
COPY --from=build /prod/backoffice/.output ./.output

# Copy ONLY production dependencies
COPY --from=deps-prod /usr/src/app/node_modules ./node_modules

EXPOSE $PORT
CMD ["bun", ".output/server/index.mjs"]
85 changes: 85 additions & 0 deletions Dockerfile.backoffice
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
ARG BUN_IMAGE=oven/bun:1.3
ARG RUNTIME_IMAGE=oven/bun:1.3-distroless
# ---- Dependencies stage ----
FROM ${BUN_IMAGE} AS deps-dev
WORKDIR /usr/src/app

# Copy only workspace manifests to maximize install cache hits
COPY package.json bun.lock ./
COPY packages/app-builder/package.json ./packages/app-builder/
COPY packages/backoffice/package.json ./packages/backoffice/
COPY packages/shared/package.json ./packages/shared/
COPY packages/marble-api/package.json ./packages/marble-api/
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
COPY packages/ui-design-system/package.json ./packages/ui-design-system/
COPY packages/ui-icons/package.json ./packages/ui-icons/
COPY packages/tailwind-preset/package.json ./packages/tailwind-preset/
COPY packages/tests/package.json ./packages/tests/

# Install WITH dev dependencies (needed for build stage)
RUN --mount=type=cache,target=/root/.bun \
bun ci

# ---- Build stage ---- (uses dev deps from above)
FROM ${BUN_IMAGE} AS build
WORKDIR /usr/src/app

# Copy full source AFTER deps to leverage layer caching
COPY . .
# Reuse cached node_modules from deps stage (root + workspace-local)
COPY --from=deps-dev /usr/src/app/node_modules ./node_modules
COPY --from=deps-dev /usr/src/app/packages/backoffice/node_modules ./packages/backoffice/node_modules

# Build-time configuration
ARG SENTRY_ORG
ENV SENTRY_ORG=$SENTRY_ORG
ARG SENTRY_PROJECT
ENV SENTRY_PROJECT=$SENTRY_PROJECT
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE=$SENTRY_RELEASE

RUN bun run -F backoffice build

# Collect build artifacts and dependencies for runtime
RUN mkdir -p /prod/backoffice && \
cp -R packages/backoffice/.output /prod/backoffice/.output

# ---- Production Dependencies stage ----
FROM ${BUN_IMAGE} AS deps-prod
WORKDIR /usr/src/app

# Copy only workspace manifests to maximize install cache hits
COPY package.json bun.lock ./
COPY packages/app-builder/package.json ./packages/app-builder/
COPY packages/backoffice/package.json ./packages/backoffice/
COPY packages/shared/package.json ./packages/shared/
COPY packages/marble-api/package.json ./packages/marble-api/
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
COPY packages/ui-design-system/package.json ./packages/ui-design-system/
COPY packages/ui-icons/package.json ./packages/ui-icons/
COPY packages/tailwind-preset/package.json ./packages/tailwind-preset/
COPY packages/tests/package.json ./packages/tests/

# Install ONLY production dependencies
RUN --mount=type=cache,target=/root/.bun \
bun install --production --frozen-lockfile

# ---- Runtime stage (backoffice) ----
FROM ${RUNTIME_IMAGE} AS backoffice
WORKDIR /prod/backoffice

ENV NODE_ENV=production
ARG PORT=8080
ENV PORT=${PORT:-8080}

ARG APP_VERSION
ENV APP_VERSION=$APP_VERSION

# Copy build output
COPY --from=build /prod/backoffice/.output ./.output

# Copy ONLY production dependencies
COPY --from=deps-prod /usr/src/app/node_modules ./node_modules

EXPOSE $PORT
CMD [".output/server/index.mjs"]
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.5.2/schema.json",

Check notice on line 2 in biome.json

View workflow job for this annotation

GitHub Actions / check / main

deserialize

The configuration schema version does not match the CLI version 2.5.9
"vcs": {
"enabled": true,
"clientKind": "git",
Expand All @@ -21,7 +21,7 @@
"!**/coverage",
"!**/public",
"!packages/marble-api/src/generated",
"!packages/app-builder/src/routeTree.gen.ts",
"!packages/*/src/routeTree.gen.ts",
"!packages-licenses.json"
]
},
Expand Down
Loading