Skip to content

Commit

Permalink
something i guess
Browse files Browse the repository at this point in the history
  • Loading branch information
malmz committed Nov 16, 2024
1 parent 28e9f60 commit 36d394b
Show file tree
Hide file tree
Showing 18 changed files with 297 additions and 131 deletions.
85 changes: 44 additions & 41 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,49 @@ name: Docker

on:
push:
tags: ["v*.*.*"]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
tags: ['v*.*.*']

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log into registry ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-and-push-image:
uses: dtekcth/workflows/.github/workflows/docker-publish.yml@v1.0.0
#env:
# REGISTRY: ghcr.io
# IMAGE_NAME: ${{ github.repository }}
#
#jobs:
# build:
# runs-on: ubuntu-latest
# permissions:
# contents: read
# packages: write
#
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4
#
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
#
# - name: Log into registry ${{ env.REGISTRY }}
# uses: docker/login-action@v3
# with:
# registry: ${{ env.REGISTRY }}
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
#
# - name: Extract Docker metadata
# id: meta
# uses: docker/metadata-action@v5
# with:
# images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
#
# - name: Build and push Docker image
# id: build-and-push
# uses: docker/build-push-action@v5
# with:
# context: .
# push: true
# tags: ${{ steps.meta.outputs.tags }}
# labels: ${{ steps.meta.outputs.labels }}
# cache-from: type=gha
# cache-to: type=gha,mode=max
5 changes: 4 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"recommendations": [
"mikestead.dotenv",
"bradlc.vscode-tailwindcss",
"biomejs.biome"
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker"
]
}
20 changes: 5 additions & 15 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
{
"files.associations": {
"*.css": "tailwindcss"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.preferTypeOnlyAutoImports": true,
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
}
"files.associations": {
"*.css": "tailwindcss"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.preferTypeOnlyAutoImports": true,
}
2 changes: 1 addition & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 24.6 95% 53.1%;
--radius: 0rem;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
Expand Down
13 changes: 12 additions & 1 deletion app/lib/.server/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { and, asc, eq, isNull } from 'drizzle-orm';
import { db } from './db';
import { type CreateAlbum, album, image } from './schema';
import { type CreateAlbum, album, image, tag } from './schema';
import { deleteAlbumFiles, deleteImageFiles } from './storage/image';

export async function createAlbum(data: CreateAlbum) {
Expand Down Expand Up @@ -50,3 +50,14 @@ export async function deleteImage(id: number) {
const [data] = await db.delete(image).where(eq(image.id, id)).returning();
deleteImageFiles(data);
}

export async function addTag(
image_id: number,
text: string,
created_by: string,
) {
db.insert(tag)
.values({ image_id, text, created_by })
.onConflictDoNothing()
.returning();
}
14 changes: 13 additions & 1 deletion app/lib/.server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { KeyCloak, type OAuth2Tokens, decodeIdToken } from 'arctic';
import { parseJWT } from 'oslo/jwt';
import type { ServerContext } from 'remix-create-express-app/context';
import { getUser } from './middleware/auth';
import type { UserClaims } from './types';

const realmURL = process.env.KEYCLOAK_ENDPOINT!;
const clientId = process.env.KEYCLOAK_CLIENTID!;
Expand All @@ -24,12 +25,23 @@ export function extractUserFromToken(tokens: OAuth2Tokens) {
(accessData.payload as Record<string, any>).resource_access?.[clientId]
.roles ?? [];

const claims = decodeIdToken(tokens.idToken()) as UserClaims;

let refreshTokenExpiresIn: number | undefined = undefined;
if (
'refresh_expires_in' in tokens.data &&
typeof tokens.data.refresh_expires_in === 'number'
) {
refreshTokenExpiresIn = tokens.data.refresh_expires_in;
}

return {
claims: decodeIdToken(tokens.idToken()) as Record<string, string>,
claims,
roles,
accessToken: tokens.accessToken(),
accessTokenExpiresAt: tokens.accessTokenExpiresAt(),
refreshToken: tokens.refreshToken(),
refreshTokenExpiresIn,
};
}

Expand Down
14 changes: 2 additions & 12 deletions app/lib/.server/middleware/session.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import type { SessionStorage, Session, AppLoadContext } from '@remix-run/node';
import {
createContext,
contextGet,
type ServerContext,
} from 'remix-create-express-app/context';
import type { MiddlewareFunctionArgs } from 'remix-create-express-app/middleware';
import type { UserState } from './types';

export type SessionMiddlewareArgs = {
isCookieSessionStorage: boolean;
};
import type { SessionState } from '../types';

// create SessionContext for use with context.get and .set
export const SessionContext =
createContext<
Session<{
user: UserState;
state: string;
codeVerifier: string;
returnTo: string;
}>
Session<SessionState>
>();

export function getSession(context: ServerContext) {
Expand Down
8 changes: 0 additions & 8 deletions app/lib/.server/middleware/types.ts

This file was deleted.

6 changes: 6 additions & 0 deletions app/lib/.server/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ export const imageRelation = relations(image, ({ one, many }) => ({
tags: many(tag),
}));

export const imageToTags = pgTable('image_to_tags', {
image_id: integer()
.notNull()
.references(() => image.id),
});

export const tag = pgTable('tag', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
text: text().notNull(),
Expand Down
22 changes: 22 additions & 0 deletions app/lib/.server/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export type UserClaims = {
sub: string;
name: string;
email: string;
} & Record<string, any>;

export interface UserState {
claims: UserClaims;
roles: string[];
accessToken: string;
accessTokenExpiresAt: Date;
refreshToken?: string;
refreshTokenExpiresAt?: Date;
}

export interface SessionState {
user: UserState;
state: string;
codeVerifier: string;
returnTo: string;
}

2 changes: 2 additions & 0 deletions app/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,5 @@ export function useIsSubmitting({
navigation.formMethod === formMethod
);
}

export const maxFileSize = 30_000_000;
2 changes: 1 addition & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function Providers({ children }: { children: React.ReactNode }) {

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang='en' suppressHydrationWarning>
<html lang='en' suppressHydrationWarning className='scroll-smooth'>
<head>
<meta charSet='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
Expand Down
34 changes: 27 additions & 7 deletions app/routes/_main.admin.$id._index/upload-button.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { useFetcher } from '@remix-run/react';
import { Loader2 } from 'lucide-react';
import { useEffect, useId, useRef } from 'react';
import { CircleX, Loader2 } from 'lucide-react';
import { useCallback, useEffect, useId, useRef, useState } from 'react';
import { toast } from 'sonner';
import type { ButtonProps } from '~/components/ui/button';
import { Button } from '~/components/ui/button';
import { cn, maxFileSize } from '~/lib/utils';
import type { action } from '../api.upload';

interface Props extends ButtonProps {
albumId: number;
}
export function UploadButton({ children, albumId, ...props }: Props) {
export function UploadButton({
children,
albumId,
className,
...props
}: Props) {
const id = useId();
const formRef = useRef<HTMLFormElement>(null);
const fetcher = useFetcher<typeof action>();
const [large, setLarge] = useState(false);

useEffect(() => {
if (fetcher.data?.success) {
Expand All @@ -28,18 +35,31 @@ export function UploadButton({ children, albumId, ...props }: Props) {
method='post'
encType='multipart/form-data'
>
<Button asChild {...props}>
<Button
asChild
className={cn(large ? 'text-red-500' : '', className)}
{...props}
>
<label htmlFor={id}>
{fetcher.state !== 'idle' && (
{fetcher.state !== 'idle' ? (
<Loader2 className='mr-2 h-4 w-4 animate-spin' />
)}
{children}
) : large ? (
<CircleX className='mr-2 h-4 w-4' />
) : null}
{large ? 'Bilden är för stor' : children}
</label>
</Button>
<input
onChange={(event) => {
const files = event.target.files;
if (!files) return;
for (const file of files) {
if (file.size > maxFileSize) {
setLarge(true);
return;
}
}
setLarge(false);
fetcher.submit(event.currentTarget.form);
}}
id={id}
Expand Down
22 changes: 21 additions & 1 deletion app/routes/_main.admin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { MetaFunction } from '@remix-run/node';
import { isRouteErrorResponse, Outlet, useRouteError } from '@remix-run/react';
import { Outlet, isRouteErrorResponse, useRouteError } from '@remix-run/react';
import { CameraOff } from 'lucide-react';
import { useEffect } from 'react';
import {
type CrumbHandle,
DynamicBreadcrum,
Expand All @@ -25,6 +27,9 @@ export default function Layout() {

export function ErrorBoundary() {
const error = useRouteError();
useEffect(() => {
console.error(error);
}, [error]);

if (isRouteErrorResponse(error)) {
return (
Expand All @@ -36,4 +41,19 @@ export function ErrorBoundary() {
</div>
);
}
if (error instanceof Error) {
return (
<div className='grid place-content-center grow'>
<h2 className='font-bold text-2xl'>Oof! Nån gick snätt!</h2>
<p className='text-lg'>{error.message}</p>
</div>
);
}

return (
<div className='grid place-content-center grow'>
<CameraOff className='h-24 w-24' />
<h2 className='font-bold text-2xl'>Oof! Nån gick snätt!</h2>
</div>
);
}
Loading

0 comments on commit 36d394b

Please sign in to comment.