diff --git a/src/labnow-open-web/src/App.jsx b/src/labnow-open-web/src/App.jsx index 5a7def4..dea475c 100644 --- a/src/labnow-open-web/src/App.jsx +++ b/src/labnow-open-web/src/App.jsx @@ -30,6 +30,7 @@ import { StopFilledAlt, } from "@carbon/icons-react"; import { useSupervisorController } from "./hooks/useSupervisorController"; +import { buildHomePath, buildWorkspacePath } from "./utils/runtimeBase"; const PROGRAM_DEFINITIONS = { caddy: { displayName: "Caddy Server", hidden: true }, @@ -63,29 +64,6 @@ const PROGRAM_DEFINITIONS = { }, }; -function normalizeBaseUrl(baseUrl) { - if (!baseUrl) { - return "/"; - } - return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`; -} - -function buildPrefixedPath(path) { - if (!path) { - return ""; - } - if (/^(https?:)?\/\//.test(path)) { - return path; - } - - const runtimeBase = - (typeof window !== "undefined" && window.__LABNOW_URL_PREFIX__) || - import.meta.env.BASE_URL; - const normalizedBase = normalizeBaseUrl(runtimeBase); - const normalizedPath = String(path).replace(/^\/+/, ""); - return `${normalizedBase}${normalizedPath}`; -} - function NotificationBar({ notice, onClose }) { if (!notice) { return null; @@ -266,7 +244,7 @@ export default function App() { @@ -348,7 +326,7 @@ export default function App() { const running = isRunningState(program.statename); const programMeta = programMetaByName[program.name]; const programLabel = programMeta?.displayName || program.name; - const programLink = programMeta?.link; + const programLink = buildWorkspacePath(programMeta?.link); const programLogo = programMeta?.logo || ""; const programDescription = programMeta?.description || ""; const programLinkEnabled = @@ -387,7 +365,7 @@ export default function App() { {programLogo ? ( diff --git a/src/labnow-open-web/src/api/supervisorApi.js b/src/labnow-open-web/src/api/supervisorApi.js index 879dfcd..8e3aea6 100644 --- a/src/labnow-open-web/src/api/supervisorApi.js +++ b/src/labnow-open-web/src/api/supervisorApi.js @@ -1,3 +1,5 @@ +import { getRuntimeApiBase } from "../utils/runtimeBase"; + function buildJsonHeaders(extraHeaders) { return { "Content-Type": "application/json", @@ -32,25 +34,7 @@ export async function resolveApiBase() { return "/api/home"; } - const runtimeBase = - (typeof window !== "undefined" && window.__LABNOW_URL_PREFIX__) || - import.meta.env.BASE_URL; - if (runtimeBase && typeof window !== "undefined") { - const pathname = new URL(runtimeBase, window.location.href).pathname; - return pathname === "/" ? "/home" : pathname.replace(/\/$/, ""); - } - - try { - const resp = await fetch(window.location.href, { method: "HEAD" }); - const base = resp.headers.get("location-base"); - if (base) { - return `${base}home`; - } - } catch (error) { - console.error("Failed to resolve location-base header", error); - } - - return "/home"; + return typeof window !== "undefined" ? getRuntimeApiBase() : "/home"; } export function createSupervisorApi(apiBase) { diff --git a/src/labnow-open-web/src/hooks/useSupervisorController.js b/src/labnow-open-web/src/hooks/useSupervisorController.js index 076064b..ff98c18 100644 --- a/src/labnow-open-web/src/hooks/useSupervisorController.js +++ b/src/labnow-open-web/src/hooks/useSupervisorController.js @@ -2,21 +2,17 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { createSupervisorApi, isRunningState, - resolveApiBase, } from "../api/supervisorApi"; +import { getRuntimeApiBase } from "../utils/runtimeBase"; export function useSupervisorController() { const [loading, setLoading] = useState(false); const [programs, setPrograms] = useState([]); - const [apiBase, setApiBase] = useState( - import.meta.env.DEV ? "/api/home" : "/home" + const [apiBase] = useState(() => + import.meta.env.DEV ? "/api/home" : getRuntimeApiBase() ); const [selectedRowKeys, setSelectedRowKeys] = useState([]); - useEffect(() => { - resolveApiBase().then(setApiBase); - }, []); - const api = useMemo(() => createSupervisorApi(apiBase), [apiBase]); const patchProgramState = useCallback((name, nextState) => { diff --git a/src/labnow-open-web/src/utils/runtimeBase.js b/src/labnow-open-web/src/utils/runtimeBase.js new file mode 100644 index 0000000..5ab1582 --- /dev/null +++ b/src/labnow-open-web/src/utils/runtimeBase.js @@ -0,0 +1,43 @@ +function isExternalUrl(path) { + return /^(https?:)?\/\//.test(path); +} + +export function getRuntimeHomeBasePath() { + const runtimeBase = + (typeof window !== "undefined" && window.__LABNOW_URL_PREFIX__) || + import.meta.env.BASE_URL || + "./"; + + if (typeof window === "undefined") { + return runtimeBase.endsWith("/") ? runtimeBase : `${runtimeBase}/`; + } + + const pathname = new URL(runtimeBase, window.location.href).pathname; + return pathname.endsWith("/") ? pathname : `${pathname}/`; +} + +export function getRuntimeApiBase() { + const homeBase = getRuntimeHomeBasePath(); + return homeBase === "/" ? "/home" : homeBase.replace(/\/$/, ""); +} + +export function buildHomePath(path) { + if (!path) { + return ""; + } + if (isExternalUrl(path)) { + return path; + } + return `${getRuntimeHomeBasePath()}${String(path).replace(/^\/+/, "")}`; +} + +export function buildWorkspacePath(path) { + if (!path) { + return ""; + } + if (isExternalUrl(path)) { + return path; + } + const prefix = getRuntimeHomeBasePath().replace(/\/home\/?$/, "/"); + return `${prefix}${String(path).replace(/^\/+/, "")}`; +} diff --git a/tool/cicd/docker-compose.labnow-open.DEV.yml b/tool/cicd/docker-compose.labnow-open.DEV.yml index 0e72c99..8463dcf 100644 --- a/tool/cicd/docker-compose.labnow-open.DEV.yml +++ b/tool/cicd/docker-compose.labnow-open.DEV.yml @@ -10,6 +10,7 @@ services: environment: - PROFILE_LOCALIZE=${PROFILE_LOCALIZE:-aliyun-pub} - ENV_PROFILE=${ENV_PROFILE:-DEV} + - STATIC_DIR=/opt/labnow-open/web env_file: ["../credentials/${ENV_PROFILE:-DEV}-labnow-open.env"] user: "0:0" ports: ["${PORT_APP:-20000}:80", "${PORT_WEB:-30000}:3000"] diff --git a/tool/cicd/run-dev.sh b/tool/cicd/run-dev.sh index 26a6ac0..1acc0c7 100755 --- a/tool/cicd/run-dev.sh +++ b/tool/cicd/run-dev.sh @@ -52,6 +52,8 @@ echo "Action: $ACTION" echo "Compose: $COMPOSE" echo "----------------------------------------" +mkdir -pv "$SCRIPT_DIR/../credentials" >/dev/null +touch "$SCRIPT_DIR/../credentials/DEV-labnow-open.env" >/dev/null case "$ACTION" in up)