diff --git a/cmd/ui/src/components/GraphButton/GraphButton.tsx b/cmd/ui/src/components/GraphButton/GraphButton.tsx index 48545c68f..a7ccae839 100644 --- a/cmd/ui/src/components/GraphButton/GraphButton.tsx +++ b/cmd/ui/src/components/GraphButton/GraphButton.tsx @@ -52,10 +52,7 @@ const GraphButton: FC = ({ onClick, displayText, disabled }) = const styles = useStyles(); return ( - ); diff --git a/cmd/ui/src/components/GraphButtons/GraphButtons.tsx b/cmd/ui/src/components/GraphButtons/GraphButtons.tsx index a0da523ba..56edf61b1 100644 --- a/cmd/ui/src/components/GraphButtons/GraphButtons.tsx +++ b/cmd/ui/src/components/GraphButtons/GraphButtons.tsx @@ -83,7 +83,12 @@ const GraphButtons: FC = ({ rankDirection, options, nonLayout {nonLayoutButtons?.length && ( <> {nonLayoutButtons.map((props, index) => ( - + ))} )} diff --git a/cmd/ui/src/components/GraphEvents.tsx b/cmd/ui/src/components/GraphEvents.tsx index a35bad941..722ebc293 100644 --- a/cmd/ui/src/components/GraphEvents.tsx +++ b/cmd/ui/src/components/GraphEvents.tsx @@ -234,7 +234,7 @@ export const GraphEvents: FC = ({ setSelectedEdge(null); setHighlightedNode(selectedNode.graphId); } - }, [selectedNode]) + }, [selectedNode]); return null; }; diff --git a/cmd/ui/src/views/Explore/ExploreSearchCombobox/ExploreSearchCombobox.tsx b/cmd/ui/src/views/Explore/ExploreSearchCombobox/ExploreSearchCombobox.tsx index 3b8a7bdf8..21cd6142f 100644 --- a/cmd/ui/src/views/Explore/ExploreSearchCombobox/ExploreSearchCombobox.tsx +++ b/cmd/ui/src/views/Explore/ExploreSearchCombobox/ExploreSearchCombobox.tsx @@ -17,7 +17,7 @@ import { List, ListItem, ListItemText, Paper, TextField, useTheme } from '@mui/material'; import { useCombobox } from 'downshift'; import { useState } from 'react'; -import { NodeIcon, SearchResultItem } from 'bh-shared-ui'; +import { NodeIcon, SearchResultItem } from 'bh-shared-ui'; import { useDebouncedValue } from 'src/hooks/useDebouncedValue'; import { getEmptyResultsText, getKeywordAndTypeValues, SearchResult, useSearch } from 'src/hooks/useSearch'; @@ -124,7 +124,7 @@ const ExploreSearchCombobox: React.FC<{ item={{ label: item.name, objectId: item.objectid, - kind: item.type + kind: item.type, }} index={index} key={index} diff --git a/justfile b/justfile index 8e3ce8c13..bde72757a 100644 --- a/justfile +++ b/justfile @@ -81,15 +81,12 @@ yarn-local *ARGS="": @yarn {{ARGS}} # run yarn commands in the context of the workspace root and rebuild containers -yarn *ARGS="": +yarn *ARGS="": && (bh-dev "build bh-ui") @yarn {{ARGS}} - @just bh-dev build bh-ui # run the code generation from the cue schema -schemagen: +schemagen: yarn-local && check-license (yarn "format") go run github.com/specterops/bloodhound/schemagen - @just check-license - @just yarn format # run imagemagick commands in the context of the project root imagemagick *ARGS: diff --git a/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.test.tsx b/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.test.tsx index b4688c4d8..07e4ecca2 100644 --- a/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.test.tsx +++ b/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.test.tsx @@ -14,9 +14,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import { fireEvent, render } from "@testing-library/react"; -import SearchCurrentNodes, { NO_RESULTS_TEXT } from "./SearchCurrentNodes"; -import { GraphNodes } from "./types"; +import { fireEvent, render } from '@testing-library/react'; +import SearchCurrentNodes, { NO_RESULTS_TEXT } from './SearchCurrentNodes'; +import { GraphNodes } from './types'; const nodes: GraphNodes = { '1': { @@ -24,37 +24,32 @@ const nodes: GraphNodes = { kind: 'Computer', objectId: '001', isTierZero: false, - lastSeen: '' + lastSeen: '', }, '2': { label: 'user_node', kind: 'User', objectId: '002', isTierZero: false, - lastSeen: '' + lastSeen: '', }, '3': { label: 'group_node', kind: 'Group', objectId: '003', isTierZero: false, - lastSeen: '' - } -} + lastSeen: '', + }, +}; const RESULT_ID = 'explore_search_result-list-item'; -describe("SearchCurrentNodes", () => { - +describe('SearchCurrentNodes', () => { const setup = () => { const testOnSelect = vi.fn(); const testOnClose = vi.fn(); const screen = render( - + ); const input = screen.getByRole('textbox'); @@ -67,10 +62,10 @@ describe("SearchCurrentNodes", () => { ...screen, input, resultList, - setInputValue - } - } - + setInputValue, + }; + }; + it('displays an autofocused text input', () => { const { input } = setup(); @@ -87,7 +82,7 @@ describe("SearchCurrentNodes", () => { it('displays expected results when searching by label', async () => { const { resultList, setInputValue, queryByText, findAllByTestId } = setup(); - + setInputValue('node'); expect(resultList).toBeInTheDocument(); expect(queryByText(NO_RESULTS_TEXT)).not.toBeInTheDocument(); @@ -99,7 +94,7 @@ describe("SearchCurrentNodes", () => { it('displays expected results when searching by objectid', async () => { const { resultList, setInputValue, queryByText, findAllByTestId } = setup(); - + setInputValue('00'); expect(resultList).toBeInTheDocument(); expect(queryByText(NO_RESULTS_TEXT)).not.toBeInTheDocument(); @@ -109,7 +104,7 @@ describe("SearchCurrentNodes", () => { expect(await findAllByTestId(RESULT_ID)).toHaveLength(1); }); - it('displays the label for each result', async () => { + it('displays the label for each result', async () => { const { setInputValue, findByTestId } = setup(); setInputValue('002'); @@ -127,4 +122,4 @@ describe("SearchCurrentNodes", () => { fireEvent.click(result); expect(testOnSelect).toHaveBeenCalled(); }); -}) +}); diff --git a/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.tsx b/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.tsx index a7f7a7fa8..a933ad111 100644 --- a/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.tsx +++ b/packages/javascript/bh-shared-ui/src/components/SearchCurrentNodes/SearchCurrentNodes.tsx @@ -14,16 +14,16 @@ // // SPDX-License-Identifier: Apache-2.0 -import { Box, List, ListItem, Paper, SxProps, TextField } from "@mui/material"; -import { useCombobox } from "downshift"; -import { FC, useEffect, useRef, useState } from "react"; -import SearchResultItem from "../SearchResultItem"; -import { FlatNode, GraphNodes } from "./types"; -import { useOnClickOutside } from "../../hooks"; -import { FixedSizeList } from "react-window"; +import { Box, List, ListItem, Paper, SxProps, TextField } from '@mui/material'; +import { useCombobox } from 'downshift'; +import { FC, useEffect, useRef, useState } from 'react'; +import SearchResultItem from '../SearchResultItem'; +import { FlatNode, GraphNodes } from './types'; +import { useOnClickOutside } from '../../hooks'; +import { FixedSizeList } from 'react-window'; -export const PLACEHOLDER_TEXT = "Search Current Results"; -export const NO_RESULTS_TEXT = "No result found in current results"; +export const PLACEHOLDER_TEXT = 'Search Current Results'; +export const NO_RESULTS_TEXT = 'No result found in current results'; const LIST_ITEM_HEIGHT = 38; const MAX_CONTAINER_HEIGHT = 350; @@ -34,7 +34,6 @@ const SearchCurrentNodes: FC<{ onSelect: (node: FlatNode) => void; onClose?: () => void; }> = ({ sx, currentNodes, onSelect, onClose }) => { - const containerRef = useRef(null); const inputRef = useRef(null); @@ -46,10 +45,10 @@ const SearchCurrentNodes: FC<{ // Node data is a lot easier to work with in the combobox if we transform to an array of flat objects useEffect(() => { const flatNodeList: FlatNode[] = Object.entries(currentNodes).map(([key, value]) => { - return { id: key, ...value } + return { id: key, ...value }; }); setFlatNodeList(flatNodeList); - }, [currentNodes]) + }, [currentNodes]); useEffect(() => inputRef.current?.focus(), []); @@ -57,7 +56,7 @@ const SearchCurrentNodes: FC<{ if (selectedNode) onSelect(selectedNode); }, [selectedNode, onSelect]); - // Since we are using a virtualized results container, we need to calculate the height for shorter + // Since we are using a virtualized results container, we need to calculate the height for shorter // lists to avoid whitespace useEffect(() => { const resultsHeight = LIST_ITEM_HEIGHT * items.length; @@ -73,7 +72,7 @@ const SearchCurrentNodes: FC<{ const { getInputProps, getMenuProps, getComboboxProps, getItemProps, inputValue } = useCombobox({ items, onInputValueChange: ({ inputValue }) => { - const filteredNodes = flatNodeList.filter(node => { + const filteredNodes = flatNodeList.filter((node) => { const label = node.label.toLowerCase(); const objectId = node.objectId.toLowerCase(); const lowercaseInputValue = inputValue?.toLowerCase() || ''; @@ -88,16 +87,16 @@ const SearchCurrentNodes: FC<{ switch (type) { case useCombobox.stateChangeTypes.ItemClick: if (changes.selectedItem) setSelectedNode(changes.selectedItem); - return { ...changes, inputValue: '' } + return { ...changes, inputValue: '' }; default: - return changes + return changes; } - } + }, }); const Row = ({ index, style }: any) => { return ( - + - ) - } + ); + }; return (
- - - { - {Row} - } - {items.length === 0 && inputValue && {NO_RESULTS_TEXT}} + + + { + + {Row} + + } + {items.length === 0 && inputValue && ( + + {NO_RESULTS_TEXT} + + )}
); -} +}; export default SearchCurrentNodes; diff --git a/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx b/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx index 6db8158f6..603b29869 100644 --- a/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx +++ b/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx @@ -14,23 +14,23 @@ // // SPDX-License-Identifier: Apache-2.0 -import { FC } from "react"; -import { Box, ListItem, ListItemText } from "@mui/material"; -import HighlightedText from "../HighlightedText"; -import NodeIcon from "../NodeIcon"; +import { FC } from 'react'; +import { Box, ListItem, ListItemText } from '@mui/material'; +import HighlightedText from '../HighlightedText'; +import NodeIcon from '../NodeIcon'; type NodeSearchResult = { label: string; objectId: string; kind: string; -} +}; const SearchResultItem: FC<{ item: NodeSearchResult; index: number; highlightedIndex?: number; keyword: string; - getItemProps: (options: any) => any + getItemProps: (options: any) => any; }> = ({ item, index, highlightedIndex, keyword, getItemProps }) => { return ( - +
} @@ -70,6 +67,6 @@ const SearchResultItem: FC<{ /> ); -} +}; export default SearchResultItem;