mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-25 09:37:37 +00:00
transfer the argument suggestion into popup, show available commands, highlight currently typing argument
This commit is contained in:
parent
5b229c2dcd
commit
fc7455b914
@ -27,10 +27,8 @@ from mitmproxy.utils.strutils import always_str
|
||||
def flow_to_json(flow: mitmproxy.flow.Flow) -> dict:
|
||||
"""
|
||||
Remove flow message content and cert to save transmission space.
|
||||
|
||||
Args:
|
||||
flow: The original flow.
|
||||
|
||||
Sync with web/src/flow.ts.
|
||||
"""
|
||||
f = {
|
||||
@ -454,12 +452,20 @@ class FlowContentView(RequestHandler):
|
||||
|
||||
|
||||
class Commands(RequestHandler):
|
||||
def get(self):
|
||||
commands = {}
|
||||
for (name, command) in self.master.commands.commands.items():
|
||||
commands[name] = []
|
||||
for parameter in command.parameters:
|
||||
commands[name].append({"name": parameter.name})
|
||||
self.write({"commands": commands})
|
||||
|
||||
def post(self):
|
||||
result = self.master.commands.execute(self.json["command"])
|
||||
if result is None:
|
||||
self.write({"result": ""})
|
||||
return
|
||||
self.write({"result": str(result)})
|
||||
self.write({ "result": result, "type": type(result).__name__ })
|
||||
|
||||
|
||||
class Events(RequestHandler):
|
||||
@ -479,16 +485,6 @@ class Options(RequestHandler):
|
||||
raise APIError(400, f"{err}")
|
||||
|
||||
|
||||
class CommandArguments(RequestHandler):
|
||||
def get(self):
|
||||
arguments = {}
|
||||
for (name, command) in self.master.commands.commands.items():
|
||||
arguments[name] = []
|
||||
for parameter in command.parameters:
|
||||
arguments[name].append(parameter.name)
|
||||
self.write(arguments)
|
||||
|
||||
|
||||
class SaveOptions(RequestHandler):
|
||||
def post(self):
|
||||
# try:
|
||||
@ -541,7 +537,7 @@ class Application(tornado.web.Application):
|
||||
(r"/", IndexHandler),
|
||||
(r"/filter-help(?:\.json)?", FilterHelp),
|
||||
(r"/updates", ClientConnection),
|
||||
(r"/commands", Commands),
|
||||
(r"/commands(?:\.json)?", Commands),
|
||||
(r"/events(?:\.json)?", Events),
|
||||
(r"/flows(?:\.json)?", Flows),
|
||||
(r"/flows/dump", DumpFlows),
|
||||
@ -559,7 +555,6 @@ class Application(tornado.web.Application):
|
||||
r"/flows/(?P<flow_id>[0-9a-f\-]+)/(?P<message>request|response)/content/(?P<content_view>[0-9a-zA-Z\-\_]+)(?:\.json)?",
|
||||
FlowContentView),
|
||||
(r"/clear", ClearAll),
|
||||
(r"/arguments(?:\.json)?", CommandArguments),
|
||||
(r"/options(?:\.json)?", Options),
|
||||
(r"/options/save", SaveOptions),
|
||||
(r"/conf\.js", Conf),
|
||||
|
@ -1,4 +1,4 @@
|
||||
.command {
|
||||
.command-title {
|
||||
background-color: #F2F2F2;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
@ -15,3 +15,17 @@
|
||||
.command-suggestion {
|
||||
background-color: #9c9c9c;
|
||||
}
|
||||
|
||||
.argument-suggestion {
|
||||
background-color: hsla(209, 52%, 84%, 0.5) !important;
|
||||
}
|
||||
|
||||
.command > .popover {
|
||||
display: block;
|
||||
position: relative;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.available-commands {
|
||||
overflow: auto;
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
import React from 'react'
|
||||
import renderer from 'react-test-renderer'
|
||||
import CommandBar from '../../../components/CommandBar'
|
||||
import { render } from "../../test-utils"
|
||||
|
||||
describe('CommandBar Component', () => {
|
||||
let commandBar = renderer.create(
|
||||
<CommandBar />),
|
||||
tree = commandBar.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
test('CommandBar Component', async () => {
|
||||
const {asFragment, store} = render(
|
||||
<CommandBar/>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
})
|
@ -3,39 +3,76 @@ import classnames from 'classnames'
|
||||
import { Key, fetchApi } from '../utils'
|
||||
import Filt from '../filt/command'
|
||||
|
||||
export function AvailableCommands({input, commands}) {
|
||||
if (!commands) return null
|
||||
let availableCommands = []
|
||||
for (const [command, args] of Object.entries(commands)) {
|
||||
if (command.startsWith(input)) {
|
||||
availableCommands.push(command)
|
||||
}
|
||||
}
|
||||
return <div className="available-commands popover bottom">Available Commands: {JSON.stringify(availableCommands)}</div>
|
||||
}
|
||||
|
||||
export function ArgumentSuggestion({nextArgs, currentArg}){
|
||||
let results = []
|
||||
for (let i = 0; i < nextArgs.length; i++) {
|
||||
if (i==currentArg) {
|
||||
results.push(<mark>{nextArgs[i]}</mark>)
|
||||
continue
|
||||
}
|
||||
results.push(<span>{nextArgs[i]} </span>)
|
||||
}
|
||||
return (<div className="argument-suggestion popover top">
|
||||
<div className="arrow"/>
|
||||
<div className="popover-content">
|
||||
Argument suggestion: {results}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default function CommandBar() {
|
||||
const [input, setInput] = useState("")
|
||||
const [command, setCommand] = useState("")
|
||||
const [results, setResults] = useState([])
|
||||
const [history, setHistory] = useState([])
|
||||
const [currentPos, setCurrentPos] = useState(0)
|
||||
const [args, setArgs] = useState({})
|
||||
const [allCommands, setAllCommands] = useState({})
|
||||
const [nextArgs, setNextArgs] = useState([])
|
||||
const [currentArg, setCurrentArg] = useState(0)
|
||||
const [commandHelp, setCommandHelp] = useState("")
|
||||
|
||||
useEffect(() => {
|
||||
fetchApi('/arguments')
|
||||
fetchApi('/commands', { method: 'GET' })
|
||||
.then(response => response.json())
|
||||
.then(data => setArgs(data))
|
||||
.then(data => setAllCommands(data))
|
||||
}, [])
|
||||
|
||||
const parseCommand = (input) => {
|
||||
const parts = Filt.parse(input)
|
||||
if (allCommands["commands"].hasOwnProperty(parts[0])){
|
||||
setCommand(parts[0])
|
||||
} else {
|
||||
setCommand("")
|
||||
}
|
||||
|
||||
const nextArgs = args[parts[0]]
|
||||
const nextArgs = allCommands["commands"][parts[0]]?.map(arg => arg.name)
|
||||
|
||||
if (nextArgs) {
|
||||
setNextArgs([parts[0], ...nextArgs])
|
||||
setCurrentArg(parts.length-1)
|
||||
}
|
||||
}
|
||||
|
||||
const onChange = (e) => {
|
||||
setCommand(e.target.value)
|
||||
setInput(e.target.value)
|
||||
}
|
||||
|
||||
const onKeyDown = (e) => {
|
||||
if (e.keyCode === Key.ENTER) {
|
||||
const body = {"command": command}
|
||||
const body = {"command": input}
|
||||
const newHistory = Object.assign([], history)
|
||||
newHistory.splice(currentPos, 0, command)
|
||||
newHistory.splice(currentPos, 0, input)
|
||||
|
||||
fetchApi(`/commands`, {
|
||||
method: 'POST',
|
||||
@ -48,21 +85,21 @@ export default function CommandBar() {
|
||||
.then(data => {
|
||||
setHistory(newHistory)
|
||||
setCurrentPos(currentPos + 1)
|
||||
setNextArgs([])
|
||||
|
||||
if (data.result == "") return
|
||||
setResults([...results, {"id": results.length, "result": data.result}])
|
||||
})
|
||||
|
||||
setCommand("")
|
||||
setInput("")
|
||||
}
|
||||
if (e.keyCode === Key.UP) {
|
||||
if (currentPos > 0) {
|
||||
setCommand(history[currentPos - 1])
|
||||
setInput(history[currentPos - 1])
|
||||
setCurrentPos(currentPos - 1)
|
||||
}
|
||||
}
|
||||
if (e.keyCode === Key.DOWN) {
|
||||
setCommand(history[currentPos])
|
||||
setInput(history[currentPos])
|
||||
if (currentPos < history.length -1) {
|
||||
setCurrentPos(currentPos + 1)
|
||||
}
|
||||
@ -71,14 +108,14 @@ export default function CommandBar() {
|
||||
}
|
||||
|
||||
const onKeyUp = (e) => {
|
||||
if (command == "") return
|
||||
parseCommand(command)
|
||||
if (input == "") return
|
||||
parseCommand(input)
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="command">
|
||||
<div className="command-title">
|
||||
Command Result
|
||||
</div>
|
||||
<div className="command-result">
|
||||
@ -88,7 +125,7 @@ export default function CommandBar() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{ nextArgs ? <div className="command-suggestion">Argument suggestion: {nextArgs.join(" ")}</div> : null }
|
||||
{ nextArgs.length > 0 && <ArgumentSuggestion nextArgs={nextArgs} currentArg={currentArg} /> }
|
||||
<div className={classnames('command-input input-group')}>
|
||||
<span className="input-group-addon">
|
||||
<i className={'fa fa-fw fa-terminal'}/>
|
||||
@ -97,12 +134,13 @@ export default function CommandBar() {
|
||||
type="text"
|
||||
placeholder="Enter command"
|
||||
className="form-control"
|
||||
value={command}
|
||||
value={input}
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onKeyUp={onKeyUp}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
{ !command && <AvailableCommands input={input} commands={allCommands["commands"]} /> }
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user