ok to save setting to file

master
codeskyblue 8 years ago
parent bc4dc97eae
commit d4574fecd5

@ -77,46 +77,36 @@
<div class="modal" id="newProgram">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>Program setting&hellip;</p>
<form>
<form id="formNewProgram" action="/api/programs" method="post">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">New program</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" placeholder="name (must be unique)">
<input type="text" name="name" v-model="program.name" class="form-control" value="h" placeholder="name (must be unique)" required>
</div>
<div class="form-group">
<label>Command</label>
<input type="text" class="form-control" placeholder="shell command, ex: redis-server --port 6379">
<input type="text" name="command" value="redis-server --port 7788" class="form-control" placeholder="shell command, ex: redis-server --port 6379">
</div>
<div class="form-group">
<label for="exampleInputFile">File input</label>
<input type="file" id="exampleInputFile">
<p class="help-block">Example block-level help text here.</p>
<label>Directory</label>
<input type="text" name="dir" class="form-control" placeholder="directory, default is /">
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Check me out
<input name="autostart" type="checkbox"> Auto start
</label>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
<button type="submit" class="btn btn-Wdefault">Submit</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
<!-- /.modal-content -->
</div>
@ -125,10 +115,12 @@
<!-- /.modal -->
</div>
<script src="/res/js/jquery-3.1.0.min.js"></script>
<script src="/res/js/jquery.form.min.js"></script>
<script src="/res/bootstrap-3.3.5/js/bootstrap.min.js"></script>
<script src="/res/js/moment.min.js"></script>
<script src="/res/js/underscore-min.js"></script>
<script src="/res/js/vue-1.0.min.js"></script>
<script src="/res/js/index.js"></script>
<script type="text/javascript">
$(function() {
$("#launchNewProgram").click(function() {

@ -1,11 +1,4 @@
jQuery('#qrcodeCanvas').qrcode({
text: "http://jetienne.com/"
});
function getExtention(fname) {
return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);
}
/* Javascript */
function pathJoin(parts, sep) {
var separator = sep || '/';
var replace = new RegExp(separator + '{1,}', 'g');
@ -22,172 +15,25 @@ function getQueryString(name) {
var vm = new Vue({
el: "#app",
data: {
message: "Hello vue.js",
location: window.location,
breadcrumb: [],
showHidden: false,
previewMode: false,
preview: {
filename: '',
filetype: '',
filesize: 0,
contentHTML: '',
},
version: "loading",
mtimeTypeFromNow: false, // or fromNow
auth: {},
search: getQueryString("search"),
files: [{
name: "loading ...",
path: "",
size: "...",
type: "dir",
}]
},
computed: {
computedFiles: function() {
var that = this;
that.preview.filename = null;
var files = this.files.filter(function(f) {
if (f.name == 'README.md') {
that.preview.filename = f.name;
}
if (!that.showHidden && f.name.slice(0, 1) === '.') {
return false;
}
return true;
});
// console.log(this.previewFile)
if (this.preview.filename) {
var name = this.preview.filename; // For now only README.md
console.log(pathJoin([location.pathname, 'README.md']))
$.ajax({
url: pathJoin([location.pathname, 'README.md']),
method: 'GET',
success: function(res) {
var converter = new showdown.Converter({
tables: true,
omitExtraWLInCodeBlocks: true,
parseImgDimensions: true,
simplifiedAutoLink: true,
literalMidWordUnderscores: true,
tasklists: true,
ghCodeBlocks: true,
smoothLivePreview: true,
});
var html = converter.makeHtml(res);
that.preview.contentHTML = html;
},
error: function(err) {
console.log(err)
}
})
}
return files;
program: {
name: "",
command: "",
dir: "",
autoStart: true,
},
},
methods: {
formatTime: function(timestamp) {
var m = moment(timestamp);
if (this.mtimeTypeFromNow) {
return m.fromNow();
}
return m.format('YYYY-MM-DD HH:mm:ss');
},
toggleHidden: function() {
this.showHidden = !this.showHidden;
},
genInstallURL: function(name) {
if (getExtention(name) == "ipa") {
urlPath = location.protocol + "//" + pathJoin([location.host, "/-/ipa/link", location.pathname, name]);
return urlPath;
}
return location.protocol + "//" + pathJoin([location.host, location.pathname, name]);
},
genQrcode: function(text, title) {
var urlPath = this.genInstallURL(text);
$("#qrcode-title").html(title || text);
$("#qrcode-link").attr("href", urlPath);
$('#qrcodeCanvas').empty().qrcode({
text: urlPath
});
$("#qrcode-modal").modal("show");
},
genDownloadURL: function(f) {
return location.origin + "/" + f.path;
},
shouldHaveQrcode: function(name) {
return ['apk', 'ipa'].indexOf(getExtention(name)) !== -1;
},
genFileClass: function(f) {
if (f.type == "dir") {
if (f.name == '.git') {
return 'fa-git-square';
}
return "fa-folder-open";
}
var ext = getExtention(f.name);
switch (ext) {
case "go":
case "py":
case "js":
case "java":
case "c":
case "cpp":
case "h":
return "fa-file-code-o";
case "pdf":
return "fa-file-pdf-o";
case "zip":
return "fa-file-zip-o";
case "mp3":
case "wav":
return "fa-file-audio-o";
case "jpg":
case "png":
case "gif":
case "jpeg":
case "tiff":
return "fa-file-picture-o";
case "ipa":
case "dmg":
return "fa-apple";
case "apk":
return "fa-android";
case "exe":
return "fa-windows";
}
return "fa-file-text-o"
},
clickFileOrDir: function(f, e) {
// TODO: fix here tomorrow
if (f.type == "file") {
return true;
}
var reqPath = pathJoin([location.pathname, f.name]);
loadFileOrDir(reqPath);
e.preventDefault()
},
changePath: function(reqPath, e) {
loadFileOrDir(reqPath);
e.preventDefault()
},
deletePathConfirm: function(f, e) {
// confirm
e.preventDefault();
$.ajax({
url: pathJoin([location.pathname, f.name]),
method: 'DELETE',
success: function(res) {
loadFileList()
},
error: function(err) {
alert(err.responseText);
}
addNewProgram: function() {
console.log("Add")
var form = $("#formNewProgram");
form.submit(function(e) {
console.log("HellO")
e.preventDefault();
console.log(e);
$("#newProgram").modal('hide')
return false;
});
// console.log(this.program.name);
},
updateBreadcrumb: function() {
var pathname = decodeURI(location.pathname || "/");
@ -207,77 +53,9 @@ var vm = new Vue({
}
return this.breadcrumb;
},
loadPreviewFile: function(filepath, e) {
if (e) {
e.preventDefault() // may be need a switch
}
var that = this;
$.getJSON(pathJoin(['/-/info', location.pathname]))
.then(function(res) {
console.log(res);
that.preview.filename = res.name;
that.preview.filesize = res.size;
return $.ajax({
url: '/' + res.path,
dataType: 'text',
});
})
.then(function(res) {
console.log(res)
that.preview.contentHTML = '<pre>' + res + '</pre>';
console.log("Finally")
})
.done(function(res) {
console.log("done", res)
});
},
loadAll: function() {
// TODO: move loadFileList here
},
}
})
window.onpopstate = function(event) {
var pathname = decodeURI(location.pathname)
loadFileList()
}
function loadFileOrDir(reqPath) {
window.history.pushState({}, "", reqPath);
loadFileList(reqPath)
}
function loadFileList(pathname) {
var pathname = pathname || location.pathname;
// console.log("load filelist:", pathname)
if (getQueryString("raw") !== "false") { // not a file preview
$.ajax({
url: pathJoin(["/-/json", pathname]),
dataType: "json",
cache: false,
success: function(res) {
res.files = _.sortBy(res.files, function(f) {
var weight = f.type == 'dir' ? 1000 : 1;
return -weight * f.mtime;
})
vm.files = res.files;
vm.auth = res.auth;
},
error: function(err) {
console.error(err)
},
});
}
vm.updateBreadcrumb();
vm.previewMode = getQueryString("raw") == "false";
if (vm.previewMode) {
vm.loadPreviewFile();
}
}
Vue.filter('fromNow', function(value) {
return moment(value).fromNow();
})
@ -291,45 +69,41 @@ Vue.filter('formatBytes', function(value) {
else return (bytes / 1073741824).toFixed(1) + " GB";
})
Dropzone.options.myDropzone = {
paramName: "file",
maxFilesize: 1024,
addRemoveLinks: true,
init: function() {
this.on("uploadprogress", function(file, progress) {
console.log("File progress", progress);
});
this.on("complete", function(file) {
console.log("reload file list")
loadFileList()
})
}
}
$(function() {
$.scrollUp({
scrollText: '', // text are defined in css
$("#formNewProgram").submit(function(e) {
var url = "/api/programs",
data = $(this).serialize();
$.ajax({
type: "POST",
url: url,
data: data,
success: function(data) {
console.log(data);
$("#newProgram").modal('hide');
},
error: function(err) {
console.log(err.responseText);
}
})
e.preventDefault()
});
// $("#formNewProgram").ajaxForm(function(e) {
// alert("Thanks");
// e.preventDefault()
// });
// var clipboard = new Clipboard('.btn');
// clipboard.on('success', function(e) {
// console.info('Action:', e.action);
// console.info('Text:', e.text);
// console.info('Trigger:', e.trigger);
// $(e.trigger)
// .tooltip('show')
// .mouseleave(function() {
// $(this).tooltip('hide');
// })
// e.clearSelection();
// });
// For page first loading
loadFileList(location.pathname + location.search)
// update version
$.getJSON("/-/sysinfo", function(res) {
vm.version = res.version;
})
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
$(e.trigger)
.tooltip('show')
.mouseleave(function() {
$(this).tooltip('hide');
})
e.clearSelection();
});
});

@ -3,6 +3,7 @@ package main
import (
"errors"
"os"
"runtime"
"time"
"github.com/qiniu/log"
@ -37,3 +38,14 @@ func IsDir(dir string) bool {
fi, err := os.Stat(dir)
return err == nil && fi.IsDir()
}
func UserHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home
}
return os.Getenv("HOME")
}

@ -25,7 +25,7 @@ func (s *Supervisor) programPath() string {
return filepath.Join(s.ConfigDir, "programs.yml")
}
func (s *Supervisor) addOrUpdateProgram(pg Program) {
func (s *Supervisor) addOrUpdateProgram(pg Program) error {
origPg, ok := s.pgMap[pg.Name]
if ok {
if !reflect.DeepEqual(origPg, &pg) {
@ -51,6 +51,7 @@ func (s *Supervisor) addOrUpdateProgram(pg Program) {
s.procMap[pg.Name] = NewProcess(pg)
log.Println("Add:", pg.Name)
}
return s.saveDB()
}
func (s *Supervisor) loadDB() error {
@ -105,11 +106,16 @@ func (s *Supervisor) hIndex(w http.ResponseWriter, r *http.Request) {
func (s *Supervisor) hAddProgram(w http.ResponseWriter, r *http.Request) {
pg := Program{
Name: r.FormValue("name"),
Command: r.FormValue("command"),
Dir: r.FormValue("dir"),
Name: r.FormValue("name"),
Command: r.FormValue("command"),
Dir: r.FormValue("dir"),
AutoStart: r.FormValue("autostart") == "on",
// TODO: missing other values
}
log.Println(r.FormValue("autostart"))
if pg.Dir == "" {
pg.Dir = "/"
}
if err := pg.Check(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@ -122,17 +128,26 @@ func (s *Supervisor) hAddProgram(w http.ResponseWriter, r *http.Request) {
"status": 1,
})
} else {
s.addOrUpdateProgram(pg)
data, _ = json.Marshal(map[string]interface{}{
"status": 0,
})
if err := s.addOrUpdateProgram(pg); err != nil {
data, _ = json.Marshal(map[string]interface{}{
"status": 1,
"error": err.Error(),
})
} else {
data, _ = json.Marshal(map[string]interface{}{
"status": 0,
})
}
}
w.Write(data)
}
func init() {
suv := &Supervisor{}
suv := &Supervisor{
ConfigDir: UserHomeDir(),
pgMap: make(map[string]*Program, 0),
procMap: make(map[string]*Process, 0),
}
r := mux.NewRouter()
r.HandleFunc("/", suv.hIndex)
r.HandleFunc("/api/programs", suv.hAddProgram).Methods("POST")

Loading…
Cancel
Save