Update apps categories

This commit is contained in:
mrsang
2021-03-31 23:09:40 +02:00
parent 3ff8f1a6eb
commit ada4358d61
92 changed files with 912 additions and 124 deletions

15
Dockman/README.md Normal file
View File

@ -0,0 +1,15 @@
# Dockman
This is an example project, generated by AntOS Development Kit
## Howto
Use the CodePad command palette to access to the SDK functionalities:
1. Create new project
2. Init the project from the current folder located in side bar
3. Build and run the project
4. Release the project in zip package
## Set up build target
Open the `project.json` file from the current project tree and add/remove
build target entries. Save the file

141
Dockman/api.lua Normal file
View File

@ -0,0 +1,141 @@
local args=...
local handle = {}
local result = function(data)
return { error = false, result = data }
end
local error = function(msg)
return {error = msg, result = false}
end
local exec = function(host, rcmd, decode)
local user = SESSION.user
if not user then return nil end
local cmd = "ssh -tt "..user.."@"..host.." "..rcmd
if decode then
cmd = cmd.." --format \\'{{json .}}\\'"
end
local f = assert(io.popen(cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
if decode then
s = s:gsub('[\n\r]+', ',')
return JSON.decodeString("["..s.."null]")
else
return s
end
end
handle.list_image = function(data)
local res = exec(data.host, "docker image ls", true)
if not res then
return error("Unable to fetch image list")
end
-- inspect images
for i,v in ipairs(res) do
v.Detail = exec(data.host, "docker image inspect "..v.ID, true)[1]
v.text = v.Detail.RepoTags[1]
if not v.text or v.text == "" then
v.text = v.ID
end
end
return result(res)
end
handle.list_container = function(data)
local res = exec(data.host, "docker ps -a -f ancestor="..data.image, true)
if not res then
return error("Unable to fetch container list")
end
for i,v in ipairs(res) do
v.Detail = exec(data.host, "docker container inspect "..v.ID, true)[1]
v.text = v.Names
if v.Detail.State.Running then
v.iconclass = "fa fa-circle running"
else
v.iconclass = "fa fa-circle stop"
end
end
return result(res)
end
handle.run_container = function(data)
local res = exec(data.host, "docker start "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
return error(res)
end
end
handle.pull_image = function(data)
local res = exec(data.host, "docker pull "..data.image, false)
return result(std.b64encode(res))
end
handle.rm_image = function(data)
local res = exec(data.host, "docker rmi "..data.id.."; sleep 2", false)
return result(res)
end
handle.create_container = function(data)
local cmd = "docker run "
for k,v in pairs(data.parameters) do
k = k:gsub(" ", "")
if k:len() == 1 then
cmd = cmd.." -"..k.." \""..v.."\" "
else
if k:match("^e_.*") then
cmd = cmd.." -e \""..k:gsub("e_","").."="..v.."\" "
else
cmd = cmd.." --"..k
if v ~= "" then
cmd = cmd.."=\""..v.."\" "
end
end
end
end
cmd = cmd.."--detach=true "..data.image
local res = exec(data.host, cmd, false)
return result(res)
end
handle.stop_container = function(data)
local res = exec(data.host, "docker stop "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
return error(res)
end
end
handle.rm_container = function(data)
local res = exec(data.host, "docker stop "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
local res = exec(data.host, "docker rm "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
error(res)
end
else
return error(res)
end
end
if args.action and handle[args.action] then
return handle[args.action](args.args)
else
return error("Invalid action parameter")
end

View File

@ -0,0 +1,15 @@
# Dockman
This is an example project, generated by AntOS Development Kit
## Howto
Use the CodePad command palette to access to the SDK functionalities:
1. Create new project
2. Init the project from the current folder located in side bar
3. Build and run the project
4. Release the project in zip package
## Set up build target
Open the `project.json` file from the current project tree and add/remove
build target entries. Save the file

141
Dockman/build/debug/api.lua Normal file
View File

@ -0,0 +1,141 @@
local args=...
local handle = {}
local result = function(data)
return { error = false, result = data }
end
local error = function(msg)
return {error = msg, result = false}
end
local exec = function(host, rcmd, decode)
local user = SESSION.user
if not user then return nil end
local cmd = "ssh -tt "..user.."@"..host.." "..rcmd
if decode then
cmd = cmd.." --format \\'{{json .}}\\'"
end
local f = assert(io.popen(cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
if decode then
s = s:gsub('[\n\r]+', ',')
return JSON.decodeString("["..s.."null]")
else
return s
end
end
handle.list_image = function(data)
local res = exec(data.host, "docker image ls", true)
if not res then
return error("Unable to fetch image list")
end
-- inspect images
for i,v in ipairs(res) do
v.Detail = exec(data.host, "docker image inspect "..v.ID, true)[1]
v.text = v.Detail.RepoTags[1]
if not v.text or v.text == "" then
v.text = v.ID
end
end
return result(res)
end
handle.list_container = function(data)
local res = exec(data.host, "docker ps -a -f ancestor="..data.image, true)
if not res then
return error("Unable to fetch container list")
end
for i,v in ipairs(res) do
v.Detail = exec(data.host, "docker container inspect "..v.ID, true)[1]
v.text = v.Names
if v.Detail.State.Running then
v.iconclass = "fa fa-circle running"
else
v.iconclass = "fa fa-circle stop"
end
end
return result(res)
end
handle.run_container = function(data)
local res = exec(data.host, "docker start "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
return error(res)
end
end
handle.pull_image = function(data)
local res = exec(data.host, "docker pull "..data.image, false)
return result(std.b64encode(res))
end
handle.rm_image = function(data)
local res = exec(data.host, "docker rmi "..data.id.."; sleep 2", false)
return result(res)
end
handle.create_container = function(data)
local cmd = "docker run "
for k,v in pairs(data.parameters) do
k = k:gsub(" ", "")
if k:len() == 1 then
cmd = cmd.." -"..k.." \""..v.."\" "
else
if k:match("^e_.*") then
cmd = cmd.." -e \""..k:gsub("e_","").."="..v.."\" "
else
cmd = cmd.." --"..k
if v ~= "" then
cmd = cmd.."=\""..v.."\" "
end
end
end
end
cmd = cmd.."--detach=true "..data.image
local res = exec(data.host, cmd, false)
return result(res)
end
handle.stop_container = function(data)
local res = exec(data.host, "docker stop "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
return error(res)
end
end
handle.rm_container = function(data)
local res = exec(data.host, "docker stop "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
local res = exec(data.host, "docker rm "..data.id, false)
res = res:gsub('[\n\r]+', '')
if res == data.id then
return result("OK")
else
error(res)
end
else
return error(res)
end
end
if args.action and handle[args.action] then
return handle[args.action](args.args)
else
return error("Invalid action parameter")
end

View File

@ -0,0 +1,34 @@
afx-app-window[data-id="Dockman"] .tab-wrapper button {
width: 100%;
height: 100%;
}
afx-app-window[data-id="Dockman"] .header .label-text {
font-weight: bold;
}
afx-app-window[data-id="Dockman"] afx-label.header
{
border-bottom: 1px solid #116cd6;
}
afx-app-window[data-id="Dockman"] .tab-wrapper {
border-bottom: 1px solid #116cd6;
}
afx-app-window[data-id="Dockman"] .tab-wrapper afx-list-view> .list-container {
overflow: hidden;
}
afx-app-window[data-id="Dockman"] afx-tree-view .afx_folder_item .itemname .label-text {
font-weight: bold;
}
afx-app-window[data-id="Dockman"] .running:before{
color: green;
}
afx-app-window[data-id="Dockman"] .stop:before{
color: red;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
{
"pkgname": "Dockman",
"app":"Dockman",
"name":"Remote Docker Manager",
"description":"Remote Docker Manager",
"info":{
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com"
},
"version":"0.1.0-b",
"category":"Development",
"iconclass":"fa fa-cubes",
"mimes":["none"],
"dependencies":[],
"locale": {}
}

View File

@ -0,0 +1,25 @@
<afx-app-window data-id="Dockman" apptitle="__(Remote Docker Manager)" width="650" height="450" >
<afx-vbox>
<afx-hbox data-height="23" class="tab-wrapper">
<afx-button data-id="add" text="" iconclass="fa fa-plus-square" data-width="23"></afx-button>
<afx-tab-bar data-id="host-tab-bar" closable="true"></afx-tab-bar>
</afx-hbox>
<afx-hbox>
<afx-vbox data-width="250">
<afx-label text = "__(Images)" class="header" iconclass='fa fa-square' data-height="23"></afx-label>
<afx-list-view data-id="img-list"></afx-list-view>
<afx-resizer data-height = "3"></afx-resizer>
<afx-label text = "__(Containers)" class="header" iconclass='fa fa-square' data-height="23"></afx-label>
<afx-list-view data-id="container-list"></afx-list-view>
</afx-vbox>
<afx-resizer data-width="3"></afx-resizer>
<afx-vbox>
<!--afx-label text = "__(Detail)" class="header" iconclass='fa fa-square' data-height="23"></afx-label-->
<afx-tree-view data-id="obj-view"></afx-tree-view>
<div data-height="25"></div>
</afx-vbox>
</afx-hbox>
</afx-vbox>
</afx-app-window>

Binary file not shown.

283
Dockman/main.coffee Normal file
View File

@ -0,0 +1,283 @@
class Dockman extends this.OS.application.BaseApplication
constructor: ( args ) ->
super "Dockman", args
main: () ->
@setting.hosts = [] unless @setting.hosts
@treeview = @find "obj-view"
@currenthost = undefined
@tabbar = @find "host-tab-bar"
@tabbar.ontabselect = (e) =>
@currenthost = e.data.item.data
@loadHost()
@tabbar.ontabclose = (e) =>
id = @setting.hosts.indexOf e.data.item.data
return false unless id >= 0
selid = @tabbar.selected
if selid is id
nid = id + 1
nid = id - 1 if id >= @setting.hosts.length - 1
@tabbar.selected = nid
@setting.hosts.splice id, 1
return true
@find("add").onbtclick = (e) =>
@openDialog("MultiInputDialog", {
title: "__(Add new Docker host)",
model: {
text: "__(Name)",
url: "__(Host url)"
},
allow_empty: false
})
.then (d) =>
@addTab d, true
@imglist = @find "img-list"
@imglist.onlistselect = (e) =>
@loadContainer e.data.item.data.text, false
tdata = { text: e.data.item.data.text, nodes: @getTreeData e.data.item.data }
@treeview.data = tdata
@treeview.expandAll()
@ctnlist = @find "container-list"
@ctnlist.onlistselect = (e) =>
tdata = { text: e.data.item.data.text, nodes: @getTreeData e.data.item.data }
@treeview.data = tdata
@treeview.expandAll()
@imglist.selected = -1
@imglist.buttons = [
{
text: "",
iconclass: "fa fa-arrow-down",
onbtclick: () =>
sel = @imglist.selectedItem
image = ""
image = sel.data.text if sel
@openDialog "PromptDialog", {
title: __("Pull image"),
label: __("Pull image:"),
value: image
}
.then (img) =>
return if img is ""
@exec("pull_image", {
host: @currenthost.url,
image: img
})
.then (r) =>
return @error r.error if r.error
@openDialog "TextDialog", {
title:__("Command output"),
disable: true,
value: atob(r.result)
}
.then (_d_) =>
@loadHost()
},
{
text: "",
iconclass: "fa fa-refresh",
onbtclick: () =>
@loadHost()
},
{
text: "",
iconclass: "fa fa-minus",
onbtclick: () =>
sel = @imglist.selectedItem
return unless sel
@ask({ title: __("Comfirm delete"), text: __("Are you sure?")})
.then (r) =>
return unless r
@exec("rm_image", {
host: @currenthost.url,
id: sel.data.ID
})
.then (r) =>
return @error r.error if r.error
@openDialog "TextDialog", {
title:__("Command output"),
disable: true,
value: r.result
}
.then (_d_) =>
@loadHost()
}
]
@ctnlist.buttons = [
{
text: "",
iconclass: "fa fa-play",
onbtclick: () =>
sel = @ctnlist.selectedItem
return unless sel and sel.data
data = sel.data
return if data.Detail.State.Running
@exec("run_container", {
host: @currenthost.url,
id: data.ID
})
.then (r) =>
return @error r.error if r.error
@notify __("Container {0} started", data.ID)
@loadContainer(data.Image, true)
},
{
text: "",
iconclass: "fa fa-stop",
onbtclick: () =>
sel = @ctnlist.selectedItem
return unless sel and sel.data
data = sel.data
return unless data.Detail.State.Running
@exec("stop_container", {
host: @currenthost.url,
id: data.ID
})
.then (r) =>
return @error r.error if r.error
@notify __("Container {0} stopped", data.ID)
@loadContainer(data.Image, true)
},
{
text: "",
iconclass: "fa fa-refresh",
onbtclick: () =>
data = @ctnlist.data[0]
if not data
sel = @imglist.selectedItem
return unless sel
image = sel.data.text
else
image = data.Image
@loadContainer(image, true)
},
{
text: "",
iconclass: "fa fa-plus",
onbtclick: () =>
if not @ctnlist.data[0]
return unless @imglist.selectedItem
image = @imglist.selectedItem.data.text
else
image = @ctnlist.data[0].Image
console.log image
@openDialog "KeyValueDialog", {
title: __("Container parameters"),
data: {
p: "8080:80",
restart: "always",
name: "Container_Name",
memory: "200m",
cpus: "1",
hostname: "Container_HostNamed"
}
}
.then (d) =>
@exec("create_container", {
host: @currenthost.url,
image: image,
parameters: d
})
.then (r) =>
return @error r.error if r.error
@openDialog "TextDialog", {
title:__("Command output"),
disable: true,
value: r.result
}
.then (_d_) =>
@loadContainer(image,true)
},
{
text: "",
iconclass: "fa fa-minus",
onbtclick: () =>
sel = @ctnlist.selectedItem
return unless sel and sel.data
data = sel.data
@ask({ title: __("Comfirm delete"), text: __("Are you sure?")})
.then (r) =>
return unless r
@exec("rm_container", {
host: @currenthost.url,
id: data.ID
})
.then (r) =>
return @error r.error if r.error
@notify __("Container {0} removed", data.ID)
@loadContainer(data.Image, true)
}
]
@tabbar.push v for v in @setting.hosts
@tabbar.selected = @setting.hosts.length - 1
addTab: (data, refresh) ->
id = @setting.hosts.length
@setting.hosts.push data
@tabbar.push data
return unless refresh
@tabbar.selected = id
exec: (action, args) ->
cmd =
path: "#{@path()}/api.lua",
parameters:
action: action,
args: args
return @call(cmd)
loadHost: () ->
return unless @currenthost
@resetView()
@exec("list_image", {
host: @currenthost.url
})
.then (d) =>
return @notify d.error if d.error
@imglist.data = d.result
.catch (e) =>
@error e.toString(), e
loadContainer: (data, cleanup) ->
@exec("list_container", {
host:@currenthost.url,
image: data
})
.then (d) =>
return @notify d.error if d.error
if cleanup
@treeview.data = {}
@ctnlist.data = []
@ctnlist.data = d.result
.catch (e) =>
@error e.toString(), e
getTreeData: (data) ->
type = typeof data
nodes = []
switch type
when "object"
for key, value of data
if key isnt "selected" and key isnt "domel"
if typeof value isnt "object"
nodes.push { text: "#{key}: #{value}" }
else
nodes.push { text: key, nodes: @getTreeData(value) }
return nodes
else
return []
resetView: () ->
@imglist.data = []
@ctnlist.data = []
@treeview.data = {}
this.OS.register "Dockman", Dockman

33
Dockman/main.css Normal file
View File

@ -0,0 +1,33 @@
afx-app-window[data-id="Dockman"] .tab-wrapper button {
width: 100%;
height: 100%;
}
afx-app-window[data-id="Dockman"] .header .label-text {
font-weight: bold;
}
afx-app-window[data-id="Dockman"] afx-label.header
{
border-bottom: 1px solid #116cd6;
}
afx-app-window[data-id="Dockman"] .tab-wrapper {
border-bottom: 1px solid #116cd6;
}
afx-app-window[data-id="Dockman"] .tab-wrapper afx-list-view> .list-container {
overflow: hidden;
}
afx-app-window[data-id="Dockman"] afx-tree-view .afx_folder_item .itemname .label-text {
font-weight: bold;
}
afx-app-window[data-id="Dockman"] .running:before{
color: green;
}
afx-app-window[data-id="Dockman"] .stop:before{
color: red;
}

16
Dockman/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"pkgname": "Dockman",
"app":"Dockman",
"name":"Remote Docker Manager",
"description":"Remote Docker Manager",
"info":{
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com"
},
"version":"0.1.0-b",
"category":"Development",
"iconclass":"fa fa-cubes",
"mimes":["none"],
"dependencies":[],
"locale": {}
}

7
Dockman/project.json Normal file
View File

@ -0,0 +1,7 @@
{
"name": "Dockman",
"css": ["main.css"],
"javascripts": [],
"coffees": ["main.coffee"],
"copies": ["scheme.html", "api.lua", "package.json", "README.md"]
}

25
Dockman/scheme.html Normal file
View File

@ -0,0 +1,25 @@
<afx-app-window data-id="Dockman" apptitle="__(Remote Docker Manager)" width="650" height="450" >
<afx-vbox>
<afx-hbox data-height="23" class="tab-wrapper">
<afx-button data-id="add" text="" iconclass="fa fa-plus-square" data-width="23"></afx-button>
<afx-tab-bar data-id="host-tab-bar" closable="true"></afx-tab-bar>
</afx-hbox>
<afx-hbox>
<afx-vbox data-width="250">
<afx-label text = "__(Images)" class="header" iconclass='fa fa-square' data-height="23"></afx-label>
<afx-list-view data-id="img-list"></afx-list-view>
<afx-resizer data-height = "3"></afx-resizer>
<afx-label text = "__(Containers)" class="header" iconclass='fa fa-square' data-height="23"></afx-label>
<afx-list-view data-id="container-list"></afx-list-view>
</afx-vbox>
<afx-resizer data-width="3"></afx-resizer>
<afx-vbox>
<!--afx-label text = "__(Detail)" class="header" iconclass='fa fa-square' data-height="23"></afx-label-->
<afx-tree-view data-id="obj-view"></afx-tree-view>
<div data-height="25"></div>
</afx-vbox>
</afx-hbox>
</afx-vbox>
</afx-app-window>