Skip to content

Commit

Permalink
fix: implement minor emui feedback tweaks (#1827)
Browse files Browse the repository at this point in the history
## Description:
A selection of smaller feedback items from the postdevconnect burndown:
* Fixed tab index onto the enclave configuration form to prevent default
focus being on the close button
* Fixed destroy enclaves dialog closing early when multiple enclaves
were destroyed
* Print the emui version on launch in the browser console
* Tooltips on enclave status and service status
* Updated file download names for artifacts and service arguments to
include `--`
* Dynamically size the log viewer based on the window size (all css, no
resize listeners).

### Screenshots


![image](https://github.com/kurtosis-tech/kurtosis/assets/4419574/14fb35b7-a593-473c-abeb-af510342515f)

![image](https://github.com/kurtosis-tech/kurtosis/assets/4419574/bb33dc8e-b1d5-4fcb-9dd7-15016b2f63f9)

![image](https://github.com/kurtosis-tech/kurtosis/assets/4419574/5d7715b3-b40a-4ee0-92c1-dfc6217bf554)

![image](https://github.com/kurtosis-tech/kurtosis/assets/4419574/6139547f-6552-4a8b-88bc-eef998383ec8)

![image](https://github.com/kurtosis-tech/kurtosis/assets/4419574/abc07414-b5d8-44bd-b047-8cf12c470520)


## Is this change user facing?
YES
  • Loading branch information
Dartoxian authored Nov 17, 2023
1 parent a07aa45 commit 8161a34
Show file tree
Hide file tree
Showing 23 changed files with 124 additions and 90 deletions.
4 changes: 2 additions & 2 deletions enclave-manager/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
"prebuild": "rm -rf ../../engine/server/webapp",
"clean": "rm -rf build",
"cleanInstall": "rm -rf node_modules; yarn install",
"start": "react-scripts start",
"start": "REACT_APP_VERSION=$(git fetch origin --tags -q && git describe --dirty --match '[0-9]*' --tags)-development react-scripts start",
"start:prod": "serve -s build",
"build": "react-scripts build",
"build": "REACT_APP_VERSION=$(git fetch origin --tags -q && git describe --dirty --match '[0-9]*' --tags) react-scripts build",
"postbuild": "cp -r build/ ../../engine/server/webapp",
"prettier": "prettier . --check",
"prettier:fix": "prettier . --write",
Expand Down
2 changes: 1 addition & 1 deletion enclave-manager/web/src/components/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const AppLayout = ({ Nav, children }: AppLayoutProps) => {
<Flex
as="main"
w={"100%"}
h={"100%"}
minH={"calc(100vh - 40px)"}
justifyContent={"flex-start"}
p={"20px 40px 20px 112px"}
className={"app-container"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const IntegerArgumentInput = (props: KurtosisArgumentTypeInputImplProps)
placeholder={props.placeholder}
width={props.width}
size={props.size || "lg"}
tabIndex={props.tabIndex}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type KurtosisArgumentTypeInputProps = {
disabled?: boolean;
width?: CSS.Property.Width;
size?: string;
tabIndex?: number;
};

export type KurtosisArgumentTypeInputImplProps = Omit<KurtosisArgumentTypeInputProps, "type" | "subType1" | "subType2">;
Expand All @@ -36,6 +37,7 @@ export const KurtosisArgumentTypeInput = ({
disabled,
width,
size,
tabIndex,
}: KurtosisArgumentTypeInputProps) => {
const childProps: KurtosisArgumentTypeInputImplProps = {
name,
Expand All @@ -45,6 +47,7 @@ export const KurtosisArgumentTypeInput = ({
disabled,
width,
size,
tabIndex,
};

switch (type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const StringArgumentInput = (props: KurtosisArgumentTypeInputImplProps) =
placeholder={props.placeholder}
width={props.width}
size={props.size || "lg"}
tabIndex={props.tabIndex}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export const LogViewer = ({
};

return (
<Flex flexDirection={"column"} gap={"32px"}>
<Flex flexDirection={"column"} position={"relative"} bg={"gray.800"}>
<Flex flexDirection={"column"} gap={"32px"} h={"100%"}>
<Flex flexDirection={"column"} position={"relative"} bg={"gray.800"} h={"100%"}>
{isDefined(ProgressWidget) && (
<Box
display={"inline-flex"}
Expand All @@ -82,7 +82,7 @@ export const LogViewer = ({
followOutput={automaticScroll}
atBottomStateChange={handleBottomStateChange}
isScrolling={setUserIsScrolling}
style={{ height: "660px" }}
style={{ height: "100%" }}
data={logLines.filter(({ message }) => isDefined(message))}
itemContent={(_, line) => <LogLine {...line} />}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
ModalHeader,
ModalOverlay,
Text,
Tooltip, useToast,
Tooltip,
useToast,
} from "@chakra-ui/react";
import { EnclaveMode } from "enclave-manager-sdk/build/engine_service_pb";
import { useMemo, useRef, useState } from "react";
Expand Down Expand Up @@ -168,7 +169,9 @@ export const ConfigureEnclaveModal = ({
}
} catch (err) {
toast({
title: `An error occurred while preparing data for running package. The package arguments were not proper JSON: ${stringifyError(err)}`,
title: `An error occurred while preparing data for running package. The package arguments were not proper JSON: ${stringifyError(
err,
)}`,
colorScheme: "red",
});
return;
Expand Down Expand Up @@ -277,7 +280,7 @@ export const ConfigureEnclaveModal = ({
<CopyButton contentName={"url"} valueToCopy={getLinkToCurrentConfig} text={"Copy link"} />
</Tooltip>
</Flex>
<KurtosisArgumentFormControl name={"enclaveName"} label={"Enclave name"} type={"string"}>
<KurtosisArgumentFormControl name={"enclaveName"} label={"Enclave name"} type={"text"}>
<StringArgumentInput
name={"enclaveName"}
disabled={isDefined(existingEnclave)}
Expand All @@ -286,6 +289,7 @@ export const ConfigureEnclaveModal = ({
return `The enclave name must match ${allowedEnclaveNamePattern}`;
}
}}
tabIndex={1}
/>
</KurtosisArgumentFormControl>
{kurtosisPackage.args.map((arg, i) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, Tooltip } from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { FiTrash2 } from "react-icons/fi";
import { useNavigate } from "react-router-dom";
import { useEmuiAppContext } from "../../../emui/EmuiAppContext";
Expand All @@ -11,28 +11,15 @@ type DeleteEnclavesButtonProps = {
};

export const DeleteEnclavesButton = ({ enclaves }: DeleteEnclavesButtonProps) => {
const { destroyEnclave } = useEmuiAppContext();
const { destroyEnclaves } = useEmuiAppContext();
const navigator = useNavigate();

const [showModal, setShowModal] = useState(false);
const [isLoading, setIsLoading] = useState(false);

const enclaveUUIDsKey = enclaves.map(({ enclaveUuid }) => enclaveUuid).join(",");

useEffect(
() => {
setIsLoading(false);
setShowModal(false);
},
// These deps are defined this way to detect whether or not the enclaves in props are actually different
[enclaveUUIDsKey],
);

const handleDelete = async () => {
setIsLoading(true);
for (const enclaveUUID of enclaves.map(({ enclaveUuid }) => enclaveUuid)) {
await destroyEnclave(enclaveUUID);
}
await destroyEnclaves(enclaves.map(({ enclaveUuid }) => enclaveUuid));
navigator("/enclaves");
setIsLoading(false);
setShowModal(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DownloadFileArtifactButton = ({ file, enclave }: DownloadFileButton
setIsLoading(true);
// todo: get tgz download instead
const fileParts = await kurtosisClient.downloadFilesArtifact(enclave, file);
const writableStream = streamsaver.createWriteStream(`${enclave.name}-${file.fileName}.tgz`);
const writableStream = streamsaver.createWriteStream(`${enclave.name}--${file.fileName}.tgz`);
const writer = writableStream.getWriter();

for await (const part of fileParts) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Tag } from "@chakra-ui/react";
import { Tag, Tooltip } from "@chakra-ui/react";
import { EnclaveContainersStatus } from "enclave-manager-sdk/build/engine_service_pb";

export function enclaveStatusToString(status: EnclaveContainersStatus) {
Expand All @@ -12,31 +12,31 @@ export function enclaveStatusToString(status: EnclaveContainersStatus) {
}
}

export function enclaveStatusToColorScheme(status: EnclaveContainersStatus) {
switch (status) {
case EnclaveContainersStatus.EnclaveContainersStatus_RUNNING:
return "green";
case EnclaveContainersStatus.EnclaveContainersStatus_STOPPED:
return "red";
case EnclaveContainersStatus.EnclaveContainersStatus_EMPTY:
return "gray";
}
}

type EnclaveStatusProps = {
status: EnclaveContainersStatus;
variant?: string;
};

export const EnclaveStatus = ({ status, variant }: EnclaveStatusProps) => {
const display = enclaveStatusToString(status);
switch (status) {
case EnclaveContainersStatus.EnclaveContainersStatus_RUNNING:
return (
<Tag variant={variant} colorScheme={"green"}>
{display}
</Tag>
);
case EnclaveContainersStatus.EnclaveContainersStatus_STOPPED:
return (
<Tag variant={variant} colorScheme={"red"}>
{display}
</Tag>
);
case EnclaveContainersStatus.EnclaveContainersStatus_EMPTY:
return (
<Tag variant={variant} colorScheme={"gray"}>
{display}
</Tag>
);
}
const colorScheme = enclaveStatusToColorScheme(status);

return (
<Tooltip closeDelay={1000} label={"This is the status of the container running the enclave"}>
<Tag variant={variant} colorScheme={colorScheme}>
{display}
</Tag>
</Tooltip>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Tag } from "@chakra-ui/react";
import { Tag, Tooltip } from "@chakra-ui/react";
import { ServiceStatus } from "enclave-manager-sdk/build/api_container_service_pb";

export function serviceStatusToString(status: ServiceStatus) {
Expand All @@ -12,31 +12,31 @@ export function serviceStatusToString(status: ServiceStatus) {
}
}

export function serviceStatusToColorScheme(status: ServiceStatus) {
switch (status) {
case ServiceStatus.RUNNING:
return "green";
case ServiceStatus.STOPPED:
return "red";
case ServiceStatus.UNKNOWN:
return "orange";
}
}

type ServiceStatusTagProps = {
status: ServiceStatus;
variant?: string;
};

export const ServiceStatusTag = ({ status, variant }: ServiceStatusTagProps) => {
const display = serviceStatusToString(status);
switch (status) {
case ServiceStatus.RUNNING:
return (
<Tag variant={variant} colorScheme={"green"}>
{display}
</Tag>
);
case ServiceStatus.STOPPED:
return (
<Tag variant={variant} colorScheme={"red"}>
{display}
</Tag>
);
case ServiceStatus.UNKNOWN:
return (
<Tag variant={variant} colorScheme={"orange"}>
{display}
</Tag>
);
}
const colorScheme = serviceStatusToColorScheme(status);

return (
<Tooltip label={"The status of the container providing this service."} openDelay={1000}>
<Tag variant={variant} colorScheme={colorScheme}>
{display}
</Tag>
</Tooltip>
);
};
7 changes: 7 additions & 0 deletions enclave-manager/web/src/components/theme/tabsTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export const tabsTheme = defineMultiStyleConfig({
},
variants: {
"soft-rounded": (props: StyleFunctionProps) => ({
root: {
height: "100%",
},
tab: {
fontStyle: "normal",
fontWeight: "medium",
Expand All @@ -27,8 +30,12 @@ export const tabsTheme = defineMultiStyleConfig({
},
textTransform: "capitalize",
},
tabpanels: {
height: "100%",
},
tabpanel: {
padding: "32px 0px",
height: "100%",
},
}),
},
Expand Down
23 changes: 23 additions & 0 deletions enclave-manager/web/src/emui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ import { EmuiAppContextProvider } from "./EmuiAppContext";
import { enclaveRoutes } from "./enclaves/EnclaveRoutes";
import { Navbar } from "./Navbar";

const logLogo = (t: string) => console.log(`%c ${t}`, "background: black; color: #00C223");
logLogo(`
///////////////////
////////// ///////////////////
.//// ,/// ///// ////*
///// /// ///// /////
,//// ,//// *//// ////*
// ///// ///// /////
*//// *//// ////*
///// ///// /////
*//// ///// /////
.//// ///// /////
./// ///// ////* //
///. ///// ////// /////
//// ////*.//// *////
//// ///// ///// /////
///// *////* .//// *////
////////////// ////////////////////
`);

console.log(`Kurtosis web UI version: ${process.env.REACT_APP_VERSION || "Unknown"}`);

export const EmuiApp = () => {
return (
<KurtosisThemeProvider>
Expand Down
26 changes: 17 additions & 9 deletions enclave-manager/web/src/emui/EmuiAppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export type EmuiAppState = {
productionMode?: boolean,
apiContainerVersionTag?: string,
) => Promise<Result<CreateEnclaveResponse, string>>;
destroyEnclave: (enclaveUUID: string) => Promise<Result<Empty, string>>;
destroyEnclaves: (enclaveUUIDs: string[]) => Promise<Result<Empty, string>[]>;
runStarlarkPackage: (
apicInfo: RemoveFunctions<EnclaveAPIContainerInfo>,
packageId: string,
Expand All @@ -64,7 +64,7 @@ const EmuiAppContext = createContext<EmuiAppState>({
refreshFilesAndArtifacts: () => null as any,
refreshStarlarkRun: () => null as any,
createEnclave: () => null as any,
destroyEnclave: () => null as any,
destroyEnclaves: () => null as any,
runStarlarkPackage: () => null as any,
});

Expand Down Expand Up @@ -153,18 +153,26 @@ export const EmuiAppContextProvider = ({ children }: PropsWithChildren) => {
[kurtosisClient],
);

const destroyEnclave = useCallback(
async (enclaveUUID: string) => {
const resp = await kurtosisClient.destroy(enclaveUUID);
if (resp.isOk) {
const destroyEnclaves = useCallback(
async (enclaveUUIDs: string[]) => {
const responses: Result<Empty, string>[] = [];
const destroyedEnclaves = new Set<string>();
for (const enclaveUUID of enclaveUUIDs) {
const resp = await kurtosisClient.destroy(enclaveUUID);
if (resp.isOk) {
destroyedEnclaves.add(enclaveUUID);
}
responses.push(resp);
}
if (destroyedEnclaves.size > 0) {
setState((state) => ({
...state,
enclaves: state.enclaves.isOk
? Result.ok(state.enclaves.value.filter((enclave) => enclave.enclaveUuid !== enclaveUUID))
? Result.ok(state.enclaves.value.filter((enclave) => !destroyedEnclaves.has(enclave.enclaveUuid)))
: state.enclaves,
}));
}
return resp;
return responses;
},
[kurtosisClient],
);
Expand Down Expand Up @@ -205,7 +213,7 @@ export const EmuiAppContextProvider = ({ children }: PropsWithChildren) => {
refreshFilesAndArtifacts,
refreshServices,
createEnclave,
destroyEnclave,
destroyEnclaves,
runStarlarkPackage,
}}
>
Expand Down
Loading

0 comments on commit 8161a34

Please sign in to comment.