diff --git a/frontend/src/api/k8s/notebooks.ts b/frontend/src/api/k8s/notebooks.ts index 8c1ddb8d80..d9ce73acd2 100644 --- a/frontend/src/api/k8s/notebooks.ts +++ b/frontend/src/api/k8s/notebooks.ts @@ -384,6 +384,7 @@ export const attachNotebookPVC = ( namespace: string, pvcName: string, mountSuffix: string, + opts?: K8sAPIOptions, ): Promise => { const patches: Patch[] = [ { @@ -399,17 +400,20 @@ export const attachNotebookPVC = ( }, ]; - return k8sPatchResource({ - model: NotebookModel, - queryOptions: { name: notebookName, ns: namespace }, - patches, - }); + return k8sPatchResource( + applyK8sAPIOptions(opts, { + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }), + ); }; export const removeNotebookPVC = ( notebookName: string, namespace: string, pvcName: string, + opts?: K8sAPIOptions, ): Promise => new Promise((resolve, reject) => { getNotebook(notebookName, namespace) @@ -438,11 +442,13 @@ export const removeNotebookPVC = ( }, ]; - k8sPatchResource({ - model: NotebookModel, - queryOptions: { name: notebookName, ns: namespace }, - patches, - }) + k8sPatchResource( + applyK8sAPIOptions(opts, { + model: NotebookModel, + queryOptions: { name: notebookName, ns: namespace }, + patches, + }), + ) .then(resolve) .catch(reject); }) diff --git a/frontend/src/api/k8s/pvcs.ts b/frontend/src/api/k8s/pvcs.ts index 9fe9a16f96..62614c0f9f 100644 --- a/frontend/src/api/k8s/pvcs.ts +++ b/frontend/src/api/k8s/pvcs.ts @@ -1,47 +1,59 @@ +import * as _ from 'lodash'; import { k8sCreateResource, k8sDeleteResource, k8sGetResource, k8sListResourceItems, k8sPatchResource, + k8sUpdateResource, } from '@openshift/dynamic-plugin-sdk-utils'; -import { K8sStatus, KnownLabels, PersistentVolumeClaimKind } from '~/k8sTypes'; +import { K8sAPIOptions, K8sStatus, KnownLabels, PersistentVolumeClaimKind } from '~/k8sTypes'; import { PVCModel } from '~/api/models'; import { translateDisplayNameForK8s } from '~/pages/projects/utils'; import { LABEL_SELECTOR_DASHBOARD_RESOURCE } from '~/const'; +import { applyK8sAPIOptions } from '~/api/apiMergeUtils'; +import { CreatingStorageObject } from '~/pages/projects/types'; export const assemblePvc = ( - pvcName: string, - projectName: string, - description: string, - pvcSize: number, -): PersistentVolumeClaimKind => ({ - apiVersion: 'v1', - kind: 'PersistentVolumeClaim', - metadata: { - name: translateDisplayNameForK8s(pvcName), - namespace: projectName, - labels: { - [KnownLabels.DASHBOARD_RESOURCE]: 'true', - }, - annotations: { - 'openshift.io/display-name': pvcName.trim(), - 'openshift.io/description': description, + data: CreatingStorageObject, + namespace: string, + editName?: string, +): PersistentVolumeClaimKind => { + const { + nameDesc: { name: pvcName, description }, + size, + } = data; + + const name = editName || translateDisplayNameForK8s(pvcName); + + return { + apiVersion: 'v1', + kind: 'PersistentVolumeClaim', + metadata: { + name, + namespace, + labels: { + [KnownLabels.DASHBOARD_RESOURCE]: 'true', + }, + annotations: { + 'openshift.io/display-name': pvcName.trim(), + 'openshift.io/description': description, + }, }, - }, - spec: { - accessModes: ['ReadWriteOnce'], - resources: { - requests: { - storage: `${pvcSize}Gi`, + spec: { + accessModes: ['ReadWriteOnce'], + resources: { + requests: { + storage: size, + }, }, + volumeMode: 'Filesystem', + }, + status: { + phase: 'Pending', }, - volumeMode: 'Filesystem', - }, - status: { - phase: 'Pending', - }, -}); + }; +}; export const getPvc = (projectName: string, pvcName: string): Promise => k8sGetResource({ @@ -68,42 +80,30 @@ export const getAvailableMultiUsePvcs = ( }), ); -export const createPvc = (data: PersistentVolumeClaimKind): Promise => - k8sCreateResource({ model: PVCModel, resource: data }); - -export const updatePvcDisplayName = ( - pvcName: string, +export const createPvc = ( + data: CreatingStorageObject, namespace: string, - displayName: string, -): Promise => - k8sPatchResource({ - model: PVCModel, - queryOptions: { name: pvcName, ns: namespace }, - patches: [ - { - op: 'replace', - path: '/metadata/annotations/openshift.io~1display-name', - value: displayName, - }, - ], - }); + opts?: K8sAPIOptions, +): Promise => { + const pvc = assemblePvc(data, namespace); -export const updatePvcDescription = ( - pvcName: string, + return k8sCreateResource( + applyK8sAPIOptions(opts, { model: PVCModel, resource: pvc }), + ); +}; + +export const updatePvc = ( + data: CreatingStorageObject, + existingData: PersistentVolumeClaimKind, namespace: string, - description: string, -): Promise => - k8sPatchResource({ - model: PVCModel, - queryOptions: { name: pvcName, ns: namespace }, - patches: [ - { - op: 'replace', - path: '/metadata/annotations/openshift.io~1description', - value: description, - }, - ], - }); + opts?: K8sAPIOptions, +): Promise => { + const pvc = assemblePvc(data, namespace, existingData.metadata.name); + + return k8sUpdateResource( + applyK8sAPIOptions(opts, { model: PVCModel, resource: _.merge({}, existingData, pvc) }), + ); +}; export const deletePvc = (pvcName: string, namespace: string): Promise => k8sDeleteResource({ @@ -115,17 +115,20 @@ export const updatePvcSize = ( pvcName: string, namespace: string, size: string, + opts?: K8sAPIOptions, ): Promise => - k8sPatchResource({ - model: PVCModel, - queryOptions: { name: pvcName, ns: namespace }, - patches: [ - { - op: 'replace', - path: '/spec/resources/requests', - value: { - storage: size, + k8sPatchResource( + applyK8sAPIOptions(opts, { + model: PVCModel, + queryOptions: { name: pvcName, ns: namespace }, + patches: [ + { + op: 'replace', + path: '/spec/resources/requests', + value: { + storage: size, + }, }, - }, - ], - }); + ], + }), + ); diff --git a/frontend/src/app/App.scss b/frontend/src/app/App.scss index 5167531596..a0cdb25bfc 100644 --- a/frontend/src/app/App.scss +++ b/frontend/src/app/App.scss @@ -1,4 +1,6 @@ -html, body, #root { +html, +body, +#root { height: 100%; } @@ -14,19 +16,25 @@ html, body, #root { flex: 1; margin: var(--pf-global--spacer--md); } + .pf-c-app-launcher__group-title { font-size: 13px; } + .pf-c-app-launcher__menu-item-external-icon { opacity: 1; color: var(--pf-global--icon--Color--light); } + &__brand { height: 36px; } } + // specificity targeting form elements to override --pf-global--FontSize--md -.pf-c-page, .pf-c-modal-box { +.pf-c-page, +.pf-c-modal-box { + .pf-c-app-launcher, .pf-c-button, .pf-c-dropdown, @@ -41,3 +49,13 @@ html, body, #root { height: auto; } } + +// temp fix until https://github.com/patternfly/patternfly-react/issues/8028 is resolved +// Remove this file and its uses after bumping to PF5 +.checkbox-radio-fix-body-width { + + .pf-c-check__body, + .pf-c-radio__body { + width: 100%; + } +} \ No newline at end of file diff --git a/frontend/src/components/ValueUnitField.tsx b/frontend/src/components/ValueUnitField.tsx index f4de70994e..0a639fe7a6 100644 --- a/frontend/src/components/ValueUnitField.tsx +++ b/frontend/src/components/ValueUnitField.tsx @@ -37,6 +37,7 @@ const ValueUnitField: React.FC = ({ setOpen(!open)}> {currentUnitOption.name} diff --git a/frontend/src/pages/clusterSettings/ClusterSettings.tsx b/frontend/src/pages/clusterSettings/ClusterSettings.tsx index f8a20e6be3..7f17fef4a5 100644 --- a/frontend/src/pages/clusterSettings/ClusterSettings.tsx +++ b/frontend/src/pages/clusterSettings/ClusterSettings.tsx @@ -25,7 +25,7 @@ const ClusterSettings: React.FC = () => { const [saving, setSaving] = React.useState(false); const [loadError, setLoadError] = React.useState(); const [clusterSettings, setClusterSettings] = React.useState(DEFAULT_CONFIG); - const [pvcSize, setPvcSize] = React.useState(DEFAULT_PVC_SIZE); + const [pvcSize, setPvcSize] = React.useState(DEFAULT_PVC_SIZE); const [userTrackingEnabled, setUserTrackingEnabled] = React.useState(false); const [cullerTimeout, setCullerTimeout] = React.useState(DEFAULT_CULLER_TIMEOUT); const { dashboardConfig } = useAppContext(); diff --git a/frontend/src/pages/clusterSettings/PVCSizeSettings.tsx b/frontend/src/pages/clusterSettings/PVCSizeSettings.tsx index 0195977829..d10fd1bd43 100644 --- a/frontend/src/pages/clusterSettings/PVCSizeSettings.tsx +++ b/frontend/src/pages/clusterSettings/PVCSizeSettings.tsx @@ -15,9 +15,9 @@ import SettingSection from '~/components/SettingSection'; import { DEFAULT_PVC_SIZE, MAX_PVC_SIZE, MIN_PVC_SIZE } from './const'; type PVCSizeSettingsProps = { - initialValue: number | string; - pvcSize: number | string; - setPvcSize: (size: number | string) => void; + initialValue: number; + pvcSize: number; + setPvcSize: (size: number) => void; }; const PVCSizeSettings: React.FC = ({ initialValue, pvcSize, setPvcSize }) => { @@ -57,7 +57,7 @@ all users." : newValue; setPvcSize(newValue); } else { - setPvcSize(modifiedValue); + setPvcSize(0); } }} /> @@ -79,8 +79,8 @@ all users." Note: PVC size must be between 1 GiB and 16384 GiB. diff --git a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionSection.tsx b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionSection.tsx index 86f5ebd55b..39800aaae3 100644 --- a/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionSection.tsx @@ -7,7 +7,6 @@ import { } from '~/pages/modelServing/screens/types'; import AWSField from '~/pages/projects/dataConnections/AWSField'; import useDataConnections from '~/pages/projects/screens/detail/data-connections/useDataConnections'; -import '~/pages/projects/screens/detail/storage/ManageStorageModal.scss'; import DataConnectionExistingField from './DataConnectionExistingField'; import DataConnectionFolderPathField from './DataConnectionFolderPathField'; diff --git a/frontend/src/pages/notebookController/const.ts b/frontend/src/pages/notebookController/const.ts index d28a998ba1..40f2b4042f 100644 --- a/frontend/src/pages/notebookController/const.ts +++ b/frontend/src/pages/notebookController/const.ts @@ -2,7 +2,6 @@ import { NotebookControllerUserState } from '~/types'; export const CUSTOM_VARIABLE = 'Custom variable'; export const EMPTY_KEY = '---NO KEY---'; -export const DEFAULT_PVC_SIZE = '20Gi'; export const CURRENT_BROWSER_TAB_PREFERENCE = 'odh.dashboard.kfnbc.tab.preference'; export const ENV_VAR_NAME_REGEX = new RegExp('^[-._a-zA-Z][-._a-zA-Z0-9]*$'); export const EMPTY_USER_STATE: NotebookControllerUserState = { diff --git a/frontend/src/pages/projects/components/PVSizeField.tsx b/frontend/src/pages/projects/components/PVSizeField.tsx index 4e8366515b..b30aa31ac0 100644 --- a/frontend/src/pages/projects/components/PVSizeField.tsx +++ b/frontend/src/pages/projects/components/PVSizeField.tsx @@ -1,59 +1,35 @@ import * as React from 'react'; -import { FormGroup, InputGroup, InputGroupText, NumberInput } from '@patternfly/react-core'; +import { FormGroup } from '@patternfly/react-core'; import { ExclamationTriangleIcon } from '@patternfly/react-icons'; -import { isHTMLInputElement } from '~/utilities/utils'; +import ValueUnitField from '~/components/ValueUnitField'; +import { MEMORY_UNITS } from '~/utilities/valueUnits'; type PVSizeFieldProps = { fieldID: string; - size: number; - setSize: (size: number) => void; + size: string; + setSize: (size: string) => void; currentSize?: string; }; -const PVSizeField: React.FC = ({ fieldID, size, setSize, currentSize }) => { - const minSize = parseInt(currentSize || '') || 1; - - const onStep = (step: number) => { - setSize(Math.max(size + step, minSize)); - }; - return ( - } - validated={currentSize ? 'warning' : 'default'} - fieldId={fieldID} - > - - onStep(1)} - onMinus={() => onStep(-1)} - onChange={(event) => { - if (isHTMLInputElement(event.target)) { - const newSize = Number(event.target.value); - setSize(isNaN(newSize) ? size : newSize); - } - }} - onBlur={(event) => { - if (isHTMLInputElement(event.target)) { - const blurSize = Number(event.target.value); - setSize(Math.max(blurSize, minSize)); - } - }} - /> - GiB - - - ); -}; +const PVSizeField: React.FC = ({ fieldID, size, setSize, currentSize }) => ( + } + validated={currentSize ? 'warning' : 'default'} + fieldId={fieldID} + > + setSize(value)} + options={MEMORY_UNITS} + value={size} + /> + +); export default PVSizeField; diff --git a/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.scss b/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.scss deleted file mode 100644 index 31610106aa..0000000000 --- a/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.scss +++ /dev/null @@ -1,12 +0,0 @@ -// temp fix until https://github.com/patternfly/patternfly-react/issues/8028 is resolved -.checkbox-radio-fix-body-width-50 { - .pf-c-check__body, .pf-c-radio__body { - width: 50%; - } -} - -.checkbox-radio-fix-body-width { - .pf-c-check__body, .pf-c-radio__body { - width: 100%; - } -} diff --git a/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.tsx b/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.tsx index d007c90736..59334b0eaa 100644 --- a/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.tsx +++ b/frontend/src/pages/projects/screens/detail/storage/ManageStorageModal.tsx @@ -1,14 +1,6 @@ import * as React from 'react'; -import { Alert, Button, Form, Modal, Stack, StackItem } from '@patternfly/react-core'; -import { - assemblePvc, - attachNotebookPVC, - createPvc, - removeNotebookPVC, - updatePvcDescription, - updatePvcDisplayName, - updatePvcSize, -} from '~/api'; +import { Form, Modal, Stack, StackItem } from '@patternfly/react-core'; +import { attachNotebookPVC, createPvc, removeNotebookPVC, updatePvc } from '~/api'; import { NotebookKind, PersistentVolumeClaimKind } from '~/k8sTypes'; import { ProjectDetailsContext } from '~/pages/projects/ProjectDetailsContext'; import { useCreateStorageObjectForNotebook } from '~/pages/projects/screens/spawner/storage/utils'; @@ -17,13 +9,12 @@ import StorageNotebookConnections from '~/pages/projects/notebook/StorageNoteboo import useRelatedNotebooks, { ConnectedNotebookContext, } from '~/pages/projects/notebook/useRelatedNotebooks'; -import { getPvcDescription, getPvcDisplayName, getPvcTotalSize } from '~/pages/projects/utils'; import NotebookRestartAlert from '~/pages/projects/components/NotebookRestartAlert'; import useWillNotebooksRestart from '~/pages/projects/notebook/useWillNotebooksRestart'; +import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; +import { getPvcDescription, getPvcDisplayName } from '~/pages/projects/utils'; import ExistingConnectedNotebooks from './ExistingConnectedNotebooks'; -import './ManageStorageModal.scss'; - type AddStorageModalProps = { existingData?: PersistentVolumeClaimKind; isOpen: boolean; @@ -52,6 +43,7 @@ const ManageStorageModal: React.FC = ({ existingData, isOp onClose(submitted); setActionInProgress(false); setRemovedNotebooks([]); + setError(undefined); resetData(); }; @@ -61,72 +53,60 @@ const ManageStorageModal: React.FC = ({ existingData, isOp const canCreate = !actionInProgress && createData.nameDesc.name.trim() && hasValidNotebookRelationship; - const submit = async () => { - setError(undefined); - setActionInProgress(true); - + const runPromiseActions = async (dryRun: boolean) => { const { - nameDesc: { name, description }, - size, forNotebook: { name: notebookName, mountPath }, } = createData; - - const pvc = assemblePvc(name, namespace, description, size); - - const handleError = (e: Error) => { - setError(e); - setActionInProgress(false); - }; - const handleNotebookNameConnection = (pvcName: string) => { - if (notebookName) { - attachNotebookPVC(notebookName, namespace, pvcName, mountPath.value) - .then(() => { - setActionInProgress(false); - onBeforeClose(true); - }) - .catch((e) => { - setError(e); - setActionInProgress(false); - }); - } else { - setActionInProgress(false); - onBeforeClose(true); - } - }; - + const pvcPromises: Promise[] = []; if (existingData) { const pvcName = existingData.metadata.name; - if (getPvcDisplayName(existingData) !== createData.nameDesc.name) { - await updatePvcDisplayName(pvcName, namespace, createData.nameDesc.name); - } - if (getPvcDescription(existingData) !== createData.nameDesc.description) { - await updatePvcDescription(pvcName, namespace, createData.nameDesc.description); + if ( + getPvcDisplayName(existingData) !== createData.nameDesc.name || + getPvcDescription(existingData) !== createData.nameDesc.description || + existingData.spec.resources.requests.storage !== createData.size + ) { + pvcPromises.push(updatePvc(createData, existingData, namespace, { dryRun })); } if (removedNotebooks.length > 0) { // Remove connected pvcs - Promise.all( - removedNotebooks.map((notebookName) => - removeNotebookPVC(notebookName, namespace, pvcName), + pvcPromises.push( + ...removedNotebooks.map((notebookName) => + removeNotebookPVC(notebookName, namespace, pvcName, { dryRun }), ), - ) - .then(() => handleNotebookNameConnection(pvcName)) - .catch(handleError); - return; + ); } - handleNotebookNameConnection(pvcName); - if (parseInt(getPvcTotalSize(existingData)) !== createData.size) { - await updatePvcSize(pvcName, namespace, `${createData.size}Gi`); + + await Promise.all(pvcPromises); + if (notebookName) { + await attachNotebookPVC(notebookName, namespace, pvcName, mountPath.value, { + dryRun, + }); } - } else { - createPvc(pvc) - .then((createdPvc) => handleNotebookNameConnection(createdPvc.metadata.name)) - .catch(handleError); + return; } + const createdPvc = await createPvc(createData, namespace, { dryRun }); + if (notebookName) { + await attachNotebookPVC(notebookName, namespace, createdPvc.metadata.name, mountPath.value, { + dryRun, + }); + } + }; + + const submit = () => { + setError(undefined); + setActionInProgress(true); + + runPromiseActions(true) + .then(() => runPromiseActions(false).then(() => onBeforeClose(true))) + .catch((e) => { + setError(e); + setActionInProgress(false); + }); }; return ( = ({ existingData, isOp isOpen={isOpen} onClose={() => onBeforeClose(false)} showClose - actions={[ - , - , - ]} + footer={ + onBeforeClose(false)} + isSubmitDisabled={!canCreate} + error={error} + alertTitle="Error creating storage" + /> + } > - - -
{ - e.preventDefault(); - submit(); - }} - > + { + e.preventDefault(); + submit(); + }} + > + + setCreateData(key, value)} currentSize={existingData?.status?.capacity?.storage} autoFocusName /> - {createData.hasExistingNotebookConnections && ( + + {createData.hasExistingNotebookConnections && ( + @@ -168,7 +152,9 @@ const ManageStorageModal: React.FC = ({ existingData, isOp loaded={notebookLoaded} error={notebookError} /> - )} + + )} + { setCreateData('forNotebook', forNotebookData); @@ -176,21 +162,14 @@ const ManageStorageModal: React.FC = ({ existingData, isOp forNotebookData={createData.forNotebook} isDisabled={connectedNotebooks.length !== 0 && removedNotebooks.length === 0} /> - - - {restartNotebooks.length !== 0 && ( - - - - )} - {error && ( - - - {error.message} - - )} -
+ {restartNotebooks.length !== 0 && ( + + + + )} +
+
); }; diff --git a/frontend/src/pages/projects/screens/spawner/service.ts b/frontend/src/pages/projects/screens/spawner/service.ts index cd3fa8a273..7deda08b56 100644 --- a/frontend/src/pages/projects/screens/spawner/service.ts +++ b/frontend/src/pages/projects/screens/spawner/service.ts @@ -1,7 +1,6 @@ import * as _ from 'lodash'; import { assembleConfigMap, - assemblePvc, assembleSecret, createConfigMap, createPvc, @@ -31,19 +30,12 @@ export const createPvcDataForNotebook = async ( projectName: string, storageData: StorageData, ): Promise<{ volumes: Volume[]; volumeMounts: VolumeMount[] }> => { - const { - storageType, - creating: { - nameDesc: { name: pvcName, description: pvcDescription }, - size, - }, - } = storageData; + const { storageType } = storageData; const { volumes, volumeMounts } = getVolumesByStorageData(storageData); if (storageType === StorageType.NEW_PVC) { - const pvcData = assemblePvc(pvcName, projectName, pvcDescription, size); - const pvc = await createPvc(pvcData); + const pvc = await createPvc(storageData.creating, projectName); const newPvcName = pvc.metadata.name; volumes.push({ name: newPvcName, persistentVolumeClaim: { claimName: newPvcName } }); volumeMounts.push({ mountPath: ROOT_MOUNT_PATH, name: newPvcName }); @@ -58,10 +50,6 @@ export const replaceRootVolumesForNotebook = async ( ): Promise<{ volumes: Volume[]; volumeMounts: VolumeMount[] }> => { const { storageType, - creating: { - nameDesc: { name: creatingName, description }, - size, - }, existing: { storage: existingName }, } = storageData; @@ -78,8 +66,7 @@ export const replaceRootVolumesForNotebook = async ( }; replacedVolumeMount = { name: existingName, mountPath: ROOT_MOUNT_PATH }; } else { - const pvcData = assemblePvc(creatingName, projectName, description, size); - const pvc = await createPvc(pvcData); + const pvc = await createPvc(storageData.creating, projectName); const newPvcName = pvc.metadata.name; replacedVolume = { name: newPvcName, persistentVolumeClaim: { claimName: newPvcName } }; replacedVolumeMount = { mountPath: ROOT_MOUNT_PATH, name: newPvcName }; diff --git a/frontend/src/pages/projects/screens/spawner/storage/StorageField.tsx b/frontend/src/pages/projects/screens/spawner/storage/StorageField.tsx index 8f74f6a47f..b6ce58c6bd 100644 --- a/frontend/src/pages/projects/screens/spawner/storage/StorageField.tsx +++ b/frontend/src/pages/projects/screens/spawner/storage/StorageField.tsx @@ -5,8 +5,6 @@ import { getDashboardMainContainer } from '~/utilities/utils'; import CreateNewStorageSection from './CreateNewStorageSection'; import AddExistingStorageField from './AddExistingStorageField'; -import '~/pages/projects/screens/detail/storage/ManageStorageModal.scss'; - type StorageFieldType = { storageData: StorageData; setStorageData: UpdateObjectAtPropAndValue; diff --git a/frontend/src/pages/projects/screens/spawner/storage/useAvailablePvcSize.ts b/frontend/src/pages/projects/screens/spawner/storage/useAvailablePvcSize.ts deleted file mode 100644 index 893074d886..0000000000 --- a/frontend/src/pages/projects/screens/spawner/storage/useAvailablePvcSize.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from 'react'; -import { AppContext } from '~/app/AppContext'; - -const DEFAULT_PVC_SIZE = 20; - -const useDefaultPvcSize = (): number => { - const { - dashboardConfig: { - spec: { notebookController }, - }, - } = React.useContext(AppContext); - - let defaultPvcSize = DEFAULT_PVC_SIZE; - if (notebookController?.pvcSize) { - const parsedConfigSize = parseInt(notebookController?.pvcSize); - if (!isNaN(parsedConfigSize)) { - defaultPvcSize = parsedConfigSize; - } - } - - return defaultPvcSize; -}; - -export default useDefaultPvcSize; diff --git a/frontend/src/pages/projects/screens/spawner/storage/useDefaultPvcSize.ts b/frontend/src/pages/projects/screens/spawner/storage/useDefaultPvcSize.ts new file mode 100644 index 0000000000..48ff049a79 --- /dev/null +++ b/frontend/src/pages/projects/screens/spawner/storage/useDefaultPvcSize.ts @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { AppContext } from '~/app/AppContext'; + +const useDefaultPvcSize = (): string => { + const { + dashboardConfig: { + spec: { notebookController }, + }, + } = React.useContext(AppContext); + + return notebookController?.pvcSize || '20Gi'; +}; + +export default useDefaultPvcSize; diff --git a/frontend/src/pages/projects/screens/spawner/storage/utils.ts b/frontend/src/pages/projects/screens/spawner/storage/utils.ts index 5a2282c438..2ba0deff6e 100644 --- a/frontend/src/pages/projects/screens/spawner/storage/utils.ts +++ b/frontend/src/pages/projects/screens/spawner/storage/utils.ts @@ -13,7 +13,7 @@ import useRelatedNotebooks, { } from '~/pages/projects/notebook/useRelatedNotebooks'; import useGenericObjectState from '~/utilities/useGenericObjectState'; import { getRootVolumeName } from '~/pages/projects/screens/spawner/spawnerUtils'; -import useDefaultPvcSize from './useAvailablePvcSize'; +import useDefaultPvcSize from './useDefaultPvcSize'; export const useCreateStorageObjectForNotebook = ( existingData?: PersistentVolumeClaimKind, @@ -22,14 +22,14 @@ export const useCreateStorageObjectForNotebook = ( setData: UpdateObjectAtPropAndValue, resetDefaults: () => void, ] => { - const defaultPvcSize = useDefaultPvcSize(); + const size = useDefaultPvcSize(); const createDataState = useGenericObjectState({ nameDesc: { name: '', k8sName: undefined, description: '', }, - size: defaultPvcSize, + size, forNotebook: { name: '', mountPath: { @@ -44,11 +44,13 @@ export const useCreateStorageObjectForNotebook = ( const existingName = existingData ? getPvcDisplayName(existingData) : ''; const existingDescription = existingData ? getPvcDescription(existingData) : ''; - const existingSize = existingData ? existingData.spec.resources.requests.storage : ''; + const existingSize = existingData ? existingData.spec.resources.requests.storage : size; const { notebooks: relatedNotebooks } = useRelatedNotebooks( ConnectedNotebookContext.REMOVABLE_PVC, existingData ? existingData.metadata.name : undefined, ); + const hasExistingNotebookConnections = relatedNotebooks.length > 0; + React.useEffect(() => { if (existingName) { setCreateData('nameDesc', { @@ -56,16 +58,17 @@ export const useCreateStorageObjectForNotebook = ( description: existingDescription, }); - if (relatedNotebooks.length > 0) { - setCreateData('hasExistingNotebookConnections', true); - } + setCreateData('hasExistingNotebookConnections', hasExistingNotebookConnections); - const newSize = parseInt(existingSize); - if (newSize) { - setCreateData('size', newSize); - } + setCreateData('size', existingSize); } - }, [existingName, existingDescription, setCreateData, relatedNotebooks, existingSize]); + }, [ + existingName, + existingDescription, + setCreateData, + hasExistingNotebookConnections, + existingSize, + ]); return createDataState; }; @@ -90,7 +93,7 @@ export const useStorageDataObject = ( setData: UpdateObjectAtPropAndValue, resetDefaults: () => void, ] => { - const defaultPvcSize = useDefaultPvcSize(); + const size = useDefaultPvcSize(); return useGenericObjectState({ storageType: notebook ? StorageType.EXISTING_PVC : StorageType.NEW_PVC, creating: { @@ -98,7 +101,7 @@ export const useStorageDataObject = ( name: '', description: '', }, - size: defaultPvcSize, + size, }, existing: { storage: getRootVolumeName(notebook), diff --git a/frontend/src/pages/projects/types.ts b/frontend/src/pages/projects/types.ts index 74645f665d..2524ecc2cc 100644 --- a/frontend/src/pages/projects/types.ts +++ b/frontend/src/pages/projects/types.ts @@ -19,7 +19,7 @@ export type NameDescType = { export type CreatingStorageObject = { nameDesc: NameDescType; - size: number; + size: string; }; export type MountPath = { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 4781bc9072..dac57bdefd 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -153,7 +153,7 @@ export type NotebookTolerationFormSettings = TolerationSettings & { export type ClusterSettingsType = { userTrackingEnabled: boolean; - pvcSize: number | string; + pvcSize: number; cullerTimeout: number; notebookTolerationSettings: TolerationSettings | null; };