diff --git a/internal/integrations/ctl/airshipctl.go b/internal/integrations/ctl/airshipctl.go
index 9d55dee..fca749c 100755
--- a/internal/integrations/ctl/airshipctl.go
+++ b/internal/integrations/ctl/airshipctl.go
@@ -19,8 +19,12 @@ import (
"opendev.org/airship/airshipctl/pkg/environment"
"opendev.org/airship/airshipctl/pkg/version"
+ "opendev.org/airship/airshipui/internal/configs"
)
+// maintain the state of a potentially long running process
+var runningRequests map[configs.WsSubComponentType]bool = make(map[configs.WsSubComponentType]bool)
+
// ctlPage struct is used for templated HTML
type ctlPage struct {
ClusterRows string
@@ -28,6 +32,8 @@ type ctlPage struct {
CredentialRows string
Title string
Version string
+ Disabled string
+ ButtonText string
}
// client provides a library of functions that enable external programs (e.g. Airship UI) to perform airshipctl
diff --git a/internal/integrations/ctl/baremetal.go b/internal/integrations/ctl/baremetal.go
index 11bfdb6..8d92659 100755
--- a/internal/integrations/ctl/baremetal.go
+++ b/internal/integrations/ctl/baremetal.go
@@ -21,6 +21,7 @@ import (
)
// HandleBaremetalRequest will flop between requests so we don't have to have them all mapped as function calls
+// This will wait for the sub component to complete before responding. The assumption is this is an async request
func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage {
response := configs.WsMessage{
Type: configs.AirshipCTL,
@@ -30,13 +31,16 @@ func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage {
var err error
var message string
- switch request.SubComponent {
+ subComponent := request.SubComponent
+ switch subComponent {
case configs.GetDefaults:
response.HTML, err = getBaremetalHTML()
- case configs.DocPull:
- message, err = c.docPull()
case configs.GenerateISO:
+ // since this is long running cache it up
+ runningRequests[subComponent] = true
message, err = c.generateIso()
+ // now that we're done forget we did anything
+ delete(runningRequests, subComponent)
default:
err = fmt.Errorf("Subcomponent %s not found", request.SubComponent)
}
@@ -61,8 +65,16 @@ func (c *client) generateIso() (string, error) {
}
func getBaremetalHTML() (string, error) {
- return getHTML("./internal/integrations/ctl/templates/baremetal.html", ctlPage{
- Title: "Baremetal",
- Version: getAirshipCTLVersion(),
- })
+ p := ctlPage{
+ Title: "Baremetal",
+ Version: getAirshipCTLVersion(),
+ ButtonText: "Generate ISO",
+ }
+
+ if _, ok := runningRequests[configs.GenerateISO]; ok {
+ p.Disabled = "disabled"
+ p.ButtonText = "In Progress"
+ }
+
+ return getHTML("./internal/integrations/ctl/templates/baremetal.html", p)
}
diff --git a/internal/integrations/ctl/templates/baremetal.html b/internal/integrations/ctl/templates/baremetal.html
index 897d184..71c4c33 100755
--- a/internal/integrations/ctl/templates/baremetal.html
+++ b/internal/integrations/ctl/templates/baremetal.html
@@ -2,4 +2,4 @@
Version: {{.Version}}
Generate ISO
-
+
diff --git a/internal/webservice/server.go b/internal/webservice/server.go
index db4ee92..e5b94da 100755
--- a/internal/webservice/server.go
+++ b/internal/webservice/server.go
@@ -31,7 +31,7 @@ var upgrader = websocket.Upgrader{
}
// this is a way to allow for arbitrary messages to be processed by the backend
-// most likely we will need to have sub components register with the system
+// the message of a specifc component is shunted to that subsystem for further processing
// TODO: make this a dynamic registration of components
var functionMap = map[configs.WsRequestType]map[configs.WsComponentType]func(configs.WsMessage) configs.WsMessage{
configs.Electron: {
diff --git a/web/js/airshipctl/airshipctl.js b/web/js/airshipctl/airshipctl.js
index 59e742b..0d279bf 100755
--- a/web/js/airshipctl/airshipctl.js
+++ b/web/js/airshipctl/airshipctl.js
@@ -26,10 +26,11 @@ document.addEventListener("DOMContentLoaded", () => {
// Displays the alerts from the backend
function handleCTLResponse(json) { // eslint-disable-line no-unused-vars
+ let message = json["type"] + " " + json["component"] + " " + json["subComponent"] + " ";
if (json.hasOwnProperty("error")) {
- showDismissableAlert("danger", json["error"], false);
+ showDismissableAlert("danger", message + json["error"], false);
} else {
- showDismissableAlert("info", json["message"], false);
+ showDismissableAlert("info", message + json["message"], true);
}
}
diff --git a/web/js/common.js b/web/js/common.js
index 0f7816d..909db98 100755
--- a/web/js/common.js
+++ b/web/js/common.js
@@ -34,20 +34,22 @@ if (document.addEventListener) {
// add dashboard links to Dropdown if present in $HOME/.airship/airshipui.json
function addServiceDashboards(json) { // eslint-disable-line no-unused-vars
- for (let i = 0; i < json.length; i++) {
- let cluster = json[i];
- for (let j = 0; j < cluster.namespaces.length; j++) {
- let namespace = cluster.namespaces[j];
- for (let k = 0; k < namespace.dashboards.length; k++) {
- let dash = namespace.dashboards[k];
- let fqdn = "";
- if (dash.fqdn === undefined) {
- fqdn = `${dash.hostname}.${cluster.namespaces[j].name}.${cluster.baseFqdn}`
- } else {
- ({ fqdn } = dash.fqdn);
+ if (json !== undefined) {
+ for (let i = 0; i < json.length; i++) {
+ let cluster = json[i];
+ for (let j = 0; j < cluster.namespaces.length; j++) {
+ let namespace = cluster.namespaces[j];
+ for (let k = 0; k < namespace.dashboards.length; k++) {
+ let dash = namespace.dashboards[k];
+ let fqdn = "";
+ if (dash.fqdn === undefined) {
+ fqdn = `${dash.hostname}.${cluster.namespaces[j].name}.${cluster.baseFqdn}`
+ } else {
+ ({ fqdn } = dash.fqdn);
+ }
+ let url = `${dash.protocol}://${fqdn}:${dash.port}/${dash.path || ""}`;
+ addDashboard("DashDropdown", dash.name, url)
}
- let url = `${dash.protocol}://${fqdn}:${dash.port}/${dash.path || ""}`;
- addDashboard("DashDropdown", dash.name, url)
}
}
}
@@ -56,11 +58,13 @@ function addServiceDashboards(json) { // eslint-disable-line no-unused-vars
// if any plugins (external executables) have a corresponding web dashboard defined,
// add them to the dropdown
function addPluginDashboards(json) { // eslint-disable-line no-unused-vars
- for (let i = 0; i < json.length; i++) {
- if (json[i].executable.autoStart && json[i].dashboard.fqdn !== undefined) {
- let dash = json[i].dashboard;
- let url = `${dash.protocol}://${dash.fqdn}:${dash.port}/${dash.path || ""}`;
- addDashboard("PluginDropdown", json[i].name, url);
+ if (json !== undefined) {
+ for (let i = 0; i < json.length; i++) {
+ if (json[i].executable.autoStart && json[i].dashboard.fqdn !== undefined) {
+ let dash = json[i].dashboard;
+ let url = `${dash.protocol}://${dash.fqdn}:${dash.port}/${dash.path || ""}`;
+ addDashboard("PluginDropdown", json[i].name, url);
+ }
}
}
}
@@ -91,12 +95,6 @@ function authenticate(json) { // eslint-disable-line no-unused-vars
view.src = json["url"];
}
-function removeElement(id) { // eslint-disable-line no-unused-vars
- if (document.contains(document.getElementById(id))) {
- document.getElementById(id).remove();
- }
-}
-
// show a dismissable alert in the UI
// if 'fade' is set to true, the alert will fade out and disappear after 5s
function showDismissableAlert(alertLevel, msg, fade) { // eslint-disable-line no-unused-vars
diff --git a/web/js/websocket.js b/web/js/websocket.js
index 805b0f4..9e581d1 100755
--- a/web/js/websocket.js
+++ b/web/js/websocket.js
@@ -75,11 +75,11 @@ function hanldleElectronMessages(json) {
authenticate(json["authentication"]);
} else {
authComplete();
- }
- if (json["plugins"] !== null) {
+ }
+ if (json.hasOwnProperty("plugins")) {
addPluginDashboards(json["plugins"]);
}
- if (json["dashboards"] !== null) {
+ if (json.hasOwnProperty("dashboards")) {
addServiceDashboards(json["dashboards"]);
}
} else if (json["component"] === "authcomplete") {