Compare commits
6 Commits
80d77a53e9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
643d504c7a | ||
|
|
c9f5f6d665 | ||
|
|
3f3d5e530c | ||
|
|
5dac1d993c | ||
|
|
264d60c855 | ||
|
|
e6a0c2f6d6 |
@@ -201,7 +201,7 @@ services:
|
||||
networks:
|
||||
- archiv-net
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health | grep -q UP || exit 1"]
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:8081/actuator/health | grep -q UP || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Used by docker-compose.yml (target: development). Source is bind-mounted in
|
||||
# dev so the COPY . below is effectively replaced at runtime; the layer still
|
||||
# exists so the image is self-contained for cold starts (e.g. devcontainer).
|
||||
FROM node:20.19.0-alpine3.21 AS development
|
||||
FROM node:22-alpine3.21 AS development
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
@@ -14,7 +14,7 @@ CMD ["npm", "run", "dev"]
|
||||
|
||||
# ── Build ────────────────────────────────────────────────────────────────────
|
||||
# Compiles the SvelteKit Node-adapter output to /app/build.
|
||||
FROM node:20.19.0-alpine3.21 AS build
|
||||
FROM node:22-alpine3.21 AS build
|
||||
WORKDIR /app
|
||||
# VITE_SENTRY_DSN is a build-time variable — Vite bakes it into the bundle.
|
||||
# Passed via docker-compose build.args; empty string disables the SDK.
|
||||
@@ -27,7 +27,7 @@ RUN npm run build
|
||||
|
||||
# ── Production ───────────────────────────────────────────────────────────────
|
||||
# Self-contained Node server. `node build` is the adapter-node entrypoint.
|
||||
FROM node:20.19.0-alpine3.21 AS production
|
||||
FROM node:22-alpine3.21 AS production
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build /app/build ./build
|
||||
|
||||
@@ -10,9 +10,12 @@ interface Props {
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
const MAX_VISIBLE_TAGS = 6;
|
||||
|
||||
const { tags, compact = false }: Props = $props();
|
||||
|
||||
const visibleTags = $derived.by(() => tags.filter(hasAnyDocuments));
|
||||
const shownTags = $derived(visibleTags.slice(0, MAX_VISIBLE_TAGS));
|
||||
</script>
|
||||
|
||||
<section class="rounded-sm border border-line bg-surface p-5 shadow-sm">
|
||||
@@ -22,7 +25,7 @@ const visibleTags = $derived.by(() => tags.filter(hasAnyDocuments));
|
||||
</h2>
|
||||
<a
|
||||
href="/themen"
|
||||
class="font-sans text-xs text-brand-mint underline-offset-2 hover:underline focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
|
||||
class="flex min-h-[44px] items-center text-[11px] font-semibold text-ink-2 no-underline focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none"
|
||||
>
|
||||
{m.themen_alle()} →
|
||||
</a>
|
||||
@@ -35,9 +38,9 @@ const visibleTags = $derived.by(() => tags.filter(hasAnyDocuments));
|
||||
class="grid gap-2 {compact ? 'grid-cols-1' : 'grid-cols-1 sm:grid-cols-2'}"
|
||||
data-compact={compact}
|
||||
>
|
||||
{#each visibleTags as tag (tag.id)}
|
||||
{#each shownTags as tag (tag.id)}
|
||||
<a
|
||||
href="/?tag={encodeURIComponent(tag.name)}"
|
||||
href="/documents?tag={encodeURIComponent(tag.name)}"
|
||||
aria-label="{tag.name}{tag.documentCount > 0
|
||||
? ', ' + m.themen_dokumente({ count: tag.documentCount })
|
||||
: ''}"
|
||||
|
||||
@@ -59,10 +59,13 @@ const greetingText = $derived.by(() => {
|
||||
<h1 class="font-serif text-[2rem] text-ink">{greetingText}</h1>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-1 gap-5 lg:grid-cols-[1fr_320px] lg:items-start">
|
||||
<div class="flex flex-col gap-5">
|
||||
<DashboardResumeStrip resumeDoc={data.resumeDoc ?? null} />
|
||||
|
||||
<ThemenWidget tags={data.tagTree ?? []} />
|
||||
|
||||
<div class="grid grid-cols-1 gap-5 lg:grid-cols-[1fr_320px] lg:items-start">
|
||||
<div class="flex flex-col gap-5">
|
||||
<EnrichmentBlock
|
||||
topDocs={data.incompleteDocs ?? []}
|
||||
totalCount={data.incompleteTotal ?? 0}
|
||||
@@ -85,12 +88,12 @@ const greetingText = $derived.by(() => {
|
||||
|
||||
<div class="flex flex-col gap-5 lg:sticky lg:top-[80px]">
|
||||
<DashboardFamilyPulse pulse={data.pulse ?? null} />
|
||||
<ThemenWidget tags={data.tagTree ?? []} compact={true} />
|
||||
<DashboardActivityFeed feed={data.activityFeed ?? []} />
|
||||
{#if data.canWrite}
|
||||
<DropZone onUploadComplete={(count) => (bannerCount = count)} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
@@ -421,7 +421,8 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
|
||||
response: { ok: true },
|
||||
data: { items: [searchItem], totalElements: 1, pageNumber: 0, pageSize: 5, totalPages: 1 }
|
||||
}) // search
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }); // stories
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }) // stories
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }); // tags/tree
|
||||
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
|
||||
typeof createApiClient
|
||||
>);
|
||||
|
||||
@@ -40,7 +40,7 @@ const visibleTree = $derived.by(() => data.tree.filter(hasAnyDocuments));
|
||||
></div>
|
||||
|
||||
<a
|
||||
href="/?tag={encodeURIComponent(tag.name)}"
|
||||
href="/documents?tag={encodeURIComponent(tag.name)}"
|
||||
aria-label="{tag.name}{tag.documentCount > 0
|
||||
? ', ' + m.themen_dokumente({ count: tag.documentCount })
|
||||
: ''}"
|
||||
@@ -58,7 +58,7 @@ const visibleTree = $derived.by(() => data.tree.filter(hasAnyDocuments));
|
||||
|
||||
{#each shownChildren as child (child.id)}
|
||||
<a
|
||||
href="/?tag={encodeURIComponent(child.name)}"
|
||||
href="/documents?tag={encodeURIComponent(child.name)}"
|
||||
class="flex min-h-[44px] items-center justify-between px-4 py-2.5 hover:bg-canvas focus-visible:bg-canvas focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none focus-visible:ring-inset"
|
||||
>
|
||||
<span class="font-sans text-sm text-ink">{child.name}</span>
|
||||
@@ -71,7 +71,7 @@ const visibleTree = $derived.by(() => data.tree.filter(hasAnyDocuments));
|
||||
|
||||
{#if hiddenCount > 0}
|
||||
<a
|
||||
href="/?tag={encodeURIComponent(tag.name)}"
|
||||
href="/documents?tag={encodeURIComponent(tag.name)}"
|
||||
class="block min-h-[44px] px-4 py-2.5 font-sans text-sm text-ink-3 hover:bg-canvas hover:text-ink focus-visible:ring-2 focus-visible:ring-brand-navy focus-visible:outline-none focus-visible:ring-inset"
|
||||
>
|
||||
{m.themen_weitere({ count: hiddenCount })} →
|
||||
|
||||
Reference in New Issue
Block a user