Skip to content

Instantly share code, notes, and snippets.

@jesuino
Created October 21, 2025 14:25
Show Gist options
  • Save jesuino/0079dfe742457d817fe51e519cd20c44 to your computer and use it in GitHub Desktop.
Save jesuino/0079dfe742457d817fe51e519cd20c44 to your computer and use it in GitHub Desktop.
diff --git a/labextension/src/components/Input.tsx b/labextension/src/components/Input.tsx
index 457b84d..044b0be 100644
--- a/labextension/src/components/Input.tsx
+++ b/labextension/src/components/Input.tsx
@@ -1,173 +1,3 @@
-// /*
-// * Copyright 2020 The Kale Authors
-// *
-// * Licensed under the Apache License, Version 2.0 (the "License");
-// * you may not use this file except in compliance with the License.
-// * You may obtain a copy of the License at
-// *
-// * http://www.apache.org/licenses/LICENSE-2.0
-// *
-// * Unless required by applicable law or agreed to in writing, software
-// * distributed under the License is distributed on an "AS IS" BASIS,
-// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// * See the License for the specific language governing permissions and
-// * limitations under the License.
-// */
-
-// import * as React from 'react';
-// import { useDebouncedCallback } from 'use-debounce';
-// import TextField, { OutlinedTextFieldProps } from '@material-ui/core/TextField';
-// import { createStyles, makeStyles } from '@material-ui/core/styles';
-
-// const useStyles = makeStyles(() =>
-// createStyles({
-// label: {
-// color: 'var(--jp-input-border-color)',
-// fontSize: 'var(--jp-ui-font-size2)',
-// },
-// input: {
-// color: 'var(--jp-ui-font-color1)',
-// },
-// textField: {
-// width: '100%',
-// },
-// helperLabel: {
-// color: 'var(--jp-info-color0)',
-// },
-// }),
-// );
-
-// // @ts-ignore
-// export interface InputProps extends OutlinedTextFieldProps {
-// value: string | number;
-// regex?: string;
-// regexErrorMsg?: string;
-// inputIndex?: number;
-// helperText?: string;
-// readOnly?: boolean;
-// validation?: 'int' | 'double';
-// variant?: 'standard' | 'outlined' | 'filled';
-// updateValue: Function;
-// onBeforeUpdate?: (value: string) => boolean;
-// }
-
-// export const Input: React.FunctionComponent<InputProps> = props => {
-// const [value, setValue] = React.useState('' as any);
-// const [error, updateError] = React.useState(false);
-// const classes = useStyles({});
-
-// const {
-// value: propsValue,
-// className,
-// helperText = null,
-// regex,
-// regexErrorMsg,
-// validation,
-// placeholder,
-// inputIndex,
-// readOnly = false,
-// variant = 'outlined',
-// InputProps,
-// updateValue,
-// onBeforeUpdate = undefined,
-// ...rest
-// } = props;
-
-// const getRegex = () => {
-// if (regex) {
-// return regex;
-// } else if (validation && validation == 'int') {
-// return /^(-\d)?\d*$/;
-// } else if (validation && validation == 'double') {
-// return /^(-\d)?\d*(\.\d)?\d*$/;
-// } else {
-// return undefined;
-// }
-// };
-
-// const getRegexMessage = () => {
-// if (regexErrorMsg) {
-// return regexErrorMsg;
-// } else if (validation && validation == 'int') {
-// return 'Integer value required';
-// } else if (validation && validation == 'double') {
-// return 'Double value required';
-// } else {
-// return undefined;
-// }
-// };
-
-// const onChange = (value: string, index: number) => {
-// // if the input domain is restricted by a regex
-// if (!getRegex()) {
-// updateValue(value, index);
-// return;
-// }
-
-// let re = new RegExp(getRegex());
-// if (!re.test(value)) {
-// updateError(true);
-// } else {
-// updateError(false);
-// updateValue(value, index);
-// }
-// };
-
-// React.useEffect(() => {
-// // need this to set the value when the notebook is loaded and the metadata
-// // is updated
-// setValue(propsValue);
-// }, [propsValue]); // Only re-run the effect if propsValue changes
-
-// const [debouncedCallback] = useDebouncedCallback(
-// // function
-// (value: string, idx: number) => {
-// onChange(value, idx);
-// },
-// // delay in ms
-// 500,
-// );
-
-// return (
-// // @ts-ignore
-// <TextField
-// {...rest}
-// variant={variant}
-// className={classes.textField}
-// error={error}
-// value={value}
-// margin="dense"
-// placeholder={placeholder}
-// spellCheck={false}
-// helperText={error ? getRegexMessage() : helperText}
-// InputProps={{
-// classes: { root: classes.input },
-// readOnly: readOnly,
-// ...InputProps,
-// }}
-// InputLabelProps={{
-// classes: { root: classes.label },
-// shrink: !!placeholder || value !== '',
-// }}
-// FormHelperTextProps={{ classes: { root: classes.helperLabel } }}
-// onChange={evt => {
-// setValue(evt.target.value);
-// if (!onBeforeUpdate) {
-// debouncedCallback(evt.target.value, inputIndex);
-// } else {
-// const r = onBeforeUpdate(evt.target.value);
-// if (r) {
-// updateError(true);
-// } else {
-// updateError(false);
-// debouncedCallback(evt.target.value, inputIndex);
-// }
-// }
-// }}
-// />
-// );
-// };
-
/*
* Copyright 2020 The Kale Authors
*
diff --git a/labextension/src/components/Select.tsx b/labextension/src/components/Select.tsx
index 6dc4096..d757371 100644
--- a/labextension/src/components/Select.tsx
+++ b/labextension/src/components/Select.tsx
@@ -14,124 +14,6 @@
// * limitations under the License.
// */
-// import * as React from 'react';
-// import TextField, { BaseTextFieldProps } from '@mui/material/TextField';
-// import { MenuItem, Zoom } from '@mui/material';
-// import { createStyles, makeStyles } from '@mui/material/styles';
-// import { styled } from '@mui/material/styles';
-// import { LightTooltip } from './LightTooltip';
-
-// export interface ISelectOption {
-// label: string;
-// value: string;
-// tooltip?: any;
-// invalid?: boolean;
-// }
-
-// const useStyles = styled(TextField)({
-// label: {
-// color: 'var(--jp-input-border-color)',
-// fontSize: 'var(--jp-ui-font-size2)',
-// },
-// input: {
-// color: 'var(--jp-ui-font-color1)',
-// },
-// textField: {
-// width: '100%',
-// },
-// menu: {
-// backgroundColor: 'var(--jp-layout-color1)',
-// color: 'var(--jp-ui-font-color1)',
-// },
-// helperLabel: {
-// color: 'var(--jp-info-color0)',
-// },
-// });
-
-// interface SelectProps extends BaseTextFieldProps {
-// index: number;
-// values: ISelectOption[];
-// variant?: 'filled' | 'standard' | 'outlined';
-// updateValue: Function;
-// }
-
-// export const Select: React.FC<SelectProps> = props => {
-// const classes = useStyles({});
-
-// const {
-// index,
-// value,
-// values,
-// helperText = null,
-// variant = 'outlined',
-// updateValue,
-// ...rest
-// } = props;
-
-// const disableMenuItem = (event: React.MouseEvent, invalidOption: boolean) => {
-// if (invalidOption) {
-// event.stopPropagation();
-// }
-// };
-
-// const getOptionClassNames = (option: any) => {
-// const classNames: string[] = [];
-// if (option.tooltip) {
-// classNames.push('menu-item-tooltip');
-// }
-// return classNames.join(' ');
-// };
-
-// return (
-// // @ts-ignore
-// <TextField
-// select
-// {...rest}
-// margin="dense"
-// value={value}
-// variant={variant}
-// className={classes.textField}
-// onChange={evt =>
-// updateValue((evt.target as HTMLInputElement).value, index)
-// }
-// InputLabelProps={{
-// classes: { root: classes.label },
-// shrink: value !== '',
-// }}
-// InputProps={{ classes: { root: classes.input } }}
-// SelectProps={{ MenuProps: { PaperProps: { className: classes.menu } } }}
-// FormHelperTextProps={{ classes: { root: classes.helperLabel } }}
-// >
-// {values.map((option: any) => (
-// <MenuItem
-// key={option.value}
-// value={option.value}
-// disabled={!!option.invalid}
-// className={getOptionClassNames(option)}
-// >
-// {option.tooltip ? (
-// <LightTooltip
-// title={option.tooltip}
-// placement="top-start"
-// interactive={!(typeof option.tooltip === 'string')}
-// TransitionComponent={Zoom}
-// >
-// <div
-// className="menu-item-label"
-// onClick={ev => disableMenuItem(ev, !!option.invalid)}
-// >
-// {option.label}
-// </div>
-// </LightTooltip>
-// ) : (
-// option.label
-// )}
-// </MenuItem>
-// ))}
-// </TextField>
-// );
-// };
-
import * as React from 'react';
import TextField, { BaseTextFieldProps } from '@mui/material/TextField';
import { MenuItem, Zoom } from '@mui/material';
diff --git a/labextension/src/index.ts b/labextension/src/index.ts
index 5a26634..27f859c 100644
--- a/labextension/src/index.ts
+++ b/labextension/src/index.ts
@@ -15,5 +15,5 @@
*/
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
-import kubeflowKalePlugin from './widget';
-export default [kubeflowKalePlugin] as JupyterFrontEndPlugin<any>[];
+import kubeflowKalePlugin, { IKubeflowKale } from './widget';
+export default [kubeflowKalePlugin] as JupyterFrontEndPlugin<IKubeflowKale>[];
diff --git a/labextension/src/lib/Commands.ts b/labextension/src/lib/Commands.ts
index ce139d5..ab706b7 100644
--- a/labextension/src/lib/Commands.ts
+++ b/labextension/src/lib/Commands.ts
@@ -37,6 +37,8 @@ import NotebookUtils from './NotebookUtils';
// } from '../widgets/VolumesPanel';
import { IDocumentManager } from '@jupyterlab/docmanager';
import CellUtils from './CellUtils';
+import { Pipeline } from '../widgets/deploys-progress/Pipeline';
+import { DeployProgressState } from '../widgets/deploys-progress/DeploysProgress';
enum RUN_CELL_STATUS {
OK = 'ok',
@@ -56,7 +58,7 @@ interface IUploadPipelineArgs {
interface IUploadPipelineResp {
already_exists: boolean;
- pipeline: { pipelineid: string; versionid: string; name: string };
+ pipeline: Pipeline;
}
interface IRunPipelineArgs {
@@ -296,7 +298,7 @@ export default class Commands {
versionId: string,
compiledPipelineMetadata: IKaleNotebookMetadata,
pipelinePackagePath: string,
- onUpdate: (params: { showRunProgress?: boolean, runPipeline?: boolean }) => void,
+ onUpdate: (deployProgress: DeployProgressState) => void,
) => {
onUpdate({ showRunProgress: true });
const runPipelineArgs: IRunPipelineArgs = {
@@ -310,9 +312,9 @@ export default class Commands {
this._kernel,
'kfp.run_pipeline',
runPipelineArgs,
- );
+ ) as Pipeline;
if (runPipeline) {
- onUpdate({ runPipeline });
+ onUpdate({ pipeline: runPipeline });
} else {
onUpdate({ showRunProgress: false, runPipeline: false });
}
diff --git a/labextension/src/lib/RPCUtils.tsx b/labextension/src/lib/RPCUtils.tsx
index bc67ad5..f1b70f5 100644
--- a/labextension/src/lib/RPCUtils.tsx
+++ b/labextension/src/lib/RPCUtils.tsx
@@ -21,7 +21,8 @@ import NotebookUtils from './NotebookUtils';
import { isError, IError, IOutput } from '@jupyterlab/nbformat';
export const globalUnhandledRejection = async (event: any) => {
- // console.error(event.reason);
+ console.log('Unhandled promise rejection:');
+ console.error(event.reason);
if (event.reason instanceof BaseError) {
console.error(event.reason.message, event.reason.error);
event.reason.showDialog().then();
diff --git a/labextension/src/widgets/LeftPanel.tsx b/labextension/src/widgets/LeftPanel.tsx
index 27e55be..ec4cdc6 100644
--- a/labextension/src/widgets/LeftPanel.tsx
+++ b/labextension/src/widgets/LeftPanel.tsx
@@ -414,12 +414,12 @@ export class KubeflowKaleLeftPanel extends React.Component<IProps, IState> {
if (!uploadPipeline) {
this.setState({ runDeployment: false });
- _updateDeployProgress({ pipeline: false });
+ _updateDeployProgress({ pipeline: undefined });
return;
}
_updateDeployProgress({
message: 'Pipeline uploaded successfully',
- pipeline: true
+ pipeline: uploadPipeline.pipeline
});
// RUN
if (this.state.deploymentType === 'run') {
diff --git a/labextension/src/widgets/deploys-progress/DeployProgress.tsx b/labextension/src/widgets/deploys-progress/DeployProgress.tsx
index bdb75fa..edbad38 100644
--- a/labextension/src/widgets/deploys-progress/DeployProgress.tsx
+++ b/labextension/src/widgets/deploys-progress/DeployProgress.tsx
@@ -28,19 +28,9 @@ import StatusRunning from '../../icons/statusRunning';
import TerminatedIcon from '../../icons/statusTerminated';
import { DeployProgressState } from './DeploysProgress';
import DeployUtils from './DeployUtils';
+import { Pipeline } from './Pipeline';
+
-// From kubeflow/pipelines repo
-enum PipelineStatus {
- ERROR = 'Error',
- FAILED = 'Failed',
- PENDING = 'Pending',
- RUNNING = 'Running',
- SKIPPED = 'Skipped',
- SUCCEEDED = 'Succeeded',
- TERMINATING = 'Terminating',
- TERMINATED = 'Terminated',
- UNKNOWN = 'Unknown'
-}
interface IDeployProgressProps extends DeployProgressState {
onRemove?: () => void;
@@ -49,87 +39,87 @@ interface IDeployProgressProps extends DeployProgressState {
export const DeployProgress: React.FunctionComponent<
IDeployProgressProps
> = props => {
- const getUploadLink = (pipeline: any) => {
+ const getUploadLink = (deployProgress: DeployProgressState) => {
// link: /_/pipeline/#/pipelines/details/<id>
// id = uploadPipeline.pipeline.id
- if (!pipeline.pipeline || !pipeline.pipeline.pipelineid) {
+ if (!deployProgress.pipeline || !deployProgress.pipeline.pipelineid) {
return '#';
}
- const link = `${window.location.origin}/_/pipeline/#/pipelines/details/${pipeline.pipeline.pipelineid}/version/${pipeline.pipeline.versionid}`;
+ const link = `${window.location.origin}/_/pipeline/#/pipelines/details/${deployProgress.pipeline.pipelineid}/version/${deployProgress.pipeline.versionid}`;
return props.namespace
? link.replace('#', `?ns=${props.namespace}#`)
: link;
};
- const getRunLink = (run: any) => {
+ const getRunLink = (run: Pipeline | undefined) => {
// link: /_/pipeline/#/runs/details/<id>
// id = runPipeline.id
- if (!run.id) {
+ if (!run?.pipelineid) {
return '#';
}
- const link = `${window.location.origin}/_/pipeline/#/runs/details/${run.id}`;
+ const link = `${window.location.origin}/_/pipeline/#/runs/details/${run.pipelineid}`;
return props.namespace
? link.replace('#', `?ns=${props.namespace}#`)
: link;
};
- const getRunText = (pipeline: any) => {
+ const getRunText = (pipeline: Pipeline) => {
switch (pipeline.status) {
case null:
- case 'Running':
+ case 'RUNNING':
return 'View';
- case 'Terminating':
- case 'Failed':
+ case 'TERMINATING':
+ case 'FAILED':
return pipeline.status as string;
default:
return 'Done';
}
};
- const getRunComponent = (pipeline: any) => {
+ const getRunComponent = (pipeline: Pipeline) => {
let IconComponent: any = UnknownIcon;
let iconColor = '#5f6368';
switch (pipeline.status) {
- case PipelineStatus.ERROR:
+ case 'ERROR':
IconComponent = ErrorIcon;
iconColor = DeployUtils.color.errorText;
// title = 'Error';
break;
- case PipelineStatus.FAILED:
+ case 'FAILED':
IconComponent = ErrorIcon;
iconColor = DeployUtils.color.errorText;
// title = 'Failed';
break;
- case PipelineStatus.PENDING:
+ case 'PENDING':
IconComponent = PendingIcon;
iconColor = DeployUtils.color.weak;
// title = 'Pending';
break;
- case PipelineStatus.RUNNING:
+ case 'RUNNING':
IconComponent = StatusRunning;
iconColor = DeployUtils.color.blue;
// title = 'Running';
break;
- case PipelineStatus.TERMINATING:
+ case 'TERMINATING':
IconComponent = StatusRunning;
iconColor = DeployUtils.color.blue;
// title = 'Terminating';
break;
- case PipelineStatus.SKIPPED:
+ case 'SKIPPED':
IconComponent = SkippedIcon;
// title = 'Skipped';
break;
- case PipelineStatus.SUCCEEDED:
+ case 'SUCCEEDED':
IconComponent = SuccessIcon;
iconColor = DeployUtils.color.success;
// title = 'Succeeded';
break;
- case PipelineStatus.TERMINATED:
+ case 'TERMINATED':
IconComponent = TerminatedIcon;
iconColor = DeployUtils.color.terminated;
// title = 'Terminated';
break;
- case PipelineStatus.UNKNOWN:
+ case 'UNKNOWN':
break;
default:
console.error('pipeline status:', pipeline.status);
@@ -220,7 +210,7 @@ export const DeployProgress: React.FunctionComponent<
uploadTpl = (
<React.Fragment>
<a
- href={getUploadLink(props.pipeline)}
+ href={getUploadLink(props)}
target="_blank"
rel="noopener noreferrer"
>
@@ -246,11 +236,11 @@ export const DeployProgress: React.FunctionComponent<
runTpl = (
<React.Fragment>
<a
- href={getRunLink(props.runPipeline)}
+ href={getRunLink(props.pipeline)}
target="_blank"
rel="noopener noreferrer"
>
- {getRunComponent(props.runPipeline)}
+ {props.pipeline && getRunComponent(props.pipeline)}
</a>
</React.Fragment>
);
diff --git a/labextension/src/widgets/deploys-progress/DeployUtils.tsx b/labextension/src/widgets/deploys-progress/DeployUtils.tsx
index 0645ba7..ff10e8b 100644
--- a/labextension/src/widgets/deploys-progress/DeployUtils.tsx
+++ b/labextension/src/widgets/deploys-progress/DeployUtils.tsx
@@ -51,7 +51,7 @@ export default class DeployUtils {
canceled: '#ff992a'
};
- public static getInfoBadge(title: string, content: any) {
+ public static getInfoBadge(title: string, content: string[]) {
return (
content && (
<a
@@ -65,7 +65,7 @@ export default class DeployUtils {
);
}
- public static getWarningBadge(title: string, content: any) {
+ public static getWarningBadge(title: string, content: string[] | undefined) {
return (
content && (
<a
diff --git a/labextension/src/widgets/deploys-progress/DeploysProgress.tsx b/labextension/src/widgets/deploys-progress/DeploysProgress.tsx
index 25e4bcb..20312c1 100644
--- a/labextension/src/widgets/deploys-progress/DeploysProgress.tsx
+++ b/labextension/src/widgets/deploys-progress/DeploysProgress.tsx
@@ -18,22 +18,21 @@ import * as React from 'react';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { DeployProgress } from './DeployProgress';
+import { Pipeline } from './Pipeline';
export type DeployProgressState = {
showValidationProgress?: boolean;
notebookValidation?: boolean;
- validationWarnings?: boolean;
- // showSnapshotProgress?: boolean;
- task?: any;
+ validationWarnings?: string[];
// snapshotWarnings?: any;
showCompileProgress?: boolean;
compiledPath?: string;
compileWarnings?: any;
showUploadProgress?: boolean;
- pipeline?: false | any;
+ pipeline?: Pipeline;
uploadWarnings?: any;
showRunProgress?: boolean;
- runPipeline?: any;
+ runPipeline?: boolean;
runWarnings?: any;
deleted?: boolean;
docManager?: IDocumentManager;
@@ -67,9 +66,6 @@ export const DeploysProgress: React.FunctionComponent<
showValidationProgress={dpState.showValidationProgress}
notebookValidation={dpState.notebookValidation}
validationWarnings={dpState.validationWarnings}
- // showSnapshotProgress={dpState.showSnapshotProgress}
- task={dpState.task}
- // snapshotWarnings={dpState.snapshotWarnings}
showCompileProgress={dpState.showCompileProgress}
compiledPath={dpState.compiledPath}
compileWarnings={dpState.compileWarnings}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment