diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1e752b78d8..8f470dc456 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -28,7 +28,7 @@ Self checklist (all need to be checked): If you have UI changes: - [ ] Included any necessary screenshots or gifs if it was a UI change. -- [ ] Included tags to the UX team if it was a UI/UX change. +- [ ] Included tags to the UX team if it was a UI/UX change (find relevant UX in the [SMEs](https://github.com/opendatahub-io/odh-dashboard/tree/main/docs/smes.md) section). After the PR is posted & before it merges: - [ ] The developer has tested their solution on a cluster by using the image produced by the PR to `main` diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 81d7cdead6..97ad7b786d 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3.7.0 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} - name: Node.js modules cache, repository diff --git a/OWNERS b/OWNERS index 6cf86d8d1c..bf019d3d5f 100644 --- a/OWNERS +++ b/OWNERS @@ -1,8 +1,17 @@ approvers: - andrewballantyne +- lucferbux +- alexcreasy +- christianvogt reviewers: -- DaoDaoNoCode -- lucferbux -- Gkrumbach07 - alexcreasy +- christianvogt +- uidoyen +- Gkrumbach07 +- lucferbux +- DaoDaoNoCode +- manaswinidas +- pnaik1 +- ppadti +- dpanshug diff --git a/docs/smes.md b/docs/smes.md new file mode 100644 index 0000000000..614dc6d8d3 --- /dev/null +++ b/docs/smes.md @@ -0,0 +1,65 @@ +# Subject Matter Experts (SMEs) + +A given subject matter expert is not necessarily the most knowledgeable in the area, but they are the one who probably knows the most about it when it was originally done or has a responsibility to expand their knowledge to know about the area going forward. Contacting them first will help with delegation of responsibilities at the Dashboard level. + +This will detail out former (or current) feature leads, area leads (has a responsibility to understand the area), as well as any other notable position in relation to the area. If you need to talk to someone or ping someone for a review, this information should help you determine who. + +Below there will be some terms like “previous” and “backup”, these are for additional context. The way you can read each are as follows: +- **previous** – the initial SME in the area. If you need legacy context, this person may be able to help +- **backup** – a good person to lean on if there is a need for any 2nd opinions, for bouncing ideas off of, or any larger discussion about direction +- **and** – Ping both during conversations – could be onboarding, could be a need to share information, best get both people involved at the same time + +General Dashboard ownership +- Infrastructure / direction + - Architect: `Andrew` ([andrewballantyne]) + - General UX: `Kyle` ([kywalker-rh]) + - App Text: `Katie` ([kaedward]) +- Testing (Integration, Unit, etc) + - Area lead: `Gage` ([Gkrumbach07]) +- Performance + - Area lead: `Lucas` ([lucferbux]) + +Dashboard features +- Data Science Projects + - Feature lead: `Andrew` ([andrewballantyne]) + - UX: `Kyle` ([kywalker-rh]) **and** `Kun` ([xianli123]) +- Data Science Pipelines + - Feature lead: `Andrew` ([andrewballantyne]) + - UX: `Yan` ([yannnz]) + - Previous: `Kyle` ([kywalker-rh]) +- Explainability, Bias + - Feature lead: `Alex` ([alexcreasy]) + - UX: `Vince` ([vconzola]) +- Model Serving (Custom runtimes, general Model Serving) + - Feature lead: `Lucas` ([lucferbux]) + - UX: `Vince` ([vconzola]) +- Model Serving - Performance metrics + - Feature lead: `Andrew` ([andrewballantyne]) + - UX: `Vince` ([vconzola]) +- BYON - Custom Notebook Images + - Feature lead: `Juntao` ([DaoDaoNoCode]) + - Backup: `Andrew` ([andrewballantyne]) + - UX: `Vince` ([vconzola]) +- Habana / Accelerators + - Feature lead: `Gage` ([Gkrumbach07]); + - Backup: `Andrew` ([andrewballantyne]) + - UX: `Yan` ([yannnz]) +- Model Registry + - Feature lead: TBD + - UX: `Sim` ([simrandhaliw]) **and** `Haley` ([yih-wang]) + + +[andrewballantyne]: https://github.com/andrewballantyne +[Gkrumbach07]: https://github.com/Gkrumbach07 +[lucferbux]: https://github.com/lucferbux +[alexcreasy]: https://github.com/alexcreasy +[DaoDaoNoCode]: https://github.com/DaoDaoNoCode + + +[kywalker-rh]: https://github.com/kywalker-rh +[kaedward]: https://github.com/kaedward +[xianli123]: https://github.com/xianli123 +[vconzola]: https://github.com/vconzola +[yannnz]: https://github.com/yannnz +[simrandhaliw]: https://github.com/simrandhaliw +[yih-wang]: https://github.com/yih-wang diff --git a/frontend/config/webpack.common.js b/frontend/config/webpack.common.js index 419040148e..c59b65211c 100644 --- a/frontend/config/webpack.common.js +++ b/frontend/config/webpack.common.js @@ -219,7 +219,9 @@ module.exports = (env) => { }, ], }), - new MonacoWebpackPlugin(), + new MonacoWebpackPlugin({ + languages: ['yaml'], + }), ], resolve: { extensions: ['.js', '.ts', '.tsx', '.jsx'], diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b95d315985..a246363ff2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -129,9 +129,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", - "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==", "optional": true }, "node_modules/@ampproject/remapping": { diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index 89da2dde65..c42d128ec2 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -26,6 +26,7 @@ import { AppContext } from './AppContext'; import { useApplicationSettings } from './useApplicationSettings'; import TelemetrySetup from './TelemetrySetup'; import { logout } from './appUtils'; +import QuickStarts from './QuickStarts'; import './App.scss'; @@ -99,7 +100,9 @@ const App: React.FC = () => { > - + + + diff --git a/frontend/src/components/FormGroupSettings.tsx b/frontend/src/components/FormGroupSettings.tsx deleted file mode 100644 index 26626614d2..0000000000 --- a/frontend/src/components/FormGroupSettings.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import * as React from 'react'; -import { - FormGroup, - Text, - HelperText, - HelperTextItem, - Alert, - AlertActionCloseButton, - Hint, - HintBody, -} from '@patternfly/react-core'; -import { GroupsConfigField, MenuItemStatus } from '~/pages/groupSettings/groupTypes'; -import { MultiSelection } from './MultiSelection'; - -type FormGroupSettingsProps = { - title: string; - body: string; - groupsField: GroupsConfigField; - items: MenuItemStatus[]; - handleMenuItemSelection: (newState: MenuItemStatus[], field: GroupsConfigField) => void; - handleClose: () => void; - error?: string; -}; - -export const FormGroupSettings: React.FC = ({ - title, - body, - groupsField, - items, - handleMenuItemSelection, - handleClose, - error, -}) => ( - - {body} - handleMenuItemSelection(newState, groupsField)} - /> - {!error && ( - <> - - - {'View, edit, or create groups in OpenShift under User Management'} - - - {groupsField === GroupsConfigField.ADMIN && ( - - - {'All cluster admins are automatically assigned as Data Science administrators.'} - - - )} - - )} - {error && ( - } - > -

{error}

-
- )} -
-); diff --git a/frontend/src/concepts/pipelines/content/configurePipelinesServer/DatabaseConnectionInputField.tsx b/frontend/src/concepts/pipelines/content/configurePipelinesServer/DatabaseConnectionInputField.tsx deleted file mode 100644 index d18421c15b..0000000000 --- a/frontend/src/concepts/pipelines/content/configurePipelinesServer/DatabaseConnectionInputField.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as React from 'react'; -import { FormGroup, TextInput } from '@patternfly/react-core'; -import PasswordInput from '~/pages/projects/components/PasswordInput'; -import { DATABASE_CONNECTION_KEYS } from './const'; - -type DatabaseConnectionInputFieldProps = { - isPassword?: boolean; - isRequired: boolean; - onChange: (key: DATABASE_CONNECTION_KEYS, value: string) => void; - type: DATABASE_CONNECTION_KEYS; - value: string; -}; - -const DatabaseConnectionInputField: React.FC = ({ - isPassword, - isRequired, - onChange, - type, - value, -}) => { - const ComponentField = isPassword ? PasswordInput : TextInput; - - return ( - - onChange(type, value)} - /> - - ); -}; - -export default DatabaseConnectionInputField; diff --git a/frontend/src/concepts/pipelines/content/pipelinesDetails/PipelineDetailsYAML.tsx b/frontend/src/concepts/pipelines/content/pipelinesDetails/PipelineDetailsYAML.tsx index 8f7f2bda8a..8df1ae1ab4 100644 --- a/frontend/src/concepts/pipelines/content/pipelinesDetails/PipelineDetailsYAML.tsx +++ b/frontend/src/concepts/pipelines/content/pipelinesDetails/PipelineDetailsYAML.tsx @@ -33,6 +33,7 @@ const PipelineDetailsYAML: React.FC = ({ filename, con isCopyEnabled isLanguageLabelVisible language={Language.yaml} + isReadOnly /> ); }; diff --git a/frontend/src/concepts/pipelines/topology/core/TaskEdge.tsx b/frontend/src/concepts/pipelines/topology/core/TaskEdge.tsx new file mode 100644 index 0000000000..aa243cdade --- /dev/null +++ b/frontend/src/concepts/pipelines/topology/core/TaskEdge.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Topology/topology-components'; +import { + observer, + Edge, + integralShapePath, + DEFAULT_SPACER_NODE_TYPE, + ConnectorArrow, +} from '@patternfly/react-topology'; +interface TaskEdgeProps { + element: Edge; + className?: string; + nodeSeparation?: number; +} + +const TaskEdge: React.FunctionComponent = ({ + element, + className, + nodeSeparation, +}) => { + const startPoint = element.getStartPoint(); + const endPoint = element.getEndPoint(); + const groupClassName = css(styles.topologyEdge, className); + const startIndent: number = element.getData()?.indent || 0; + + return ( + + + + {element.getTarget().getType() !== DEFAULT_SPACER_NODE_TYPE ? ( + + ) : null} + + ); +}; + +export default observer(TaskEdge); diff --git a/frontend/src/concepts/pipelines/topology/core/factories.ts b/frontend/src/concepts/pipelines/topology/core/factories.ts index 90f4aca898..2156503a37 100644 --- a/frontend/src/concepts/pipelines/topology/core/factories.ts +++ b/frontend/src/concepts/pipelines/topology/core/factories.ts @@ -6,12 +6,11 @@ import { GraphComponent, ModelKind, SpacerNode, - TaskEdge, withPanZoom, withSelection, } from '@patternfly/react-topology'; import StandardTaskNode from '~/concepts/pipelines/topology/core/customNodes/StandardTaskNode'; - +import TaskEdge from './TaskEdge'; // Topology gap... their types have issues with Strict TS mode // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/frontend/src/concepts/secrets/apiHooks/useSecret.ts b/frontend/src/concepts/secrets/apiHooks/useSecret.ts deleted file mode 100644 index a4c0a79175..0000000000 --- a/frontend/src/concepts/secrets/apiHooks/useSecret.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; -import useFetchState, { FetchStateCallbackPromise, NotReadyError } from '~/utilities/useFetchState'; -import { getSecret } from '~/api'; -import { SecretKind } from '~/k8sTypes'; - -const useSecret = (name: string | null, namespace: string) => { - const callback = React.useCallback>( - (opts) => { - if (!name) { - return Promise.reject(new NotReadyError('Secret name is missing')); - } - return getSecret(namespace, name, opts); - }, - [name, namespace], - ); - - return useFetchState(callback, null); -}; - -export default useSecret; diff --git a/frontend/src/pages/enabledApplications/EnabledApplications.tsx b/frontend/src/pages/enabledApplications/EnabledApplications.tsx index e112137016..8114c42d3b 100644 --- a/frontend/src/pages/enabledApplications/EnabledApplications.tsx +++ b/frontend/src/pages/enabledApplications/EnabledApplications.tsx @@ -5,7 +5,6 @@ import { useWatchComponents } from '~/utilities/useWatchComponents'; import { OdhApplication } from '~/types'; import ApplicationsPage from '~/pages/ApplicationsPage'; import OdhAppCard from '~/components/OdhAppCard'; -import QuickStarts from '~/app/QuickStarts'; import { fireTrackingEvent } from '~/utilities/segmentIOUtils'; const description = `Launch your enabled applications, view documentation, or get started with quick start instructions and tasks.`; @@ -74,13 +73,7 @@ const EnabledApplications: React.FC = () => { }, [components, loaded]); return ( - - - + ); }; diff --git a/frontend/src/pages/learningCenter/LearningCenter.tsx b/frontend/src/pages/learningCenter/LearningCenter.tsx index 17e5a7a8b9..5a778ccaaf 100644 --- a/frontend/src/pages/learningCenter/LearningCenter.tsx +++ b/frontend/src/pages/learningCenter/LearningCenter.tsx @@ -9,7 +9,6 @@ import { useWatchDocs } from '~/utilities/useWatchDocs'; import { useBrowserStorage } from '~/components/browserStorage'; import { useQueryParams } from '~/utilities/useQueryParams'; import ApplicationsPage from '~/pages/ApplicationsPage'; -import QuickStarts from '~/app/QuickStarts'; import { DOC_LINK, ODH_PRODUCT_NAME } from '~/utilities/const'; import { combineCategoryAnnotations } from '~/utilities/utils'; import { useDeepCompareMemoize } from '~/utilities/useDeepCompareMemoize'; @@ -230,10 +229,4 @@ export const LearningCenter: React.FC = () => { ); }; -const LearningCenterWrapper: React.FC = () => ( - - - -); - -export default LearningCenterWrapper; +export default LearningCenter; diff --git a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAddTemplate.tsx b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAddTemplate.tsx index bb42ff04a0..47fac284d0 100644 --- a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAddTemplate.tsx +++ b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAddTemplate.tsx @@ -21,7 +21,10 @@ import { createServingRuntimeTemplateBackend, updateServingRuntimeTemplateBackend, } from '~/services/templateService'; -import { getServingRuntimeDisplayNameFromTemplate } from './utils'; +import { + getServingRuntimeDisplayNameFromTemplate, + getServingRuntimeNameFromTemplate, +} from './utils'; import { CustomServingRuntimeContext } from './CustomServingRuntimeContext'; type CustomServingRuntimeAddTemplateProps = { @@ -33,13 +36,35 @@ const CustomServingRuntimeAddTemplate: React.FC { const { dashboardNamespace } = useDashboardNamespace(); const { refreshData } = React.useContext(CustomServingRuntimeContext); - const { state } = useLocation(); + const { state }: { state?: { template: TemplateKind } } = useLocation(); + + const copiedServingRuntimeString = React.useMemo( + () => + state + ? YAML.stringify({ + ...state.template.objects[0], + metadata: { + ...state.template.objects[0].metadata, + name: `${getServingRuntimeNameFromTemplate(state.template)}-copy`, + annotations: { + ...state.template.objects[0].metadata.annotations, + 'openshift.io/display-name': `Copy of ${getServingRuntimeDisplayNameFromTemplate( + state.template, + )}`, + 'openshift.io/description': + state.template.objects[0].metadata.annotations?.['openshift.io/description'], + }, + }, + }) + : '', + [state], + ); - const stringifiedTemplate = existingTemplate - ? YAML.stringify(existingTemplate.objects[0]) - : state - ? YAML.stringify(state.template) - : ''; + const stringifiedTemplate = React.useMemo( + () => + existingTemplate ? YAML.stringify(existingTemplate.objects[0]) : copiedServingRuntimeString, + [copiedServingRuntimeString, existingTemplate], + ); const [code, setCode] = React.useState(stringifiedTemplate); const [loading, setIsLoading] = React.useState(false); const [error, setError] = React.useState(undefined); @@ -108,7 +133,7 @@ const CustomServingRuntimeAddTemplate: React.FC diff --git a/frontend/src/pages/projects/components/PVSizeField.tsx b/frontend/src/pages/projects/components/PVSizeField.tsx index b6352fecf5..bf22b92c89 100644 --- a/frontend/src/pages/projects/components/PVSizeField.tsx +++ b/frontend/src/pages/projects/components/PVSizeField.tsx @@ -21,7 +21,7 @@ const PVSizeField: React.FC = ({ fieldID, size, setSize, curre label="Persistent storage size" helperText={ currentSize - ? "Increase the capacity of storage data. Note that capacity can't be less than the current storage size. This can be a time-consuming process." + ? 'Storage size can only be increased. If you do so, the workbench will restart and be unavailable for a period of time that is usually proportional to the size change.' : '' } helperTextIcon={} diff --git a/frontend/src/pages/projects/notebook/NotebookStatusToggle.tsx b/frontend/src/pages/projects/notebook/NotebookStatusToggle.tsx index 83b54db070..cc63f9c3a6 100644 --- a/frontend/src/pages/projects/notebook/NotebookStatusToggle.tsx +++ b/frontend/src/pages/projects/notebook/NotebookStatusToggle.tsx @@ -8,7 +8,7 @@ import { computeNotebooksTolerations } from '~/utilities/tolerations'; import { useAppContext } from '~/app/AppContext'; import { currentlyHasPipelines } from '~/concepts/pipelines/elyra/utils'; import { NotebookState } from './types'; -import useRefreshNotebookUntilStart from './useRefreshNotebookUntilStart'; +import useRefreshNotebookUntilStartOrStop from './useRefreshNotebookUntilStartOrStop'; import StopNotebookConfirmModal from './StopNotebookConfirmModal'; import useStopNotebookModalAvailability from './useStopNotebookModalAvailability'; import NotebookStatusText from './NotebookStatusText'; @@ -24,12 +24,12 @@ const NotebookStatusToggle: React.FC = ({ doListen, enablePipelines, }) => { - const { notebook, isStarting, isRunning, refresh } = notebookState; + const { notebook, isStarting, isRunning, isStopping, refresh } = notebookState; const gpuNumber = useNotebookGPUNumber(notebook); const { size } = useNotebookDeploymentSize(notebook); const [isOpenConfirm, setOpenConfirm] = React.useState(false); const [inProgress, setInProgress] = React.useState(false); - const listenToNotebookStart = useRefreshNotebookUntilStart(notebookState, doListen); + const listenToNotebookStart = useRefreshNotebookUntilStartOrStop(notebookState, doListen); const [dontShowModalValue] = useStopNotebookModalAvailability(); const { dashboardConfig } = useAppContext(); const notebookName = notebook.metadata.name; @@ -42,8 +42,8 @@ const NotebookStatusToggle: React.FC = ({ let label = ''; if (isStarting) { label = 'Starting...'; - } else if (inProgress) { - label = isChecked ? 'Starting...' : 'Stopping...'; + } else if (isStopping) { + label = 'Stopping...'; } else { label = isRunning ? 'Running' : 'Stopped'; } @@ -72,7 +72,7 @@ const NotebookStatusToggle: React.FC = ({ setInProgress(true); stopNotebook(notebookName, notebookNamespace).then(() => { refresh().then(() => setInProgress(false)); - listenToNotebookStart(false); + listenToNotebookStart(true, true); }); }, [notebookName, notebookNamespace, refresh, listenToNotebookStart, fireNotebookTrackingEvent]); @@ -82,7 +82,7 @@ const NotebookStatusToggle: React.FC = ({ { diff --git a/frontend/src/pages/projects/notebook/service.ts b/frontend/src/pages/projects/notebook/service.ts index 550b087a49..c7bb080223 100644 --- a/frontend/src/pages/projects/notebook/service.ts +++ b/frontend/src/pages/projects/notebook/service.ts @@ -34,6 +34,8 @@ export const getNotebooksStatus = async ( notebook: notebooks[i], isStarting: !isStopped && !podsReady, isRunning: !isStopped && podsReady, + isStopping: isStopped && podsReady, + isStopped: isStopped && !podsReady, runningPodUid: pods[0]?.metadata?.uid || '', }, ]; diff --git a/frontend/src/pages/projects/notebook/types.ts b/frontend/src/pages/projects/notebook/types.ts index 5046993f6b..d8d889905d 100644 --- a/frontend/src/pages/projects/notebook/types.ts +++ b/frontend/src/pages/projects/notebook/types.ts @@ -5,6 +5,8 @@ export type NotebookDataState = { notebook: NotebookKind; isStarting: boolean; isRunning: boolean; + isStopping: boolean; + isStopped: boolean; runningPodUid: string; }; diff --git a/frontend/src/pages/projects/notebook/useRefreshNotebookUntilStart.ts b/frontend/src/pages/projects/notebook/useRefreshNotebookUntilStartOrStop.ts similarity index 59% rename from frontend/src/pages/projects/notebook/useRefreshNotebookUntilStart.ts rename to frontend/src/pages/projects/notebook/useRefreshNotebookUntilStartOrStop.ts index a005745447..7d4f9455ab 100644 --- a/frontend/src/pages/projects/notebook/useRefreshNotebookUntilStart.ts +++ b/frontend/src/pages/projects/notebook/useRefreshNotebookUntilStartOrStop.ts @@ -2,11 +2,12 @@ import * as React from 'react'; import { FAST_POLL_INTERVAL } from '~/utilities/const'; import { NotebookState } from './types'; -const useRefreshNotebookUntilStart = ( +const useRefreshNotebookUntilStartOrStop = ( notebookState: NotebookState, doListen: boolean, -): ((listen: boolean) => void) => { +): ((listen: boolean, stop?: boolean) => void) => { const [watchingForNotebook, setWatchingForNotebook] = React.useState(false); + const [watchingForStop, setWatchingForStop] = React.useState(false); const lastNotebookState = React.useRef(notebookState); lastNotebookState.current = notebookState; @@ -14,8 +15,9 @@ const useRefreshNotebookUntilStart = ( let interval: ReturnType; if (watchingForNotebook && doListen) { interval = setInterval(() => { - const { isRunning, refresh } = lastNotebookState.current; - if (!isRunning) { + const { isRunning, isStopped, refresh } = lastNotebookState.current; + const condition = watchingForStop ? isStopped : isRunning; + if (!condition) { refresh().catch((e) => { /* eslint-disable-next-line no-console */ console.error('Error refreshing, stopping notebook refresh', e); @@ -30,11 +32,15 @@ const useRefreshNotebookUntilStart = ( return () => { clearInterval(interval); }; - }, [watchingForNotebook, doListen]); + }, [watchingForStop, watchingForNotebook, doListen]); - return React.useCallback((listen: boolean) => { + /** + * The second parameter allows listening for the notebook to be stopped. Default is to wait until started. + */ + return React.useCallback((listen: boolean, waitForStop = false) => { + setWatchingForStop(waitForStop); setWatchingForNotebook(listen); }, []); }; -export default useRefreshNotebookUntilStart; +export default useRefreshNotebookUntilStartOrStop; diff --git a/frontend/src/pages/projects/screens/detail/ProjectDetailsComponents.tsx b/frontend/src/pages/projects/screens/detail/ProjectDetailsComponents.tsx index 6f0126e7b8..29e7803662 100644 --- a/frontend/src/pages/projects/screens/detail/ProjectDetailsComponents.tsx +++ b/frontend/src/pages/projects/screens/detail/ProjectDetailsComponents.tsx @@ -12,7 +12,6 @@ import { ProjectSectionID } from './types'; import StorageList from './storage/StorageList'; import { ProjectSectionTitles } from './const'; import DataConnectionsList from './data-connections/DataConnectionsList'; -import useCheckLogoutParams from './useCheckLogoutParams'; type SectionType = { id: ProjectSectionID; @@ -36,7 +35,6 @@ const ProjectDetailsComponents: React.FC = () => { const pipelinesEnabled = featureFlagEnabled(dashboardConfig.spec.dashboardConfig.disablePipelines) && dashboardConfig.status.dependencyOperators.redhatOpenshiftPipelines.available; - useCheckLogoutParams(); const sections: SectionType[] = [ { diff --git a/frontend/src/pages/projects/screens/detail/notebooks/NotebookTableRow.tsx b/frontend/src/pages/projects/screens/detail/notebooks/NotebookTableRow.tsx index c54bcede43..979a5c1e23 100644 --- a/frontend/src/pages/projects/screens/detail/notebooks/NotebookTableRow.tsx +++ b/frontend/src/pages/projects/screens/detail/notebooks/NotebookTableRow.tsx @@ -94,7 +94,7 @@ const NotebookTableRow: React.FC = ({ { navigate( diff --git a/frontend/src/pages/projects/screens/detail/useCheckLogoutParams.ts b/frontend/src/pages/projects/screens/detail/useCheckLogoutParams.ts index 7f160015eb..bfad924785 100644 --- a/frontend/src/pages/projects/screens/detail/useCheckLogoutParams.ts +++ b/frontend/src/pages/projects/screens/detail/useCheckLogoutParams.ts @@ -17,7 +17,7 @@ const useCheckLogoutParams = (): void => { React.useEffect(() => { const deleteLogoutParam = () => { queryParams.delete('notebookLogout'); - setQueryParams(queryParams); + setQueryParams(queryParams, { replace: true }); }; if (notebookLogout) { if (notebook) { diff --git a/frontend/src/pages/projects/screens/spawner/storage/useNotebookRootStorage.ts b/frontend/src/pages/projects/screens/spawner/storage/useNotebookRootStorage.ts deleted file mode 100644 index 7770636ced..0000000000 --- a/frontend/src/pages/projects/screens/spawner/storage/useNotebookRootStorage.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react'; -import { getPvc } from '~/api'; -import { NotebookKind, PersistentVolumeClaimKind } from '~/k8sTypes'; -import { ROOT_MOUNT_PATH } from '~/pages/projects/pvc/const'; - -const useNotebookRootStorage = (notebook?: NotebookKind): PersistentVolumeClaimKind | undefined => { - const [pvc, setPvc] = React.useState(); - - React.useEffect(() => { - if (notebook) { - const volumeMounts = notebook.spec.template.spec.containers[0].volumeMounts || []; - const volumeMount = volumeMounts.find( - (volumeMount) => volumeMount.mountPath === ROOT_MOUNT_PATH, - ); - if (!volumeMount) { - /* eslint-disable-next-line no-console */ - console.error('No storage mounted on root path'); - setPvc(undefined); - } else { - getPvc(notebook.metadata.namespace, volumeMount.name).then((pvc) => setPvc(pvc)); - } - } - }, [notebook]); - - return pvc; -}; - -export default useNotebookRootStorage; diff --git a/frontend/src/pages/projects/typeHelpers.ts b/frontend/src/pages/projects/typeHelpers.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frontend/src/utilities/imageUtils.ts b/frontend/src/utilities/imageUtils.ts index 5870c3ac83..d2bda5123b 100644 --- a/frontend/src/utilities/imageUtils.ts +++ b/frontend/src/utilities/imageUtils.ts @@ -139,7 +139,7 @@ export const getImageTagVersion = ( if (image?.tags.length > 1) { const defaultTag = getDefaultTag(buildStatuses, image); if (image.name === selectedImage && selectedTag) { - return `${selectedTag} ${selectedTag === defaultTag?.name ? ' (default)' : ''}`; + return selectedTag; } return defaultTag?.name ?? image.tags[0].name; } diff --git a/frontend/src/utilities/useDebounce.ts b/frontend/src/utilities/useDebounce.ts deleted file mode 100644 index cb0f7c0fdc..0000000000 --- a/frontend/src/utilities/useDebounce.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; - -function useDebounce(value: T, delay?: number): T { - const [debouncedValue, setDebouncedValue] = React.useState(value); - - React.useEffect(() => { - const timer = setTimeout(() => setDebouncedValue(value), delay || 500); - - return () => { - clearTimeout(timer); - }; - }, [value, delay]); - - return debouncedValue; -} - -export default useDebounce;