fix(docker): добавить переменную окружения для внутреннего URL бэкенда
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-image (push) Successful in 1m34s
Docker images / frontend-image (push) Successful in 1m38s
Docker images / updater-image (push) Successful in 37s
Docker images / notify-webhook (push) Has been skipped
Docker images / publish-release (push) Successful in 6s

This commit is contained in:
Denozordec
2026-05-12 22:21:57 +07:00
parent 49d14a00af
commit f69e65b014
6 changed files with 42 additions and 10 deletions
+1
View File
@@ -40,6 +40,7 @@ ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_TELEMETRY_DISABLED=1
ENV HOSTNAME=0.0.0.0 ENV HOSTNAME=0.0.0.0
ENV PORT=3000 ENV PORT=3000
ENV BACKEND_INTERNAL_URL=http://backend:8000
COPY --from=build /app/public ./public COPY --from=build /app/public ./public
COPY --from=build /app/.next/standalone ./ COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static COPY --from=build /app/.next/static ./.next/static
+14 -3
View File
@@ -751,8 +751,8 @@ function RunRowDetail({ r }: { r: SchedulerRunRowDto }) {
} }
export default function DataCollectionPage() { export default function DataCollectionPage() {
const { mode, backendUrl } = useDataSource() const { mode, backendUrl, prefsHydrated } = useDataSource()
const isLive = mode === "live" const isLive = prefsHydrated && mode === "live"
const apiFetch = useMemo(() => makeApiFetch(backendUrl), [backendUrl]) const apiFetch = useMemo(() => makeApiFetch(backendUrl), [backendUrl])
const [trafficCollector, setTrafficCollector] = useState<CollectorSettingsDto | null>(null) const [trafficCollector, setTrafficCollector] = useState<CollectorSettingsDto | null>(null)
@@ -1003,7 +1003,18 @@ export default function DataCollectionPage() {
<div className="flex-1 overflow-y-auto p-6"> <div className="flex-1 overflow-y-auto p-6">
<div className="flex flex-col gap-5 max-w-[1100px] mx-auto w-full"> <div className="flex flex-col gap-5 max-w-[1100px] mx-auto w-full">
{!isLive && ( {!prefsHydrated && (
<Card>
<CardHeader>
<CardTitle className="text-base">Загрузка настроек подключения</CardTitle>
<CardDescription className="text-xs">
Читаем режим данных и адрес API из локальных настроек.
</CardDescription>
</CardHeader>
</Card>
)}
{prefsHydrated && !isLive && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-base">Нужен live-режим</CardTitle> <CardTitle className="text-base">Нужен live-режим</CardTitle>
+4
View File
@@ -18,8 +18,12 @@ services:
image: git.shts.su/denozord/mikrotikmanager-frontend:latest image: git.shts.su/denozord/mikrotikmanager-frontend:latest
container_name: mmapp-frontend container_name: mmapp-frontend
restart: unless-stopped restart: unless-stopped
depends_on:
- backend
ports: ports:
- "3000:3000" - "3000:3000"
environment:
BACKEND_INTERNAL_URL: http://backend:8000
labels: labels:
mmapp.updater.managed: "true" mmapp.updater.managed: "true"
mmapp.updater.target: frontend mmapp.updater.target: frontend
+12 -5
View File
@@ -59,9 +59,13 @@ function normalizeBackendUrl(url: string): string {
} }
export function DataSourceProvider({ children }: { children: React.ReactNode }) { export function DataSourceProvider({ children }: { children: React.ReactNode }) {
const [mode, setModeState] = useState<DataSourceMode>(defaultDataSourceMode) const [mode, setModeState] = useState<DataSourceMode>(() =>
const [backendUrl, setBackendUrlState] = useState(LOCAL_DEFAULT_BACKEND_URL) typeof window === "undefined" ? defaultDataSourceMode() : readStoredMode(),
const [prefsHydrated, setPrefsHydrated] = useState(false) )
const [backendUrl, setBackendUrlState] = useState(() =>
typeof window === "undefined" ? LOCAL_DEFAULT_BACKEND_URL : readStoredBackendUrl(),
)
const [prefsHydrated, setPrefsHydrated] = useState(() => typeof window !== "undefined")
const [backendStatus, setBackendStatus] = useState<boolean | undefined>(undefined) const [backendStatus, setBackendStatus] = useState<boolean | undefined>(undefined)
const backendUrlLocked = isBackendUrlLocked() const backendUrlLocked = isBackendUrlLocked()
const mockModeAvailable = isMockDataSourceAvailable() const mockModeAvailable = isMockDataSourceAvailable()
@@ -91,9 +95,12 @@ export function DataSourceProvider({ children }: { children: React.ReactNode })
}, [backendUrlLocked]) }, [backendUrlLocked])
const checkBackend = useCallback(async () => { const checkBackend = useCallback(async () => {
const url = normalizeBackendUrl(backendUrl) const healthUrl =
configuredBackendUrl().kind === "same-origin"
? "/health"
: `${normalizeBackendUrl(backendUrl)}/health`
try { try {
const res = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3000) }) const res = await fetch(healthUrl, { signal: AbortSignal.timeout(3000) })
setBackendStatus(res.ok) setBackendStatus(res.ok)
} catch { } catch {
setBackendStatus(false) setBackendStatus(false)
+10 -1
View File
@@ -1,3 +1,5 @@
import { configuredBackendUrl } from "@/lib/backend-url"
export class ApiClientError extends Error { export class ApiClientError extends Error {
constructor( constructor(
message: string, message: string,
@@ -13,13 +15,20 @@ function trimBaseUrl(baseUrl: string): string {
return baseUrl.replace(/\/$/, "") return baseUrl.replace(/\/$/, "")
} }
function resolveRequestUrl(baseUrl: string, path: string): string {
if (path.startsWith("/") && configuredBackendUrl().kind === "same-origin") {
return path
}
return trimBaseUrl(baseUrl) + path
}
export async function requestJson<T>( export async function requestJson<T>(
baseUrl: string, baseUrl: string,
path: string, path: string,
init?: RequestInit, init?: RequestInit,
): Promise<T> { ): Promise<T> {
const hasBody = init?.body != null const hasBody = init?.body != null
const res = await fetch(trimBaseUrl(baseUrl) + path, { const res = await fetch(resolveRequestUrl(baseUrl, path), {
...init, ...init,
headers: { headers: {
...(hasBody ? { "Content-Type": "application/json" } : {}), ...(hasBody ? { "Content-Type": "application/json" } : {}),
+1 -1
View File
File diff suppressed because one or more lines are too long