Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Add Remix "Trellix" example app #5

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
node_modules
.DS_Store
1 change: 1 addition & 0 deletions seed/remix-trellix/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
12 changes: 12 additions & 0 deletions seed/remix-trellix/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
"overrides": [
{
"rules": {
"no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": "warn"
}
}
]
};
7 changes: 7 additions & 0 deletions seed/remix-trellix/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules

/.cache
/build
/public/build
.env
/prisma/dev.db
3 changes: 3 additions & 0 deletions seed/remix-trellix/.snaplet/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"targetDatabaseUrl": "postgresql://postgres@localhost:5432/trellix"
}
57 changes: 57 additions & 0 deletions seed/remix-trellix/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# base node image
FROM node:18-bullseye-slim as base

# Install openssl for Prisma
RUN apt-get update && apt-get install -y openssl

ENV NODE_ENV production

# Install all node_modules, including dev dependencies
FROM base as deps

RUN mkdir /app
WORKDIR /app

ADD package.json package-lock.json ./
RUN npm install --production=false

# Setup production node_modules
FROM base as production-deps

RUN mkdir /app
WORKDIR /app

COPY --from=deps /app/node_modules /app/node_modules
ADD package.json package-lock.json ./
RUN npm prune --production

# Build the app
FROM base as build

RUN mkdir /app
WORKDIR /app

COPY --from=deps /app/node_modules /app/node_modules

ADD prisma .
RUN npx prisma generate

ADD . .
RUN npm run build

# Finally, build the production image with minimal footprint
FROM base

ENV NODE_ENV production

RUN mkdir /app
WORKDIR /app

COPY --from=production-deps /app/node_modules /app/node_modules
COPY --from=build /app/node_modules/.prisma /app/node_modules/.prisma
COPY --from=build /app/build /app/build
COPY --from=build /app/public /app/public
ADD . .

# CMD ["npm", "run", "start"]
ENTRYPOINT [ "./start.sh" ]
5 changes: 5 additions & 0 deletions seed/remix-trellix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```sh
npm i
npx prisma migrate dev
npm run dev
```
66 changes: 66 additions & 0 deletions seed/remix-trellix/app/auth/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { type DataFunctionArgs, createCookie, redirect } from "@remix-run/node";

let secret = process.env.COOKIE_SECRET || "default";
if (secret === "default") {
console.warn(
"🚨 No COOKIE_SECRET environment variable set, using default. The app is insecure in production.",
);
secret = "default-secret";
}

let cookie = createCookie("auth", {
secrets: [secret],
// 30 days
maxAge: 30 * 24 * 60 * 60,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});

export async function getAuthFromRequest(
request: Request,
): Promise<string | null> {
let userId = await cookie.parse(request.headers.get("Cookie"));
return userId ?? null;
}

export async function setAuthOnResponse(
response: Response,
userId: string,
): Promise<Response> {
let header = await cookie.serialize(userId);
response.headers.append("Set-Cookie", header);
return response;
}

export async function requireAuthCookie(request: Request) {
let userId = await getAuthFromRequest(request);
if (!userId) {
throw redirect("/login", {
headers: {
"Set-Cookie": await cookie.serialize("", {
maxAge: 0,
}),
},
});
}
return userId;
}

export async function redirectIfLoggedInLoader({ request }: DataFunctionArgs) {
let userId = await getAuthFromRequest(request);
if (userId) {
throw redirect("/home");
}
return null;
}

export async function redirectWithClearedCookie(): Promise<Response> {
return redirect("/", {
headers: {
"Set-Cookie": await cookie.serialize(null, {
expires: new Date(0),
}),
},
});
}
14 changes: 14 additions & 0 deletions seed/remix-trellix/app/components/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { forwardRef } from "react";

export let Button = forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>((props, ref) => {
return (
<button
{...props}
ref={ref}
className="flex w-full justify-center rounded-md bg-brand-blue px-1 py-1 text-sm font-semibold leading-6 text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-blue"
/>
);
});
46 changes: 46 additions & 0 deletions seed/remix-trellix/app/components/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { forwardRef, useId } from "react";

export let Input = forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement>
>((props, ref) => {
return (
<input
{...props}
ref={ref}
className="form-input block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-brand-blue sm:text-sm sm:leading-6"
/>
);
});

export let Label = forwardRef<
HTMLLabelElement,
React.LabelHTMLAttributes<HTMLLabelElement>
>((props, ref) => {
return (
<label
{...props}
ref={ref}
className="block text-sm font-medium leading-6 text-gray-900"
/>
);
});

export let LabeledInput = forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement> & {
label: React.ReactNode;
id?: string;
}
>(({ id, label, ...props }, ref) => {
let uid = useId();
id = id ?? uid;
return (
<>
<Label htmlFor={id}>{label}</Label>
<div className="mt-2">
<Input {...props} ref={ref} id={id} />
</div>
</>
);
});
9 changes: 9 additions & 0 deletions seed/remix-trellix/app/db/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

process.on("beforeExit", () => {
prisma.$disconnect();
});

export { prisma };
10 changes: 10 additions & 0 deletions seed/remix-trellix/app/http/bad-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function notFound() {
return new Response("Not Found", { status: 404, statusText: "Not Found" });
}

export function badRequest(body: string) {
return new Response(body, {
status: 400,
statusText: "Bad Request",
});
}
135 changes: 135 additions & 0 deletions seed/remix-trellix/app/icons/icons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading