Created
October 21, 2025 14:25
-
-
Save jesuino/0079dfe742457d817fe51e519cd20c44 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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