From c839abcbc16bb6d55338ac69faa4442c45b4e75c Mon Sep 17 00:00:00 2001 From: its-a-feature Date: Tue, 5 May 2026 17:20:23 -0500 Subject: [PATCH] updated single task view page --- .../SingleTaskView/IncludeMoreTasksDialog.js | 69 ++++---- .../pages/SingleTaskView/MetadataTable.js | 30 +++- .../pages/SingleTaskView/SingleTaskView.js | 145 ++++++++++++----- .../SingleTaskView/TaskArtifactsTable.js | 46 +++--- .../SingleTaskView/TaskCredentialsTable.js | 73 +++++---- .../pages/SingleTaskView/TaskFilesTable.js | 89 ++++++----- .../SingleTaskView/TaskMITREATTACKTable.js | 38 ++--- MythicReactUI/src/themes/GlobalStyles.js | 147 ++++++++++++++++++ 8 files changed, 444 insertions(+), 193 deletions(-) diff --git a/MythicReactUI/src/components/pages/SingleTaskView/IncludeMoreTasksDialog.js b/MythicReactUI/src/components/pages/SingleTaskView/IncludeMoreTasksDialog.js index c6fc15a0..6c1b2caa 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/IncludeMoreTasksDialog.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/IncludeMoreTasksDialog.js @@ -1,4 +1,4 @@ -import React, {useState, useRef, useEffect} from 'react'; +import React, {useState, useEffect} from 'react'; import Button from '@mui/material/Button'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; @@ -8,7 +8,7 @@ import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import Select from '@mui/material/Select'; import InputLabel from '@mui/material/InputLabel'; -import Input from '@mui/material/Input'; +import Typography from '@mui/material/Typography'; export function IncludeMoreTasksDialog(props) { const [taskSelected, setTaskSelected] = useState(0); @@ -22,7 +22,6 @@ export function IncludeMoreTasksDialog(props) { {"type": "callback", "text": "This Callback"}, {"type": "operator", "text": "All callbacks but limited by operator"} ]; - const inputRef = useRef(null); const onRequestSubmit = () => { props.submitFetchTasks({ taskSelected, @@ -43,59 +42,69 @@ export function IncludeMoreTasksDialog(props) { if(props.taskOptions.length > 0){ setTaskSelected(props.taskOptions[0]); } - }, [props.tasks, props.taskOptions]) + }, [props.taskOptions]) return ( Add More Tasks to View - - - - View More Tasks Around Task: + +
+
+
+ Task window + Choose the anchor task and how many nearby tasks to pull into this view. +
+
+ + View More Tasks Around Task -

- - setBeforeCount(value)} name={"Number of tasks before"} /> - setAfterCount(value)} name={"Number of tasks after"} /> - - - Search Type +
+ setBeforeCount(value)} name={"Number of tasks before"} marginBottom="0px" /> + setAfterCount(value)} name={"Number of tasks after"} marginBottom="0px" /> +
+
+
+
+
+ Search scope + Limit the neighboring task search to this callback, all callbacks, or an operator. +
+
+ + Search Type -

