Skip to content

Commit

Permalink
Lilo (#434)
Browse files Browse the repository at this point in the history
* Initial lilo setup (WIP)

Prototype the lilo worker with a login flow

* Implement logout and start implementing jwts

* Working external api sort of

* Add user api key to scalar reference

* Update schema and add all migrations

* Format

* Start implementing full stackiness

* Revert "Start implementing full stackiness"

This reverts commit 0c53b37.

* Add a spa dashboard because reasons

* Start integrating hono client in the spa dashboard because reasons

* Add hooks for fetching api keys and add support for github avatar

* Refactor lilo worker file structure

* Use common utilities between external and internal projects api

* Add projects to frontend

* Factor out api reference

* Start ripping out cors stuff

* Truncate migrations and update drizzle-kit in other services repos

* Move session secret requirement to the internal api setup

* Remove cors funkiness

* Prepare lilo for deployment

* Bind static assets

* Add allow list

* Smoothe out some styles and add api reference in nav

* Add loading states

* Add first steps for doing AI

* Format

* Add a readme to the lilo dir

* Remove the title and favicon from vite

* Add lilo deploy script

* Add script for enabling new users

* Add fiberplane/embedded to lilo
  • Loading branch information
brettimus authored Jan 16, 2025
1 parent 9a92bf5 commit 7aaa7cd
Show file tree
Hide file tree
Showing 92 changed files with 5,975 additions and 77 deletions.
9 changes: 6 additions & 3 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}
},
{
"include": ["studio"],
"include": ["studio", "lilo/lilo-frontend"],
"linter": {
"enabled": true,
"rules": {
Expand Down Expand Up @@ -72,7 +72,8 @@
"packages/client-library-otel",
"api",
"honc-code-gen",
"fp-services"
"fp-services",
"lilo/lilo-worker"
],
"linter": {
"enabled": true,
Expand Down Expand Up @@ -102,10 +103,12 @@
"honc-code-gen/storage/**/*",
// Client library and website related
"dist",
"lilo/lilo-frontend/dist",
"lilo/lilo-worker/public",
"www/",
".astro",
// ignore all tsconfig.json files
"tsconfig.json",
"tsconfig*.json",
// ignore any test data files
"test-data/*.js",
// fpx-workers build files
Expand Down
2 changes: 1 addition & 1 deletion fp-services/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@cloudflare/workers-types": "^4.20241112.0",
"drizzle-kit": "^0.24.2",
"drizzle-kit": "^0.30.0",
"wrangler": "^3.91.0"
}
}
2 changes: 1 addition & 1 deletion honc-code-gen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"@langchain/langgraph": "^0.2.28",
"ai": "^3.4.33",
"dotenv": "^16.4.7",
"drizzle-kit": "^0.24.2",
"drizzle-kit": "^0.30.0",
"drizzle-orm": "^0.33.0",
"drizzle-zod": "^0.5.1",
"hono": "^4.6.13",
Expand Down
27 changes: 27 additions & 0 deletions lilo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Lilo

This is a dashboard + external API for "Lilo" - a tool for generating API testing workflows from user stories.

There's more info in each of the `README.md` files in the `lilo-worker` and `lilo-frontend` directories.

For the record:

- `lilo-worker` is the backend, and it has both an internal API and an external API
- `lilo-frontend` is the dashboard that talks to the internal API, and links to the external API reference (powered by Scalar)

The frontend also imports `hono/client` to talk to the internal API. It also needs to import some types from `lilo-worker`, but it does so in kind of a janky way because I'm not great at configuring separate typescript projects to talk to each other.

## Setup

Run the backend:
```bash
cd lilo-worker
# follow setup instructions
pnpm dev
```

Run the frontend:
```bash
cd lilo-frontend
pnpm dev
```
24 changes: 24 additions & 0 deletions lilo/lilo-frontend/.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?
9 changes: 9 additions & 0 deletions lilo/lilo-frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Lilo Frontend

This is the frontend for Lilo. It's built with Vite and React.

## HACKS

We need to include `@types/node` and `@cloudflare/workers-types` in the types array in `tsconfig.app.json` because Hono RPC client imports types from it.

I think this means the frontend build will not throw typescript errors when you import node builtins or Cloudflare Workers types. Beware.
27 changes: 27 additions & 0 deletions lilo/lilo-frontend/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "../../node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["../../biome.jsonc"],
"files": {
"ignore": [
"dist",
"node_modules",
"tsconfig.node.json",
"tsconfig.app.json"
]
},
"overrides": [
{
"include": ["src"],
"linter": {
"enabled": true,
"rules": {
"suspicious": {
"noArrayIndexKey": {
"level": "off"
}
}
}
}
}
]
}
21 changes: 21 additions & 0 deletions lilo/lilo-frontend/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "stone",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
13 changes: 13 additions & 0 deletions lilo/lilo-frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/lilo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lilo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
43 changes: 43 additions & 0 deletions lilo/lilo-frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "lilo-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"format": "biome check . --write",
"lint": "biome lint . && pnpm run typecheck",
"preview": "vite preview"
},
"dependencies": {
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.2",
"@tanstack/react-query": "^5.61.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"hono": "^4.6.13",
"lucide-react": "^0.468.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20241205.0",
"@types/node": "^22.10.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"globals": "^15.12.0",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.1"
}
}
6 changes: 6 additions & 0 deletions lilo/lilo-frontend/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
20 changes: 20 additions & 0 deletions lilo/lilo-frontend/public/lilo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions lilo/lilo-frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Button } from "./components/ui/button";
import { Toaster } from "./components/ui/toaster";
import { LOGOUT_PATH } from "./constants";
import { useSession } from "./hooks/use-session";
import { Layout } from "./layout";
import { DashboardPage } from "./pages/DashboardPage";

const queryClient = new QueryClient();

function AuthContent() {
const { data: session, isLoading } = useSession();

if (isLoading) {
return (
<div className="flex h-screen w-screen items-center justify-center bg-gray-100">
<div className="flex items-center space-x-2">
<div className="w-6 h-6 border-4 border-t-transparent border-blue-500 rounded-full animate-spin" />
<div className="text-lg text-gray-700">
Loading Lilo&mdash;Look at Lilo Load!
</div>
</div>
</div>
);
}

if (!session) {
return (
<div className="flex h-screen w-screen flex-col items-center justify-center gap-4">
<h1 className="text-4xl font-bold">Welcome to Lilo</h1>
<Button asChild>
<a
className="mb-12 text-primary-foreground hover:text-primary-foreground/90"
href="/auth/github"
>
Login with GitHub
</a>
</Button>
</div>
);
}

if (!session.user.allowed) {
return (
<div className="flex h-screen w-screen flex-col items-center justify-center gap-4">
<h1 className="text-4xl font-bold">You are not on the list!</h1>
<p className="text-lg">Ask Brett to add you to the list</p>
<a href={LOGOUT_PATH} className="text-lg">
Log out
</a>
</div>
);
}

return (
<Layout>
<DashboardPage />
<Toaster />
</Layout>
);
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<AuthContent />
</QueryClientProvider>
);
}

export default App;
48 changes: 48 additions & 0 deletions lilo/lilo-frontend/src/components/ui/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import * as React from "react";

import { cn } from "@/lib/utils";

const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className,
)}
{...props}
/>
));
Avatar.displayName = AvatarPrimitive.Root.displayName;

const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;

const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className,
)}
{...props}
/>
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;

export { Avatar, AvatarImage, AvatarFallback };
Loading

0 comments on commit 7aaa7cd

Please sign in to comment.