Skip to content

Commit

Permalink
[UI] Get kubeflow namespace from kfp UI (#2655)
Browse files Browse the repository at this point in the history
* Get kubeflow namespace from kfp UI

* Add a react context that makes namespace available anywhere.

* Move KFP_FLAGS check to index.tsx

* Update index.tsx
  • Loading branch information
Bobgy authored and k8s-ci-robot committed Nov 28, 2019
1 parent 7e327ae commit 675b1cd
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 10 deletions.
1 change: 1 addition & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
window.KFP_FLAGS={};
window.KFP_FLAGS.DEPLOYMENT=null;
</script>
<script id="kubeflow-client-placeholder"></script>
</head>
<body>
<noscript>
Expand Down
16 changes: 12 additions & 4 deletions frontend/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,14 @@ app.all(BASEPATH + '/' + v1beta1Prefix + '/*', proxy({
}));

const DEFAULT_FLAG = 'window.KFP_FLAGS.DEPLOYMENT=null';
function modifyFeatureFlags(indexHtml: string): string {
const KUBEFLOW_CLIENT_PLACEHOLDER = '<script id="kubeflow-client-placeholder"></script>';
function replaceRuntimeContent(indexHtml: string): string {
if (DEPLOYMENT === Deployments.KUBEFLOW) {
return indexHtml.replace(DEFAULT_FLAG, 'window.KFP_FLAGS.DEPLOYMENT="KUBEFLOW"');
return indexHtml.replace(DEFAULT_FLAG, 'window.KFP_FLAGS.DEPLOYMENT="KUBEFLOW"')
.replace(
KUBEFLOW_CLIENT_PLACEHOLDER,
`<script id="kubeflow-client-placeholder" src="/dashboard_lib.bundle.js"></script>`
);
} else {
return indexHtml;
}
Expand All @@ -428,15 +433,18 @@ fs.readFile(path.resolve(staticDir, 'index.html'), (err, data) => {
indexHtml = data.toString();
// sanity checking
if (!indexHtml.includes(DEFAULT_FLAG)) {
throw new Error(`Error: cannot find DEFAULT_FLAG in index html. Its content: ${indexHtml}`);
throw new Error(`Error: cannot find default flag: '${DEFAULT_FLAG}' in index html. Its content: '${indexHtml}'.`);
}
if (!indexHtml.includes(KUBEFLOW_CLIENT_PLACEHOLDER)) {
throw new Error(`Error: cannot find kubeflow client placeholder: '${KUBEFLOW_CLIENT_PLACEHOLDER}' in index html. Its content: '${indexHtml}'.`)
}
}
});

function handleIndexHtml(req, res) {
if (indexHtml) {
res.contentType('text/html');
res.send(modifyFeatureFlags(indexHtml));
res.send(replaceRuntimeContent(indexHtml));
} else {
res.send(404);
}
Expand Down
26 changes: 21 additions & 5 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { init as initKfClient, NamespaceContextProvider } from './lib/KubeflowClient';
import './CSSReset';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
Expand All @@ -22,9 +23,14 @@ import Router from './components/Router';
import { cssRule } from 'typestyle';
import { theme, fonts } from './Css';
import { HashRouter } from 'react-router-dom';
import { KFP_FLAGS, Deployments } from './lib/Flags';

// TODO: license headers

if (KFP_FLAGS.DEPLOYMENT === Deployments.KUBEFLOW) {
initKfClient();
}

cssRule('html, body, #root', {
background: 'white',
color: 'rgba(0, 0, 0, .66)',
Expand All @@ -36,10 +42,20 @@ cssRule('html, body, #root', {
});

ReactDOM.render(
<MuiThemeProvider theme={theme}>
<HashRouter>
<Router />
</HashRouter>
</MuiThemeProvider>,
KFP_FLAGS.DEPLOYMENT === Deployments.KUBEFLOW ? (
<MuiThemeProvider theme={theme}>
<NamespaceContextProvider>
<HashRouter>
<Router />
</HashRouter>
</NamespaceContextProvider>
</MuiThemeProvider>
) : (
<MuiThemeProvider theme={theme}>
<HashRouter>
<Router />
</HashRouter>
</MuiThemeProvider>
),
document.getElementById('root'),
);
11 changes: 11 additions & 0 deletions frontend/src/lib/Flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum Deployments {
KUBEFLOW = 'KUBEFLOW',
}

export const KFP_FLAGS = {
DEPLOYMENT:
// tslint:disable-next-line:no-string-literal
window && window['KFP_FLAGS'] && window['KFP_FLAGS']['DEPLOYMENT'] === Deployments.KUBEFLOW
? Deployments.KUBEFLOW
: undefined,
};
50 changes: 50 additions & 0 deletions frontend/src/lib/KubeflowClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { logger } from './Utils';

declare global {
interface Window {
// Provided by:
// 1. https://github.com/kubeflow/kubeflow/tree/master/components/centraldashboard#client-side-library
// 2. /frontend/server/server.ts -> KUBEFLOW_CLIENT_PLACEHOLDER
centraldashboard: any;
}
}

let namespace: string | undefined;
let registeredHandler: undefined | ((namespace: string) => void);
function onNamespaceChanged(handler: (namespace: string) => void) {
registeredHandler = handler;
}

export function init(): void {
try {
// Init method will invoke the callback with the event handler instance
// and a boolean indicating whether the page is iframed or not
window.centraldashboard.CentralDashboardEventHandler.init((cdeh: any) => {
// Binds a callback that gets invoked anytime the Dashboard's
// namespace is changed
cdeh.onNamespaceSelected = (newNamespace: string) => {
namespace = newNamespace;
if (registeredHandler) {
registeredHandler(namespace);
}
};
});
} catch (err) {
logger.error('Failed to initialize central dashboard client', err);
}
}

const NamespaceContext = React.createContext<string | undefined>(undefined);
export const NamespaceContextConsumer = NamespaceContext.Consumer;
export class NamespaceContextProvider extends React.Component {
state = {
namespace,
};
componentDidMount() {
onNamespaceChanged(ns => this.setState({ namespace: ns }));
}
render() {
return <NamespaceContext.Provider value={this.state.namespace} {...this.props} />;
}
}
2 changes: 1 addition & 1 deletion frontend/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
"jsx-no-bind": false,
"jsx-no-lambda": false,
"max-classes-per-file": false,
"member-access": false,
"ordered-imports": false,
"semicolon": [true, "always", "ignore-bound-class-methods"],
"typedef": [true, "call-signature"],
"no-unused-variable": true,
"variable-name": [
true,
Expand Down

0 comments on commit 675b1cd

Please sign in to comment.