Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI] Get kubeflow namespace from kfp UI #2655

Merged
merged 4 commits into from
Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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