Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve logging part 1 #1728

Merged
merged 17 commits into from
Nov 9, 2023
Merged
23 changes: 22 additions & 1 deletion enclave-manager/web/src/client/enclaveManager/KurtosisClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { PromiseClient } from "@connectrpc/connect";
import { RunStarlarkPackageArgs, ServiceInfo } from "enclave-manager-sdk/build/api_container_service_pb";
import {
FilesArtifactNameAndUuid,
RunStarlarkPackageArgs,
ServiceInfo,
} from "enclave-manager-sdk/build/api_container_service_pb";
import {
CreateEnclaveArgs,
DestroyEnclaveArgs,
Expand All @@ -14,6 +18,7 @@ import {
GetListFilesArtifactNamesAndUuidsRequest,
GetServicesRequest,
GetStarlarkRunRequest,
InspectFilesArtifactContentsRequest,
RunStarlarkPackageRequest,
} from "enclave-manager-sdk/build/kurtosis_enclave_manager_api_pb";
import { EnclaveFullInfo } from "../../emui/enclaves/types";
Expand Down Expand Up @@ -135,6 +140,22 @@ export abstract class KurtosisClient {
}, `KurtosisClient could not listFilesArtifactNamesAndUuids for ${enclave.name}`);
}

async inspectFilesArtifactContents(enclave: RemoveFunctions<EnclaveInfo>, file: FilesArtifactNameAndUuid) {
return await asyncResult(() => {
const apicInfo = enclave.apiContainerInfo;
assertDefined(
apicInfo,
`Cannot listFilesArtifactNamesAndUuids because the passed enclave '${enclave.name}' does not have apicInfo`,
);
const request = new InspectFilesArtifactContentsRequest({
apicIpAddress: apicInfo.bridgeIpAddress,
apicPort: apicInfo.grpcPortInsideEnclave,
fileNamesAndUuid: file,
});
return this.client.inspectFilesArtifactContents(request, this.getHeaderOptions());
}, `KurtosisClient could not inspectFilesArtifactContents for ${enclave.name}`);
}

async createEnclave(
enclaveName: string,
apiContainerLogLevel: string,
Expand Down
3 changes: 3 additions & 0 deletions enclave-manager/web/src/components/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export const CodeEditor = ({ text, onTextChange, showLineNumbers }: CodeEditorPr
selectionHighlight: !isReadOnly,
occurrencesHighlight: !isReadOnly,
overviewRulerLanes: isReadOnly ? 0 : 3,
scrollbar: {
alwaysConsumeMouseWheel: false,
},
}}
defaultLanguage={"json"}
theme={"vs-dark"}
Expand Down
42 changes: 32 additions & 10 deletions enclave-manager/web/src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { Button, ButtonProps, useToast } from "@chakra-ui/react";
import { Button, ButtonProps, IconButton, IconButtonProps, useToast } from "@chakra-ui/react";
import { FiCopy } from "react-icons/fi";
import { isDefined } from "../utils";

