Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e4a90920d | |||
| 7951e09238 | |||
| eab781794e | |||
| f7c70603f2 | |||
| b7ebd321d0 | |||
| ef252d5cab | |||
| 0768e10403 | |||
| 820805b063 | |||
| 194c0b0405 | |||
| e7689eabad | |||
| 0e22171779 | |||
| d47dea6933 |
1
.hgtags
Normal file
1
.hgtags
Normal file
@@ -0,0 +1 @@
|
||||
b851907a3b9abbf00ed0dab049478ab4770e23e0 release-1.0.0
|
||||
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
.PHONY: all clean
|
||||
|
||||
VERSION := 1.0.0
|
||||
VERSION := 1.0.1
|
||||
|
||||
OBJS := webcmd-$(VERSION)-linux64.tar.xz \
|
||||
webcmd-$(VERSION)-linux32.tar.xz \
|
||||
|
||||
2
Task.go
2
Task.go
@@ -87,7 +87,7 @@ func (this *App) LaunchTask(workDir string, params []string) (taskRef string, er
|
||||
|
||||
task := this.tasks[ref]
|
||||
task.output = append(task.output, OutputLine{isError: isError, text: text})
|
||||
if len(task.output) > 2*this.cfg.MaxHistoryLines {
|
||||
if this.cfg.MaxHistoryLines > 0 && len(task.output) > 2*this.cfg.MaxHistoryLines {
|
||||
task.output = task.output[this.cfg.MaxHistoryLines:]
|
||||
}
|
||||
this.tasks[ref] = task
|
||||
|
||||
@@ -16,5 +16,13 @@ See the included `webcmd.conf-sample` file for an example configuration implemen
|
||||
|
||||
=CHANGELOG=
|
||||
|
||||
2017-03-27 1.0.1
|
||||
- Enhancement: Simplify configuration file format, allow parsing const strings directly
|
||||
- Enhancement: Improve time format display
|
||||
- Fix an issue with pasting into form fields on Firefox Mobile
|
||||
- Fix an issue with not consistently interpreting `MaxHistoryLines:0` as infinite history
|
||||
- Fix a cosmetic issue with mobile viewports
|
||||
- Fix a cosmetic issue with task ordering
|
||||
|
||||
2017-03-25 1.0.0
|
||||
- Initial public release
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
{
|
||||
"Title": "Ping",
|
||||
"Execution": [
|
||||
{"ParamType": 0, "Value": "/bin/ping"},
|
||||
{"ParamType": 0, "Value": "-c"},
|
||||
{"ParamType": 0, "Value": "4"},
|
||||
{"ParamType": 0, "Value": "--"},
|
||||
"/bin/ping",
|
||||
"-c",
|
||||
"4",
|
||||
"--",
|
||||
{"ParamType": 1, "Value": "example.com", "Description": "Target host"}
|
||||
]
|
||||
}
|
||||
|
||||
41
config.go
41
config.go
@@ -1,5 +1,10 @@
|
||||
package webcmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type ParamType int
|
||||
|
||||
const (
|
||||
@@ -16,15 +21,47 @@ const (
|
||||
)
|
||||
|
||||
type InputParam struct {
|
||||
Description string `json:",omitempty"` // only use for editable parameters
|
||||
Description string `json:",omitempty"` // only used for editable parameters
|
||||
ParamType ParamType
|
||||
Value string
|
||||
}
|
||||
|
||||
func (ip *InputParam) UnmarshalJSON(b []byte) error {
|
||||
switch b[0] {
|
||||
case '"':
|
||||
ip.Description = ""
|
||||
ip.ParamType = PARAMTYPE_CONST
|
||||
tmp := ""
|
||||
err := json.Unmarshal(b, &tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip.Value = tmp
|
||||
|
||||
case '{':
|
||||
read := struct {
|
||||
Description string `json:",omitempty"`
|
||||
ParamType ParamType
|
||||
Value string
|
||||
}{}
|
||||
err := json.Unmarshal(b, &read)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ip = read
|
||||
return nil
|
||||
|
||||
default:
|
||||
return errors.New("Malformed InputParam")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type CommandConfig struct {
|
||||
Title string
|
||||
WorkingDir string // default empty-string: getcwd()
|
||||
Execution []InputParam // TODO allow plain strings as a shorthand for PARAMTYPE_CONST
|
||||
Execution []InputParam // Can be unmarshalled using plain strings
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
|
||||
@@ -23,8 +23,8 @@ func (this *App) Serve_Homepage(w http.ResponseWriter) {
|
||||
case PARAMTYPE_CONST:
|
||||
// not configurable parameter
|
||||
case PARAMTYPE_STRING:
|
||||
fmt.Fprintf(w, `<input type="text" name="param[%d]" placeholder="%s" title="%s" value="%s"><br>`,
|
||||
i, hesc(param.Description), hesc(param.Description), hesc(param.Value))
|
||||
fmt.Fprintf(w, `<input type="text" name="param[%d]" placeholder="%s" value="%s"><br>`,
|
||||
i, hesc(param.Description), hesc(param.Value))
|
||||
case PARAMTYPE_OPTIONAL:
|
||||
fmt.Fprintf(w, `<input type="hidden" name="param[%d]" value="off"><label><input type="checkbox" name="param[%d]" value="on">%s</label><br>`,
|
||||
i, i, hesc(param.Description))
|
||||
|
||||
37
tpl_Tasks.go
37
tpl_Tasks.go
@@ -3,9 +3,29 @@ package webcmd
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TaskListItem struct {
|
||||
ref string
|
||||
start int64
|
||||
}
|
||||
|
||||
type TaskList []TaskListItem
|
||||
|
||||
func (tl TaskList) Len() int {
|
||||
return len(tl)
|
||||
}
|
||||
|
||||
func (tl TaskList) Swap(i, j int) {
|
||||
tl[i], tl[j] = tl[j], tl[i]
|
||||
}
|
||||
|
||||
func (tl TaskList) Less(i, j int) bool {
|
||||
return tl[i].start < tl[j].start
|
||||
}
|
||||
|
||||
func (this *App) Serve_Tasks(w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", "text/html;charset=UTF-8")
|
||||
|
||||
@@ -26,15 +46,28 @@ func (this *App) Serve_Tasks(w http.ResponseWriter) {
|
||||
|
||||
this.tasksMtx.RLock()
|
||||
defer this.tasksMtx.RUnlock()
|
||||
|
||||
tl := make(TaskList, 0, len(this.tasks))
|
||||
for ref, t := range this.tasks {
|
||||
tl = append(tl, TaskListItem{ref, t.started})
|
||||
}
|
||||
sort.Sort(tl)
|
||||
|
||||
for _, tlRef := range tl {
|
||||
ref := tlRef.ref
|
||||
t := this.tasks[ref]
|
||||
|
||||
startTime := time.Unix(t.started, 0)
|
||||
|
||||
fmt.Fprintf(w,
|
||||
`<tr>
|
||||
<td><a href="/task/%s">%s</td>
|
||||
<td>%s</td>
|
||||
<td><span title="%s">%s</span></td>
|
||||
<td>
|
||||
`,
|
||||
hesc(ref), hesc(ref),
|
||||
hesc(time.Unix(t.started, 0).Format(time.RFC822Z)),
|
||||
hesc(startTime.Format(time.RFC3339)),
|
||||
hesc(startTime.Format(time.RFC822)),
|
||||
)
|
||||
|
||||
if t.Finished() {
|
||||
|
||||
@@ -13,6 +13,7 @@ func (this *App) ServePartial_Header(w http.ResponseWriter, slug string) {
|
||||
<meta charset="UTF-8">
|
||||
<title>`+hesc(this.cfg.AppTitle)+`</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<meta viewport="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<h2>`+hesc(this.cfg.AppTitle)+`</h2>
|
||||
|
||||
Reference in New Issue
Block a user