diff --git a/ui/README.md b/ui/README.md index ff253e6ddc..2df3760f84 100644 --- a/ui/README.md +++ b/ui/README.md @@ -24,6 +24,14 @@ Your hosting environment should make the Conductor Server API available on the s See `docker/serverAndUI` for an `nginx` based example. +#### Different host path +The static UI would work when rendered from any host route. +The default is '/'. You can customize this by setting the 'homepage' field in package.json +Refer +- https://docs.npmjs.com/cli/v9/configuring-npm/package-json#homepage +- https://create-react-app.dev/docs/deployment/#building-for-relative-paths + + ### Customization Hooks For ease of maintenance, a number of touch points for customization have been removed to `/plugins`. diff --git a/ui/package.json b/ui/package.json index 33b909bb13..623a5c6dc1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "3.7.2", + "version": "3.8.0", "dependencies": { "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", diff --git a/ui/src/components/NavLink.jsx b/ui/src/components/NavLink.jsx index ae47b24f4e..9ccb93364f 100644 --- a/ui/src/components/NavLink.jsx +++ b/ui/src/components/NavLink.jsx @@ -4,12 +4,14 @@ import { Link } from "@material-ui/core"; import LaunchIcon from "@material-ui/icons/Launch"; import Url from "url-parse"; import { useEnv } from "../plugins/env"; +import { getBasename } from "../utils/helpers"; +import { cleanDuplicateSlash } from "../plugins/fetch"; // 1. Strip `navigate` from props to prevent error // 2. Preserve stack param export default React.forwardRef((props, ref) => { - const { navigate, path, newTab, ...rest } = props; + const { navigate, path, newTab, absolutePath = false, ...rest } = props; const { stack, defaultStack } = useEnv(); const url = new Url(path, {}, true); @@ -24,8 +26,9 @@ export default React.forwardRef((props, ref) => { ); } else { + const href = absolutePath ? url.toString() : cleanDuplicateSlash(getBasename() + "/" + url.toString()); return ( - + {rest.children}   diff --git a/ui/src/index.js b/ui/src/index.js index 52201aeaae..eb1b10ecf1 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -8,6 +8,7 @@ import { BrowserRouter } from "react-router-dom"; import CssBaseline from "@material-ui/core/CssBaseline"; import { QueryClient, QueryClientProvider } from "react-query"; import { ReactQueryDevtools } from "react-query/devtools"; +import { getBasename } from "./utils/helpers"; const queryClient = new QueryClient({ defaultOptions: { @@ -22,7 +23,7 @@ ReactDOM.render( // - + diff --git a/ui/src/plugins/AppLogo.jsx b/ui/src/plugins/AppLogo.jsx index 2650542836..ad825e5bcd 100644 --- a/ui/src/plugins/AppLogo.jsx +++ b/ui/src/plugins/AppLogo.jsx @@ -1,5 +1,7 @@ import React from "react"; import { makeStyles } from "@material-ui/core/styles"; +import { getBasename } from "../utils/helpers"; +import { cleanDuplicateSlash } from "./fetch"; const useStyles = makeStyles((theme) => ({ logo: { @@ -11,5 +13,6 @@ const useStyles = makeStyles((theme) => ({ export default function AppLogo() { const classes = useStyles(); - return Conductor; + const logoPath = getBasename() + '/logo.svg'; + return Conductor; } diff --git a/ui/src/plugins/fetch.js b/ui/src/plugins/fetch.js index bf4ba2fe8b..aabb5b1bdd 100644 --- a/ui/src/plugins/fetch.js +++ b/ui/src/plugins/fetch.js @@ -1,3 +1,4 @@ +import { getBasename } from "../utils/helpers"; import { useEnv } from "./env"; export function useFetchContext() { @@ -15,8 +16,9 @@ export function fetchWithContext( ) { const newParams = { ...fetchParams }; - const newPath = `/api/${path}`; - const cleanPath = newPath.replace(/([^:]\/)\/+/g, "$1"); // Cleanup duplicated slashes + const basename = getBasename(); + const newPath = basename + `/api/${path}`; + const cleanPath = cleanDuplicateSlash(newPath); // Cleanup duplicated slashes return fetch(cleanPath, newParams) .then((res) => Promise.all([res, res.text()])) @@ -38,3 +40,7 @@ export function fetchWithContext( } }); } + +export function cleanDuplicateSlash(path) { + return path.replace(/([^:]\/)\/+/g, "$1"); +} diff --git a/ui/src/utils/helpers.js b/ui/src/utils/helpers.js index a514ce606a..11bf45e943 100644 --- a/ui/src/utils/helpers.js +++ b/ui/src/utils/helpers.js @@ -1,5 +1,6 @@ import { format, formatDuration, intervalToDuration } from "date-fns"; import _ from "lodash"; +import packageJson from '../../package.json'; export function timestampRenderer(date) { if (_.isNil(date)) return null; @@ -88,3 +89,11 @@ export function isEmptyIterable(iterable) { } return true; } + +export function getBasename() { + let basename = '/'; + try{ + basename = new URL(packageJson.homepage).pathname; + } catch(e) {} + return _.isEmpty(basename) ? '/' : basename; +}