Skip to content

Commit

Permalink
Fix: Kedro-Viz doesn't work when hosted via a URL subpath (#1621)
Browse files Browse the repository at this point in the history
* Fix: Kedro-Viz doesn't work when hosted via a URL subpath

* Pathname updated for experiment-tracking

Also pathRoot moved to util to break circular dependency

* graphql endpoint url fix

* Lint error fix

* deploy-viz-metadata api fix

* Release note added

* Update RELEASE.md

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

---------

Co-authored-by: Tynan DeBold <thdebold@gmail.com>
  • Loading branch information
jitu5 and tynandebold authored Nov 6, 2023
1 parent 6c063bf commit c59df4d
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 39 deletions.
1 change: 1 addition & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Please follow the established format:

- Fix dataset factory patterns in Experiment Tracking. (#1588)
- Improved feedback for copy to clipboard feature. (#1614)
- Ensure Kedro-Viz works when hosted on a URL subpath. (#1621)

# Release 6.6.1

Expand Down
4 changes: 4 additions & 0 deletions package/kedro_viz/api/graphql/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
graphql_app: GraphQL = GraphQL(schema, graphiql=False)
router.add_route("/graphql", graphql_app)
router.add_websocket_route("/graphql", graphql_app)

# {subpath:path} is to handle urls with subpath e.g. demo.kedro.org/web
router.add_route("/{subpath:path}/graphql", graphql_app)
router.add_websocket_route("/{subpath:path}/graphql", graphql_app)
9 changes: 2 additions & 7 deletions src/apollo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@ import {
split,
} from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { replaceMatches } from '../utils';

const { pathname } = window.location;
const sanitizedPathname = replaceMatches(pathname, {
'experiment-tracking': '',
});
import { sanitizedPathname } from '../utils';

const httpLink = createHttpLink({
// our graphql endpoint, normally here: http://localhost:4141/graphql
uri: `${sanitizedPathname}graphql`,
uri: `${sanitizedPathname()}graphql`,
fetch,
});

Expand Down
11 changes: 3 additions & 8 deletions src/components/global-toolbar/global-toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
toggleShareableUrlModal,
toggleTheme,
} from '../../actions';
import { isRunningLocally, replaceMatches } from '../../utils';
import { isRunningLocally, sanitizedPathname } from '../../utils';

import DownloadIcon from '../icons/download';
import ExperimentsIcon from '../icons/experiments';
Expand All @@ -30,11 +30,6 @@ export const GlobalToolbar = ({
onToggleTheme,
theme,
}) => {
const { pathname } = window.location;
const sanitizedPathname = replaceMatches(pathname, {
'experiment-tracking': '',
});

return (
<>
<div className="pipeline-global-toolbar">
Expand All @@ -46,7 +41,7 @@ export const GlobalToolbar = ({
disabled={false}
icon={LogoIcon}
/>
<NavLink exact to={{ pathname: sanitizedPathname }}>
<NavLink exact to={{ pathname: sanitizedPathname() }}>
<IconButton
ariaLabel={'View your pipeline'}
dataTest={'View your pipeline'}
Expand All @@ -63,7 +58,7 @@ export const GlobalToolbar = ({
<NavLink
exact
id="experiment-tracking-nav-button"
to={{ pathname: `${sanitizedPathname}experiment-tracking` }}
to={{ pathname: `${sanitizedPathname()}experiment-tracking` }}
>
<IconButton
ariaLabel={'View your experiments'}
Expand Down
16 changes: 10 additions & 6 deletions src/components/shareable-url-modal/shareable-url-metadata.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { useEffect, useState } from 'react';
import { sanitizedPathname } from '../../utils';

const ShareableUrlMetadata = () => {
const [metadata, setMetadata] = useState(null);

useEffect(() => {
async function fetchData() {
try {
const request = await fetch('/api/deploy-viz-metadata', {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
const request = await fetch(
`${sanitizedPathname()}api/deploy-viz-metadata`,
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}
);
const response = await request.json();

if (request.ok) {
Expand Down
11 changes: 3 additions & 8 deletions src/components/wrapper/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import classnames from 'classnames';
import { isRunningLocally, replaceMatches } from '../../utils';
import { isRunningLocally, sanitizedPathname } from '../../utils';
import { useApolloQuery } from '../../apollo/utils';
import { client } from '../../apollo/config';
import { GraphQLProvider } from '../provider/provider';
Expand All @@ -21,11 +21,6 @@ import './wrapper.scss';
* Main app container. Handles showing/hiding the sidebar nav, and theme classes.
*/
export const Wrapper = ({ displayGlobalToolbar, theme }) => {
const { pathname } = window.location;
const sanitizedPathname = replaceMatches(pathname, {
'experiment-tracking': '',
});

const { data: versionData } = useApolloQuery(GET_VERSIONS, {
client,
skip: !displayGlobalToolbar || !isRunningLocally(),
Expand Down Expand Up @@ -63,11 +58,11 @@ export const Wrapper = ({ displayGlobalToolbar, theme }) => {
/>
)}
<Switch>
<Route exact path={sanitizedPathname}>
<Route exact path={sanitizedPathname()}>
<FlowChartWrapper />
<FeatureHints />
</Route>
<Route path={`${sanitizedPathname}experiment-tracking`}>
<Route path={`${sanitizedPathname()}experiment-tracking`}>
<ExperimentWrapper />
</Route>
</Switch>
Expand Down
19 changes: 10 additions & 9 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const pathRoot = './api';
import { sanitizedPathname } from './utils';

export const localStorageName = 'KedroViz';
export const localStorageFlowchartLink = 'KedroViz-link-to-flowchart';
Expand Down Expand Up @@ -123,19 +123,20 @@ export const params = {
};

const activePipeline = `${params.pipeline}=:pipelineId`;
const pathname = sanitizedPathname();

export const routes = {
flowchart: {
main: '/',
focusedNode: `/?${activePipeline}&${params.focused}=:id`,
selectedNode: `/?${activePipeline}&${params.selected}=:id`,
selectedName: `/?${activePipeline}&${params.selectedName}=:fullName`,
selectedPipeline: `/?${activePipeline}`,
main: pathname,
focusedNode: `${pathname}?${activePipeline}&${params.focused}=:id`,
selectedNode: `${pathname}?${activePipeline}&${params.selected}=:id`,
selectedName: `${pathname}?${activePipeline}&${params.selectedName}=:fullName`,
selectedPipeline: `${pathname}?${activePipeline}`,
},
experimentTracking: {
main: '/experiment-tracking',
selectedView: `/experiment-tracking?${params.view}=:view`,
selectedRuns: `/experiment-tracking?${params.run}=:ids&${params.view}=:view&${params.comparisonMode}=:isComparison`,
main: `${pathname}experiment-tracking`,
selectedView: `${pathname}experiment-tracking?${params.view}=:view`,
selectedRuns: `${pathname}experiment-tracking?${params.run}=:ids&${params.view}=:view&${params.comparisonMode}=:isComparison`,
},
};

Expand Down
18 changes: 17 additions & 1 deletion src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//--- Useful JS utility functions ---//
import { pathRoot } from '../config';
const pathRoot = './api';

/**
* Loop through an array and output to an object
Expand Down Expand Up @@ -198,3 +198,19 @@ export const isRunningLocally = () => {
return true;
}
};

/**
* Sanitized pathname with experiment-tracking string and check if path containing trailing slash
* @returns {string} Sanitized pathname
*/
export const sanitizedPathname = () => {
const { pathname } = window.location;
const sanitizedPathname = replaceMatches(pathname, {
'experiment-tracking': '',
});
const pathnameWithTrailingSlash = sanitizedPathname.endsWith('/')
? sanitizedPathname
: `${sanitizedPathname}/`; // the `pathname` will have a trailing slash if it didn't initially

return pathnameWithTrailingSlash;
};

0 comments on commit c59df4d

Please sign in to comment.