Skip to content

Commit

Permalink
Revert "feat: service logs full download (#1895)"
Browse files Browse the repository at this point in the history
This reverts commit b91333f.
  • Loading branch information
h4ck3rk3y committed Dec 12, 2023
1 parent b7c3451 commit 4072d42
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 156 deletions.
18 changes: 3 additions & 15 deletions enclave-manager/web/src/components/DownloadButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Button, ButtonProps, IconButton, IconButtonProps } from "@chakra-ui/react";
import { FiDownload } from "react-icons/fi";
import streamsaver from "streamsaver";
import { isAsyncIterable, isDefined, stripAnsi } from "../utils";
import { isDefined } from "../utils";
import { saveTextAsFile } from "../utils/download";

type DownloadButtonProps<IsIconButton extends boolean> = (IsIconButton extends true ? IconButtonProps : ButtonProps) & {
valueToDownload?: (() => string) | (() => AsyncIterable<string>) | string | null;
valueToDownload?: (() => string) | string | null;
fileName: string;
text?: IsIconButton extends true ? string : never;
isIconButton?: IsIconButton;
Expand All @@ -18,20 +17,9 @@ export const DownloadButton = <IsIconButton extends boolean>({
isIconButton,
...buttonProps
}: DownloadButtonProps<IsIconButton>) => {
const handleDownloadClick = async () => {
const handleDownloadClick = () => {
if (isDefined(valueToDownload)) {
const v = typeof valueToDownload === "string" ? valueToDownload : valueToDownload();

if (isAsyncIterable(v)) {
const writableStream = streamsaver.createWriteStream(fileName);
const writer = writableStream.getWriter();

for await (const part of v) {
await writer.write(new TextEncoder().encode(`${stripAnsi(part)}\n`));
}
await writer.close();
return;
}
saveTextAsFile(v, fileName);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const theme = extendTheme({
const outline = theme.components.Button.variants!.outline(props);
return {
...outline,
_hover: { ...outline._hover, bg: "gray.600" },
_hover: { ...outline._hover, bg: "gray.700" },
color: `${props.colorScheme}.400`,
borderColor: "gray.300",
};
Expand Down
19 changes: 17 additions & 2 deletions enclave-manager/web/src/components/PackageSourceButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { PropsWithChildren } from "react";
import { IoLogoGithub } from "react-icons/io";
import { useKurtosisPackageIndexerClient } from "../client/packageIndexer/KurtosisPackageIndexerClientContext";
import { isDefined, wrapResult } from "../utils";
import { CopyButton } from "./CopyButton";

type EnclaveSourceProps = PropsWithChildren<
ButtonProps & {
source: "loading" | string | null;
hideCopy?: boolean;
}
>;

export const PackageSourceButton = ({ source, children, ...buttonProps }: EnclaveSourceProps) => {
export const PackageSourceButton = ({ source, hideCopy, children, ...buttonProps }: EnclaveSourceProps) => {
const kurtosisIndexer = useKurtosisPackageIndexerClient();

if (!isDefined(source)) {
Expand Down Expand Up @@ -61,5 +63,18 @@ export const PackageSourceButton = ({ source, children, ...buttonProps }: Enclav
}
}

return <ButtonGroup>{button}</ButtonGroup>;
return (
<ButtonGroup>
{button}
{!hideCopy && (
<CopyButton
contentName={"package id"}
valueToCopy={source}
isIconButton
aria-label={"Copy package id"}
size={buttonProps.size || "xs"}
/>
)}
</ButtonGroup>
);
};
37 changes: 13 additions & 24 deletions enclave-manager/web/src/components/catalog/KurtosisPackageCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, Icon, Image, Text } from "@chakra-ui/react";
import { Flex, Icon, Image, Text } from "@chakra-ui/react";
import { IoStar } from "react-icons/io5";
import { Link } from "react-router-dom";
import { useKurtosisClient } from "../../client/enclaveManager/KurtosisClientContext";
Expand Down Expand Up @@ -41,30 +41,19 @@ export const KurtosisPackageCard = ({ kurtosisPackage }: KurtosisPackageCardProp
<Text noOfLines={2} fontSize={"lg"}>
{readablePackageName(kurtosisPackage.name)}
</Text>
<Box
flex={"1"}
sx={{
containerType: "size",
containerName: "details-container",
"@container details-container (min-height: 30px)": {
"> div": { flexDirection: "column", justifyContent: "flex-end", height: "100%" },
},
}}
>
<Flex justifyContent={"space-between"} fontSize={"xs"} gap={"8px"}>
<Text as={"span"} textTransform={"capitalize"}>
{kurtosisPackage.repositoryMetadata?.owner.replaceAll("-", " ") || "Unknown owner"}
</Text>
<Flex gap={"4px"} alignItems={"center"}>
{kurtosisPackage.stars > 0 && (
<>
<Icon color="gray.500" as={IoStar} />
<Text as={"span"}>{kurtosisPackage.stars.toString()}</Text>
</>
)}
</Flex>
<Flex justifyContent={"space-between"} fontSize={"xs"}>
<Text as={"span"} textTransform={"capitalize"}>
{kurtosisPackage.repositoryMetadata?.owner.replaceAll("-", " ") || "Unknown owner"}
</Text>
<Flex gap={"4px"} alignItems={"center"}>
{kurtosisPackage.stars > 0 && (
<>
<Icon color="gray.500" as={IoStar} />
<Text as={"span"}>{kurtosisPackage.stars.toString()}</Text>
</>
)}
</Flex>
</Box>
</Flex>
</Flex>
</Flex>
<Flex gap={"16px"} width={"100%"}>
Expand Down
83 changes: 39 additions & 44 deletions enclave-manager/web/src/components/enclaves/logs/LogViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
Text,
Tooltip,
} from "@chakra-ui/react";
import { throttle } from "lodash";
import { debounce, throttle } from "lodash";
import { ChangeEvent, MutableRefObject, ReactElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { FiSearch } from "react-icons/fi";
import { MdArrowBackIosNew, MdArrowForwardIos } from "react-icons/md";
Expand All @@ -39,8 +39,6 @@ type LogViewerProps = {
ProgressWidget?: ReactElement;
logsFileName?: string;
searchEnabled?: boolean;
copyLogsEnabled?: boolean;
onGetAllLogs?: () => AsyncIterable<string>;
};

type SearchBaseState = {
Expand Down Expand Up @@ -71,8 +69,6 @@ export const LogViewer = ({
ProgressWidget,
logsFileName,
searchEnabled,
copyLogsEnabled,
onGetAllLogs,
}: LogViewerProps) => {
const virtuosoRef = useRef<VirtuosoHandle>(null);
const [logLines, setLogLines] = useState(propsLogLines);
Expand All @@ -98,7 +94,7 @@ export const LogViewer = ({
}
};

const handleSearchStateChange = useCallback((updater: ((prevState: SearchState) => SearchState) | SearchState) => {
const handleSearchStateChange = (updater: ((prevState: SearchState) => SearchState) | SearchState) => {
setSearchState((prevState) => {
const newState = typeof updater === "object" ? updater : updater(prevState);
if (
Expand All @@ -110,7 +106,7 @@ export const LogViewer = ({
}
return newState;
});
}, []);
};

const getLogsValue = () => {
return logLines
Expand Down Expand Up @@ -183,19 +179,17 @@ export const LogViewer = ({
</FormLabel>
</FormControl>
<ButtonGroup>
{copyLogsEnabled && (
<CopyButton
contentName={"logs"}
valueToCopy={getLogsValue}
size={"sm"}
isDisabled={logLines.length === 0}
isIconButton
aria-label={"Copy logs"}
color={"gray.100"}
/>
)}
<CopyButton
contentName={"logs"}
valueToCopy={getLogsValue}
size={"sm"}
isDisabled={logLines.length === 0}
isIconButton
aria-label={"Copy logs"}
color={"gray.100"}
/>
<DownloadButton
valueToDownload={onGetAllLogs || getLogsValue}
valueToDownload={getLogsValue}
size={"sm"}
fileName={logsFileName || `logs.txt`}
isDisabled={logLines.length === 0}
Expand All @@ -219,8 +213,6 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo
const searchRef: MutableRefObject<HTMLInputElement | null> = useRef(null);
const [showSearchForm, setShowSearchForm] = useState(false);

const maybeCurrentSearchIndex = searchState.type === "success" ? searchState.currentSearchIndex : null;

const updateMatches = useCallback(
(searchTerm: string) => {
if (isNotEmpty(searchTerm)) {
Expand Down Expand Up @@ -255,38 +247,44 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo
[logLines, onChangeSearchState],
);

const throttledUpdateMatches = useMemo(() => throttle(updateMatches, 300), [updateMatches]);
const debouncedUpdateMatches = useMemo(() => debounce(updateMatches, 100), [updateMatches]);

const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
onChangeSearchState((state) => ({ ...state, rawSearchTerm: e.target.value }));
throttledUpdateMatches(e.target.value);
debouncedUpdateMatches(e.target.value);
};

const updateSearchIndexBounded = useCallback(
(newIndex: number) => {
onChangeSearchState((searchState) => {
if (searchState.type !== "success" || searchState.searchMatchesIndices.length === 0) {
return searchState;
}
if (newIndex > searchState.searchMatchesIndices.length - 1) {
newIndex = 0;
}
if (newIndex < 0) {
newIndex = searchState.searchMatchesIndices.length - 1;
}
return { ...searchState, currentSearchIndex: newIndex };
});
if (searchState.type !== "success") {
return;
}
if (newIndex > searchState.searchMatchesIndices.length - 1) {
newIndex = 0;
}
if (newIndex < 0) {
newIndex = searchState.searchMatchesIndices.length - 1;
}
onChangeSearchState((state) => ({ ...state, currentSearchIndex: newIndex }));
},
[onChangeSearchState],
[onChangeSearchState, searchState],
);

const handlePriorMatchClick = useCallback(() => {
updateSearchIndexBounded(isDefined(maybeCurrentSearchIndex) ? maybeCurrentSearchIndex - 1 : 0);
}, [updateSearchIndexBounded, maybeCurrentSearchIndex]);
updateSearchIndexBounded(
searchState.type === "success" && isDefined(searchState.currentSearchIndex)
? searchState.currentSearchIndex - 1
: 0,
);
}, [updateSearchIndexBounded, searchState]);

const handleNextMatchClick = useCallback(() => {
updateSearchIndexBounded(isDefined(maybeCurrentSearchIndex) ? maybeCurrentSearchIndex + 1 : 0);
}, [updateSearchIndexBounded, maybeCurrentSearchIndex]);
updateSearchIndexBounded(
searchState.type === "success" && isDefined(searchState.currentSearchIndex)
? searchState.currentSearchIndex + 1
: 0,
);
}, [updateSearchIndexBounded, searchState]);

const handleClearSearch = useCallback(() => {
onChangeSearchState({ type: "init", rawSearchTerm: "" });
Expand Down Expand Up @@ -315,12 +313,9 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo
searchRef.current.focus();
}
},
enter: () => {
next: () => {
handleNextMatchClick();
},
"shift-enter": () => {
handlePriorMatchClick();
},
escape: () => {
if (isDefined(searchRef.current) && searchRef.current === document.activeElement) {
handleClearSearch();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Checkbox, Text } from "@chakra-ui/react";
import { Button, Checkbox } from "@chakra-ui/react";
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
import { FilesArtifactNameAndUuid, ServiceInfo } from "enclave-manager-sdk/build/api_container_service_pb";
import { EnclaveContainersStatus } from "enclave-manager-sdk/build/engine_service_pb";
Expand Down Expand Up @@ -93,9 +93,7 @@ export const EnclavesTable = ({ enclavesData, selection, onSelectionChange }: En
cell: (nameCell) => (
<Link to={`/enclave/${nameCell.row.original.uuid}/overview`}>
<Button size={"sm"} variant={"ghost"}>
<Text as={"span"} maxW={"200px"} textOverflow={"ellipsis"} overflow={"hidden"}>
{nameCell.row.original.name}
</Text>
{nameCell.row.original.name}
</Button>
</Link>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const DownloadFileArtifactButton = ({ file, enclave }: DownloadFileButton

const handleDownloadClick = async () => {
setIsLoading(true);
// todo: get tgz download instead
const fileParts = await kurtosisClient.downloadFilesArtifact(enclave, file);
const writableStream = streamsaver.createWriteStream(`${enclave.name}--${file.fileName}.tgz`);
const writer = writableStream.getWriter();
Expand Down
45 changes: 17 additions & 28 deletions enclave-manager/web/src/components/useKeyboardAction.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,33 @@
import { useEffect } from "react";
import { isDefined } from "../utils";

export type KeyboardActions = "escape" | "find" | "omniFind" | "enter" | "shift-enter";
export type KeyboardActions = "escape" | "find" | "omniFind" | "next";

export type OnCtrlPressHandlers = Partial<Record<KeyboardActions, () => void>>;

const getEventType = (e: KeyboardEvent): KeyboardActions | null => {
const eventIsType = (e: KeyboardEvent, type: KeyboardActions) => {
const ctrlOrMeta = e.ctrlKey || e.metaKey;

if (ctrlOrMeta && e.keyCode === 70) {
// F
return "find";
switch (type) {
case "find":
return ctrlOrMeta && e.keyCode === 70; // F
case "next":
return ctrlOrMeta && e.keyCode === 71; // G
case "omniFind":
return ctrlOrMeta && e.keyCode === 75; // K
case "escape":
return e.key === "Escape" || e.keyCode === 27;
}
if (e.shiftKey && e.keyCode === 13) {
// shift + enter
return "shift-enter";
}
if (e.keyCode === 13) {
// enter
return "enter";
}
if (ctrlOrMeta && e.keyCode === 75) {
// K
return "omniFind";
}
if (e.key === "Escape" || e.keyCode === 27) {
return "escape";
}
return null;
};

export const useKeyboardAction = (handlers: OnCtrlPressHandlers) => {
useEffect(() => {
const listener = function (e: KeyboardEvent) {
const eventType = getEventType(e);
const handler = isDefined(eventType) ? handlers[eventType] : null;
if (isDefined(handler)) {
e.preventDefault();
handler();
return;
for (const [handlerType, handler] of Object.entries(handlers)) {
if (eventIsType(e, handlerType as KeyboardActions)) {
e.preventDefault();
handler();
return;
}
}
};
window.addEventListener("keydown", listener);
Expand Down
Loading

0 comments on commit 4072d42

Please sign in to comment.