зеркало из https://github.com/microsoft/mouselog.git
Add captor pages.
This commit is contained in:
Родитель
e4e8bc8b8c
Коммит
6cf586ff2a
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/microsoft/mouselog/object"
|
||||
)
|
||||
|
||||
func (c *ApiController) GetCaptors() {
|
||||
c.Data["json"] = object.GetCaptors()
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) GetCaptor() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetCaptor(id)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) UpdateCaptor() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var captor object.Captor
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &captor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.UpdateCaptor(id, &captor)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) AddCaptor() {
|
||||
var captor object.Captor
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &captor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.AddCaptor(&captor)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) DeleteCaptor() {
|
||||
var captor object.Captor
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &captor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.DeleteCaptor(&captor)
|
||||
c.ServeJSON()
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package object
|
||||
|
||||
type Captor struct {
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
|
||||
Title string `xorm:"varchar(100)" json:"title"`
|
||||
Script string `xorm:"mediumtext" json:"script"`
|
||||
}
|
||||
|
||||
func GetCaptors() []*Captor {
|
||||
captors := []*Captor{}
|
||||
err := ormManager.engine.Desc("created_time").Find(&captors)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return captors
|
||||
}
|
||||
|
||||
func GetCaptor(id string) *Captor {
|
||||
s := Captor{Name: id}
|
||||
existed, err := ormManager.engine.Get(&s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &s
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateCaptor(id string, captor *Captor) bool {
|
||||
if GetCaptor(id) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := ormManager.engine.Id(id).AllCols().Update(captor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//return affected != 0
|
||||
return true
|
||||
}
|
||||
|
||||
func AddCaptor(captor *Captor) bool {
|
||||
affected, err := ormManager.engine.Insert(captor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
func DeleteCaptor(captor *Captor) bool {
|
||||
affected, err := ormManager.engine.Id(captor.Name).Delete(&Captor{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
|
@ -104,4 +104,9 @@ func (a *OrmManager) createTables() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.engine.Sync2(new(Captor))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,10 @@ func init() {
|
|||
beego.Router("/api/update-faker", &controllers.ApiController{}, "POST:UpdateFaker")
|
||||
beego.Router("/api/add-faker", &controllers.ApiController{}, "POST:AddFaker")
|
||||
beego.Router("/api/delete-faker", &controllers.ApiController{}, "POST:DeleteFaker")
|
||||
|
||||
beego.Router("/api/get-captors", &controllers.ApiController{}, "GET:GetCaptors")
|
||||
beego.Router("/api/get-captor", &controllers.ApiController{}, "GET:GetCaptor")
|
||||
beego.Router("/api/update-captor", &controllers.ApiController{}, "POST:UpdateCaptor")
|
||||
beego.Router("/api/add-captor", &controllers.ApiController{}, "POST:AddCaptor")
|
||||
beego.Router("/api/delete-captor", &controllers.ApiController{}, "POST:DeleteCaptor")
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import ImpressionPage from "./ImpressionPage";
|
|||
import PagePage from "./PagePage";
|
||||
import FakerListPage from "./FakerListPage";
|
||||
import FakerEditPage from "./FakerEditPage";
|
||||
import CaptorListPage from "./CaptorListPage";
|
||||
import CaptorEditPage from "./CaptorEditPage";
|
||||
|
||||
const {Text} = Typography;
|
||||
const {Header, Footer} = Layout;
|
||||
|
@ -57,6 +59,8 @@ class App extends React.Component {
|
|||
this.setState({selectedMenuKey: 6});
|
||||
} else if (path.includes('fakers')) {
|
||||
this.setState({selectedMenuKey: 7});
|
||||
} else if (path.includes('captors')) {
|
||||
this.setState({selectedMenuKey: 8});
|
||||
} else {
|
||||
this.setState({selectedMenuKey: 1});
|
||||
}
|
||||
|
@ -142,6 +146,11 @@ class App extends React.Component {
|
|||
Fakers
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="8">
|
||||
<a href="/captors">
|
||||
Captors
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="100" style={{float: 'right'}}>
|
||||
<a target="_blank" href="https://github.com/microsoft/mouselog">
|
||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/microsoft/mouselog?style=social" />
|
||||
|
@ -174,6 +183,8 @@ class App extends React.Component {
|
|||
<Route path="/rules/" component={RuleListPage}/>
|
||||
<Route exact path="/fakers/" component={FakerListPage}/>
|
||||
<Route exact path="/fakers/:fakerName" component={FakerEditPage}/>
|
||||
<Route exact path="/captors/" component={CaptorListPage}/>
|
||||
<Route exact path="/captors/:captorName" component={CaptorEditPage}/>
|
||||
<Route exact path="/websites/" component={WebsiteListPage}/>
|
||||
<Route exact path="/websites/:websiteId" component={WebsiteEditPage}/>
|
||||
<Route exact path="/websites/:websiteId/sessions" component={SessionPage}/>
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row} from 'antd';
|
||||
import * as CaptorBackend from "./backend/CaptorBackend";
|
||||
import * as Setting from "./Setting";
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2'
|
||||
import "codemirror/lib/codemirror.css"
|
||||
require("codemirror/mode/lua/lua");
|
||||
|
||||
class CaptorEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
captorName: props.match.params.captorName,
|
||||
captor: null,
|
||||
tasks: [],
|
||||
resources: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.getCaptor();
|
||||
}
|
||||
|
||||
getCaptor() {
|
||||
CaptorBackend.getCaptor(this.state.captorName)
|
||||
.then((captor) => {
|
||||
this.setState({
|
||||
captor: captor,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseCaptorField(key, value) {
|
||||
// if ([].includes(key)) {
|
||||
// value = Setting.myParseInt(value);
|
||||
// }
|
||||
return value;
|
||||
}
|
||||
|
||||
updateCaptorField(key, value) {
|
||||
value = this.parseCaptorField(key, value);
|
||||
|
||||
let captor = this.state.captor;
|
||||
captor[key] = value;
|
||||
this.setState({
|
||||
captor: captor,
|
||||
});
|
||||
}
|
||||
|
||||
renderCaptor() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
Edit Captor
|
||||
<Button type="primary" onClick={this.submitCaptorEdit.bind(this)}>Save</Button>
|
||||
</div>
|
||||
} style={{marginLeft: '5px'}} type="inner">
|
||||
<Row style={{marginTop: '10px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={2}>
|
||||
Name:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.captor.name} onChange={e => {
|
||||
this.updateCaptorField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={2}>
|
||||
Title:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.captor.title} onChange={e => {
|
||||
this.updateCaptorField('title', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: '20px'}} >
|
||||
<Col style={{marginTop: '5px'}} span={2}>
|
||||
Script:
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<CodeMirror
|
||||
value={this.state.captor.script}
|
||||
options={{mode: 'lua', theme: "default"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateCaptorField('script', value);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
submitCaptorEdit() {
|
||||
let captor = Setting.deepCopy(this.state.captor);
|
||||
CaptorBackend.updateCaptor(this.state.captorName, captor)
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
Setting.showMessage("success", `Successfully saved`);
|
||||
this.setState({
|
||||
captorName: this.state.captor.name,
|
||||
});
|
||||
this.props.history.push(`/captors/${this.state.captor.name}`);
|
||||
} else {
|
||||
Setting.showMessage("error", `failed to save: server side failure`);
|
||||
this.updateCaptorField('name', this.state.captorName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `failed to save: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Row style={{width: "100%"}}>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{
|
||||
this.state.captor !== null ? this.renderCaptor() : null
|
||||
}
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{margin: 10}}>
|
||||
<Col span={2}>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<Button type="primary" size="large" onClick={this.submitCaptorEdit.bind(this)}>Save</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CaptorEditPage;
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {Button, Col, Popconfirm, Row, Table} from 'antd';
|
||||
import moment from "moment";
|
||||
import * as Setting from "./Setting";
|
||||
import * as CaptorBackend from "./backend/CaptorBackend";
|
||||
|
||||
class CaptorListPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
captors: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.getCaptors();
|
||||
}
|
||||
|
||||
getCaptors() {
|
||||
CaptorBackend.getCaptors()
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
captors: res,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
newCaptor() {
|
||||
return {
|
||||
owner: "admin", // this.props.account.username,
|
||||
name: `captor_${this.state.captors.length}`,
|
||||
createdTime: moment().format(),
|
||||
title: `New Captor - ${this.state.captors.length}`,
|
||||
script: "script code",
|
||||
}
|
||||
}
|
||||
|
||||
addCaptor() {
|
||||
const newCaptor = this.newCaptor();
|
||||
CaptorBackend.addCaptor(newCaptor)
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Captor added successfully`);
|
||||
this.setState({
|
||||
captors: Setting.prependRow(this.state.captors, newCaptor),
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Captor failed to add: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteCaptor(i) {
|
||||
CaptorBackend.deleteCaptor(this.state.captors[i])
|
||||
.then((res) => {
|
||||
Setting.showMessage("success", `Captor deleted successfully`);
|
||||
this.setState({
|
||||
captors: Setting.deleteRow(this.state.captors, i),
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `Captor failed to delete: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(captors) {
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '120px',
|
||||
sorter: (a, b) => a.name.localeCompare(b.name),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<a href={`/captors/${text}`}>{text}</a>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Title',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
// width: '80px',
|
||||
sorter: (a, b) => a.title.localeCompare(b.title),
|
||||
},
|
||||
{
|
||||
title: 'Created Time',
|
||||
dataIndex: 'createdTime',
|
||||
key: 'createdTime',
|
||||
width: '160px',
|
||||
sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Script',
|
||||
dataIndex: 'script',
|
||||
key: 'script',
|
||||
width: '120px',
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => a.script.localeCompare(b.script),
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
dataIndex: '',
|
||||
key: 'op',
|
||||
width: '160px',
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => Setting.goToLink(`/captors/${record.name}`)}>Edit</Button>
|
||||
<Popconfirm
|
||||
title={`Sure to delete captor: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteCaptor(index)}
|
||||
>
|
||||
<Button style={{marginBottom: '10px'}} type="danger">Delete</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table columns={columns} dataSource={captors} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
|
||||
title={() => (
|
||||
<div>
|
||||
Captors
|
||||
<Button type="primary" size="small" onClick={this.addCaptor.bind(this)}>Add</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={captors === null}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Row style={{width: "100%"}}>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
{
|
||||
this.renderTable(this.state.captors)
|
||||
}
|
||||
</Col>
|
||||
<Col span={1}>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CaptorListPage;
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getCaptors() {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-captors`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function getCaptor(id) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-captor?id=${id}`, {
|
||||
method: "GET",
|
||||
credentials: "include"
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updateCaptor(id, captor) {
|
||||
return fetch(`${Setting.ServerUrl}/api/update-captor?id=${id}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(captor),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addCaptor(captor) {
|
||||
return fetch(`${Setting.ServerUrl}/api/add-captor`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(captor),
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deleteCaptor(captor) {
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-captor`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(captor),
|
||||
}).then(res => res.json());
|
||||
}
|
Загрузка…
Ссылка в новой задаче