Skip to content

Commit

Permalink
UI performance and feature updates
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Jul 29, 2024
1 parent f557670 commit 9ecf431
Show file tree
Hide file tree
Showing 40 changed files with 982 additions and 556 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.3.0-rc5] - 2024-07-29

### Changed

- Many UI updates check out [UI Fixes](/MythicReactUI/CHANGELOG.MD) for 2.0.4

## [3.3.0-rc2] - 2024-07-11

### Changed
Expand Down
17 changes: 17 additions & 0 deletions MythicReactUI/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.4] - 2024-07-29

### Changed

- adjusted auto scrolling of tasks to not happen unless you're scrolled to the bottom already
- using the old callbacks table view, the callback you're interacting with will be highlighted
- tasks are auto expanded on the single task view page
- the file browser now has some "history" for the last 20 folders visited with forward/backward arrows
- the file browser now has an "up" button to go up one folder in addition to double clicking a folder to go down one
- fixed an issue where sometimes a task's output browser script wouldn't render
- condensed the views of tables in browser scripts, file browser, process browser, and active callbacks table to be able to view more at once
- removed agent icons from the active callbacks table and replaced with text of payload type name to make things cleaner when compact
- updated interactive callback controls to have a different background color to make the input fields more obvious
- adjusted task displays to link to both task and callbacks along with tooltips on hover
- fixed an issue where you could do multiple context menues in the file browser tree view
- fixed pty's command history to reset after issuing a task so that it's more consistent

## [0.2.3] - 2024-07-17

