Skip to content

Commit

Permalink
DEVPROD-8364: Extract command section metadata and manage open/close …
Browse files Browse the repository at this point in the history
…state (#197)
  • Loading branch information
SupaJoon authored Jun 28, 2024
1 parent 0e2481c commit e982220
Show file tree
Hide file tree
Showing 17 changed files with 613 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ describe("getLinesInProcessedLogLinesFromSelectedLines", () => {
2,
{ range: { end: 4, start: 3 }, rowType: RowType.SkippedLines },
{
functionID: "function-4",
functionName: "test",
isOpen: true,
range: { end: 6, start: 4 },
rowType: RowType.SectionHeader,
},
{
commandID: "command-4",
commandName: "shell.exec",
functionName: "test",
functionID: "function-4",
isOpen: true,
range: { end: 6, start: 4 },
rowType: RowType.SubsectionHeader,
Expand Down
5 changes: 3 additions & 2 deletions apps/parsley/src/components/LogRow/RowRenderer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const ParsleyRow: RowRendererFunction = ({ processedLogLines }) => {
searchState,
sectioning,
} = useLogContext();
const { openSection } = sectioning;
const { toggleFunctionSection } = sectioning;
const { prettyPrint, wordWrapFormat, wrap } = preferences;

const { searchTerm } = searchState;
Expand Down Expand Up @@ -76,9 +76,10 @@ const ParsleyRow: RowRendererFunction = ({ processedLogLines }) => {
if (isSectionHeaderRow(processedLogLine)) {
return (
<SectionHeader
functionID={processedLogLine.functionID}
functionName={processedLogLine.functionName}
lineIndex={index}
onOpen={openSection}
onToggle={toggleFunctionSection}
open={processedLogLine.isOpen}
status={SectionStatus.Pass} // TODO: Update in DEVPROD-5295
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const Container = styled.div`
`;

const sectionHeaderProps = {
onOpen: () => {},
functionID: "function-4",
onToggle: () => {},
open: true,
status: SectionStatus.Pass,
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ describe("SectionHeader", () => {

it("should call onOpen function when 'open' button is clicked", async () => {
const user = userEvent.setup();
const onOpen = vi.fn();
render(<SectionHeader {...sectionHeaderProps} onOpen={onOpen} />);
const onToggle = vi.fn();
render(<SectionHeader {...sectionHeaderProps} onToggle={onToggle} />);
const openButton = screen.getByDataCy("caret-toggle");
await user.click(openButton);
expect(onOpen).toHaveBeenCalledTimes(1);
expect(onOpen).toHaveBeenCalledWith("load_data", true);
expect(onToggle).toHaveBeenCalledTimes(1);
expect(onToggle).toHaveBeenCalledWith({
functionID: "function-4",
isOpen: true,
});
});

it("open and close state is controlled by the 'open' prop", async () => {
Expand All @@ -72,9 +75,10 @@ describe("SectionHeader", () => {
});

const sectionHeaderProps = {
functionID: "function-4",
functionName: "load_data",
lineIndex: 0,
onOpen: vi.fn(),
onToggle: vi.fn(),
open: false,
status: SectionStatus.Pass,
};
10 changes: 6 additions & 4 deletions apps/parsley/src/components/LogRow/SectionHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ import { useLogWindowAnalytics } from "analytics";
import { Row } from "components/LogRow/types";
import { SectionStatus } from "constants/logs";
import { size } from "constants/tokens";
import { OpenSection } from "hooks/useSections";
import { ToggleFunctionSection } from "hooks/useSections";
import { CaretToggle } from "../CaretToggle";

const { gray } = palette;

interface SectionHeaderProps extends Row {
functionName: string;
onOpen: OpenSection;
functionID: string;
onToggle: ToggleFunctionSection;
open: boolean;
status: SectionStatus;
}

const SectionHeader: React.FC<SectionHeaderProps> = ({
functionID,
functionName,
onOpen,
onToggle,
open,
status,
}) => {
Expand All @@ -39,7 +41,7 @@ const SectionHeader: React.FC<SectionHeaderProps> = ({
sectionName: functionName,
sectionType: "function",
});
onOpen(functionName, !open);
onToggle({ functionID, isOpen: !open });
}}
open={open}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const SubsectionHeaderStory = () => {
{...SubsectionHeaderProps}
commandName="shell.exec"
lineIndex={0}
onOpen={({ isOpen }) => setOpen(isOpen)}
onToggle={({ isOpen }) => setOpen(isOpen)}
open={open}
/>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ describe("SubsectionHeader", () => {

it("should call onOpen function when 'open' button is clicked", async () => {
const user = userEvent.setup();
const onOpen = vi.fn();
render(<SubsectionHeader {...sectionHeaderProps} onOpen={onOpen} />);
const onToggle = vi.fn();
render(<SubsectionHeader {...sectionHeaderProps} onToggle={onToggle} />);
const openButton = screen.getByDataCy("caret-toggle");
await user.click(openButton);
expect(onOpen).toHaveBeenCalledTimes(1);
expect(onOpen).toHaveBeenCalledWith({
expect(onToggle).toHaveBeenCalledTimes(1);
expect(onToggle).toHaveBeenCalledWith({
commandID: "command-1",
functionID: "function-1",
isOpen: true,
Expand Down Expand Up @@ -63,6 +63,6 @@ const sectionHeaderProps = {
commandName: "shell.exec",
functionID: "function-1",
lineIndex: 0,
onOpen: vi.fn(),
onToggle: vi.fn(),
open: false,
};
11 changes: 4 additions & 7 deletions apps/parsley/src/components/LogRow/SubsectionHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Body } from "@leafygreen-ui/typography";
import { useLogWindowAnalytics } from "analytics";
import { Row } from "components/LogRow/types";
import { size } from "constants/tokens";
import { ToggleCommandSection } from "hooks/useSections";
import { CaretToggle } from "../CaretToggle";

const { gray } = palette;
Expand All @@ -12,19 +13,15 @@ interface SectionHeaderProps extends Row {
commandName: string;
functionID: string;
commandID: string;
onOpen: (v: {
commandID: string;
functionID: string;
isOpen: boolean;
}) => void;
onToggle: ToggleCommandSection;
open: boolean;
}

const SubsectionHeader: React.FC<SectionHeaderProps> = ({
commandID,
commandName,
functionID,
onOpen,
onToggle,
open,
}) => {
const { sendEvent } = useLogWindowAnalytics();
Expand All @@ -39,7 +36,7 @@ const SubsectionHeader: React.FC<SectionHeaderProps> = ({
sectionName: commandName,
sectionType: "command",
});
onOpen({ commandID, functionID, isOpen: !open });
onToggle({ commandID, functionID, isOpen: !open });
}}
open={open}
/>
Expand Down
79 changes: 59 additions & 20 deletions apps/parsley/src/hooks/useSections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,30 @@ import { useToastContext } from "context/toast";
import { useParsleySettings } from "hooks/useParsleySettings";
import { reportError } from "utils/errorReporting";
import { releaseSectioning } from "utils/featureFlag";
import { SectionEntry, parseSections } from "./utils";
import { SectionData, parseSections } from "./utils";

export type SectionState = { [functionName: string]: { isOpen: boolean } };
export type OpenSection = (functionName: string, isOpen: boolean) => void;
export type SectionState = {
[functionID: string]: {
isOpen: boolean;
commands: { [commandID: string]: { isOpen: boolean } };
};
};

export type ToggleCommandSection = (props: {
functionID: string;
commandID: string;
isOpen: boolean;
}) => void;

export type ToggleFunctionSection = (props: {
functionID: string;
isOpen: boolean;
}) => void;

export interface UseSectionsResult {
sectionData: SectionEntry[] | undefined;
openSection: OpenSection;
sectionData: SectionData | undefined;
toggleCommandSection: ToggleCommandSection;
toggleFunctionSection: ToggleFunctionSection;
sectionState: SectionState | undefined;
sectioningEnabled: boolean;
}
Expand All @@ -27,7 +43,7 @@ export const useSections = ({
renderingType,
}: Props): UseSectionsResult => {
const dispatchToast = useToastContext();
const [sectionData, setSectionData] = useState<SectionEntry[] | undefined>();
const [sectionData, setSectionData] = useState<SectionData | undefined>();
const [sectionState, setSectionState] = useState<SectionState>();

const { settings } = useParsleySettings();
Expand Down Expand Up @@ -56,30 +72,53 @@ export const useSections = ({

useEffect(() => {
if (sectionData && sectionState === undefined) {
setSectionState(sectionData.reduce(closeAllSectionsReducer, {}));
setSectionState(populateSectionState(sectionData));
}
}, [sectionData, sectionState]);

const openSection = useCallback(
(functionName: string, isOpen: boolean) => {
if (sectionState) {
setSectionState((currentState) => ({
...currentState,
[functionName]: { isOpen },
}));
}
const toggleFunctionSection: ToggleFunctionSection = useCallback(
({ functionID, isOpen }) => {
setSectionState((currentState) => {
if (currentState) {
const nextState = { ...currentState };
nextState[functionID].isOpen = isOpen;
return nextState;
}
return currentState;
});
},
[sectionState],
);
const toggleCommandSection: ToggleCommandSection = useCallback(
({ commandID, functionID, isOpen }) => {
setSectionState((currentState) => {
if (currentState) {
const nextState = { ...currentState };
nextState[functionID].commands[commandID].isOpen = isOpen;
return nextState;
}
return currentState;
});
},
[sectionState],
);
return {
openSection,
sectionData,
sectionState,
sectioningEnabled,
toggleCommandSection,
toggleFunctionSection,
};
};

const closeAllSectionsReducer = (
accum: SectionState,
{ functionName }: SectionEntry,
) => ({ ...accum, ...{ [functionName]: { isOpen: false } } });
const populateSectionState = (sectionData: SectionData): SectionState => {
const { commands, functions } = sectionData;
const sectionState: SectionState = {};
functions.forEach(({ functionID }) => {
sectionState[functionID] = { commands: {}, isOpen: false };
});
commands.forEach(({ commandID, functionID }) => {
sectionState[functionID].commands[commandID] = { isOpen: false };
});
return sectionState;
};
Loading

0 comments on commit e982220

Please sign in to comment.