UNPKG

@datalayer/core

Version:

[![Datalayer](https://assets.datalayer.tech/datalayer-25.svg)](https://datalayer.io)

170 lines (169 loc) 8.78 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; /* * Copyright (c) 2023-2025 Datalayer, Inc. * Distributed under the terms of the Modified BSD License. */ import { useCallback, useEffect, useState, } from 'react'; import { CameraIcon } from '@datalayer/icons-react'; import { ActionList, ActionMenu, Flash, FormControl, Select, Spinner, } from '@primer/react'; import { Dialog } from '@primer/react/experimental'; import { Box } from '@datalayer/primer-addons'; import { useToast } from '../../hooks'; import { createRuntimeSnapshot, getRuntimeSnapshots, loadBrowserRuntimeSnapshot, loadRuntimeSnapshot, } from '../../stateful/runtimes'; import { useRuntimesStore } from '../../state'; import { createRuntimeSnapshotName } from '../../utils'; /** * Runtime Snapshot menu component. */ export function RuntimeSnapshotMenu({ children, connection, podName, multiServiceManager, disabled = false, }) { const { addRuntimeSnapshot, runtimesRunUrl, runtimeSnapshots, setRuntimeSnapshots, } = useRuntimesStore(); const { enqueueToast, trackAsyncTask } = useToast(); const [openLoadDialog, setOpenLoadDialog] = useState(false); const [loadingRuntimeSnapshot, setLoadingRuntimeSnapshot] = useState(false); const [takingRuntimeSnapshot, setTakingRuntimeSnapshot] = useState(false); const [selection, setSelection] = useState(runtimeSnapshots[0]?.id ?? ''); const [error, setError] = useState(); useEffect(() => { getRuntimeSnapshots() .then(snapshots => { setRuntimeSnapshots(snapshots); if (!selection && snapshots.length > 0) { setSelection(snapshots[0].id); } }) .catch(reason => { console.error(`Failed to fetch remote kernel snapshots; ${reason}`); }); }, [runtimesRunUrl]); const onLoadRuntimeSnapshot = useCallback(() => { setError(undefined); setOpenLoadDialog(true); }, []); const onRuntimeSnapshotChanged = useCallback(event => { setSelection(event.target.value); }, []); const onLoadRuntimeSnapshotSubmit = useCallback(async ({ id, connection, podName, }) => { if (podName) { await loadRuntimeSnapshot({ id: podName, from: id }); enqueueToast(`Runtime snapshot ${podName} is loaded.`, { variant: 'success', }); } else if (connection) { await loadBrowserRuntimeSnapshot({ connection, id }); enqueueToast(`Runtime snapshot ${id} is loaded.`, { variant: 'success', }); } }, []); const onTakeRuntimeSnapshot = useCallback(async () => { try { setTakingRuntimeSnapshot(true); let snapshot; let task; let ref = ''; let snapshotName = ''; if (podName && multiServiceManager?.remote) { snapshotName = createRuntimeSnapshotName('cloud'); task = multiServiceManager.remote.runtimesManager.snapshotRuntime({ podName, name: snapshotName, description: snapshotName, stop: false, }); ref = podName.split('-', 2).reverse()[0]; task.then(s => { snapshot = s; }); } else if (connection && multiServiceManager?.browser) { const model = connection.model; ref = model.id; snapshotName = createRuntimeSnapshotName('browser'); let isPending = true; task = createRuntimeSnapshot({ connection: multiServiceManager.browser.kernels.connectTo({ model, }), metadata: { filename: `${snapshotName}.data` }, onUploadProgress: () => { if (isPending) { isPending = false; // Get the kernel snapshot uid. getRuntimeSnapshots().then(snapshots => { snapshot = snapshots.find(s => s.name === snapshotName); }); } }, }); } if (task) { trackAsyncTask(task, { error: { message: (reason, data) => { const msg = reason === 'Empty snapshot' ? `Runtime ${ref} will not be snapshotted as it does not contain any serializable state.` : `Failed to snapshot runtime ${ref} - ${reason}`; return msg; }, }, pending: { message: `Taking a snapshot of runtime ${ref}…` }, success: { message: () => `Runtime ${ref} successfully snapshotted as ${snapshotName}.`, }, }); await task; if (snapshot) { addRuntimeSnapshot(snapshot); } } } finally { setTakingRuntimeSnapshot(false); } }, [connection, podName, multiServiceManager]); return (_jsxs(_Fragment, { children: [_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { leadingVisual: CameraIcon, variant: "invisible", size: "small", disabled: loadingRuntimeSnapshot || takingRuntimeSnapshot || disabled, children: children }), _jsx(ActionMenu.Overlay, { children: _jsxs(ActionList, { children: [_jsx(ActionList.Item, { onSelect: onLoadRuntimeSnapshot, disabled: loadingRuntimeSnapshot || runtimeSnapshots.length === 0, children: "Load a runtime snapshot\u2026" }), _jsx(ActionList.Item, { onSelect: onTakeRuntimeSnapshot, disabled: takingRuntimeSnapshot, children: "Take a runtime snapshot" })] }) })] }), openLoadDialog && (_jsx(Dialog, { title: _jsx("span", { style: { color: 'var(--fgColor-default)' }, children: "Choose a runtime snapshot to load" }), onClose: () => { setOpenLoadDialog(false); }, footerButtons: [ { buttonType: 'default', content: 'Cancel', onClick: event => { if (!event.defaultPrevented) { event.preventDefault(); setOpenLoadDialog(false); } }, }, { buttonType: 'primary', content: loadingRuntimeSnapshot ? (_jsx(Spinner, { size: "small" })) : ('Load'), disabled: loadingRuntimeSnapshot, onClick: async (event) => { if (!event.defaultPrevented) { event.preventDefault(); setLoadingRuntimeSnapshot(true); try { setError(undefined); const snapshot = runtimeSnapshots.find(s => s.id === selection); if (snapshot && (connection || podName)) { await onLoadRuntimeSnapshotSubmit({ connection, id: snapshot.id, podName, }); } else { setError('No runtime snapshot found.'); } } finally { setLoadingRuntimeSnapshot(false); setOpenLoadDialog(false); } } }, autoFocus: true, }, ], children: _jsxs(Box, { as: "form", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Snapshot" }), _jsx(Select, { name: "snapshot", value: selection, onChange: onRuntimeSnapshotChanged, block: true, children: runtimeSnapshots.map(s => (_jsx(Select.Option, { value: s.id, children: s.name ? `${s.name} (${s.id})` : s.id }, s.id))) })] }), error && _jsx(Flash, { variant: "danger", children: error })] }) }))] })); }