### Changed
Expand Down
4 changes: 3 additions & 1 deletion MythicReactUI/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export function App(props) {
contrast: themeMode === 'dark' ? '#000' : '#fff',
},
textBackgroundColor: themeMode === 'dark' ? '#272c2f' : '#e9eaea',
textBackgroundColorMythic: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
textBackgroundColorPrimary: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
textBackgroundColorSuccess: themeMode === 'dark' ? '#09a21a' : '#70e373',
textBackgroundColorError: themeMode === 'dark' ? '#9f1616' : '#f19da3',
graphGroup: themeMode === 'dark' ? '#394c5d' : '#d3d7e8',
Expand All @@ -104,6 +104,8 @@ export function App(props) {
successOnMain: '#1ae302',
errorOnMain: '#ff656b',
infoOnMain: '#67ceff',
selectedCallbackColor: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
selectedCallbackHierarchyColor: themeMode === 'dark' ? '#273e5d' : '#deeff8',
materialReactTableHeader: themeMode === 'dark' ? '#484848' : '#d5d5d5',
tableBorder: themeMode === 'dark' ? 'rgba(81,81,81,1)' : 'rgba(224,224,224,1)',
tableHover: themeMode === 'dark' ? 'rgba(60,60,60)' : 'rgb(232,232,232)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export function MythicDisplayTextDialog(props) {
<React.Fragment>
<DialogTitle id="form-dialog-title">{props.title}</DialogTitle>
<DialogContent dividers={true}>
<MythicTextField multiline={true} value={props.value} onChange={()=>{}} />
<pre style={{whiteSpace: "pre-wrap"}}>
{props.value}
</pre>
</DialogContent>
<DialogActions>
<Button onClick={props.onClose} variant="contained" color="primary">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,7 @@ import ErrorIcon from '@mui/icons-material/Error';
import { useTheme } from '@mui/material/styles';
import { Typography } from '@mui/material';
import { MythicStyledTooltip } from "./MythicStyledTooltip";
import Grow from '@mui/material/Grow';
import Popper from '@mui/material/Popper';
import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import Paper from '@mui/material/Paper';
import WidgetsIcon from '@mui/icons-material/Widgets';
import ListSubheader from '@mui/material/ListSubheader';

const PREFIX = 'FileBrowserVirtualTree';

Expand Down Expand Up @@ -151,16 +144,15 @@ const VirtualTreeRow = ({
onExpandNode,
onCollapseNode,
onDoubleClickNode,
contextMenuOptions,
onContextMenu,
tabInfo,
selectedFolderData,
...ListProps
}) => {
const itemTreeData = ListProps.data[ListProps.index];
const item = ListProps.treeRootData[itemTreeData.group]?.[itemTreeData.host]?.[itemTreeData.full_path_text] || itemTreeData;
//console.log("item", item, "itemlookup", ListProps.treeRootData[itemTreeData.host]?.[itemTreeData.name])
const dropdownAnchorRef = React.useRef(null);
const theme = useTheme();

const handleOnClickButton = (e) => {
e.stopPropagation();
if (itemTreeData.isOpen) {
Expand All @@ -173,42 +165,25 @@ const VirtualTreeRow = ({
const handleOnClickRow = (e) => {
onSelectNode(item.id, {...item, group: itemTreeData.group, host: itemTreeData.host});
};
const [openContextMenu, setOpenContextMenu] = React.useState(false);

const handleContextClick = useCallback(
(event) => {
event.preventDefault();
event.stopPropagation();
if(item.root){

}else if(item.is_group){

}else {
if(contextMenuOptions && contextMenuOptions.length > 0){
setOpenContextMenu(true);
}
const handleContextClick = (e) => {
onContextMenu({event: e, item, itemTreeData});
}
const selectedPath = () => {
if(itemTreeData.group === selectedFolderData.group && itemTreeData.host === selectedFolderData.host){
if(itemTreeData.root){
return "selectedCallbackHierarchy";
}
if(selectedFolderData.id === itemTreeData.id){
return "selectedCallback";
}

},
[contextMenuOptions] // eslint-disable-line react-hooks/exhaustive-deps
);
const handleMenuItemClick = (event, index, callback_id, callback_display_id) => {
event.preventDefault();
event.stopPropagation();
contextMenuOptions[index].click({event,
node: {...item, group: itemTreeData.group, host: itemTreeData.host},
callback_id, callback_display_id
});
setOpenContextMenu(false);
};
const handleClose = (event) => {
if (dropdownAnchorRef.current && dropdownAnchorRef.current.contains(event.target)) {
return;
}
setOpenContextMenu(false);
};
return "";
}
return (
<div className={"hoverme"} style={ListProps.style} onContextMenu={handleContextClick} ref={dropdownAnchorRef} onClick={handleOnClickRow}>
<div className={`hoverme ${selectedPath()}`}
style={ListProps.style}
onContextMenu={handleContextClick}
onClick={handleOnClickRow}>
<div style={{display: 'flex' , marginBottom: "1px", flexGrow: 1, width: "100%"}}>
{[...Array(itemTreeData.depth)].map((o, i) => (
<div
Expand All @@ -225,54 +200,7 @@ const VirtualTreeRow = ({
style={{ backgroundColor: theme.body, color: theme.text, alignItems: 'center', display: 'flex', paddingRight: "10px", textDecoration: itemTreeData.deleted ? 'line-through' : '' }}

>
<Popper open={openContextMenu} anchorEl={dropdownAnchorRef.current} role={undefined} transition style={{zIndex: 4}}>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === 'bottom' ? 'left top' : 'left bottom',
}}
>
<Paper className={"dropdownMenuColored"}>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu" style={{paddingTop: 0}} >
<ListSubheader component={"li"} className={"MuiListSubheader-root"}>
Act from current Callback: {tabInfo["displayID"]}
</ListSubheader>
{contextMenuOptions.map((option, index) => (
<MenuItem
key={option.name + index}
onClick={(event) => handleMenuItemClick(event, index, tabInfo["callbackID"], tabInfo["displayID"])}
>
{option.name}
</MenuItem>
))}
{
item?.callback && item?.["callback"]?.["id"] !== tabInfo["callbackID"] &&
<ListSubheader component={"li"} className={"MuiListSubheader-root"}>
Act from originating Callback: {item?.callback?.["display_id"] || tabInfo["displayID"]}
</ListSubheader>
}
{
item?.callback && item?.["callback"]?.["id"] !== tabInfo["callbackID"] &&
contextMenuOptions.map((option, index) => (
<MenuItem
key={option.name + index}
onClick={(event) => handleMenuItemClick(event, index,
item?.["callback"]?.["id"] || tabInfo["callbackID"],
item?.["callback"]?.["display_id"] || tabInfo["displayID"])}
>
{option.name}
</MenuItem>
))
}

</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
{itemTreeData.is_group ? (
<WidgetsIcon style={{marginLeft: "3px", marginRight: "5px" }} />
): itemTreeData.root ? (
Expand Down Expand Up @@ -328,8 +256,9 @@ const FileBrowserVirtualTree = ({
onSelectNode,
onExpandNode,
onCollapseNode,
contextMenuOptions,
onContextMenu,
showDeletedFiles,
selectedFolderData,
tabInfo,
}) => {
const flattenNode = useCallback(
Expand Down Expand Up @@ -401,7 +330,6 @@ const FileBrowserVirtualTree = ({
},
[openNodes, showDeletedFiles] // eslint-disable-line react-hooks/exhaustive-deps
);

const flattenedNodes = useMemo(() => {
//console.log("in tree", treeRootData, treeAdjMatrix)
// need to return an array
Expand Down Expand Up @@ -471,11 +399,12 @@ const FileBrowserVirtualTree = ({
<VirtualTreeRow
{...ListProps}
tabInfo={tabInfo}
selectedFolderData={selectedFolderData}
treeRootData={treeRootData}
onSelectNode={onSelectNode}
onExpandNode={onExpandNode}
onCollapseNode={onCollapseNode}
contextMenuOptions={contextMenuOptions}
onContextMenu={onContextMenu}
/>
)}
</List>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const CellPreMemo = ({ VariableSizeGridProps: { style, rowIndex, columnIndex, da
const item = data.items[rowIndex][columnIndex];
const cellStyle = item?.props?.cellData?.cellStyle || {};
const rowStyle = data.items[rowIndex][columnIndex]?.props?.rowData?.rowStyle || {};
const selectedClass = data.items[rowIndex][columnIndex]?.props?.rowData?.selected ? "selectedCallback" : "";
const onMouseEnter = () => {
const cells = document.getElementsByClassName(rowClassName);
if(cells.length > 0){
Expand Down Expand Up @@ -56,14 +57,14 @@ const CellPreMemo = ({ VariableSizeGridProps: { style, rowIndex, columnIndex, da
);
return (
<div style={{...style, ...cellStyle, ...rowStyle}}
className={`${classes.cell} ${rowClassName}`}
className={`${classes.cell} ${rowClassName} ${selectedClass}`}
onDoubleClick={handleDoubleClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onContextMenu={handleContextClick}
ref={dropdownAnchorRef}
>
<div className={classes.cellInner}>
<div className={classes.cellInner} style={{height: style.height}}>
{item}
</div>
<ContextMenu dropdownAnchorRef={dropdownAnchorRef} contextMenuOptions={contextMenuOptions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import DraggableHandles from './DraggableHandles';
import {classes} from './styles';
const HeaderCellContext = createContext({});

const MIN_COLUMN_WIDTH = 100;
const MIN_COLUMN_WIDTH = 50;

const CellRenderer = (VariableSizeGridProps) => {
return VariableSizeGridProps.rowIndex === 0 ? null : <Cell VariableSizeGridProps={VariableSizeGridProps} />;
Expand Down Expand Up @@ -137,6 +137,9 @@ const ResizableGridWrapper = ({
};

const autosizeColumn = ({columnIndex}) => {
if(columns[columnIndex].disableDoubleClick){
return
}
const longestElementInColumn = Math.max(...items.map((itemRow) => {
if(!columns[columnIndex].key){
if(columns[columnIndex].plaintext){
Expand All @@ -153,6 +156,12 @@ const ResizableGridWrapper = ({
if(columns[columnIndex].key === "mythictree_groups"){
return itemRow[columnIndex]?.props?.cellData.length;
}
if(columns[columnIndex].type === "size"){
if(itemRow[columnIndex]?.props?.cellData){
return String(itemRow[columnIndex]?.props?.cellData?.plaintext)?.length;
}
return itemRow[columnIndex].length;
}
try{
items = JSON.parse(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key]);
if(Array.isArray(items) && items.length > 0){
Expand All @@ -162,8 +171,11 @@ const ResizableGridWrapper = ({
//console.log(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key])
}
let data = itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key];
if(columns[columnIndex].inMetadata){
return itemRow[columnIndex]?.props?.cellData.length;
}
if(!data){
return 3;
return MIN_COLUMN_WIDTH;
}
if(data.plaintext){
return String(data.plaintext).length || -1;
Expand All @@ -172,7 +184,6 @@ const ResizableGridWrapper = ({
}
//return String(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key]).length || -1;
} else if(typeof(itemRow[columnIndex]?.props?.cellData) === "string") {

try {
items = JSON.parse(itemRow[columnIndex]?.props?.cellData);
if (Array.isArray(items) && items.length > 0) {
Expand All @@ -190,10 +201,14 @@ const ResizableGridWrapper = ({
}));
const updatedWidths = columnWidths.map((columnWidth, index) => {
if (columnIndex === index) {
if(isNaN(longestElementInColumn)){
return MIN_COLUMN_WIDTH;
}
return Math.floor(Math.max(longestElementInColumn * 10 + 40, MIN_COLUMN_WIDTH));
}
return Math.floor(columnWidth);
});
//console.log(updatedWidths, longestElementInColumn);
setColumnWidths(updatedWidths);
};

Expand Down Expand Up @@ -224,7 +239,7 @@ const ResizableGridWrapper = ({
rowHeight={getRowHeight}
itemData={{ items: itemsWithHeader, onDoubleClickRow, gridUUID, rowContextMenuOptions}}
innerElementType={innerElementType}
overscanRowCount={5}
overscanRowCount={10}
onScroll={({ scrollLeft }) => {
if (dragHandlesRef.current) {
dragHandlesRef.current.scrollTo({ left: scrollLeft });
Expand Down Expand Up @@ -259,7 +274,7 @@ const MythicResizableGrid = ({
contextMenuOptions,
rowContextMenuOptions,
widthMeasureKey,
rowHeight = 32,
rowHeight = 20,
}) => {
return (
<AutoSizer style={{height: "100%"}}>
Expand Down
2 changes: 1 addition & 1 deletion MythicReactUI/src/components/pages/Callbacks/Callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export function Callbacks({me}) {
<SpeedDialWrapper setTopDisplay={setTopDisplay} />
<Split direction="vertical" sizes={[30, 70]} minSize={[0,0]} style={{ height: "100%" }}>
<div className="bg-gray-base">
<CallbacksTop topDisplay={topDisplay} onOpenTab={onOpenTab.current} me={me}/>
<CallbacksTop topDisplay={topDisplay} onOpenTab={onOpenTab.current} me={me} clickedTabId={clickedTabId}/>
</div>
<div className="bg-gray-mid">
<CallbacksTabs
Expand Down
Loading

0 comments on commit 9ecf431

Please sign in to comment.