Ongoing UI work

This commit is contained in:
jamesread 2021-10-17 23:32:05 +01:00
parent 39647c6d2d
commit afd8353b6f
6 changed files with 171 additions and 39 deletions

View File

@ -14,14 +14,15 @@ message ActionButton {
} }
message ActionArgument { message ActionArgument {
string variable = 1; string name = 1;
string label = 2; string label = 2;
string type = 3; string type = 3;
string defaultValue = 4;
repeated ActionArgumentValue values = 4; repeated ActionArgumentChoice choices = 5;
} }
message ActionArgumentValue { message ActionArgumentChoice {
string value = 1; string value = 1;
string label = 2; string label = 2;
} }

View File

@ -15,13 +15,14 @@ type ActionButton struct {
} }
type ActionArgument struct { type ActionArgument struct {
Variable string Name string
Label string Label string
Type string Type string
Values []ActionArgumentValue Default string
Choices []ActionArgumentChoice
} }
type ActionArgumentValue struct { type ActionArgumentChoice struct {
Value string Value string
Label string Label string
} }

View File

@ -2,16 +2,14 @@ package grpcapi
import ( import (
ctx "context" ctx "context"
"crypto/md5"
"fmt"
pb "github.com/jamesread/OliveTin/gen/grpc" pb "github.com/jamesread/OliveTin/gen/grpc"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"google.golang.org/grpc" "google.golang.org/grpc"
"net" "net"
acl "github.com/jamesread/OliveTin/internal/acl"
config "github.com/jamesread/OliveTin/internal/config" config "github.com/jamesread/OliveTin/internal/config"
executor "github.com/jamesread/OliveTin/internal/executor" executor "github.com/jamesread/OliveTin/internal/executor"
acl "github.com/jamesread/OliveTin/internal/acl"
) )
var ( var (
@ -66,22 +64,8 @@ func actionButtonsCfgToPb(cfgActionButtons []config.ActionButton, user *acl.User
continue continue
} }
btn := pb.ActionButton{ btn := buildButton(action, user)
Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))), res.Actions = append(res.Actions, btn)
Title: action.Title,
Icon: lookupHTMLIcon(action.Icon),
CanExec: acl.IsAllowedExec(cfg, user, &action),
}
for _, cfgArg := range action.Arguments {
pbArg := pb.ActionArgument {
Label: cfgArg.Label,
}
btn.Arguments = append(btn.Arguments, &pbArg)
}
res.Actions = append(res.Actions, &btn)
} }
return res return res

View File

@ -0,0 +1,47 @@
package grpcapi
import (
"fmt"
"crypto/md5"
pb "github.com/jamesread/OliveTin/gen/grpc"
config "github.com/jamesread/OliveTin/internal/config"
acl "github.com/jamesread/OliveTin/internal/acl"
)
func buildButton(action config.ActionButton, user *acl.User) (*pb.ActionButton) {
btn := pb.ActionButton{
Id: fmt.Sprintf("%x", md5.Sum([]byte(action.Title))),
Title: action.Title,
Icon: lookupHTMLIcon(action.Icon),
CanExec: acl.IsAllowedExec(cfg, user, &action),
}
for _, cfgArg := range action.Arguments {
pbArg := pb.ActionArgument {
Name: cfgArg.Name,
Label: cfgArg.Label,
Type: cfgArg.Type,
DefaultValue: cfgArg.Default,
Choices: buildChoices(cfgArg.Choices),
}
btn.Arguments = append(btn.Arguments, &pbArg)
}
return &btn
}
func buildChoices(choices []config.ActionArgumentChoice) ([]*pb.ActionArgumentChoice) {
ret := []*pb.ActionArgumentChoice{}
for _, cfgChoice := range choices {
pbChoice := pb.ActionArgumentChoice {
Value: cfgChoice.Value,
Label: cfgChoice.Label,
}
ret = append(ret, &pbChoice);
}
return ret;
}

View File

@ -2,17 +2,86 @@
class ArgumentForm extends window.HTMLFormElement { class ArgumentForm extends window.HTMLFormElement {
setup(json, callback) { setup(json, callback) {
this.setAttribute('class', 'actionArguments') this.setAttribute('class', 'actionArguments')
this.title = document.createElement("h1")
this.title.innerHTML = "Action Arguments"
this.appendChild(this.title);
let a = document.createElement("span")
a.innerText = "Hi"
frm.appendChild(a)
console.log(json) console.log(json)
this.domWrapper = document.createElement('div')
this.domWrapper.classList += 'wrapper'
this.appendChild(this.domWrapper)
this.domTitle = document.createElement('h2')
this.domTitle.innerText = json.title + ": Arguments"
this.domWrapper.appendChild(this.domTitle);
this.domIcon = document.createElement('span');
this.domIcon.classList += 'icon'
this.domIcon.setAttribute('role', 'img')
this.domIcon.innerHTML = json.icon
this.domTitle.prepend(this.domIcon)
let a = document.createElement("span")
a.innerText = "This is test version of the form."
this.domWrapper.appendChild(a)
this.createDomFormArguments(json.arguments)
this.domWrapper.appendChild(this.createDomSubmit())
console.log(json)
}
createDomSubmit() {
let el = document.createElement('button')
el.setAttribute('action', 'submit')
el.innerText = "Run"
return el
}
createDomFormArguments(args) {
for (let arg of args) {
let domFieldWrapper = document.createElement('p');
domFieldWrapper.appendChild(this.createDomLabel(arg))
domFieldWrapper.appendChild(this.createDomInput(arg))
this.domWrapper.appendChild(domFieldWrapper)
}
}
createDomLabel(arg) {
let domLbl = document.createElement('label')
domLbl.innerText = arg.label + ':';
domLbl.setAttribute('for', arg.name)
return domLbl;
}
createDomInput(arg) {
let domEl = null;
if (arg.choices.length > 0) {
domEl = document.createElement('select')
for (let choice of arg.choices) {
domEl.appendChild(this.createSelectOption(choice))
}
} else {
domEl = document.createElement('input')
}
domEl.setAttribute('id', arg.name)
domEl.value = arg.defaultValue
return domEl;
}
createSelectOption(choice) {
let domEl = document.createElement('option')
domEl.setAttribute('value', choice.value)
domEl.innerText = choice.label
return domEl
} }
} }

View File

@ -237,11 +237,41 @@ details[open] {
} }
form.actionArguments { form.actionArguments {
border-radius: 1em;
position: absolute; position: absolute;
top: 1em; top: 0;
left: 1em; bottom: 0;
right: 1em; left: 0;
right: 0;
padding: 1em; padding: 1em;
background-color: #fff; box-shadow: 0 0 6px 0 #aaa;
background-color: #dee3e7;
}
h2 {
font-size: 1em;
}
h2 span.icon {
vertical-align: middle;
padding-right: .2em;
}
form div.wrapper {
border-radius: 1em;
box-shadow: 0 0 10px 0 #444;
background-color: white;
border: 1px solid #999;
text-align: left;
padding: 1em;
}
label {
width: 30%;
text-align: right;
display: inline-block;
padding-right: 1em;
}
input {
padding: .6em;
} }