parent
e90f1e8e87
commit
442aad83ec
|
@ -2,9 +2,13 @@
|
|||
|
||||
## Feature
|
||||
|
||||
* download files #26
|
||||
* add goto last line toolbar #21
|
||||
|
||||
## Fix
|
||||
|
||||
* all cmds should be pass straight back to user
|
||||
* timeout on none ending cmds #34
|
||||
|
||||
# 0.1.1
|
||||
|
||||
|
|
29
api.go
29
api.go
|
@ -3,8 +3,10 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"kumoly.io/tools/configui/configui"
|
||||
)
|
||||
|
@ -70,6 +72,7 @@ func Apply(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
result, err := file.Do()
|
||||
log.Println(err)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -77,10 +80,36 @@ func Apply(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func Download(w http.ResponseWriter, r *http.Request) {
|
||||
if name := r.URL.Query().Get("name"); name != "" {
|
||||
if name == "ConfigUI" {
|
||||
data, err := GetConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="ConfigUI.json"`)
|
||||
w.Write(data)
|
||||
return
|
||||
}
|
||||
file, ok := files[name]
|
||||
if !ok {
|
||||
MakeResponse(w, 404, []byte("file not found"))
|
||||
return
|
||||
}
|
||||
data, err := file.Read()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="`+filepath.Base(file.Path)+`"`)
|
||||
w.Write(data)
|
||||
return
|
||||
}
|
||||
fs := []string{}
|
||||
for _, v := range files {
|
||||
fs = append(fs, v.Path)
|
||||
}
|
||||
if flagConfigPath != "" {
|
||||
fs = append(fs, flagConfigPath)
|
||||
}
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="export.tar.gz"`)
|
||||
bundle(w, fs, false)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os/exec"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var UNIX_SHELL = "sh"
|
||||
|
@ -54,15 +55,30 @@ func (f *File) Do() (string, error) {
|
|||
if f.Action == "" {
|
||||
return "", nil
|
||||
}
|
||||
cmd := exec.Command(UNIX_SHELL, "-c", f.Action)
|
||||
timeout := time.After(2 * time.Second)
|
||||
cmd := &exec.Cmd{}
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command(WIN_SHELL, "/c", f.Action)
|
||||
} else {
|
||||
exec.Command(UNIX_SHELL, "-c", f.Action)
|
||||
}
|
||||
var out []byte
|
||||
done := make(chan struct{}, 1)
|
||||
go func() {
|
||||
out, _ = cmd.CombinedOutput()
|
||||
// real cmd err is only pass down
|
||||
// if err != nil {
|
||||
// return string(out), err
|
||||
// }
|
||||
done <- struct{}{}
|
||||
}()
|
||||
select {
|
||||
case <-timeout:
|
||||
cmd.Process.Kill()
|
||||
return "", errors.New("command timeout")
|
||||
case <-done:
|
||||
return string(out), nil
|
||||
}
|
||||
out, _ := cmd.CombinedOutput()
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func ReadConfig(confstr string) ([]File, error) {
|
||||
|
|
|
@ -58,7 +58,8 @@ async function FileApply(){
|
|||
method: 'POST',
|
||||
})
|
||||
if(!res.ok){
|
||||
handleError(res)
|
||||
const result = await handleError(res)
|
||||
result_editor.session.setValue(result)
|
||||
return
|
||||
}
|
||||
const result = await res.text()
|
||||
|
@ -69,6 +70,7 @@ async function FileApply(){
|
|||
async function handleError(res){
|
||||
const msg = await res.text()
|
||||
ShowError(msg)
|
||||
return msg
|
||||
}
|
||||
|
||||
// starting point
|
||||
|
|
19
release.sh
19
release.sh
|
@ -0,0 +1,19 @@
|
|||
VERSION=$(git describe --tags --abbrev=0)
|
||||
BUILD=$(git rev-parse --short HEAD)
|
||||
PROJ=$(basename "$(PWD)")
|
||||
HUB=hub.kumoly.io
|
||||
HUB_PROJECT=tools
|
||||
LDFLAGS='-ldflags "-X main.Version=${VERSION} -X main.Build=${BUILD} -w"'
|
||||
|
||||
PLATFORMS='darwin linux'
|
||||
ARCHITECTURES=amd64
|
||||
APPS=configui
|
||||
|
||||
echo $LDFLAGS
|
||||
|
||||
build(){
|
||||
foreach GOOS $1
|
||||
echo $GOOS
|
||||
}
|
||||
|
||||
build $PLATFORMS
|
|
@ -3,8 +3,15 @@
|
|||
// }
|
||||
|
||||
#editor,#result_editor {
|
||||
height: 75vh;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
width: inherit !important;
|
||||
}
|
||||
|
||||
#editor {
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
#result_editor {
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@ $modal-content-width: 90vw;
|
|||
position: fixed; /* Sit on top of the page content */
|
||||
top: 1;
|
||||
left: 50%;
|
||||
z-index: 2;
|
||||
z-index: 50;
|
||||
transform: translateX(-50%)
|
||||
}
|
||||
|
||||
#title {
|
||||
padding: 0.5rem;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
{{define "components/editor"}}
|
||||
{{template "components/toolbar" .}}
|
||||
|
||||
<container class="container is-max-desktop">
|
||||
<!-- <container class="container is-max-desktop"> -->
|
||||
<div id="editor">{{.File.Content}}</div>
|
||||
</container>
|
||||
<!-- </container> -->
|
||||
<script>
|
||||
function setEditor(){
|
||||
var beautify = ace.require("ace/ext/beautify");
|
||||
|
|
|
@ -29,6 +29,9 @@ function setResult(){
|
|||
result_editor.setTheme("ace/theme/monokai");
|
||||
result_editor.session.setMode("ace/mode/sh");
|
||||
result_editor.setReadOnly(true);
|
||||
result_editor.setOptions({
|
||||
maxLines: 1000
|
||||
});
|
||||
}
|
||||
|
||||
function ResultViewTog(){
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
<div class="level-left">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<div class="select">
|
||||
<button class="button is-small" onclick="editor.gotoLine(editor.session.getLength())">Bottom</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<div class="select is-small">
|
||||
<select onchange="SetTabstop(this)">
|
||||
<option value="0">Tabstop</option>
|
||||
<option value="4">Tabstop 4</option>
|
||||
|
@ -13,13 +16,13 @@
|
|||
</div>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button" id="toolFollow" onclick="toolFollow()">Follow</button>
|
||||
<button class="button is-small" id="toolFollow" onclick="toolFollow()">Follow</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button" onclick="toolFormat()">Format</button>
|
||||
<button class="button is-small" onclick="toolFormat()">Format</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button is-light is-danger" id="toolWrap" onclick="toggleWrap()">NoWrap</button>
|
||||
<button class="button is-small is-light is-danger" id="toolWrap" onclick="toggleWrap()">NoWrap</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,29 +30,30 @@
|
|||
<div class="level-right">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<button class="button" id="toolRefresh" onclick="toolRefresh()">Refresh</button>
|
||||
<button class="button is-small" id="toolRefresh" onclick="toolRefresh()">Refresh</button>
|
||||
</p>
|
||||
{{if not .File.RO}}
|
||||
<p class="control">
|
||||
{{if eq .File.Alias "ConfigUI"}}
|
||||
<button class="button" id="toolSave" onclick="toolSave()">Apply</button>
|
||||
<button class="button is-small" id="toolSave" onclick="toolSave()">Apply</button>
|
||||
{{else}}
|
||||
<button class="button" id="toolSave" onclick="toolSave()">Save</button>
|
||||
<button class="button is-small" id="toolSave" onclick="toolSave()">Save</button>
|
||||
{{end}}
|
||||
</p>
|
||||
{{end}}
|
||||
{{if .File.Action}}
|
||||
<p class="control">
|
||||
<button class="button has-tooltip-arrow"
|
||||
<button class="button is-small has-tooltip-arrow"
|
||||
data-tooltip="{{.File.Action}}"
|
||||
id="toolApply" onclick="toolApply()"
|
||||
>Apply</button>
|
||||
</p>
|
||||
|
||||
{{/* <p class="control">
|
||||
<a class="button" href="/api/dl?name">Download</a>
|
||||
</p> */}}
|
||||
{{end}}
|
||||
|
||||
{{/* TEST */}}
|
||||
<p class="control">
|
||||
<a class="button is-small" href="/api/export?name={{.File.Alias}}">Download</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ var Active = "{{.File.Alias}}";
|
|||
</script>
|
||||
|
||||
<section class="hero is-small is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="hero-body" id="title">
|
||||
<p class="title">
|
||||
ConfigUI
|
||||
</p>
|
||||
|
@ -19,7 +19,7 @@ var Active = "{{.File.Alias}}";
|
|||
{{template "components/menu" .}}
|
||||
</div>
|
||||
<div class="box has-text-centered">
|
||||
<a href="/api/export" class="button">Export Files</a>
|
||||
<a href="/api/export" class="button is-small">Export Files</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
|
|
Loading…
Reference in New Issue