mirror of
https://github.com/its-a-feature/Mythic
synced 2026-06-08 14:55:38 +00:00
343 lines
10 KiB
JavaScript
343 lines
10 KiB
JavaScript
import React from 'react';
|
|
import { PayloadsTable } from './PayloadsTable';
|
|
import {useMutation, gql, useSubscription, useQuery, useLazyQuery} from '@apollo/client';
|
|
import { snackActions } from '../../utilities/Snackbar';
|
|
import {getSkewedNow} from "../../utilities/Time";
|
|
|
|
export const payloadFragment = gql`
|
|
fragment payloadData on payload {
|
|
build_message
|
|
build_phase
|
|
build_stderr
|
|
callback_alert
|
|
callback_allowed
|
|
id
|
|
uuid
|
|
description
|
|
deleted
|
|
auto_generated
|
|
payloadtype {
|
|
id
|
|
name
|
|
}
|
|
payload_build_steps(order_by: {step_number: asc}) {
|
|
step_name
|
|
step_number
|
|
step_success
|
|
step_skip
|
|
start_time
|
|
end_time
|
|
step_stdout
|
|
step_stderr
|
|
id
|
|
}
|
|
tags {
|
|
tagtype {
|
|
name
|
|
color
|
|
id
|
|
}
|
|
id
|
|
}
|
|
filemetum {
|
|
agent_file_id
|
|
filename_text
|
|
id
|
|
tags {
|
|
tagtype {
|
|
name
|
|
color
|
|
id
|
|
}
|
|
id
|
|
}
|
|
}
|
|
payloadc2profiles {
|
|
c2profile {
|
|
running
|
|
name
|
|
is_p2p
|
|
container_running
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
const SUB_Payloads = gql`
|
|
${payloadFragment}
|
|
subscription SubPayloadsQuery($now: timestamp!) {
|
|
payload_stream(batch_size: 10, cursor: {initial_value: {timestamp: $now}, ordering: ASC}) {
|
|
...payloadData
|
|
}
|
|
}
|
|
`;
|
|
const PayloadsQuery = gql`
|
|
${payloadFragment}
|
|
query PayloadsQuery($offset: Int!, $limit: Int!, $showDeleted: Boolean!, $showAutogenerated: Boolean!) {
|
|
payload(order_by: {id: desc}, offset: $offset, limit: $limit, where: {auto_generated: {_eq: $showAutogenerated}, deleted: {_eq: $showDeleted}}) {
|
|
...payloadData
|
|
}
|
|
payload_aggregate(where: {auto_generated: {_eq: $showAutogenerated}, deleted: {_eq: $showDeleted}}) {
|
|
aggregate {
|
|
count
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
export const payloadsDelete = gql`
|
|
mutation PayloadsDeletePayloadMutation($payload_uuid: String!) {
|
|
updatePayload(payload_uuid: $payload_uuid, deleted: true) {
|
|
status
|
|
error
|
|
id
|
|
deleted
|
|
}
|
|
}
|
|
`;
|
|
export const payloadsCallbackAlert = gql`
|
|
mutation PayloadsCallbackAlertMutation($payload_uuid: String!, $callback_alert: Boolean!) {
|
|
updatePayload(callback_alert: $callback_alert, payload_uuid: $payload_uuid) {
|
|
id
|
|
callback_alert
|
|
status
|
|
error
|
|
}
|
|
}
|
|
`;
|
|
export const restorePayloadMutation = gql`
|
|
mutation RestorePayloadToUndeleted($payload_uuid: String!){
|
|
updatePayload(deleted: false, payload_uuid: $payload_uuid) {
|
|
id
|
|
deleted
|
|
status
|
|
error
|
|
}
|
|
}
|
|
`;
|
|
export const payloadsCallbackAllowed = gql`
|
|
mutation PayloadsCallbackAllowedMutation($payload_uuid: String!, $callback_allowed: Boolean!) {
|
|
updatePayload(callback_allowed: $callback_allowed, payload_uuid: $payload_uuid) {
|
|
id
|
|
callback_allowed
|
|
status
|
|
error
|
|
}
|
|
}
|
|
`;
|
|
|
|
export function Payloads(props){
|
|
const [fromNow, setFromNow] = React.useState((getSkewedNow()).toISOString());
|
|
const [payloads, setPayloads] = React.useState([]);
|
|
const [pageData, setPageData] = React.useState({
|
|
"totalCount": 0,
|
|
"fetchLimit": 20,
|
|
"showDeleted": false,
|
|
"showAutogenerated": false,
|
|
});
|
|
const mountedRef = React.useRef(true);
|
|
const [openBackdrop, setOpenBackdrop] = React.useState(true);
|
|
useSubscription(SUB_Payloads, {
|
|
variables: {now: fromNow},
|
|
fetchPolicy: "no-cache",
|
|
onData: ({data}) => {
|
|
//console.log("got data", subscriptionData.data.payload_stream)
|
|
if(!mountedRef.current){
|
|
return null;
|
|
}
|
|
const updated = data.data.payload_stream.reduce( (prev, cur) => {
|
|
const index = prev.findIndex( (p) => p.id === cur.id );
|
|
if(index > -1){
|
|
prev[index] = {...cur};
|
|
return [...prev];
|
|
}else{
|
|
return [cur, ...prev];
|
|
}
|
|
}, [...payloads])
|
|
updated.sort( (a,b) => a.id > b.id ? -1 : 1);
|
|
setPayloads(updated);
|
|
},
|
|
onCompleted: (data) => {
|
|
console.log("completed")
|
|
},
|
|
onError: (data) => {
|
|
snackActions.warning("Failed to get payloads");
|
|
console.log(data);
|
|
}
|
|
});
|
|
|
|
useQuery(PayloadsQuery, {
|
|
variables: {offset: 0, limit: pageData.fetchLimit, showDeleted: false, showAutogenerated: false},
|
|
fetchPolicy: "no-cache",
|
|
onCompleted: (data) => {
|
|
let tempPageData = {...pageData};
|
|
tempPageData.totalCount = data.payload_aggregate.aggregate.count;
|
|
setPageData(tempPageData);
|
|
setPayloads(data.payload);
|
|
setOpenBackdrop(false);
|
|
},
|
|
onError: (data) => {
|
|
|
|
}
|
|
})
|
|
const [fetchNewPage] = useLazyQuery(PayloadsQuery, {
|
|
onCompleted: (data) => {
|
|
snackActions.dismiss();
|
|
let tempPageData = {...pageData};
|
|
tempPageData.totalCount = data.payload_aggregate.aggregate.count;
|
|
setPageData(tempPageData);
|
|
setPayloads(data.payload);
|
|
setOpenBackdrop(false);
|
|
},
|
|
onError: (data) => {
|
|
|
|
}
|
|
})
|
|
const onChangePage = (event, value) => {
|
|
snackActions.info("Fetching page...");
|
|
setOpenBackdrop(true);
|
|
fetchNewPage({variables: {offset: (value - 1) * pageData.fetchLimit, limit: pageData.fetchLimit, showDeleted: pageData.showDeleted, showAutogenerated: pageData.showAutogenerated}})
|
|
}
|
|
const [deletePayload] = useMutation(payloadsDelete, {
|
|
onCompleted: (data) => {
|
|
if(data.updatePayload.status === "success"){
|
|
const updated = payloads.map( (p) => {
|
|
if(data.updatePayload.id === p.id){
|
|
return {...p, deleted: true};
|
|
}else{
|
|
return {...p}
|
|
}
|
|
});
|
|
setPayloads(updated);
|
|
snackActions.success("Successfully deleted");
|
|
}else{
|
|
snackActions.error(data.updatePayload.error);
|
|
}
|
|
|
|
},
|
|
onError: (data) => {
|
|
snackActions.warning("Failed to delete payload");
|
|
console.log(data);
|
|
}
|
|
});
|
|
const [restorePayload] = useMutation(restorePayloadMutation, {
|
|
onCompleted: (data) => {
|
|
const updated = payloads.map( (payload) => {
|
|
if(payload.id === data.updatePayload.id){
|
|
return {...payload, ...data.updatePayload};
|
|
}else{
|
|
return {...payload};
|
|
}
|
|
});
|
|
setPayloads(updated);
|
|
if(data.updatePayload.deleted === false){
|
|
snackActions.success("Successfully marked payload as not deleted");
|
|
}
|
|
},
|
|
onError: (data) => {
|
|
snackActions.warning("Failed to mark as not deleted");
|
|
console.log(data);
|
|
}
|
|
});
|
|
const [callbackAlert] = useMutation(payloadsCallbackAlert, {
|
|
onCompleted: (data) => {
|
|
const updated = payloads.map( (payload) => {
|
|
if(payload.id === data.updatePayload.id){
|
|
return {...payload, ...data.updatePayload};
|
|
}else{
|
|
return {...payload};
|
|
}
|
|
});
|
|
if(data.updatePayload.callback_alert){
|
|
snackActions.success("Now Alerting on New Callbacks");
|
|
}else{
|
|
snackActions.success("No Longer Alerting on New Callbacks");
|
|
}
|
|
|
|
setPayloads(updated);
|
|
},
|
|
onError: (data) => {
|
|
snackActions.warning("Failed to update callback alerting status");
|
|
console.log(data);
|
|
}
|
|
});
|
|
const [callbackAllowed] = useMutation(payloadsCallbackAllowed, {
|
|
onCompleted: (data) => {
|
|
const updated = payloads.map( (payload) => {
|
|
if(payload.id === data.updatePayload.id){
|
|
return {...payload, ...data.updatePayload};
|
|
}else{
|
|
return {...payload};
|
|
}
|
|
});
|
|
if(data.updatePayload.callback_allowed){
|
|
snackActions.success("Now Allowing New Callbacks from this Payload");
|
|
}else{
|
|
snackActions.success("No Longer Allowing New Callbacks from this Payload");
|
|
}
|
|
|
|
setPayloads(updated);
|
|
},
|
|
onError: (data) => {
|
|
snackActions.warning("Failed to update callback alerting status");
|
|
console.log(data);
|
|
}
|
|
});
|
|
const onDeletePayload = (payload_uuid) => {
|
|
deletePayload({variables: {payload_uuid}});
|
|
}
|
|
const onUpdateCallbackAlert = (payload_uuid, callback_alert) => {
|
|
callbackAlert({
|
|
variables: {payload_uuid, callback_alert}
|
|
|
|
});
|
|
}
|
|
const onRestorePayload = (payload_uuid) => {
|
|
restorePayload({
|
|
variables: {payload_uuid}
|
|
})
|
|
}
|
|
const onChangeShowDeleted = (showDeleted) => {
|
|
setPageData({...pageData, showDeleted: showDeleted});
|
|
if(showDeleted){
|
|
snackActions.info("Fetching deleted payloads...");
|
|
} else {
|
|
snackActions.info("Hiding deleted payloads...");
|
|
}
|
|
fetchNewPage({variables: {offset:0, limit: pageData.fetchLimit, showDeleted: showDeleted, showAutogenerated: pageData.showAutogenerated}});
|
|
}
|
|
const onChangeShowAutogenerated = (showAutogenerated) => {
|
|
setPageData({...pageData, showAutogenerated: showAutogenerated});
|
|
if(showAutogenerated){
|
|
snackActions.info("Fetching auto generated payloads...");
|
|
} else {
|
|
snackActions.info("Hiding auto generated payloads...");
|
|
}
|
|
fetchNewPage({variables: {offset:0, limit: pageData.fetchLimit, showDeleted: pageData.showDeleted, showAutogenerated: showAutogenerated}});
|
|
}
|
|
const onCallbacksAllowedChanged = (payload_uuid, callback_allowed) => {
|
|
callbackAllowed({variables: {payload_uuid, callback_allowed}});
|
|
}
|
|
React.useEffect( () => {
|
|
return() => {
|
|
mountedRef.current = false;
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
return (
|
|
<div style={{display: "flex", height: "100%", flexDirection: "column", position: "relative"}}>
|
|
|
|
<PayloadsTable pageData={pageData} me={props.me}
|
|
openBackdrop={openBackdrop}
|
|
onDeletePayload={onDeletePayload}
|
|
onUpdateCallbackAlert={onUpdateCallbackAlert}
|
|
payload={payloads}
|
|
onRestorePayload={onRestorePayload}
|
|
onChangePage={onChangePage}
|
|
onChangeShowDeleted={onChangeShowDeleted}
|
|
onCallbacksAllowedChanged={onCallbacksAllowedChanged}
|
|
onChangeShowAutogenerated={onChangeShowAutogenerated}
|
|
/>
|
|
</div>
|
|
|
|
);
|
|
}
|