student table optimization adn docker testing
This commit is contained in:
29
apps/admin/Dockerfile
Normal file
29
apps/admin/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM node:22-alpine AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
FROM base AS builder
|
||||
RUN apk update && apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
RUN pnpm add -g turbo@^2
|
||||
COPY . .
|
||||
RUN turbo prune admin --docker
|
||||
|
||||
FROM base AS installer
|
||||
RUN apk update && apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/out/json/ .
|
||||
RUN pnpm fetch --frozen-lockfile
|
||||
RUN pnpm install --offline --frozen-lockfile --prod=false
|
||||
COPY --from=builder /app/out/full/ .
|
||||
RUN pnpm turbo run build
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
|
||||
USER nextjs
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
CMD node apps/web/server.js
|
||||
@@ -1,19 +1,13 @@
|
||||
import Login from '@/components/login';
|
||||
import Studs from '@/components/studs';
|
||||
import { db, admins } from '@workspace/db';
|
||||
import { auth, signIn, signOut } from '@/auth';
|
||||
import { db, students } from '@workspace/db';
|
||||
import { auth, signOut } from '@/auth';
|
||||
|
||||
async function getStudents() {
|
||||
'use server';
|
||||
const s = await db.select().from(admins);
|
||||
const s = await db.select().from(students);
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
async function logIn() {
|
||||
'use server';
|
||||
await signIn('google');
|
||||
}
|
||||
|
||||
async function logOut() {
|
||||
'use server';
|
||||
await signOut();
|
||||
@@ -25,7 +19,6 @@ export default async function Page() {
|
||||
<div className="flex items-center justify-center min-h-svh">
|
||||
<div className="flex flex-col items-center justify-center gap-4">
|
||||
<h1 className="text-2xl font-bold">Hello admin {session?.user?.name}</h1>
|
||||
{!session?.user && <Login action={logIn} />}
|
||||
<Studs action={getStudents} logOut={logOut} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,20 +6,39 @@ const studentSelectSchema = createSelectSchema(students);
|
||||
export type Student = z.infer<typeof studentSelectSchema>;
|
||||
|
||||
export const columns: ColumnDef<Student>[] = [
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: 'ID',
|
||||
},
|
||||
{
|
||||
accessorKey: 'firstName',
|
||||
header: 'First Name',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'lastName',
|
||||
header: 'Last Name',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'rollNumber',
|
||||
header: 'Roll Number',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'email',
|
||||
header: 'Email',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'yearOfGraduation',
|
||||
header: 'Year of Graduation',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'degree',
|
||||
header: 'Degree',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
{
|
||||
accessorKey: 'branch',
|
||||
header: 'Branch',
|
||||
filterFn: 'includesString',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
|
||||
import {
|
||||
Table,
|
||||
@@ -21,6 +27,7 @@ export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
30
apps/admin/app/(main)/students/error.tsx
Normal file
30
apps/admin/app/(main)/students/error.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
|
||||
export default function Error({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
console.error('Students page error:', error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-10">
|
||||
<div className="flex flex-col items-center justify-center space-y-4 p-8">
|
||||
<h2 className="text-2xl font-semibold">Something went wrong!</h2>
|
||||
<p className="text-muted-foreground text-center">
|
||||
Failed to load students data. Please try again.
|
||||
</p>
|
||||
<Button onClick={reset} variant="outline">
|
||||
Try again
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
63
apps/admin/app/(main)/students/loading.tsx
Normal file
63
apps/admin/app/(main)/students/loading.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Skeleton } from '@workspace/ui/components/skeleton';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@workspace/ui/components/table';
|
||||
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div className="container mx-auto py-10">
|
||||
<div className="space-y-4">
|
||||
{/* Header skeleton */}
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Students</h1>
|
||||
<Skeleton className="h-4 w-24" />
|
||||
</div>
|
||||
|
||||
{/* Table skeleton */}
|
||||
<div className="rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
<Skeleton className="h-4 w-8" />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Skeleton className="h-4 w-32" />
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{Array.from({ length: 8 }).map((_, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4 w-8" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4 w-24" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4 w-24" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4 w-40" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,16 +3,32 @@ import { DataTable } from './data-table';
|
||||
import { db, students } from '@workspace/db';
|
||||
|
||||
async function getData(): Promise<Student[]> {
|
||||
const data = db.select().from(students);
|
||||
const data = await db.select().from(students);
|
||||
return data;
|
||||
}
|
||||
|
||||
export default async function DemoPage() {
|
||||
async function StudentsTable() {
|
||||
const data = await getData();
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-10">
|
||||
<DataTable columns={columns} data={data} />
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Students</h1>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{data.length} {data.length === 1 ? 'student' : 'students'} total
|
||||
</div>
|
||||
</div>
|
||||
<DataTable columns={columns} data={data} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function StudentsPage() {
|
||||
return (
|
||||
<StudentsTable />
|
||||
);
|
||||
}
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
@@ -1,6 +1,12 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
import path from 'path';
|
||||
|
||||
const __dirname = path.resolve();
|
||||
|
||||
const nextConfig = {
|
||||
transpilePackages: ['@workspace/ui', '@workspace/db'],
|
||||
output: 'standalone',
|
||||
outputFileTracingRoot: path.join(__dirname, '../../'),
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/postcss": "^4.0.8",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@workspace/db": "workspace:*",
|
||||
"@workspace/ui": "workspace:*",
|
||||
@@ -22,6 +23,7 @@
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"tailwindcss": "^4.0.8",
|
||||
"zod": "^3.25.67"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
38
apps/student/Dockerfile
Normal file
38
apps/student/Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
||||
FROM node:22-alpine AS base
|
||||
|
||||
FROM base AS builder
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
RUN corepack enable pnpm && pnpm add -g turbo@^2
|
||||
COPY . .
|
||||
|
||||
RUN turbo prune student --docker
|
||||
|
||||
FROM base AS installer
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/out/json/ .
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY --from=builder /app/out/full/ .
|
||||
RUN pnpm turbo run build
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
USER nextjs
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
|
||||
CMD node apps/web/server.js
|
||||
@@ -1,6 +1,12 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
import path from 'path';
|
||||
|
||||
const __dirname = path.resolve();
|
||||
|
||||
const nextConfig = {
|
||||
transpilePackages: ['@workspace/ui', '@workspace/db'],
|
||||
output: 'standalone',
|
||||
outputFileTracingRoot: path.join(__dirname, '../../'),
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
Reference in New Issue
Block a user