Skip to content

Commit 9ecf431

Browse files
committed
UI performance and feature updates
1 parent f557670 commit 9ecf431

40 files changed

+982
-556
lines changed

CHANGELOG.MD

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.3.0-rc5] - 2024-07-29
8+
9+
### Changed
10+
11+
- Many UI updates check out [UI Fixes](/MythicReactUI/CHANGELOG.MD) for 2.0.4
12+
713
## [3.3.0-rc2] - 2024-07-11
814

915
### Changed

MythicReactUI/CHANGELOG.MD

+17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

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

926
### Changed

MythicReactUI/src/components/App.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export function App(props) {
9191
contrast: themeMode === 'dark' ? '#000' : '#fff',
9292
},
9393
textBackgroundColor: themeMode === 'dark' ? '#272c2f' : '#e9eaea',
94-
textBackgroundColorMythic: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
94+
textBackgroundColorPrimary: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
9595
textBackgroundColorSuccess: themeMode === 'dark' ? '#09a21a' : '#70e373',
9696
textBackgroundColorError: themeMode === 'dark' ? '#9f1616' : '#f19da3',
9797
graphGroup: themeMode === 'dark' ? '#394c5d' : '#d3d7e8',
@@ -104,6 +104,8 @@ export function App(props) {
104104
successOnMain: '#1ae302',
105105
errorOnMain: '#ff656b',
106106
infoOnMain: '#67ceff',
107+
selectedCallbackColor: themeMode === 'dark' ? '#436b9f' : '#aadcf5',
108+
selectedCallbackHierarchyColor: themeMode === 'dark' ? '#273e5d' : '#deeff8',
107109
materialReactTableHeader: themeMode === 'dark' ? '#484848' : '#d5d5d5',
108110
tableBorder: themeMode === 'dark' ? 'rgba(81,81,81,1)' : 'rgba(224,224,224,1)',
109111
tableHover: themeMode === 'dark' ? 'rgba(60,60,60)' : 'rgb(232,232,232)',

MythicReactUI/src/components/MythicComponents/MythicDisplayTextDialog.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export function MythicDisplayTextDialog(props) {
1212
<React.Fragment>
1313
<DialogTitle id="form-dialog-title">{props.title}</DialogTitle>
1414
<DialogContent dividers={true}>
15-
<MythicTextField multiline={true} value={props.value} onChange={()=>{}} />
15+
<pre style={{whiteSpace: "pre-wrap"}}>
16+
{props.value}
17+
</pre>
1618
</DialogContent>
1719
<DialogActions>
1820
<Button onClick={props.onClose} variant="contained" color="primary">

MythicReactUI/src/components/MythicComponents/MythicFileBrowserVirtualTree.js

+22-93
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,7 @@ import ErrorIcon from '@mui/icons-material/Error';
1212
import { useTheme } from '@mui/material/styles';
1313
import { Typography } from '@mui/material';
1414
import { MythicStyledTooltip } from "./MythicStyledTooltip";
15-
import Grow from '@mui/material/Grow';
16-
import Popper from '@mui/material/Popper';
17-
import MenuItem from '@mui/material/MenuItem';
18-
import MenuList from '@mui/material/MenuList';
19-
import ClickAwayListener from '@mui/material/ClickAwayListener';
20-
import Paper from '@mui/material/Paper';
2115
import WidgetsIcon from '@mui/icons-material/Widgets';
22-
import ListSubheader from '@mui/material/ListSubheader';
2316

2417
const PREFIX = 'FileBrowserVirtualTree';
2518

@@ -151,16 +144,15 @@ const VirtualTreeRow = ({
151144
onExpandNode,
152145
onCollapseNode,
153146
onDoubleClickNode,
154-
contextMenuOptions,
147+
onContextMenu,
155148
tabInfo,
149+
selectedFolderData,
156150
...ListProps
157151
}) => {
158152
const itemTreeData = ListProps.data[ListProps.index];
159153
const item = ListProps.treeRootData[itemTreeData.group]?.[itemTreeData.host]?.[itemTreeData.full_path_text] || itemTreeData;
160154
//console.log("item", item, "itemlookup", ListProps.treeRootData[itemTreeData.host]?.[itemTreeData.name])
161-
const dropdownAnchorRef = React.useRef(null);
162155
const theme = useTheme();
163-
164156
const handleOnClickButton = (e) => {
165157
e.stopPropagation();
166158
if (itemTreeData.isOpen) {
@@ -173,42 +165,25 @@ const VirtualTreeRow = ({
173165
const handleOnClickRow = (e) => {
174166
onSelectNode(item.id, {...item, group: itemTreeData.group, host: itemTreeData.host});
175167
};
176-
const [openContextMenu, setOpenContextMenu] = React.useState(false);
177-
178-
const handleContextClick = useCallback(
179-
(event) => {
180-
event.preventDefault();
181-
event.stopPropagation();
182-
if(item.root){
183-
184-
}else if(item.is_group){
185-
186-
}else {
187-
if(contextMenuOptions && contextMenuOptions.length > 0){
188-
setOpenContextMenu(true);
189-
}
168+
const handleContextClick = (e) => {
169+
onContextMenu({event: e, item, itemTreeData});
170+
}
171+
const selectedPath = () => {
172+
if(itemTreeData.group === selectedFolderData.group && itemTreeData.host === selectedFolderData.host){
173+
if(itemTreeData.root){
174+
return "selectedCallbackHierarchy";
175+
}
176+
if(selectedFolderData.id === itemTreeData.id){
177+
return "selectedCallback";
190178
}
191-
192-
},
193-
[contextMenuOptions] // eslint-disable-line react-hooks/exhaustive-deps
194-
);
195-
const handleMenuItemClick = (event, index, callback_id, callback_display_id) => {
196-
event.preventDefault();
197-
event.stopPropagation();
198-
contextMenuOptions[index].click({event,
199-
node: {...item, group: itemTreeData.group, host: itemTreeData.host},
200-
callback_id, callback_display_id
201-
});
202-
setOpenContextMenu(false);
203-
};
204-
const handleClose = (event) => {
205-
if (dropdownAnchorRef.current && dropdownAnchorRef.current.contains(event.target)) {
206-
return;
207179
}
208-
setOpenContextMenu(false);
209-
};
180+
return "";
181+
}
210182
return (
211-
<div className={"hoverme"} style={ListProps.style} onContextMenu={handleContextClick} ref={dropdownAnchorRef} onClick={handleOnClickRow}>
183+
<div className={`hoverme ${selectedPath()}`}
184+
style={ListProps.style}
185+
onContextMenu={handleContextClick}
186+
onClick={handleOnClickRow}>
212187
<div style={{display: 'flex' , marginBottom: "1px", flexGrow: 1, width: "100%"}}>
213188
{[...Array(itemTreeData.depth)].map((o, i) => (
214189
<div
@@ -225,54 +200,7 @@ const VirtualTreeRow = ({
225200
style={{ backgroundColor: theme.body, color: theme.text, alignItems: 'center', display: 'flex', paddingRight: "10px", textDecoration: itemTreeData.deleted ? 'line-through' : '' }}
226201

227202
>
228-
<Popper open={openContextMenu} anchorEl={dropdownAnchorRef.current} role={undefined} transition style={{zIndex: 4}}>
229-
{({ TransitionProps, placement }) => (
230-
<Grow
231-
{...TransitionProps}
232-
style={{
233-
transformOrigin: placement === 'bottom' ? 'left top' : 'left bottom',
234-
}}
235-
>
236-
<Paper className={"dropdownMenuColored"}>
237-
<ClickAwayListener onClickAway={handleClose}>
238-
<MenuList id="split-button-menu" style={{paddingTop: 0}} >
239-
<ListSubheader component={"li"} className={"MuiListSubheader-root"}>
240-
Act from current Callback: {tabInfo["displayID"]}
241-
</ListSubheader>
242-
{contextMenuOptions.map((option, index) => (
243-
<MenuItem
244-
key={option.name + index}
245-
onClick={(event) => handleMenuItemClick(event, index, tabInfo["callbackID"], tabInfo["displayID"])}
246-
>
247-
{option.name}
248-
</MenuItem>
249-
))}
250-
{
251-
item?.callback && item?.["callback"]?.["id"] !== tabInfo["callbackID"] &&
252-
<ListSubheader component={"li"} className={"MuiListSubheader-root"}>
253-
Act from originating Callback: {item?.callback?.["display_id"] || tabInfo["displayID"]}
254-
</ListSubheader>
255-
}
256-
{
257-
item?.callback && item?.["callback"]?.["id"] !== tabInfo["callbackID"] &&
258-
contextMenuOptions.map((option, index) => (
259-
<MenuItem
260-
key={option.name + index}
261-
onClick={(event) => handleMenuItemClick(event, index,
262-
item?.["callback"]?.["id"] || tabInfo["callbackID"],
263-
item?.["callback"]?.["display_id"] || tabInfo["displayID"])}
264-
>
265-
{option.name}
266-
</MenuItem>
267-
))
268-
}
269203

270-
</MenuList>
271-
</ClickAwayListener>
272-
</Paper>
273-
</Grow>
274-
)}
275-
</Popper>
276204
{itemTreeData.is_group ? (
277205
<WidgetsIcon style={{marginLeft: "3px", marginRight: "5px" }} />
278206
): itemTreeData.root ? (
@@ -328,8 +256,9 @@ const FileBrowserVirtualTree = ({
328256
onSelectNode,
329257
onExpandNode,
330258
onCollapseNode,
331-
contextMenuOptions,
259+
onContextMenu,
332260
showDeletedFiles,
261+
selectedFolderData,
333262
tabInfo,
334263
}) => {
335264
const flattenNode = useCallback(
@@ -401,7 +330,6 @@ const FileBrowserVirtualTree = ({
401330
},
402331
[openNodes, showDeletedFiles] // eslint-disable-line react-hooks/exhaustive-deps
403332
);
404-
405333
const flattenedNodes = useMemo(() => {
406334
//console.log("in tree", treeRootData, treeAdjMatrix)
407335
// need to return an array
@@ -471,11 +399,12 @@ const FileBrowserVirtualTree = ({
471399
<VirtualTreeRow
472400
{...ListProps}
473401
tabInfo={tabInfo}
402+
selectedFolderData={selectedFolderData}
474403
treeRootData={treeRootData}
475404
onSelectNode={onSelectNode}
476405
onExpandNode={onExpandNode}
477406
onCollapseNode={onCollapseNode}
478-
contextMenuOptions={contextMenuOptions}
407+
onContextMenu={onContextMenu}
479408
/>
480409
)}
481410
</List>

MythicReactUI/src/components/MythicComponents/MythicResizableGrid/Cell.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const CellPreMemo = ({ VariableSizeGridProps: { style, rowIndex, columnIndex, da
2222
const item = data.items[rowIndex][columnIndex];
2323
const cellStyle = item?.props?.cellData?.cellStyle || {};
2424
const rowStyle = data.items[rowIndex][columnIndex]?.props?.rowData?.rowStyle || {};
25+
const selectedClass = data.items[rowIndex][columnIndex]?.props?.rowData?.selected ? "selectedCallback" : "";
2526
const onMouseEnter = () => {
2627
const cells = document.getElementsByClassName(rowClassName);
2728
if(cells.length > 0){
@@ -56,14 +57,14 @@ const CellPreMemo = ({ VariableSizeGridProps: { style, rowIndex, columnIndex, da
5657
);
5758
return (
5859
<div style={{...style, ...cellStyle, ...rowStyle}}
59-
className={`${classes.cell} ${rowClassName}`}
60+
className={`${classes.cell} ${rowClassName} ${selectedClass}`}
6061
onDoubleClick={handleDoubleClick}
6162
onMouseEnter={onMouseEnter}
6263
onMouseLeave={onMouseLeave}
6364
onContextMenu={handleContextClick}
6465
ref={dropdownAnchorRef}
6566
>
66-
<div className={classes.cellInner}>
67+
<div className={classes.cellInner} style={{height: style.height}}>
6768
{item}
6869
</div>
6970
<ContextMenu dropdownAnchorRef={dropdownAnchorRef} contextMenuOptions={contextMenuOptions}

MythicReactUI/src/components/MythicComponents/MythicResizableGrid/MythicResizableGrid.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import DraggableHandles from './DraggableHandles';
99
import {classes} from './styles';
1010
const HeaderCellContext = createContext({});
1111

12-
const MIN_COLUMN_WIDTH = 100;
12+
const MIN_COLUMN_WIDTH = 50;
1313

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

139139
const autosizeColumn = ({columnIndex}) => {
140+
if(columns[columnIndex].disableDoubleClick){
141+
return
142+
}
140143
const longestElementInColumn = Math.max(...items.map((itemRow) => {
141144
if(!columns[columnIndex].key){
142145
if(columns[columnIndex].plaintext){
@@ -153,6 +156,12 @@ const ResizableGridWrapper = ({
153156
if(columns[columnIndex].key === "mythictree_groups"){
154157
return itemRow[columnIndex]?.props?.cellData.length;
155158
}
159+
if(columns[columnIndex].type === "size"){
160+
if(itemRow[columnIndex]?.props?.cellData){
161+
return String(itemRow[columnIndex]?.props?.cellData?.plaintext)?.length;
162+
}
163+
return itemRow[columnIndex].length;
164+
}
156165
try{
157166
items = JSON.parse(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key]);
158167
if(Array.isArray(items) && items.length > 0){
@@ -162,8 +171,11 @@ const ResizableGridWrapper = ({
162171
//console.log(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key])
163172
}
164173
let data = itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key];
174+
if(columns[columnIndex].inMetadata){
175+
return itemRow[columnIndex]?.props?.cellData.length;
176+
}
165177
if(!data){
166-
return 3;
178+
return MIN_COLUMN_WIDTH;
167179
}
168180
if(data.plaintext){
169181
return String(data.plaintext).length || -1;
@@ -172,7 +184,6 @@ const ResizableGridWrapper = ({
172184
}
173185
//return String(itemRow[columnIndex]?.props?.rowData?.[columns[columnIndex].key]).length || -1;
174186
} else if(typeof(itemRow[columnIndex]?.props?.cellData) === "string") {
175-
176187
try {
177188
items = JSON.parse(itemRow[columnIndex]?.props?.cellData);
178189
if (Array.isArray(items) && items.length > 0) {
@@ -190,10 +201,14 @@ const ResizableGridWrapper = ({
190201
}));
191202
const updatedWidths = columnWidths.map((columnWidth, index) => {
192203
if (columnIndex === index) {
204+
if(isNaN(longestElementInColumn)){
205+
return MIN_COLUMN_WIDTH;
206+
}
193207
return Math.floor(Math.max(longestElementInColumn * 10 + 40, MIN_COLUMN_WIDTH));
194208
}
195209
return Math.floor(columnWidth);
196210
});
211+
//console.log(updatedWidths, longestElementInColumn);
197212
setColumnWidths(updatedWidths);
198213
};
199214

@@ -224,7 +239,7 @@ const ResizableGridWrapper = ({
224239
rowHeight={getRowHeight}
225240
itemData={{ items: itemsWithHeader, onDoubleClickRow, gridUUID, rowContextMenuOptions}}
226241
innerElementType={innerElementType}
227-
overscanRowCount={5}
242+
overscanRowCount={10}
228243
onScroll={({ scrollLeft }) => {
229244
if (dragHandlesRef.current) {
230245
dragHandlesRef.current.scrollTo({ left: scrollLeft });
@@ -259,7 +274,7 @@ const MythicResizableGrid = ({
259274
contextMenuOptions,
260275
rowContextMenuOptions,
261276
widthMeasureKey,
262-
rowHeight = 32,
277+
rowHeight = 20,
263278
}) => {
264279
return (
265280
<AutoSizer style={{height: "100%"}}>

MythicReactUI/src/components/pages/Callbacks/Callbacks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export function Callbacks({me}) {
174174
<SpeedDialWrapper setTopDisplay={setTopDisplay} />
175175
<Split direction="vertical" sizes={[30, 70]} minSize={[0,0]} style={{ height: "100%" }}>
176176
<div className="bg-gray-base">
177-
<CallbacksTop topDisplay={topDisplay} onOpenTab={onOpenTab.current} me={me}/>
177+
<CallbacksTop topDisplay={topDisplay} onOpenTab={onOpenTab.current} me={me} clickedTabId={clickedTabId}/>
178178
</div>
179179
<div className="bg-gray-mid">
180180
<CallbacksTabs

0 commit comments

Comments
 (0)