reduce image size of hub and disptach container
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
|
|
||||||
ARG NEXT_PUBLIC_DISPATCH_URL
|
ARG NEXT_PUBLIC_DISPATCH_URL="http://localhost:3001"
|
||||||
ARG NEXT_PUBLIC_DISPATCH_SERVER_URL
|
ARG NEXT_PUBLIC_DISPATCH_SERVER_URL="http://localhost:4001"
|
||||||
ARG NEXT_PUBLIC_HUB_URL
|
ARG NEXT_PUBLIC_HUB_URL="http://localhost:3002"
|
||||||
ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID
|
ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID="1"
|
||||||
ARG NEXT_PUBLIC_LIVEKIT_URL
|
ARG NEXT_PUBLIC_LIVEKIT_URL="http://localhost:7880"
|
||||||
ARG NEXT_PUBLIC_DISCORD_URL
|
ARG NEXT_PUBLIC_DISCORD_URL="https://discord.com"
|
||||||
ARG NEXT_PUBLIC_OPENAIP_ACCESS
|
ARG NEXT_PUBLIC_OPENAIP_ACCESS=""
|
||||||
|
|
||||||
ENV NEXT_PUBLIC_DISPATCH_SERVER_URL=$NEXT_PUBLIC_DISPATCH_SERVER_URL
|
ENV NEXT_PUBLIC_DISPATCH_SERVER_URL=$NEXT_PUBLIC_DISPATCH_SERVER_URL
|
||||||
ENV NEXT_PUBLIC_DISPATCH_URL=$NEXT_PUBLIC_DISPATCH_URL
|
ENV NEXT_PUBLIC_DISPATCH_URL=$NEXT_PUBLIC_DISPATCH_URL
|
||||||
@@ -16,13 +16,13 @@ ENV NEXT_PUBLIC_LIVEKIT_URL=$NEXT_PUBLIC_LIVEKIT_URL
|
|||||||
ENV NEXT_PUBLIC_OPENAIP_ACCESS=$NEXT_PUBLIC_OPENAIP_ACCESS
|
ENV NEXT_PUBLIC_OPENAIP_ACCESS=$NEXT_PUBLIC_OPENAIP_ACCESS
|
||||||
ENV NEXT_PUBLIC_DISCORD_URL=$NEXT_PUBLIC_DISCORD_URL
|
ENV NEXT_PUBLIC_DISCORD_URL=$NEXT_PUBLIC_DISCORD_URL
|
||||||
|
|
||||||
|
FROM base AS builder
|
||||||
|
|
||||||
ENV PNPM_HOME="/usr/local/pnpm"
|
ENV PNPM_HOME="/usr/local/pnpm"
|
||||||
ENV PATH="${PNPM_HOME}:${PATH}"
|
ENV PATH="${PNPM_HOME}:${PATH}"
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
RUN pnpm add -g turbo@^2.5
|
RUN pnpm add -g turbo@^2.5
|
||||||
|
|
||||||
FROM base AS builder
|
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
@@ -31,12 +31,20 @@ WORKDIR /usr/app
|
|||||||
RUN echo "NEXT_PUBLIC_HUB_URL is: $NEXT_PUBLIC_HUB_URL"
|
RUN echo "NEXT_PUBLIC_HUB_URL is: $NEXT_PUBLIC_HUB_URL"
|
||||||
RUN echo "NEXT_PUBLIC_DISPATCH_SERVICE_ID is: $NEXT_PUBLIC_DISPATCH_SERVICE_ID"
|
RUN echo "NEXT_PUBLIC_DISPATCH_SERVICE_ID is: $NEXT_PUBLIC_DISPATCH_SERVICE_ID"
|
||||||
RUN echo "NEXT_PUBLIC_DISPATCH_SERVER_URL is: $NEXT_PUBLIC_DISPATCH_SERVER_URL"
|
RUN echo "NEXT_PUBLIC_DISPATCH_SERVER_URL is: $NEXT_PUBLIC_DISPATCH_SERVER_URL"
|
||||||
|
RUN echo "NEXT_PUBLIC_LIVEKIT_URL is: $NEXT_PUBLIC_LIVEKIT_URL"
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN turbo prune dispatch --docker
|
RUN turbo prune dispatch --docker
|
||||||
|
|
||||||
FROM base AS installer
|
FROM base AS installer
|
||||||
|
|
||||||
|
ENV PNPM_HOME="/usr/local/pnpm"
|
||||||
|
ENV PATH="${PNPM_HOME}:${PATH}"
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
RUN pnpm add -g turbo@^2.5
|
||||||
|
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
@@ -50,19 +58,25 @@ COPY --from=builder /usr/app/out/full/ .
|
|||||||
|
|
||||||
RUN turbo run build
|
RUN turbo run build
|
||||||
|
|
||||||
FROM base AS runner
|
FROM node:22-alpine AS runner
|
||||||
WORKDIR /usr/app
|
WORKDIR /usr/app
|
||||||
|
|
||||||
# Don't run production as root
|
# Don't run production as root
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
RUN adduser --system --uid 1001 nextjs
|
RUN adduser --system --uid 1001 nextjs
|
||||||
USER nextjs
|
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
# Automatically leverage output traces to reduce image size
|
||||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
COPY --from=installer --chown=nextjs:nodejs /usr/app/ ./
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/standalone ./
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/static ./apps/dispatch/.next/static
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/public ./apps/dispatch/public
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
# Expose the application port
|
# Expose the application port
|
||||||
EXPOSE 3001
|
EXPOSE 3001
|
||||||
|
|
||||||
CMD ["pnpm", "--dir", "apps/dispatch", "run", "start"]
|
ENV PORT=3001
|
||||||
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "apps/dispatch/server.js"]
|
||||||
@@ -2,7 +2,6 @@ import { MissionSdsLog, Station } from "@repo/db";
|
|||||||
import { fmsStatusDescription } from "_data/fmsStatusDescription";
|
import { fmsStatusDescription } from "_data/fmsStatusDescription";
|
||||||
import { DisplayLineProps } from "(app)/pilot/_components/mrt/Mrt";
|
import { DisplayLineProps } from "(app)/pilot/_components/mrt/Mrt";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { syncTabs } from "zustand-sync-tabs";
|
|
||||||
|
|
||||||
interface SetSdsPageParams {
|
interface SetSdsPageParams {
|
||||||
page: "sds";
|
page: "sds";
|
||||||
@@ -41,133 +40,126 @@ interface MrtStore {
|
|||||||
setLines: (lines: MrtStore["lines"]) => void;
|
setLines: (lines: MrtStore["lines"]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMrtStore = create<MrtStore>(
|
export const useMrtStore = create<MrtStore>((set) => ({
|
||||||
syncTabs(
|
page: "home",
|
||||||
(set) => ({
|
pageData: {
|
||||||
page: "home",
|
message: "",
|
||||||
pageData: {
|
},
|
||||||
message: "",
|
lines: [
|
||||||
},
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: "VAR.#",
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: "No Data",
|
|
||||||
textSize: "3",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
setLines: (lines) => set({ lines }),
|
|
||||||
setPage: (pageData) => {
|
|
||||||
switch (pageData.page) {
|
|
||||||
case "home": {
|
|
||||||
const { station, fmsStatus } = pageData as SetHomePageParams;
|
|
||||||
set({
|
|
||||||
page: "home",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: `${station?.bosCallsign}`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{ textLeft: "ILS VAR#", textSize: "3" },
|
|
||||||
{
|
|
||||||
textLeft: fmsStatus,
|
|
||||||
style: { fontWeight: "extrabold" },
|
|
||||||
textSize: "4",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: fmsStatusDescription[fmsStatus],
|
|
||||||
textSize: "1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "sending-status": {
|
|
||||||
const { station } = pageData as SetSendingStatusPageParams;
|
|
||||||
set({
|
|
||||||
page: "sending-status",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: `${station?.bosCallsign}`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{ textLeft: "ILS VAR#", textSize: "3" },
|
|
||||||
{
|
|
||||||
textMid: "sending...",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "4",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: "Status wird gesendet...",
|
|
||||||
textSize: "1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "new-status": {
|
|
||||||
const { station } = pageData as SetNewStatusPageParams;
|
|
||||||
set({
|
|
||||||
page: "new-status",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: `${station?.bosCallsign}`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{ textLeft: "ILS VAR#", textSize: "3" },
|
|
||||||
{
|
|
||||||
textLeft: "empfangen",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "4",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "sds": {
|
|
||||||
const { sdsMessage } = pageData as SetSdsPageParams;
|
|
||||||
const msg = sdsMessage.data.message;
|
|
||||||
set({
|
|
||||||
page: "sds",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: `SDS-Nachricht`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: msg,
|
|
||||||
style: {
|
|
||||||
whiteSpace: "normal",
|
|
||||||
overflowWrap: "break-word",
|
|
||||||
wordBreak: "break-word",
|
|
||||||
display: "block",
|
|
||||||
maxWidth: "100%",
|
|
||||||
maxHeight: "100%",
|
|
||||||
overflow: "auto",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
lineHeight: "1.2em",
|
|
||||||
},
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
set({ page: "home" });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
name: "mrt-store", // unique name
|
textLeft: "VAR.#",
|
||||||
|
textSize: "2",
|
||||||
},
|
},
|
||||||
),
|
{
|
||||||
);
|
textLeft: "No Data",
|
||||||
|
textSize: "3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setLines: (lines) => set({ lines }),
|
||||||
|
setPage: (pageData) => {
|
||||||
|
switch (pageData.page) {
|
||||||
|
case "home": {
|
||||||
|
const { station, fmsStatus } = pageData as SetHomePageParams;
|
||||||
|
set({
|
||||||
|
page: "home",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textLeft: `${station?.bosCallsign}`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
{ textLeft: "ILS VAR#", textSize: "3" },
|
||||||
|
{
|
||||||
|
textLeft: fmsStatus,
|
||||||
|
style: { fontWeight: "extrabold" },
|
||||||
|
textSize: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: fmsStatusDescription[fmsStatus],
|
||||||
|
textSize: "1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "sending-status": {
|
||||||
|
const { station } = pageData as SetSendingStatusPageParams;
|
||||||
|
set({
|
||||||
|
page: "sending-status",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textLeft: `${station?.bosCallsign}`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
{ textLeft: "ILS VAR#", textSize: "3" },
|
||||||
|
{
|
||||||
|
textMid: "sending...",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: "Status wird gesendet...",
|
||||||
|
textSize: "1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "new-status": {
|
||||||
|
const { station } = pageData as SetNewStatusPageParams;
|
||||||
|
set({
|
||||||
|
page: "new-status",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textLeft: `${station?.bosCallsign}`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
{ textLeft: "ILS VAR#", textSize: "3" },
|
||||||
|
{
|
||||||
|
textLeft: "empfangen",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "4",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "sds": {
|
||||||
|
const { sdsMessage } = pageData as SetSdsPageParams;
|
||||||
|
const msg = sdsMessage.data.message;
|
||||||
|
set({
|
||||||
|
page: "sds",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textLeft: `SDS-Nachricht`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: msg,
|
||||||
|
style: {
|
||||||
|
whiteSpace: "normal",
|
||||||
|
overflowWrap: "break-word",
|
||||||
|
wordBreak: "break-word",
|
||||||
|
display: "block",
|
||||||
|
maxWidth: "100%",
|
||||||
|
maxHeight: "100%",
|
||||||
|
overflow: "auto",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
lineHeight: "1.2em",
|
||||||
|
},
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
set({ page: "home" });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Mission, Station, User } from "@repo/db";
|
import { Mission, Station, User } from "@repo/db";
|
||||||
import { DisplayLineProps } from "(app)/pilot/_components/dme/Dme";
|
import { DisplayLineProps } from "(app)/pilot/_components/dme/Dme";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { syncTabs } from "zustand-sync-tabs";
|
|
||||||
|
|
||||||
interface SetHomePageParams {
|
interface SetHomePageParams {
|
||||||
page: "home";
|
page: "home";
|
||||||
@@ -45,197 +44,190 @@ interface MrtStore {
|
|||||||
|
|
||||||
let interval: NodeJS.Timeout | null = null;
|
let interval: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
export const useDmeStore = create<MrtStore>(
|
export const useDmeStore = create<MrtStore>((set) => ({
|
||||||
syncTabs(
|
page: "home",
|
||||||
(set) => ({
|
pageData: {
|
||||||
page: "home",
|
message: "",
|
||||||
pageData: {
|
},
|
||||||
message: "",
|
lines: [
|
||||||
},
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textMid: "VAR . DME# No Data",
|
|
||||||
textSize: "2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
setLines: (lines) => set({ lines }),
|
|
||||||
latestMission: null,
|
|
||||||
setPage: (pageData) => {
|
|
||||||
if (interval) clearInterval(interval);
|
|
||||||
switch (pageData.page) {
|
|
||||||
case "home": {
|
|
||||||
const setHomePage = () =>
|
|
||||||
set({
|
|
||||||
page: "home",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textMid: pageData.station.bosCallsign
|
|
||||||
? `${pageData.station.bosCallsign}`
|
|
||||||
: "no Data",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
{
|
|
||||||
textMid: new Date().toLocaleDateString("de-DE", {
|
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textMid: new Date().toLocaleTimeString(),
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
{
|
|
||||||
textMid: `${pageData.user.lastname} ${pageData.user.firstname}`,
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
setHomePage();
|
|
||||||
|
|
||||||
interval = setInterval(() => {
|
|
||||||
setHomePage();
|
|
||||||
}, 1000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "new-mission": {
|
|
||||||
set({
|
|
||||||
page: "new-mission",
|
|
||||||
lines: [
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
{
|
|
||||||
textMid: "new mission received",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "mission": {
|
|
||||||
set({
|
|
||||||
latestMission: pageData.mission,
|
|
||||||
page: "mission",
|
|
||||||
lines: [
|
|
||||||
{
|
|
||||||
textLeft: `${pageData.mission.missionKeywordAbbreviation}`,
|
|
||||||
textRight: pageData.mission.Stations.map((s) => s.bosCallsignShort).join(","),
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
...(pageData.mission.type == "primär"
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
textMid: `${pageData.mission.missionKeywordName}`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
|
|
||||||
{ textLeft: `${pageData.mission.addressStreet}` },
|
|
||||||
{
|
|
||||||
textLeft: `${pageData.mission.addressZip} ${pageData.mission.addressCity}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textMid: "Weitere Standortinformationen:",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: pageData.mission.addressAdditionalInfo || "keine Daten",
|
|
||||||
},
|
|
||||||
...(pageData.mission.type === "sekundär"
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
textMid: "Zielort:",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: pageData.mission.addressMissionDestination || "keine Daten",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(pageData.mission.missionPatientInfo &&
|
|
||||||
pageData.mission.missionPatientInfo.length > 0
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
textMid: "Patienteninfos:",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: pageData.mission.missionPatientInfo,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(pageData.mission.missionAdditionalInfo &&
|
|
||||||
pageData.mission.missionAdditionalInfo.length > 0
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
textMid: "Weitere Infos:",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
textLeft: pageData.mission.missionAdditionalInfo,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "error": {
|
|
||||||
set({
|
|
||||||
page: "error",
|
|
||||||
lines: [
|
|
||||||
{ textMid: "Fehler:" },
|
|
||||||
{
|
|
||||||
textMid: pageData.error,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "acknowledge": {
|
|
||||||
set({
|
|
||||||
page: "acknowledge",
|
|
||||||
lines: [
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
{
|
|
||||||
textMid: "Einsatz angenommen",
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
set({
|
|
||||||
page: "error",
|
|
||||||
lines: [
|
|
||||||
{ textMid: "Fehler:" },
|
|
||||||
{
|
|
||||||
textMid: `Unbekannte Seite`,
|
|
||||||
style: { fontWeight: "bold" },
|
|
||||||
},
|
|
||||||
{ textMid: "⠀" },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
name: "dme-store", // unique name
|
textLeft: "",
|
||||||
},
|
},
|
||||||
),
|
{
|
||||||
);
|
textMid: "VAR . DME# No Data",
|
||||||
|
textSize: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
setLines: (lines) => set({ lines }),
|
||||||
|
latestMission: null,
|
||||||
|
setPage: (pageData) => {
|
||||||
|
if (interval) clearInterval(interval);
|
||||||
|
switch (pageData.page) {
|
||||||
|
case "home": {
|
||||||
|
const setHomePage = () =>
|
||||||
|
set({
|
||||||
|
page: "home",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textMid: pageData.station.bosCallsign
|
||||||
|
? `${pageData.station.bosCallsign}`
|
||||||
|
: "no Data",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
{
|
||||||
|
textMid: new Date().toLocaleDateString("de-DE", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textMid: new Date().toLocaleTimeString(),
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
{
|
||||||
|
textMid: `${pageData.user.lastname} ${pageData.user.firstname}`,
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
setHomePage();
|
||||||
|
|
||||||
|
interval = setInterval(() => {
|
||||||
|
setHomePage();
|
||||||
|
}, 1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "new-mission": {
|
||||||
|
set({
|
||||||
|
page: "new-mission",
|
||||||
|
lines: [
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
{
|
||||||
|
textMid: "new mission received",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "mission": {
|
||||||
|
set({
|
||||||
|
latestMission: pageData.mission,
|
||||||
|
page: "mission",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
textLeft: `${pageData.mission.missionKeywordAbbreviation}`,
|
||||||
|
textRight: pageData.mission.Stations.map((s) => s.bosCallsignShort).join(","),
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
...(pageData.mission.type == "primär"
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
textMid: `${pageData.mission.missionKeywordName}`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
|
||||||
|
{ textLeft: `${pageData.mission.addressStreet}` },
|
||||||
|
{
|
||||||
|
textLeft: `${pageData.mission.addressZip} ${pageData.mission.addressCity}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textMid: "Weitere Standortinformationen:",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: pageData.mission.addressAdditionalInfo || "keine Daten",
|
||||||
|
},
|
||||||
|
...(pageData.mission.type === "sekundär"
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
textMid: "Zielort:",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: pageData.mission.addressMissionDestination || "keine Daten",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
...(pageData.mission.missionPatientInfo &&
|
||||||
|
pageData.mission.missionPatientInfo.length > 0
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
textMid: "Patienteninfos:",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: pageData.mission.missionPatientInfo,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
...(pageData.mission.missionAdditionalInfo &&
|
||||||
|
pageData.mission.missionAdditionalInfo.length > 0
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
textMid: "Weitere Infos:",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
textLeft: pageData.mission.missionAdditionalInfo,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "error": {
|
||||||
|
set({
|
||||||
|
page: "error",
|
||||||
|
lines: [
|
||||||
|
{ textMid: "Fehler:" },
|
||||||
|
{
|
||||||
|
textMid: pageData.error,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "acknowledge": {
|
||||||
|
set({
|
||||||
|
page: "acknowledge",
|
||||||
|
lines: [
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
{
|
||||||
|
textMid: "Einsatz angenommen",
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
set({
|
||||||
|
page: "error",
|
||||||
|
lines: [
|
||||||
|
{ textMid: "Fehler:" },
|
||||||
|
{
|
||||||
|
textMid: `Unbekannte Seite`,
|
||||||
|
style: { fontWeight: "bold" },
|
||||||
|
},
|
||||||
|
{ textMid: "⠀" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|||||||
1
apps/dispatch/next-env.d.ts
vendored
1
apps/dispatch/next-env.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {};
|
const nextConfig = {
|
||||||
|
output: "standalone",
|
||||||
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@@ -60,7 +60,6 @@
|
|||||||
"tailwindcss": "^4.1.11",
|
"tailwindcss": "^4.1.11",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"zod": "^3.25.67",
|
"zod": "^3.25.67",
|
||||||
"zustand": "^5.0.6",
|
"zustand": "^5.0.6"
|
||||||
"zustand-sync-tabs": "^0.2.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
|
|
||||||
|
|
||||||
ENV PNPM_HOME="/usr/local/pnpm"
|
|
||||||
ENV PATH="${PNPM_HOME}:${PATH}"
|
|
||||||
|
|
||||||
ARG NEXT_PUBLIC_HUB_URL
|
ARG NEXT_PUBLIC_HUB_URL
|
||||||
ARG NEXT_PUBLIC_HUB_SERVER_URL
|
ARG NEXT_PUBLIC_HUB_SERVER_URL
|
||||||
ARG NEXT_PUBLIC_DISCORD_URL
|
ARG NEXT_PUBLIC_DISCORD_URL
|
||||||
@@ -16,13 +12,13 @@ ENV NEXT_PUBLIC_DISCORD_URL=${NEXT_PUBLIC_DISCORD_URL}
|
|||||||
ENV NEXT_PUBLIC_MOODLE_URL=${NEXT_PUBLIC_MOODLE_URL}
|
ENV NEXT_PUBLIC_MOODLE_URL=${NEXT_PUBLIC_MOODLE_URL}
|
||||||
ENV NEXT_PUBLIC_DISPATCH_URL=${NEXT_PUBLIC_DISPATCH_URL}
|
ENV NEXT_PUBLIC_DISPATCH_URL=${NEXT_PUBLIC_DISPATCH_URL}
|
||||||
|
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
||||||
|
|
||||||
|
|
||||||
RUN echo "NEXT_PUBLIC_DISCORD_URL=${NEXT_PUBLIC_DISCORD_URL}"
|
|
||||||
RUN pnpm add -g turbo@^2.5
|
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
|
|
||||||
|
ENV PNPM_HOME="/usr/local/pnpm"
|
||||||
|
ENV PATH="${PNPM_HOME}:${PATH}"
|
||||||
|
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
RUN pnpm add -g turbo@^2.5
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
@@ -33,6 +29,13 @@ COPY . .
|
|||||||
RUN turbo prune hub --docker
|
RUN turbo prune hub --docker
|
||||||
|
|
||||||
FROM base AS installer
|
FROM base AS installer
|
||||||
|
|
||||||
|
ENV PNPM_HOME="/usr/local/pnpm"
|
||||||
|
ENV PATH="${PNPM_HOME}:${PATH}"
|
||||||
|
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
RUN pnpm add -g turbo@^2.5
|
||||||
|
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
@@ -44,21 +47,27 @@ RUN pnpm install
|
|||||||
# Build the project
|
# Build the project
|
||||||
COPY --from=builder /usr/app/out/full/ .
|
COPY --from=builder /usr/app/out/full/ .
|
||||||
|
|
||||||
RUN turbo run build
|
RUN turbo run build --filter=hub...
|
||||||
|
|
||||||
FROM base AS runner
|
FROM node:22-alpine AS runner
|
||||||
WORKDIR /usr/app
|
WORKDIR /usr/app
|
||||||
|
|
||||||
# Don't run production as root
|
# Don't run production as root
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
RUN adduser --system --uid 1001 nextjs
|
RUN adduser --system --uid 1001 nextjs
|
||||||
USER nextjs
|
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
# Automatically leverage output traces to reduce image size
|
||||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
COPY --from=installer --chown=nextjs:nodejs /usr/app/ ./
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/.next/standalone ./
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/.next/static ./apps/hub/.next/static
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/public ./apps/hub/public
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
# Expose the application port
|
# Expose the application port
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["pnpm", "--dir", "apps/hub", "run", "start"]
|
ENV PORT=3000
|
||||||
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "apps/hub/server.js"]
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
/* const removeImports = require("next-remove-imports")(); */
|
/* const removeImports = require("next-remove-imports")(); */
|
||||||
/* const nextConfig = removeImports({}); */
|
/* const nextConfig = removeImports({}); */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
output: "standalone",
|
||||||
images: {
|
images: {
|
||||||
domains: ["cdn.discordapp.com", "nextcloud.virtualairrescue.com"],
|
domains: ["cdn.discordapp.com", "nextcloud.virtualairrescue.com"],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"node": ">=18",
|
"node": ">=18",
|
||||||
"pnpm": ">=10"
|
"pnpm": ">=10"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.28.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|||||||
521
pnpm-lock.yaml
generated
521
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,9 @@ overrides:
|
|||||||
next@>=15.0.0 <=15.4.4: '>=15.4.5'
|
next@>=15.0.0 <=15.4.4: '>=15.4.5'
|
||||||
next@>=15.0.0-canary.0 <15.4.7: '>=15.4.7'
|
next@>=15.0.0-canary.0 <15.4.7: '>=15.4.7'
|
||||||
next@>=15.4.0-canary.0 <15.4.8: '>=15.4.8'
|
next@>=15.4.0-canary.0 <15.4.8: '>=15.4.8'
|
||||||
|
next@>=15.4.0-canary.0 <15.4.9: '>=15.4.9'
|
||||||
nodemailer@<7.0.7: '>=7.0.7'
|
nodemailer@<7.0.7: '>=7.0.7'
|
||||||
nodemailer@<=7.0.10: '>=7.0.11'
|
nodemailer@<=7.0.10: '>=7.0.11'
|
||||||
playwright@<1.55.1: '>=1.55.1'
|
playwright@<1.55.1: '>=1.55.1'
|
||||||
|
preact@>=10.26.5 <10.26.10: '>=10.26.10'
|
||||||
|
qs@<6.14.1: '>=6.14.1'
|
||||||
|
|||||||
Reference in New Issue
Block a user