From a6ecb54cc4a215002c22893c6f1ff8da9b0acceb Mon Sep 17 00:00:00 2001
From: Nick O'Leary <nick.oleary@gmail.com>
Date: Tue, 31 Mar 2020 19:25:20 +0100
Subject: [PATCH 1/2] Clear node.close timeout to avoid unnecessary work on
 restart

---
 .../node_modules/@node-red/runtime/lib/nodes/flows/Flow.js   | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
index 5fa77d505..c132b507b 100644
--- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
+++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
@@ -571,15 +571,18 @@ function stopNode(node,removed) {
     Log.trace("Stopping node "+node.type+":"+node.id+(removed?" removed":""));
     const start = Date.now();
     const closePromise = node.close(removed);
+    let closeTimer = null;
     const closeTimeout = new Promise((resolve,reject) => {
-        setTimeout(() => {
+        closePromise = setTimeout(() => {
             reject("Close timed out");
         }, nodeCloseTimeout);
     });
     return Promise.race([closePromise,closeTimeout]).then(() => {
+        clearTimeout(closeTimer);
         var delta = Date.now() - start;
         Log.trace("Stopped node "+node.type+":"+node.id+" ("+delta+"ms)" );
     }).catch(err => {
+        clearTimeout(closeTimer);
         node.error(Log._("nodes.flows.stopping-error",{message:err}));
         Log.debug(err.stack);
     })

From f058de8bcd7d74bd9c5d5972ebaf951c833df3a6 Mon Sep 17 00:00:00 2001
From: Nick O'Leary <nick.oleary@gmail.com>
Date: Thu, 2 Apr 2020 16:49:58 +0100
Subject: [PATCH 2/2] Update TypedInput to use flexbox and remove resizing code

---
 .../src/js/ui/common/typedInput.js            | 68 +++----------------
 .../src/sass/ui/common/typedInput.scss        | 21 ++----
 2 files changed, 16 insertions(+), 73 deletions(-)

diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
index cb4de12d2..88c842c2f 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
@@ -488,56 +488,6 @@
                 done(labelWidth);
             }
         },
-        _resize: function() {
-            var that = this;
-            if (this.uiWidth !== null) {
-                this.uiSelect.width(this.uiWidth);
-            }
-            var type = this.typeMap[this.propertyType];
-            if (type && type.hasValue === false) {
-                this.selectTrigger.addClass("red-ui-typedInput-full-width");
-            } else {
-                this.selectTrigger.removeClass("red-ui-typedInput-full-width");
-                this._getLabelWidth(this.selectTrigger, function(labelWidth) {
-                    that.elementDiv.css('left',labelWidth+"px");
-                    that.valueLabelContainer.css('left',labelWidth+"px");
-                    if (that.optionExpandButton.shown) {
-                        that.elementDiv.css('right',"22px");
-                        that.valueLabelContainer.css('right',"22px");
-                    } else {
-                        that.elementDiv.css('right','0');
-                        that.valueLabelContainer.css('right','0');
-                        that.input.css({
-                            'border-top-right-radius': '4px',
-                            'border-bottom-right-radius': '4px'
-                        });
-                    }
-                    if (that.optionSelectTrigger) {
-                        if (type && type.options && type.hasValue === true) {
-                            that.optionSelectLabel.css({'left':'auto'})
-                            that._getLabelWidth(that.optionSelectLabel, function(lw) {
-                                that.optionSelectTrigger.css({'width':(23+lw)+"px"});
-                                that.elementDiv.css('right',(23+lw)+"px");
-                                that.input.css({
-                                    'border-top-right-radius': 0,
-                                    'border-bottom-right-radius': 0
-                                });
-                            });
-                        } else {
-                            that.optionSelectLabel.css({'left':'0'})
-                            that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
-                            if (!that.optionExpandButton.shown) {
-                                that.elementDiv.css({'right':0});
-                                that.input.css({
-                                    'border-top-right-radius': '4px',
-                                    'border-bottom-right-radius': '4px'
-                                });
-                            }
-                        }
-                    }
-                });
-            }
-        },
         _updateOptionSelectLabel: function(o) {
             var opt = this.typeMap[this.propertyType];
             this.optionSelectLabel.empty();
@@ -565,7 +515,6 @@
                 }
                 if (opt.hasValue) {
                     this.optionValue = o.value;
-                    this._resize();
                     this.input.trigger('change',this.propertyType,this.value());
                 }
             } else {
@@ -605,11 +554,12 @@
                 this.propertyType = null;
                 this.type(currentType);
             }
