From afd8353b6f0f549eedca239ae479144c0041bada Mon Sep 17 00:00:00 2001 From: jamesread Date: Sun, 17 Oct 2021 23:32:05 +0100 Subject: [PATCH] Ongoing UI work --- OliveTin.proto | 7 +-- internal/config/config.go | 7 +-- internal/grpcapi/grpcApi.go | 22 ++------ internal/grpcapi/grpcApiButtons.go | 47 ++++++++++++++++ webui/js/ArgumentForm.js | 87 ++++++++++++++++++++++++++---- webui/style.css | 40 ++++++++++++-- 6 files changed, 171 insertions(+), 39 deletions(-) create mode 100644 internal/grpcapi/grpcApiButtons.go diff --git a/OliveTin.proto b/OliveTin.proto index f348b45..91dab54 100644 --- a/OliveTin.proto +++ b/OliveTin.proto @@ -14,14 +14,15 @@ message ActionButton { } message ActionArgument { - string variable = 1; + string name = 1; string label = 2; string type = 3; + string defaultValue = 4; - repeated ActionArgumentValue values = 4; + repeated ActionArgumentChoice choices = 5; } -message ActionArgumentValue { +message ActionArgumentChoice { string value = 1; string label = 2; } diff --git a/internal/config/config.go b/internal/config/config.go index 661551e..8f4e22d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,13 +15,14 @@ type ActionButton struct { } type ActionArgument struct { - Variable string + Name string Label string Type string - Values []ActionArgumentValue + Default string + Choices []ActionArgumentChoice } -type ActionArgumentValue struct { +type ActionArgumentChoice struct { Value string Label string } diff --git a/internal/grpcapi/grpcApi.go b/internal/grpcapi/grpcApi.go index 6309e47..393f6cd 100644 --- a/internal/grpcapi/grpcApi.go +++ b/internal/grpcapi/grpcApi.go @@ -2,16 +2,14 @@ package grpcapi import ( ctx "context" - "crypto/md5" - "fmt" pb "github.com/jamesread/OliveTin/gen/grpc" log "github.com/sirupsen/logrus" "google.golang.org/grpc" "net" - acl "github.com/jamesread/OliveTin/internal/acl" config "github.com/jamesread/OliveTin/internal/config" executor "github.com/jamesread/OliveTin/internal/executor" + acl "github.com/jamesread/OliveTin/internal/acl" ) var ( @@ -66,22 +64,8 @@ func actionButtonsCfgToPb(cfgActionButtons []config.ActionButton, user *acl.User continue } - 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 { - Label: cfgArg.Label, - } - - btn.Arguments = append(btn.Arguments, &pbArg) - } - - res.Actions = append(res.Actions, &btn) + btn := buildButton(action, user) + res.Actions = append(res.Actions, btn) } return res diff --git a/internal/grpcapi/grpcApiButtons.go b/internal/grpcapi/grpcApiButtons.go new file mode 100644 index 0000000..e9141a5 --- /dev/null +++ b/internal/grpcapi/grpcApiButtons.go @@ -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; +} diff --git a/webui/js/ArgumentForm.js b/webui/js/ArgumentForm.js index f47af1b..bf0f706 100644 --- a/webui/js/ArgumentForm.js +++ b/webui/js/ArgumentForm.js @@ -2,17 +2,86 @@ class ArgumentForm extends window.HTMLFormElement { setup(json, callback) { 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) + + 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 } } diff --git a/webui/style.css b/webui/style.css index 216e637..c750539 100644 --- a/webui/style.css +++ b/webui/style.css @@ -237,11 +237,41 @@ details[open] { } form.actionArguments { - border-radius: 1em; position: absolute; - top: 1em; - left: 1em; - right: 1em; + top: 0; + bottom: 0; + left: 0; + right: 0; 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; }