type CopyButtonProps = ButtonProps & {
type CopyButtonProps<IsIconButton extends boolean> = (IsIconButton extends true ? IconButtonProps : ButtonProps) & {
valueToCopy?: (() => string) | string | null;
text?: string;
text?: IsIconButton extends true ? string : never;
isIconButton?: IsIconButton;
contentName: string;
};

export const CopyButton = ({ valueToCopy, text, contentName, ...buttonProps }: CopyButtonProps) => {
export const CopyButton = <IsIconButton extends boolean>({
valueToCopy,
text,
contentName,
isIconButton,
...buttonProps
}: CopyButtonProps<IsIconButton>) => {
const toast = useToast();

const handleCopyClick = () => {
Expand All @@ -22,13 +29,28 @@ export const CopyButton = ({ valueToCopy, text, contentName, ...buttonProps }: C
}
};

if (!isDefined(valueToCopy)) {
if (!isDefined(valueToCopy) && !isDefined(buttonProps.onClick)) {
return null;
}

return (
<Button leftIcon={<FiCopy />} size={"xs"} colorScheme={"darkBlue"} onClick={handleCopyClick} {...buttonProps}>
{text || "Copy"}
</Button>
);
if (isIconButton) {
return (
<IconButton
icon={<FiCopy />}
size={"xs"}
variant={"ghost"}
colorScheme={"darkBlue"}
onClick={handleCopyClick}
{...(buttonProps as IconButtonProps)}
>
{text || "Copy"}
</IconButton>
);
} else {
return (
<Button leftIcon={<FiCopy />} size={"xs"} colorScheme={"darkBlue"} onClick={handleCopyClick} {...buttonProps}>
{text || "Copy"}
</Button>
);
}
};
22 changes: 11 additions & 11 deletions enclave-manager/web/src/components/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TriangleDownIcon, TriangleUpIcon } from "@chakra-ui/icons";
import { chakra, Table, Tbody, Td, Th, Thead, Tr } from "@chakra-ui/react";
import { Button, chakra, Table, Tbody, Td, Th, Thead, Tr } from "@chakra-ui/react";
import {
ColumnDef,
flexRender,
Expand Down Expand Up @@ -79,13 +79,18 @@ export function DataTable<Data extends object>({
isNumeric={meta?.isNumeric}
textAlign={!!meta?.centerAligned ? "center" : undefined}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getCanSort() && (
<Button variant={"sortableHeader"} size={"xs"}>
{flexRender(header.column.columnDef.header, header.getContext())}
</Button>
)}
{!header.column.getCanSort() && flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getIsSorted() && (
<chakra.span pl="4">
{header.column.getIsSorted() === "desc" ? (
<TriangleDownIcon aria-label="sorted descending" />
<TriangleDownIcon aria-label="sorted descending" color={"gray.400"} />
) : (
<TriangleUpIcon aria-label="sorted ascending" />
<TriangleUpIcon aria-label="sorted ascending" color={"gray.400"} />
)}
</chakra.span>
)}
Expand All @@ -97,16 +102,11 @@ export function DataTable<Data extends object>({
</Thead>
<Tbody>
{table.getRowModel().rows.map((row) => (
<Tr key={row.id} bg={row.getIsSelected() ? "kurtosisSelected.100" : ""}>
<Tr key={row.id} bg={row.getIsSelected() ? "gray.700" : ""}>
{row.getVisibleCells().map((cell) => {
const meta = cell.column.columnDef.meta;
return (
<Td
key={cell.id}
isNumeric={meta?.isNumeric}
textAlign={!!meta?.centerAligned ? "center" : undefined}
width={cell.column.getSize()}
>
<Td key={cell.id} isNumeric={meta?.isNumeric} textAlign={!!meta?.centerAligned ? "center" : undefined}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Td>
);
Expand Down
52 changes: 36 additions & 16 deletions enclave-manager/web/src/components/DownloadButton.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
import { Button, ButtonProps } from "@chakra-ui/react";
import { Button, ButtonProps, IconButton, IconButtonProps } from "@chakra-ui/react";
import { FiDownload } from "react-icons/fi";
import { isDefined } from "../utils";
import { saveTextAsFile } from "../utils/download";

type DownloadButtonProps = ButtonProps & {
type DownloadButtonProps<IsIconButton extends boolean> = (IsIconButton extends true ? IconButtonProps : ButtonProps) & {
valueToDownload?: (() => string) | string | null;
fileName: string;
text?: string;
text?: IsIconButton extends true ? string : never;
isIconButton?: IsIconButton;
};

export const DownloadButton = ({ valueToDownload, text, fileName, ...buttonProps }: DownloadButtonProps) => {
export const DownloadButton = <IsIconButton extends boolean>({
valueToDownload,
text,
fileName,
isIconButton,
...buttonProps
}: DownloadButtonProps<IsIconButton>) => {
const handleDownloadClick = () => {
if (isDefined(valueToDownload)) {
const v = typeof valueToDownload === "string" ? valueToDownload : valueToDownload();
saveTextAsFile(v, fileName);
}
};

if (!isDefined(valueToDownload)) {
if (!isDefined(valueToDownload) && !isDefined(buttonProps.onClick)) {
return null;
}

return (
<Button
leftIcon={<FiDownload />}
size={"xs"}
colorScheme={"darkBlue"}
onClick={handleDownloadClick}
{...buttonProps}
>
{text || "Download"}
</Button>
);
if (isIconButton) {
return (
<IconButton
icon={<FiDownload />}
size={"xs"}
variant={"ghost"}
colorScheme={"darkBlue"}
onClick={handleDownloadClick}
{...(buttonProps as IconButtonProps)}
/>
);
} else {
return (
<Button
leftIcon={<FiDownload />}
size={"xs"}
colorScheme={"darkBlue"}
onClick={handleDownloadClick}
{...buttonProps}
>
{text || "Download"}
</Button>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { KurtosisAlertModal } from "./KurtosisAlertModal";

type FeatureNotImplementedModalProps = {
featureName: string;
issueUrl: string;
message?: string;
isOpen: boolean;
onClose: () => void;
};

export const FeatureNotImplementedModal = ({
featureName,
issueUrl,
message,
isOpen,
onClose,
Expand All @@ -18,14 +20,15 @@ export const FeatureNotImplementedModal = ({
title={`${featureName} unavailable`}
isOpen={isOpen}
onClose={onClose}
confirmText={"Submit Request"}
confirmText={"Go to Issue"}
onConfirm={() => {
onClose();
window.open("https://github.com/kurtosis-tech/kurtosis/issues", "_blank");
window.open(issueUrl, "_blank");
}}
confirmButtonProps={{ colorScheme: "kurtosisGreen" }}
content={
message || `${featureName} is not currently available. Please open a feature request if you'd like to use this.`
message ||
`${featureName} is not currently available. Please comment/upvote the issue if you would like to use it.`
}
/>
);
Expand Down
16 changes: 10 additions & 6 deletions enclave-manager/web/src/components/KurtosisThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ const theme = extendTheme({
body: `'Inter', sans-serif`,
},
colors: {
kurtosisSelected: {
100: "#292929",
},
kurtosisGreen: {
100: "#005e11",
200: "#008c19",
Expand All @@ -48,6 +45,7 @@ const theme = extendTheme({
700: "#99f7aa",
},
darkBlue: {
200: "#516A77",
400: "#516A77",
},
gray: {
Expand Down Expand Up @@ -99,8 +97,7 @@ const theme = extendTheme({
},
variants: {
outline: (props: StyleFunctionProps) => ({
_hover: { bg: "initial", borderColor: `${props.colorScheme}.400` },
_active: { bg: "initial" },
_hover: { borderColor: `${props.colorScheme}.400` },
color: `${props.colorScheme}.400`,
borderColor: "gray.300",
}),
Expand Down Expand Up @@ -131,8 +128,15 @@ const theme = extendTheme({
})),
ghost: defineStyle((props) => ({
_hover: { bg: "gray.650" },
color: `gray.100`,
})),
sortableHeader: (props: StyleFunctionProps) => {
const ghost = theme.components.Button.variants!.ghost(props);
return {
...ghost,
color: "gray.100",
textTransform: "uppercase",
};
},
nav: {
_active: {
bg: "gray.600",
Expand Down
9 changes: 6 additions & 3 deletions enclave-manager/web/src/components/enclaves/logs/LogLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const LogLine = ({ timestamp, message, status }: LogLineProps) => {
};

return (
<Flex borderBottom={"1px solid #444444"} p={"14px 0"} m={"0 16px"} gap={"8px"} alignItems={"center"}>
<Flex p={"2px 0"} m={"0 16px"} gap={"8px"} alignItems={"top"}>
{isDefined(timestamp) && (
<Box
as={"pre"}
Expand All @@ -35,8 +35,11 @@ export const LogLine = ({ timestamp, message, status }: LogLineProps) => {
fontWeight={600}
fontFamily={logFontFamily}
color={"grey"}
minW={"200px"}
>
{timestamp.toLocal().toFormat("yyyy-MM-dd HH:MM:ss.SSS ZZZZ")} |
<>
{timestamp.toLocal().toFormat("yyyy-MM-dd HH:mm:ss.SSS ZZZZ")}
</>
</Box>
)}
<Box
Expand All @@ -48,7 +51,7 @@ export const LogLine = ({ timestamp, message, status }: LogLineProps) => {
fontFamily={logFontFamily}
color={statusToColor(status)}
>
{message || <i>No message</i>}
{message}
</Box>
</Flex>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const LogViewer = ({

return (
<Flex flexDirection={"column"} gap={"32px"}>
<Flex flexDirection={"column"} position={"relative"} bg={"gray.800"} borderRadius={"8px"}>
<Flex flexDirection={"column"} position={"relative"} bg={"gray.800"}>
{isDefined(ProgressWidget) && (
<Box
display={"inline-flex"}
Expand Down Expand Up @@ -84,7 +84,7 @@ export const LogViewer = ({
isScrolling={setUserIsScrolling}
style={{ height: "660px" }}
data={logLines.filter(({ message }) => isDefined(message))}
itemContent={(index, line) => <LogLine {...line} />}
itemContent={(_, line) => <LogLine {...line} />}
/>
{isDefined(progressPercent) && (
<Progress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export const ConfigureEnclaveModal = ({
<Modal closeOnOverlayClick={false} isOpen={isOpen} onClose={handleClose} isCentered size={"5xl"}>
<ModalOverlay />
<ModalContent>
<ModalHeader textAlign={"center"}>Enclave Configuration</ModalHeader>
<ModalHeader textAlign={"center"}>{!isDefined(existingEnclave) && "New "}Enclave Configuration</ModalHeader>
<ModalCloseButton />
<EnclaveConfigurationForm
ref={formRef}
Expand All @@ -187,7 +187,7 @@ export const ConfigureEnclaveModal = ({
>
<ModalBody p={"0px"}>
<Flex fontSize={"sm"} justifyContent={"center"} alignItems={"center"} gap={"12px"} pb={"12px"}>
<Text>Deploying</Text>
<Text>Configuring</Text>
<EnclaveSourceButton source={kurtosisPackage.name} size={"sm"} variant={"outline"} color={"gray.100"} />
</Flex>
{isDefined(error) && <KurtosisAlert message={error} />}
Expand Down Expand Up @@ -220,7 +220,7 @@ export const ConfigureEnclaveModal = ({
Cancel
</Button>
<Button type={"submit"} isLoading={isLoading} colorScheme={"kurtosisGreen"}>
Run
{existingEnclave ? "Update" : "Run"}
</Button>
</Flex>
</ModalFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const ManualCreateEnclaveModal = ({ isOpen, onClose, onConfirm }: ManualC
disabled: isLoading,
required: true,
})}
autoFocus={true}
/>
</InputGroup>
<FormErrorMessage>{errors.url?.message}</FormErrorMessage>
Expand Down
Loading