-            setTimeout(function() {that._resize();},0);
         },
         width: function(desiredWidth) {
             this.uiWidth = desiredWidth;
-            this._resize();
+            if (this.uiWidth !== null) {
+                this.uiSelect.width(this.uiWidth);
+            }
         },
         value: function(value) {
             var that = this;
@@ -680,8 +630,6 @@
                         }
                         else if (opt.icon.indexOf("/") !== -1) {
                             image = new Image();
-                            image.onload = function() { that._resize(); }
-                            image.onerror = function() { that._resize(); }
                             image.name = opt.icon;
                             image.src = mapDeprecatedIcon(opt.icon);
                             $('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
@@ -693,6 +641,12 @@
                     if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
                         this.selectLabel.text(opt.label);
                     }
+                    if (opt.hasValue === false) {
+                        this.selectTrigger.addClass("red-ui-typedInput-full-width");
+                    } else {
+                        this.selectTrigger.removeClass("red-ui-typedInput-full-width");
+                    }
+
                     if (this.optionMenu) {
                         this.optionMenu.remove();
                         this.optionMenu = null;
@@ -881,9 +835,6 @@
                         this._trigger("typechange",null,this.propertyType);
                         this.input.trigger('change',this.propertyType,this.value());
                     }
-                    if (!image) {
-                        this._resize();
-                    }
                 }
             }
         },
@@ -910,7 +861,6 @@
         },
         show: function() {
             this.uiSelect.show();
-            this._resize();
         },
         hide: function() {
             this.uiSelect.hide();
diff --git a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss
index be2d50674..243c42e17 100644
--- a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss
+++ b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss
@@ -18,7 +18,7 @@
     border: 1px solid $form-input-border-color;
     border-radius: 4px;
     height: 34px;
-    display: inline-block;
+    display: inline-flex;
     padding: 0;
     margin: 0;
     vertical-align: middle;
@@ -26,12 +26,7 @@
     overflow:visible;
     position: relative;
     .red-ui-typedInput-input-wrap {
-        position: absolute;
-        left:0;
-        right:0;
-        top:0;
-        bottom:0;
-        outline: red;
+        flex-grow: 1;
     }
     input.red-ui-typedInput-input {
         width: 100%;
@@ -49,7 +44,7 @@
         border-color: $form-input-focus-color !important;
     }
     .red-ui-typedInput-value-label {
-        position: absolute;
+        flex-grow: 1;
         display: inline-block;
         height: 32px;
         box-sizing: border-box;
@@ -104,12 +99,11 @@ button.red-ui-typedInput-option-trigger
  {
     text-align: left;
     border: none;
-    position: absolute;
+    flex-basis: auto;
     box-sizing: border-box;
     border-top-left-radius: 4px;
     border-bottom-left-radius: 4px;
     padding: 0 1px 0 5px;
-    display:inline-block;
     background: $form-button-background;
     height: 32px;
     line-height: 30px;
@@ -151,7 +145,7 @@ button.red-ui-typedInput-option-trigger
         text-decoration: none;
     }
     &.red-ui-typedInput-full-width {
-        width: 100%;
+        flex-grow: 1;
         border-top-right-radius: 4px;
         border-bottom-right-radius: 4px;
     }
@@ -167,7 +161,6 @@ button.red-ui-typedInput-option-expand {
     border-bottom-right-radius: 4px;
     border-top-left-radius: 0;
     border-bottom-left-radius: 0;
-    right: 0;
 }
 
 button.red-ui-typedInput-option-trigger {
@@ -176,8 +169,8 @@ button.red-ui-typedInput-option-trigger {
     border-top-right-radius: 4px;
     border-bottom-right-radius: 4px;
     padding: 0 0 0 0;
-    position:absolute;
-    right: 0;
+    position:relative;
+    flex-grow: 1;
     .red-ui-typedInput-option-label {
         background:$form-button-background;
         color: $form-text-color;