- - {searchTerm === 'operator' ? ( - {setOperator(value)}} value={operator} name={"Operator Username"}/> - ) : null} - + {searchTerm === 'operator' ? ( + {setOperator(value)}} value={operator} name={"Operator Username"} marginBottom="0px" /> + ) : null} +
- - +
); } - diff --git a/MythicReactUI/src/components/pages/SingleTaskView/MetadataTable.js b/MythicReactUI/src/components/pages/SingleTaskView/MetadataTable.js index 65838a6a..3aa96f58 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/MetadataTable.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/MetadataTable.js @@ -1,10 +1,11 @@ import React, {useEffect} from 'react'; -import {useLazyQuery, gql } from '@apollo/client'; +import {gql } from '@apollo/client'; import {TaskArtifactsTable} from './TaskArtifactsTable'; import {TaskMITREATTACKTable} from './TaskMITREATTACKTable'; import {TaskFilesTable} from './TaskFilesTable'; import {TaskCredentialsTable} from './TaskCredentialsTable'; import {useMythicLazyQuery} from "../../utilities/useMythicLazyQuery"; +import {MythicEmptyState} from "../../MythicComponents/MythicStateDisplay"; const MetadataQuery = gql` @@ -68,10 +69,22 @@ query taskMetadataQuery($task_range: [Int!]) { }`; export function TaskMetadataTable(props){ const [tasks, setTasks] = React.useState([]); + const metadataQueryOptions = React.useMemo(() => ({fetchPolicy: "no-cache"}), []); + const hasMetadata = React.useMemo(() => { + return tasks.some((task) => ( + task.credentials.length > 0 || + task.filemeta.length > 0 || + task.taskartifacts.length > 0 || + task.attacktasks.length > 0 + )); + }, [tasks]); - const getMetadata = useMythicLazyQuery(MetadataQuery, {fetchPolicy: "no-cache" - }); + const getMetadata = useMythicLazyQuery(MetadataQuery, metadataQueryOptions); useEffect( () => { + if(props.taskIDs.length === 0){ + setTasks([]); + return; + } getMetadata({variables: {task_range: props.taskIDs } }).then(({data}) => { setTasks(data.task); }).catch(({data}) => { @@ -79,11 +92,20 @@ export function TaskMetadataTable(props){ }); }, [props.taskIDs, getMetadata]); return ( -
+
+ {tasks.length > 0 && !hasMetadata && +
+ +
+ }
); } diff --git a/MythicReactUI/src/components/pages/SingleTaskView/SingleTaskView.js b/MythicReactUI/src/components/pages/SingleTaskView/SingleTaskView.js index 24170a66..11bbf125 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/SingleTaskView.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/SingleTaskView.js @@ -3,18 +3,23 @@ import {TaskDisplay} from '../Callbacks/TaskDisplay'; import {gql, useLazyQuery, useQuery } from '@apollo/client'; import {useParams} from "react-router-dom"; import {TaskMetadataTable} from './MetadataTable'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import {Button, Link} from '@mui/material'; +import Checkbox from '@mui/material/Checkbox'; +import {Link} from '@mui/material'; import {IncludeMoreTasksDialog} from './IncludeMoreTasksDialog'; import { MythicDialog } from '../../MythicComponents/MythicDialog'; import {snackActions} from '../../utilities/Snackbar'; import {copyStringToClipboard} from '../../utilities/Clipboard'; -import Switch from '@mui/material/Switch'; -import {useTheme} from '@mui/material/styles'; import {taskingDataFragment} from '../Callbacks/CallbackMutations' import {meState} from "../../../cache"; import { useReactiveVar } from '@apollo/client'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd'; +import PlaylistRemoveIcon from '@mui/icons-material/PlaylistRemove'; +import DeleteIcon from '@mui/icons-material/Delete'; +import CloseIcon from '@mui/icons-material/Close'; +import {MythicPageBody} from "../../MythicComponents/MythicPageBody"; +import {MythicPageHeader, MythicPageHeaderChip, MythicSectionHeader} from "../../MythicComponents/MythicPageHeader"; +import {MythicToolbarButton} from "../../MythicComponents/MythicTableToolbar"; const tasksQuery = gql` ${taskingDataFragment} @@ -82,7 +87,11 @@ export function SingleTaskView(props){ const [tasks, setTasks] = React.useState([]); const [removing, setRemoving] = React.useState(false); const [openIncludeMoreTasksDialog, setOpenIncludeMoreTasksDialog] = React.useState(false); - const theme = useTheme(); + const taskCount = tasks.filter((task) => task.type === "task").length; + const callbackCount = tasks.filter((task) => task.type === "callback").length; + const selectedRemoveCount = tasks.filter((task) => task.type === "task" && task.checked).length; + const taskCountLabel = taskCount === 1 ? "1 task" : `${taskCount} tasks`; + const callbackCountLabel = callbackCount === 1 ? "1 callback" : `${callbackCount} callbacks`; const mergeData = (taskData) => { let allNewParents = taskData.filter( (task) => task.parent_task_id === null); let allData = []; @@ -163,18 +172,36 @@ export function SingleTaskView(props){ }); setTasks(updated); } - const removeTasksButton = () => { - removing ? setRemoving(false) : setRemoving(true); - const remainingTasks = tasks.filter( (task) => !task.checked); + const enterRemoveMode = () => { + setRemoving(true); + } + const cancelRemoveMode = () => { + setRemoving(false); + setTasks(tasks.map((task) => task.type === "task" ? {...task, checked: false} : task)); + } + const removeSelectedTasks = () => { + const remainingTaskRows = tasks.filter( (task) => task.type === "task" && !task.checked); + const remainingCallbackDisplayIds = new Set(remainingTaskRows.map( (task) => task.callback.display_id)); + const remainingTasks = tasks.filter( (task) => { + if(task.type === "task"){ + return !task.checked; + } + return remainingCallbackDisplayIds.has(task.display_id); + }).map((task) => task.type === "task" ? {...task, checked: false} : task); setTasks(remainingTasks); const remainingTaskIDs = remainingTasks.reduce( (prev, cur) => { if(cur.type === "task"){ - return [...prev, cur.display_id]; + const subIds = cur.tasks.filter( (subTask) => !prev.includes(subTask.display_id)).map( (subTask) => subTask.display_id); + if(prev.includes(cur.display_id)){ + return [...prev, ...subIds]; + } + return [...prev, cur.display_id, ...subIds]; }else{ return [...prev]; } }, []); setTaskIDs(remainingTaskIDs); + setRemoving(false); } const collapse_range = (all_nums) =>{ // takes in an array of the expanded numbers and collapses it down @@ -242,44 +269,84 @@ export function SingleTaskView(props){ getTasks({variables: {task_range: [parseInt(taskId)]}}); } }, [getTasks, taskId]); + const getCallbackTitle = (callback) => { + const domain = callback.domain === "" ? "" : `${callback.domain}\\`; + const integrity = callback.integrity_level > 2 ? "*" : ""; + return `${domain}${callback.user}${integrity}@${callback.host}`; + } return ( -
- - - Task View - - - - -
+ + + + + {removing && 0 ? "warning" : undefined} />} + + } + actions={ + <> + }> + Share Link + + {removing ? ( + <> + }> + Cancel + + }> + Remove Selected + + + ) : ( + }> + Remove Tasks + + )} + + } + /> +
{tasks.map( (task) => ( task.type === "task" ? ( -
-
+
+
{removing ? ( - + ) : null}
) : ( - - - {task.domain === "" ? null : (task.domain + "\\")}{task.user}{task.integrity_level > 2 ? ("*") : null}@{task.host} ( - {task.display_id} - ) - - - + + Callback #{task.display_id} + + } + actions={ + {setTaskSearchInfo(task.display_id)}} startIcon={}> + Include Tasks + + } + sx={{mt: 0.75}} + /> )) ) @@ -292,7 +359,7 @@ export function SingleTaskView(props){ /> } -
+ ); } // diff --git a/MythicReactUI/src/components/pages/SingleTaskView/TaskArtifactsTable.js b/MythicReactUI/src/components/pages/SingleTaskView/TaskArtifactsTable.js index aa8e4992..f5754f23 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/TaskArtifactsTable.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/TaskArtifactsTable.js @@ -1,17 +1,14 @@ import React, { useEffect } from 'react'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import {useTheme} from '@mui/material/styles'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; +import MythicStyledTableCell from '../../MythicComponents/MythicTableCell'; +import {MythicPageHeaderChip, MythicSectionHeader} from "../../MythicComponents/MythicPageHeader"; export function TaskArtifactsTable(props){ const [artifacts, setArtifacts] = React.useState([]); - const theme = useTheme(); useEffect( () => { const condensed = props.tasks.reduce( (prev, tsk) => { @@ -24,38 +21,37 @@ export function TaskArtifactsTable(props){ if(artifacts.length === 0){ return null } + const artifactCountLabel = artifacts.length === 1 ? "1 artifact" : `${artifacts.length} artifacts`; return ( - - - - Artifact Tasks - - - - - - +
+ } + /> + +
- Task ID - Artifact Type - Host - Artifact + Task ID + Artifact Type + Host + Artifact {artifacts.map( (artifact) => ( - {artifact.display_id} - {artifact.base_artifact} - {artifact.host} - {artifact.artifact_text} + {artifact.display_id} + {artifact.base_artifact} + {artifact.host} + {artifact.artifact_text} ))}
-
-
+
); } diff --git a/MythicReactUI/src/components/pages/SingleTaskView/TaskCredentialsTable.js b/MythicReactUI/src/components/pages/SingleTaskView/TaskCredentialsTable.js index bd12bd12..ee88aa84 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/TaskCredentialsTable.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/TaskCredentialsTable.js @@ -1,23 +1,21 @@ import React, { useEffect } from 'react'; import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import {useTheme} from '@mui/material/styles'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import { MythicStyledTooltip } from '../../MythicComponents/MythicStyledTooltip'; import { copyStringToClipboard } from '../../utilities/Clipboard'; -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faCopy} from '@fortawesome/free-solid-svg-icons'; import {IconButton} from '@mui/material'; import {snackActions} from '../../utilities/Snackbar'; +import MythicStyledTableCell from '../../MythicComponents/MythicTableCell'; +import {MythicPageHeaderChip, MythicSectionHeader} from "../../MythicComponents/MythicPageHeader"; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import {MythicStatusChip} from "../../MythicComponents/MythicStatusChip"; export function TaskCredentialsTable(props){ const [credentials, setCredentials] = React.useState([]); - const theme = useTheme(); useEffect( () => { const condensed = props.tasks.reduce( (prev, tsk) => { @@ -29,25 +27,25 @@ export function TaskCredentialsTable(props){ if(credentials.length === 0){ return null } + const credentialCountLabel = credentials.length === 1 ? "1 credential" : `${credentials.length} credentials`; return ( - - - - Credentials - - - - - - +
+ } + /> + +
- Task - Type - Realm - Account - Credentials - Comment + Task + Type + Realm + Account + Credentials + Comment @@ -57,8 +55,7 @@ export function TaskCredentialsTable(props){
-
-
+
); } @@ -75,30 +72,32 @@ const CredentialTableRow = ({cred}) => { } return ( - {cred.display_id} - {cred.type} - {cred.realm} - {cred.account} - + {cred.display_id} + + + + {cred.realm} + {cred.account} + {cred.credential_text.length > 64 ? ( - +
- onCopyToClipboard(cred.credential_text)} size="small"> - + onCopyToClipboard(cred.credential_text)} size="small"> + - {displayCred} - + {displayCred} +
) : ( - {displayCred} + {displayCred} )} -
- {cred.comment} + + {cred.comment}
) } diff --git a/MythicReactUI/src/components/pages/SingleTaskView/TaskFilesTable.js b/MythicReactUI/src/components/pages/SingleTaskView/TaskFilesTable.js index e2b13848..03313ebf 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/TaskFilesTable.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/TaskFilesTable.js @@ -1,20 +1,18 @@ import React, { useEffect } from 'react'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import {useTheme} from '@mui/material/styles'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import Link from '@mui/material/Link'; import {b64DecodeUnicode} from '../Callbacks/ResponseDisplay'; +import MythicStyledTableCell from '../../MythicComponents/MythicTableCell'; +import {MythicPageHeaderChip, MythicSectionHeader} from "../../MythicComponents/MythicPageHeader"; +import {MythicStatusChip} from "../../MythicComponents/MythicStatusChip"; export function TaskFilesTable(props){ const [files, setFiles] = React.useState([]); - const theme = useTheme(); useEffect( () => { const condensed = props.tasks.reduce( (prev, tsk) => { @@ -27,56 +25,73 @@ export function TaskFilesTable(props){ if(files.length === 0){ return null } + const fileCountLabel = files.length === 1 ? "1 file" : `${files.length} files`; return ( - - - - Files / Screenshots - - - - - - +
+ } + /> + +
- Filename - Type - Remote Path - Comment - Hashes + Filename + Type + Remote Path + Comment + Hashes {files.map( (file) => ( - + {!file.deleted && file.complete ? ( - {b64DecodeUnicode(file.filename_text)} + {b64DecodeUnicode(file.filename_text)} ) : ( !file.complete ? ( b64DecodeUnicode(file.filename_text) + " (" + file.chunks_received + "/" + file.total_chunks + ")" ) : (b64DecodeUnicode(file.filename_text)) )} - - - {file.is_screenshot ? ("Screenshot") : ( - file.is_payload ? ("Payload") : ( - file.is_download_from_agent ? ("Download") : ( - "Upload" - ) - ) - )} - - {b64DecodeUnicode(file.full_remote_path_text) === "" ? ("") : (file.host + "\n" + b64DecodeUnicode(file.full_remote_path_text)) } - {file.comment} - {"MD5: "}{file.md5}
{"SHA1: "}{file.sha1}
+ + + + + {b64DecodeUnicode(file.full_remote_path_text) === "" ? ("") : (file.host + "\n" + b64DecodeUnicode(file.full_remote_path_text)) } + {file.comment} + +
+ MD5: {file.md5} + SHA1: {file.sha1} +
+
))}
-
-
+
); } + +const TaskFileTypeChip = ({file}) => { + if(file.deleted){ + return ; + } + if(!file.complete){ + return ; + } + if(file.is_screenshot){ + return ; + } + if(file.is_payload){ + return ; + } + if(file.is_download_from_agent){ + return ; + } + return ; +} diff --git a/MythicReactUI/src/components/pages/SingleTaskView/TaskMITREATTACKTable.js b/MythicReactUI/src/components/pages/SingleTaskView/TaskMITREATTACKTable.js index 271202a1..cdc49f58 100644 --- a/MythicReactUI/src/components/pages/SingleTaskView/TaskMITREATTACKTable.js +++ b/MythicReactUI/src/components/pages/SingleTaskView/TaskMITREATTACKTable.js @@ -1,17 +1,14 @@ import React, { useEffect } from 'react'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import {useTheme} from '@mui/material/styles'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; +import MythicStyledTableCell from '../../MythicComponents/MythicTableCell'; +import {MythicPageHeaderChip, MythicSectionHeader} from "../../MythicComponents/MythicPageHeader"; export function TaskMITREATTACKTable(props){ const [attacks, setAttacks] = React.useState([]); - const theme = useTheme(); useEffect( () => { const condensed = props.tasks.reduce( (prev, tsk) => { @@ -32,34 +29,33 @@ export function TaskMITREATTACKTable(props){ if(attacks.length === 0){ return null } + const attackCountLabel = attacks.length === 1 ? "1 technique" : `${attacks.length} techniques`; return ( - - - - MITRE ATT&CK Mappings - - - - - - +
+ } + /> + +
- Technique ID - Technique + Technique ID + Technique {attacks.map( (attack) => ( - {attack.attack.t_num} - {attack.attack.name} + {attack.attack.t_num} + {attack.attack.name} ))}
-
-
+
); } diff --git a/MythicReactUI/src/themes/GlobalStyles.js b/MythicReactUI/src/themes/GlobalStyles.js index 4005b697..06bba8f8 100644 --- a/MythicReactUI/src/themes/GlobalStyles.js +++ b/MythicReactUI/src/themes/GlobalStyles.js @@ -1124,6 +1124,153 @@ tspan { .mythic-form-switch-control { flex: 0 0 auto; } +.mythic-single-task-list { + display: flex; + flex-direction: column; + gap: 0.5rem; + min-height: 0; + min-width: 0; + overflow: visible; + width: 100%; +} +.mythic-single-task-card-row { + align-items: flex-start; + display: grid; + gap: 0.5rem; + grid-template-columns: minmax(0, 1fr); + min-width: 0; + width: 100%; +} +.mythic-single-task-card-row-removing { + grid-template-columns: minmax(0, 1fr) auto; +} +.mythic-single-task-display { + min-width: 0; + width: 100%; +} +.mythic-single-task-remove-control { + align-items: center; + background-color: ${(props) => props.theme.palette.mode === "dark" ? alpha(props.theme.palette.error.main, 0.14) : alpha(props.theme.palette.error.main, 0.08)}; + border: 1px solid ${(props) => alpha(props.theme.palette.error.main, props.theme.palette.mode === "dark" ? 0.45 : 0.28)}; + border-radius: ${(props) => props.theme.shape.borderRadius}px; + color: ${(props) => props.theme.palette.error.main}; + cursor: pointer; + display: flex; + flex-direction: column; + flex: 0 0 auto; + font-size: 0.72rem; + font-weight: 750; + gap: 0.1rem; + justify-content: center; + margin-top: 4px; + min-height: 52px; + min-width: 4.25rem; + padding: 0.35rem 0.45rem; + transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease; +} +.mythic-single-task-remove-control:hover, +.mythic-single-task-remove-control-selected { + background-color: ${(props) => alpha(props.theme.palette.error.main, props.theme.palette.mode === "dark" ? 0.24 : 0.14)}; + border-color: ${(props) => alpha(props.theme.palette.error.main, props.theme.palette.mode === "dark" ? 0.72 : 0.48)}; +} +.mythic-single-task-remove-control .MuiCheckbox-root { + padding: 0; +} +.mythic-single-task-callback-link { + color: inherit !important; + font-weight: 800; + overflow-wrap: anywhere; +} +.mythic-single-task-metadata { + display: flex; + flex-direction: column; + gap: 0.6rem; + margin-top: 0.3rem; + min-width: 0; + width: 100%; +} +.mythic-single-task-metadata-section { + display: flex; + flex-direction: column; + gap: 0.4rem; + min-width: 0; + width: 100%; +} +.mythic-single-task-table-wrap { + background-color: ${(props) => props.theme.surfaces?.raised || props.theme.palette.background.paper}; + overflow: auto; +} +.mythic-single-task-table { + min-width: 48rem; + table-layout: fixed; +} +.mythic-single-task-files-table { + min-width: 68rem; +} +.mythic-single-task-mitre-table { + min-width: 32rem; +} +.mythic-single-task-cell-break { + overflow-wrap: anywhere; + white-space: pre-wrap; + word-break: break-word; +} +.mythic-single-task-table-link { + color: inherit !important; + font-weight: 700; + text-decoration: underline !important; +} +.mythic-single-task-hash-list { + display: flex; + flex-direction: column; + font-family: ${(props) => props.theme.typography.fontFamilyMono || "monospace"}; + font-size: 0.74rem; + gap: 0.2rem; + overflow-wrap: anywhere; +} +.mythic-single-task-credential-cell { + align-items: flex-start; + display: flex; + gap: 0.45rem; + min-width: 0; +} +.mythic-single-task-credential-text { + max-width: 42rem; + min-width: 0; + overflow-wrap: anywhere; + word-break: break-word; +} +.mythic-single-task-empty-card { + background-color: ${(props) => props.theme.surfaces?.raised || props.theme.palette.background.paper}; + border: 1px solid ${(props) => props.theme.table?.borderSoft || props.theme.borderColor}; + border-radius: ${(props) => props.theme.shape.borderRadius}px; + min-width: 0; + width: 100%; +} +.mythic-single-task-dialog-control { + margin-top: 0.45rem !important; +} +.mythic-single-task-dialog-grid { + align-items: flex-start; + display: grid; + gap: 0.65rem; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); + margin-top: 0.65rem; + min-width: 0; +} +@media screen and (max-width: 760px) { + .mythic-single-task-card-row-removing { + grid-template-columns: minmax(0, 1fr); + } + .mythic-single-task-remove-control { + align-items: center; + flex-direction: row; + justify-content: flex-start; + margin-top: 0; + min-height: 38px; + width: 100%; + } +} .mythic-create-flow-shell { display: flex; flex-direction: column;