mirror of
https://github.com/vee1e/mitmproxy.git
synced 2026-09-01 18:27:18 +00:00
[web] replay multiple selected flows (#7674)
Co-authored-by: Maximilian Hils <git@maximilianhils.com>
This commit is contained in:
parent
d48f9ae59c
commit
01a5cceeac
6 changed files with 23 additions and 17 deletions
|
|
@ -58,7 +58,7 @@
|
|||
([#7652](https://github.com/mitmproxy/mitmproxy/pull/7652), @lups2000)
|
||||
- `mitmproxy.dns.Message` has been renamed to `mitmproxy.dns.DNSMessage`
|
||||
([#7670](https://github.com/mitmproxy/mitmproxy/pull/7670), @mhils)
|
||||
- Added support for selecting multiple flows in mitmweb using Ctrl+Click and Shift+Click. Multi-selection is now supported for deleting, duplicating, marking, reverting, resuming, and aborting flows.
|
||||
- Added support for selecting multiple flows in mitmweb using Ctrl+Click and Shift+Click. Multi-selection is now supported for deleting, duplicating, marking, reverting, replaying ,resuming, and aborting flows.
|
||||
([#7319](https://github.com/mitmproxy/mitmproxy/pull/7319), @lups2000, @mhils)
|
||||
|
||||
[tree-sitter]: https://tree-sitter.github.io/tree-sitter/
|
||||
|
|
|
|||
|
|
@ -255,6 +255,8 @@ describe("flows actions", () => {
|
|||
const tflow = TFlow();
|
||||
tflow.intercepted = true;
|
||||
tflow.modified = true;
|
||||
// @ts-expect-error TFlow is Required<> for other tests.
|
||||
tflow.websocket = undefined;
|
||||
const ttcpflow = TTCPFlow();
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -316,7 +318,7 @@ describe("flows actions", () => {
|
|||
});
|
||||
|
||||
it("should handle replay action", () => {
|
||||
store.dispatch(flowActions.replay(tflow));
|
||||
store.dispatch(flowActions.replay([tflow]));
|
||||
expect(fetchApi).toBeCalledWith(
|
||||
"/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/replay",
|
||||
{ method: "POST" },
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ export const quickactions: FlowColumn = ({ flow }) => {
|
|||
<a
|
||||
href="#"
|
||||
className="quickaction"
|
||||
onClick={() => dispatch(flowActions.replay(flow))}
|
||||
onClick={() => dispatch(flowActions.replay([flow]))}
|
||||
>
|
||||
<i className="fa fa-fw fa-repeat text-primary" />
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
duplicate as duplicateFlows,
|
||||
kill as killFlows,
|
||||
remove as removeFlows,
|
||||
replay as replayFlow,
|
||||
replay as replayFlows,
|
||||
resume as resumeFlows,
|
||||
revert as revertFlows,
|
||||
mark as markFlows,
|
||||
|
|
@ -29,9 +29,6 @@ export default function FlowMenu(): JSX.Element {
|
|||
const selectedFlows = useAppSelector((state) => state.flows.selected);
|
||||
const flow = selectedFlows[0];
|
||||
|
||||
const hasSingleFlowSelected = useAppSelector(
|
||||
(state) => state.flows.selected.length === 1,
|
||||
);
|
||||
const canResumeOrKillAny = selectedFlows.some(canResumeOrKill);
|
||||
|
||||
if (selectedFlows.length === 0) return <div />;
|
||||
|
|
@ -43,10 +40,8 @@ export default function FlowMenu(): JSX.Element {
|
|||
<Button
|
||||
title="[r]eplay flow"
|
||||
icon="fa-repeat text-primary"
|
||||
onClick={() => dispatch(replayFlow(flow))}
|
||||
disabled={
|
||||
!canReplay(flow) || !hasSingleFlowSelected
|
||||
}
|
||||
onClick={() => dispatch(replayFlows(selectedFlows))}
|
||||
disabled={!selectedFlows.some(canReplay)}
|
||||
>
|
||||
Replay
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ import { fetchApi } from "../utils";
|
|||
import * as store from "./utils/store";
|
||||
import Filt from "../filt/filt";
|
||||
import { Flow } from "../flow";
|
||||
import { canResumeOrKill, canRevert, sortFunctions } from "../flow/utils";
|
||||
import {
|
||||
canReplay,
|
||||
canResumeOrKill,
|
||||
canRevert,
|
||||
sortFunctions,
|
||||
} from "../flow/utils";
|
||||
import { AppDispatch, RootState } from "./store";
|
||||
import { State } from "./utils/store";
|
||||
|
||||
|
|
@ -255,8 +260,14 @@ export function duplicate(flows: Flow[]) {
|
|||
);
|
||||
}
|
||||
|
||||
export function replay(flow: Flow) {
|
||||
return () => fetchApi(`/flows/${flow.id}/replay`, { method: "POST" });
|
||||
export function replay(flows: Flow[]) {
|
||||
flows = flows.filter(canReplay);
|
||||
return () =>
|
||||
Promise.all(
|
||||
flows.map((flow) =>
|
||||
fetchApi(`/flows/${flow.id}/replay`, { method: "POST" }),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function revert(flows: Flow[]) {
|
||||
|
|
|
|||
|
|
@ -107,9 +107,7 @@ export function onKeyDown(e: KeyboardEvent) {
|
|||
}
|
||||
|
||||
case "r": {
|
||||
if (selectedFlows.length === 1) {
|
||||
dispatch(flowsActions.replay(flow));
|
||||
}
|
||||
dispatch(flowsActions.replay(selectedFlows));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue