Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

Commit

Permalink
Feat: Enable hosting app in any route, with easy config (#3722)
Browse files Browse the repository at this point in the history
* Enable hosting app in any route, with easy config

* Review Comments
  • Loading branch information
haricane8133 authored Nov 29, 2023
1 parent fb70f49 commit 0f187bf
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 7 deletions.
8 changes: 8 additions & 0 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
7 changes: 5 additions & 2 deletions ui/src/components/NavLink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -24,8 +26,9 @@ export default React.forwardRef((props, ref) => {
</Link>
);
} else {
const href = absolutePath ? url.toString() : cleanDuplicateSlash(getBasename() + "/" + url.toString());
return (
<Link ref={ref} target="_blank" href={url.toString()}>
<Link ref={ref} target="_blank" href={href}>
{rest.children}
&nbsp;
<LaunchIcon fontSize="small" style={{ verticalAlign: "middle" }} />
Expand Down
3 changes: 2 additions & 1 deletion ui/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -22,7 +23,7 @@ ReactDOM.render(
//<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ThemeProvider>
<BrowserRouter>
<BrowserRouter basename={getBasename()}>
<CssBaseline />
<ReactQueryDevtools initialIsOpen={true} />

Expand Down
5 changes: 4 additions & 1 deletion ui/src/plugins/AppLogo.jsx
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -11,5 +13,6 @@ const useStyles = makeStyles((theme) => ({

export default function AppLogo() {
const classes = useStyles();
return <img src="/logo.svg" alt="Conductor" className={classes.logo} />;
const logoPath = getBasename() + '/logo.svg';
return <img src={cleanDuplicateSlash(logoPath)} alt="Conductor" className={classes.logo} />;
}
10 changes: 8 additions & 2 deletions ui/src/plugins/fetch.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getBasename } from "../utils/helpers";
import { useEnv } from "./env";

export function useFetchContext() {
Expand All @@ -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()]))
Expand All @@ -38,3 +40,7 @@ export function fetchWithContext(
}
});
}

export function cleanDuplicateSlash(path) {
return path.replace(/([^:]\/)\/+/g, "$1");
}
9 changes: 9 additions & 0 deletions ui/src/utils/helpers.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
}

0 comments on commit 0f187bf

Please sign in to comment.