Skip to content

Commit

Permalink
feat: enclave builder improvements from feedback (#2202)
Browse files Browse the repository at this point in the history
## Description:
This PR adds some fixes to the enclave builder based on feedback
received on slack.:
* Show the enclave builder in a drawer
* Reorder the ports input
* Prevent self referencing variables
* Don't require a slash prefix on file names

## Is this change user facing?
YES

## References (if applicable):
* This PR is based on top of #2201 .
  • Loading branch information
Dartoxian authored Feb 22, 2024
1 parent 486ea2e commit 8080f4f
Show file tree
Hide file tree
Showing 22 changed files with 176 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useSettings } from "../../settings";
import { KURTOSIS_BUILD_ENCLAVE_URL_ARG } from "./configuration/drawer/constants";
import { EnclaveBuilderModal } from "./modals/EnclaveBuilderModal";
import { EnclaveBuilderDrawer } from "./enclaveBuilder/EnclaveBuilderDrawer";

export const BuildEnclave = () => {
const { settings } = useSettings();
Expand All @@ -27,5 +27,5 @@ export const BuildEnclave = () => {
return null;
}

return <EnclaveBuilderModal isOpen={buildEnclaveOpen} onClose={handleCloseBuildEnclave} />;
return <EnclaveBuilderDrawer isOpen={buildEnclaveOpen} onClose={handleCloseBuildEnclave} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { FiEdit2 } from "react-icons/fi";
import { useSettings } from "../../settings";
import { EnclaveFullInfo } from "../types";
import { CreateOrConfigureEnclaveDrawer } from "./configuration/drawer/CreateOrConfigureEnclaveDrawer";
import { starlarkScriptContainsEMUIBuildState } from "./modals/enclaveBuilder/utils";
import { EnclaveBuilderModal } from "./modals/EnclaveBuilderModal";
import { EnclaveBuilderDrawer } from "./enclaveBuilder/EnclaveBuilderDrawer";
import { starlarkScriptContainsEMUIBuildState } from "./enclaveBuilder/utils";
import { PackageLoadingModal } from "./modals/PackageLoadingModal";

type EditEnclaveButtonProps = ButtonProps & {
Expand Down Expand Up @@ -114,7 +114,7 @@ const EditFromScriptButton = ({ enclave, ...buttonProps }: EditFromScriptButtonP
Edit
</Button>
</Tooltip>
<EnclaveBuilderModal
<EnclaveBuilderDrawer
isOpen={showBuilderModal}
onClose={() => setShowBuilderModal(false)}
existingEnclave={enclave}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {
Button,
ButtonGroup,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
Flex,
ListItem,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
Tooltip,
UnorderedList,
Expand All @@ -21,19 +21,19 @@ import { Edge, Node, ReactFlowProvider } from "reactflow";
import "reactflow/dist/style.css";
import { useEnclavesContext } from "../../EnclavesContext";
import { EnclaveFullInfo } from "../../types";
import { ViewStarlarkModal } from "./enclaveBuilder/modals/ViewStarlarkModal";
import { KurtosisNodeData } from "./enclaveBuilder/types";
import { getInitialGraphStateFromEnclave, getNodeName } from "./enclaveBuilder/utils";
import { useVariableContext, VariableContextProvider } from "./enclaveBuilder/VariableContextProvider";
import { Visualiser, VisualiserImperativeAttributes } from "./enclaveBuilder/Visualiser";
import { ViewStarlarkModal } from "./modals/ViewStarlarkModal";
import { KurtosisNodeData } from "./types";
import { getInitialGraphStateFromEnclave, getNodeName } from "./utils";
import { useVariableContext, VariableContextProvider } from "./VariableContextProvider";
import { Visualiser, VisualiserImperativeAttributes } from "./Visualiser";

type EnclaveBuilderModalProps = {
type EnclaveBuilderDrawerProps = {
isOpen: boolean;
onClose: () => void;
existingEnclave?: RemoveFunctions<EnclaveFullInfo>;
};

export const EnclaveBuilderModal = (props: EnclaveBuilderModalProps) => {
export const EnclaveBuilderDrawer = (props: EnclaveBuilderDrawerProps) => {
const variableContextKey = useRef(0);
const [error, setError] = useState<string>();

Expand Down Expand Up @@ -82,22 +82,22 @@ export const EnclaveBuilderModal = (props: EnclaveBuilderModalProps) => {

return (
<VariableContextProvider key={variableContextKey.current} initialData={initialData}>
<EnclaveBuilderModalImpl {...props} initialNodes={initialNodes} initialEdges={initialEdges} />
<EnclaveBuilderDrawerImpl {...props} initialNodes={initialNodes} initialEdges={initialEdges} />
</VariableContextProvider>
);
};

type EnclaveBuilderModalImplProps = EnclaveBuilderModalProps & {
type EnclaveBuilderDrawerImplProps = EnclaveBuilderDrawerProps & {
initialNodes: Node[];
initialEdges: Edge[];
};
const EnclaveBuilderModalImpl = ({
const EnclaveBuilderDrawerImpl = ({
isOpen,
onClose,
existingEnclave,
initialNodes,
initialEdges,
}: EnclaveBuilderModalImplProps) => {
}: EnclaveBuilderDrawerImplProps) => {
const navigator = useNavigate();
const visualiserRef = useRef<VisualiserImperativeAttributes | null>(null);
const { createEnclave, runStarlarkScript } = useEnclavesContext();
Expand Down Expand Up @@ -158,14 +158,14 @@ const EnclaveBuilderModalImpl = ({
};

return (
<Modal isOpen={isOpen} onClose={!isLoading ? onClose : () => null} closeOnEsc={false}>
<ModalOverlay />
<ModalContent h={"89vh"} minW={"1300px"}>
<ModalHeader>
<Drawer size={"full"} isOpen={isOpen} onClose={!isLoading ? onClose : () => null} closeOnEsc={false}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader>
{isDefined(existingEnclave) ? `Editing ${existingEnclave.name}` : "Build a new Enclave"}
</ModalHeader>
<ModalCloseButton />
<ModalBody paddingInline={"0"}>
</DrawerHeader>
<DrawerCloseButton />
<DrawerBody paddingInline={"0"} p={"0"}>
{isDefined(error) && <KurtosisAlert message={error} />}
<ReactFlowProvider>
<Visualiser
Expand All @@ -175,8 +175,8 @@ const EnclaveBuilderModalImpl = ({
existingEnclave={existingEnclave}
/>
</ReactFlowProvider>
</ModalBody>
<ModalFooter>
</DrawerBody>
<DrawerFooter>
<ButtonGroup>
<Button onClick={onClose} isDisabled={isLoading}>
Close
Expand Down Expand Up @@ -207,13 +207,13 @@ const EnclaveBuilderModalImpl = ({
</Button>
</Tooltip>
</ButtonGroup>
</ModalFooter>
</ModalContent>
</DrawerFooter>
</DrawerContent>
<ViewStarlarkModal
isOpen={isDefined(currentStarlarkPreview)}
onClose={() => setCurrentStarlarkPreview(undefined)}
starlark={currentStarlarkPreview}
/>
</Modal>
</Drawer>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { memo } from "react";
import { NodeProps } from "reactflow";
import { KurtosisFormControl } from "../../form/KurtosisFormControl";
import { StringArgumentInput } from "../../form/StringArgumentInput";
import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { FileTreeArgumentInput } from "./input/FileTreeArgumentInput";
import { validateName } from "./input/validators";
import { KurtosisNode } from "./KurtosisNode";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Flex, Icon, IconButton, Text, useToken } from "@chakra-ui/react";
import { isDefined } from "kurtosis-ui-components";
import { debounce } from "lodash";
import { FC, memo, PropsWithChildren, useEffect, useMemo } from "react";
import { FC, memo, PropsWithChildren, useCallback, useEffect, useMemo } from "react";
import { DefaultValues, FormProvider, useForm } from "react-hook-form";
import { FiCpu, FiFile, FiTerminal, FiTrash } from "react-icons/fi";
import { RxCornerBottomRight } from "react-icons/rx";
Expand Down Expand Up @@ -39,14 +39,7 @@ type KurtosisNodeProps = PropsWithChildren<{
}>;

export const KurtosisNode = memo(
<DataType extends KurtosisNodeData>({
id,

selected,
minWidth,
maxWidth,
children,
}: KurtosisNodeProps) => {
<DataType extends KurtosisNodeData>({ id, selected, minWidth, maxWidth, children }: KurtosisNodeProps) => {
const { data } = useVariableContext();
const nodeData = data[id] as DataType;

Expand Down Expand Up @@ -168,21 +161,33 @@ type ZoomAwareNodeContentProps = PropsWithChildren<{

const ZoomAwareNodeContent = ({ name, type, onDelete, children }: ZoomAwareNodeContentProps) => {
const viewport = useViewport();
const { zoomOut, zoomIn } = useReactFlow();
return (
<ZoomAwareNodeContentImpl name={name} type={type} onDelete={onDelete} zoom={viewport.zoom}>
{children}
</ZoomAwareNodeContentImpl>
);
};

const handleScroll = (e: React.WheelEvent<HTMLDivElement>) => {
if (e.currentTarget.scrollTop === 0 && e.deltaY < 0) {
zoomIn();
}
if (
Math.abs(e.currentTarget.scrollHeight - e.currentTarget.clientHeight - e.currentTarget.scrollTop) <= 1 &&
e.deltaY > 0
) {
zoomOut();
}
};
type ZoomAwareNodeContentImplProps = ZoomAwareNodeContentProps & { zoom: number };

if (viewport.zoom < 0.4) {
const ZoomAwareNodeContentImpl = memo(({ name, type, onDelete, zoom, children }: ZoomAwareNodeContentImplProps) => {
const { zoomOut, zoomIn } = useReactFlow();
const handleScroll = useCallback(
(e: React.WheelEvent<HTMLDivElement>) => {
if (e.currentTarget.scrollTop === 0 && e.deltaY < 0) {
zoomIn();
}
if (
Math.abs(e.currentTarget.scrollHeight - e.currentTarget.clientHeight - e.currentTarget.scrollTop) <= 1 &&
e.deltaY > 0
) {
zoomOut();
}
},
[zoomOut, zoomIn],
);

if (zoom < 0.4) {
return (
<Flex gap={"20px"} alignItems={"center"} justifyContent={"center"} h={"100%"}>
<Icon as={nodeIcons[type]} h={"40px"} w={"40px"} />
Expand Down Expand Up @@ -228,4 +233,4 @@ const ZoomAwareNodeContent = ({ name, type, onDelete, children }: ZoomAwareNodeC
</Flex>
</>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"
import { isDefined } from "kurtosis-ui-components";
import { memo } from "react";
import { NodeProps } from "reactflow";
import { BooleanArgumentInput } from "../../form/BooleanArgumentInput";
import { CodeEditorInput } from "../../form/CodeEditorInput";
import { KurtosisFormControl } from "../../form/KurtosisFormControl";
import { ListArgumentInput } from "../../form/ListArgumentInput";
import { StringArgumentInput } from "../../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../../form/types";
import { BooleanArgumentInput } from "../form/BooleanArgumentInput";
import { CodeEditorInput } from "../form/CodeEditorInput";
import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../form/types";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { validateDockerLocator, validateDurationString, validateName } from "./input/validators";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
import { isDefined } from "kurtosis-ui-components";
import { memo } from "react";
import { NodeProps } from "reactflow";
import { BooleanArgumentInput } from "../../form/BooleanArgumentInput";
import { DictArgumentInput } from "../../form/DictArgumentInput";
import { IntegerArgumentInput } from "../../form/IntegerArgumentInput";
import { KurtosisFormControl } from "../../form/KurtosisFormControl";
import { ListArgumentInput } from "../../form/ListArgumentInput";
import { StringArgumentInput } from "../../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../../form/types";
import { BooleanArgumentInput } from "../form/BooleanArgumentInput";
import { DictArgumentInput } from "../form/DictArgumentInput";
import { IntegerArgumentInput } from "../form/IntegerArgumentInput";
import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { KurtosisFormInputProps } from "../form/types";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { PortConfigurationField } from "./input/PortConfigurationInput";
Expand All @@ -21,6 +22,10 @@ export const KurtosisServiceNode = memo(
const { data } = useVariableContext();
const nodeData = data[id] as KurtosisServiceNodeData;

if (!isDefined(nodeData)) {
return null;
}

return (
<KurtosisNode id={id} selected={selected} minWidth={650} maxWidth={800}>
<Flex gap={"16px"}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"
import { isDefined } from "kurtosis-ui-components";
import { memo } from "react";
import { NodeProps } from "reactflow";
import { BooleanArgumentInput } from "../../form/BooleanArgumentInput";
import { CodeEditorInput } from "../../form/CodeEditorInput";
import { DictArgumentInput } from "../../form/DictArgumentInput";
import { KurtosisFormControl } from "../../form/KurtosisFormControl";
import { ListArgumentInput } from "../../form/ListArgumentInput";
import { StringArgumentInput } from "../../form/StringArgumentInput";
import { BooleanArgumentInput } from "../form/BooleanArgumentInput";
import { CodeEditorInput } from "../form/CodeEditorInput";
import { DictArgumentInput } from "../form/DictArgumentInput";
import { KurtosisFormControl } from "../form/KurtosisFormControl";
import { ListArgumentInput } from "../form/ListArgumentInput";
import { StringArgumentInput } from "../form/StringArgumentInput";
import { MentionStringArgumentInput } from "./input/MentionStringArgumentInput";
import { MountArtifactFileInput } from "./input/MountArtifactFileInput";
import { validateDockerLocator, validateDurationString, validateName } from "./input/validators";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Button, ButtonGroup, Flex, Icon } from "@chakra-ui/react";
import Dagre from "@dagrejs/dagre";
import { RemoveFunctions } from "kurtosis-ui-components";
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from "react";
import { FiShare2 } from "react-icons/fi";
import {
Background,
BackgroundVariant,
Expand All @@ -15,7 +16,7 @@ import {
XYPosition,
} from "reactflow";
import { v4 as uuidv4 } from "uuid";
import { EnclaveFullInfo } from "../../../types";
import { EnclaveFullInfo } from "../../types";
import { KurtosisArtifactNode } from "./KurtosisArtifactNode";
import { nodeIcons } from "./KurtosisNode";
import { KurtosisPythonNode } from "./KurtosisPythonNode";
Expand Down Expand Up @@ -229,22 +230,34 @@ export const Visualiser = forwardRef<VisualiserImperativeAttributes, VisualiserP
);

return (
<Flex flexDirection={"column"} h={"100%"} gap={"8px"}>
<ButtonGroup paddingInline={6}>
<Button onClick={onLayout}>Do Layout</Button>
<Button leftIcon={<Icon as={nodeIcons["service"]} />} onClick={handleAddServiceNode}>
Add Service Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["artifact"]} />} onClick={handleAddArtifactNode}>
Add Files Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["shell"]} />} onClick={handleAddShellNode}>
Add Shell Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["python"]} />} onClick={handleAddPythonNode}>
Add Python Node
</Button>
</ButtonGroup>
<Flex position="relative" flexDirection={"column"} h={"100%"} gap={"8px"}>
<Box
borderRadius={"5px"}
position={"absolute"}
zIndex={"99999"}
top={"20px"}
left={"20px"}
bg={"gray.800"}
p={"8px"}
>
<ButtonGroup size={"sm"}>
<Button leftIcon={<Icon as={FiShare2} />} onClick={onLayout}>
Auto-Layout
</Button>
<Button leftIcon={<Icon as={nodeIcons["service"]} />} onClick={handleAddServiceNode}>
Add Service Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["artifact"]} />} onClick={handleAddArtifactNode}>
Add Files Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["shell"]} />} onClick={handleAddShellNode}>
Add Shell Node
</Button>
<Button leftIcon={<Icon as={nodeIcons["python"]} />} onClick={handleAddPythonNode}>
Add Python Node
</Button>
</ButtonGroup>
</Box>
<Box bg={"gray.900"} flex={"1"}>
<ReactFlow
minZoom={0.1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FileTree, FileTreeNode, isDefined } from "kurtosis-ui-components";
import { useMemo, useState } from "react";
import { Controller } from "react-hook-form";
import { FiPlus } from "react-icons/fi";
import { KurtosisFormInputProps } from "../../../form/types";
import { KurtosisFormInputProps } from "../../form/types";
import { EditFileModal } from "../modals/EditFileModal";
import { NewFileModal } from "../modals/NewFileModal";

Expand Down
Loading

0 comments on commit 8080f4f

Please sign in to comment.