Skip to content
Draft
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
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
**/.env*
**/*.js
!**/jest.config.js
**/*.d.ts
**/*.dbml
**/node_modules
fly.toml
Expand Down
29 changes: 29 additions & 0 deletions apps/cli/src/compose/docker-compose-launchpad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
configs:
launchpad_proxy:
content: |
http:
routers:
launchpad:
rule: "Path(`/`) || PathPrefix(`/assets`)"
service: launchpad
services:
launchpad:
loadBalancer:
servers:
- url: "http://launchpad:80"

services:
launchpad:
image: cartesi/rollups-launchpad:devel
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:80/"]
start_period: 10s
start_interval: 200ms
interval: 10s
timeout: 1s
retries: 5

proxy:
configs:
- source: launchpad_proxy
target: /etc/traefik/conf.d/launchpad.yaml
9 changes: 9 additions & 0 deletions apps/cli/src/exec/rollups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ const availableServices: Service[] = [
waitTitle: `${chalk.cyan("explorer")} service starting...`,
errorTitle: `${chalk.red("explorer")} service failed`,
},
{
name: "launchpad",
file: "docker-compose-launchpad.yaml",
healthySemaphore: "launchpad",
healthyTitle: (port) =>
`${chalk.cyan("launchpad")} service ready at ${chalk.cyan(`${host}:${port}/`)}`,
waitTitle: `${chalk.cyan("launchpad")} service starting...`,
errorTitle: `${chalk.red("launchpad")} service failed`,
},
{
name: "graphql",
file: "docker-compose-graphql.yaml",
Expand Down
24 changes: 24 additions & 0 deletions apps/launchpad/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 1 addition & 0 deletions apps/launchpad/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps = true
50 changes: 50 additions & 0 deletions apps/launchpad/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Prune stage
FROM node:22.14.0-alpine AS pruner

WORKDIR /app

# Install pnpm and turbo
RUN corepack enable && corepack prepare pnpm@latest --activate

# Copy files needed for pruning
COPY . .

# Prune the workspace for the launchpad app
RUN pnpm dlx turbo prune @cartesi/launchpad --docker

# Build stage
FROM node:22.14.0-alpine AS builder

WORKDIR /app

# Install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate

# Copy the pruned workspace
COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml

# Install dependencies
RUN pnpm install --frozen-lockfile

# Copy source code from pruned workspace
COPY --from=pruner /app/out/full/ .

# Build the application
RUN pnpm build --filter=@cartesi/launchpad

# Runtime stage
FROM nginx:alpine

# Copy the built assets from build stage to nginx
COPY --from=builder /app/apps/launchpad/dist /usr/share/nginx/html

# Copy custom nginx config if needed
# COPY nginx.conf /etc/nginx/conf.d/default.conf

# Expose port 80
EXPOSE 80

# Start nginx
CMD ["nginx", "-g", "daemon off;"]
8 changes: 8 additions & 0 deletions apps/launchpad/docker-bake.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
target "docker-metadata-action" {}
target "docker-platforms" {}

target "default" {
inherits = ["docker-metadata-action", "docker-platforms"]
context = "../.."
dockerfile = "apps/launchpad/Dockerfile"
}
3 changes: 3 additions & 0 deletions apps/launchpad/docker-bake.override.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target "default" {
tags = ["cartesi/rollups-launchpad:devel"]
}
6 changes: 6 additions & 0 deletions apps/launchpad/docker-bake.platforms.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target "docker-platforms" {
platforms = [
"linux/amd64",
"linux/arm64"
]
}
12 changes: 12 additions & 0 deletions apps/launchpad/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>🚀 Cartesi Rollups Launchpad</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
37 changes: 37 additions & 0 deletions apps/launchpad/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@cartesi/launchpad",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build:docker": "docker buildx bake --load",
"preview": "vite preview"
},
"dependencies": {
"@apollo/client": "^3.13.5",
"@mantine/core": "^8.1.1",
"@mantine/hooks": "^8.1.1",
"@tabler/icons-react": "^3.31.0",
"@tanstack/react-query": "5.80.10",
"graphql": "^16.10.0",
"json-rpc-2.0": "^1.7.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"viem": "latest",
"wagmi": "latest"
},
"devDependencies": {
"@types/react": "^19.0.12",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.2.1",
"@wagmi/cli": "latest",
"buffer": "^6.0.3",
"postcss": "^8.5.3",
"postcss-preset-mantine": "^1.17.0",
"postcss-simple-vars": "^7.0.1",
"typescript": "^5.4.5",
"vite": "^6.2.3"
}
}
14 changes: 14 additions & 0 deletions apps/launchpad/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
plugins: {
"postcss-preset-mantine": {},
"postcss-simple-vars": {
variables: {
"mantine-breakpoint-xs": "36em",
"mantine-breakpoint-sm": "48em",
"mantine-breakpoint-md": "62em",
"mantine-breakpoint-lg": "75em",
"mantine-breakpoint-xl": "88em",
},
},
},
};
27 changes: 27 additions & 0 deletions apps/launchpad/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Center, Group, Image, Stack } from "@mantine/core";

import ServiceComponent from "./Service";
import logo from "./img/cartesi.svg";
import { services } from "./services";

function App() {
return (
<Stack p={60} gap={60}>
<Center>
<Image src={logo} alt="logo" w={100} />
</Center>
<Group justify="center">
<Stack gap={20}>
{services.map((service) => (
<ServiceComponent
key={service.name}
service={service}
/>
))}
</Stack>
</Group>
</Stack>
);
}

export default App;
70 changes: 70 additions & 0 deletions apps/launchpad/src/Service.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
ActionIcon,
Alert,
Anchor,
Badge,
Group,
Image,
Stack,
ThemeIcon,
Title,
} from "@mantine/core";
import { IconCheck, IconExternalLink, IconX } from "@tabler/icons-react";
import { FC, useEffect, useState } from "react";
import { Service } from "./services";

interface ServiceProps {
service: Service;
}

const ServiceComponent: FC<ServiceProps> = ({ service }) => {
const { logo, name, endpoint, error, actionComponent, href, isHealthy } =
service;
const [healthy, setHealthy] = useState(false);

useEffect(() => {
isHealthy().then(setHealthy);
}, [isHealthy]);

return (
<Stack>
<Group justify="space-between" gap={100}>
<Group>
<Image src={logo} alt={name} w={30} />
<Title order={4}>{name}</Title>
</Group>
<Group>
{actionComponent}
{href && (
<Anchor component="a" href={href} target="_blank">
<ActionIcon disabled={!healthy} variant="subtle">
<IconExternalLink />
</ActionIcon>
</Anchor>
)}
<Badge
variant="default"
size="lg"
style={{ textTransform: "none" }}
>
{endpoint}
</Badge>
{healthy ? (
<ThemeIcon color="green" radius="xl" size="sm">
<IconCheck
style={{ width: "70%", height: "70%" }}
/>
</ThemeIcon>
) : (
<ThemeIcon color="red" radius="xl" size="sm">
<IconX style={{ width: "70%", height: "70%" }} />
</ThemeIcon>
)}
</Group>
</Group>
{error && <Alert color="red">{error}</Alert>}
</Stack>
);
};

export default ServiceComponent;
4 changes: 4 additions & 0 deletions apps/launchpad/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const getEnvUrl = () =>
import.meta.env.MODE === "development"
? "http://127.0.0.1:6751/"
: `${window.location.href}`;
Binary file added apps/launchpad/src/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions apps/launchpad/src/img/cartesi.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading