Move remaining library dialogs to new style

This commit is contained in:
Nick O'Leary
2019-04-24 11:50:24 +01:00
parent 6f37d5ca5c
commit 5e43a02cd3
11 changed files with 335 additions and 253 deletions

View File

@@ -462,14 +462,8 @@ var RED = (function() {
null
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
{id:"menu-item-import-library",label:RED._("menu.label.library"),onselect:"core:library-import"}
]});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"},
{id:"menu-item-export-library",label:RED._("menu.label.library"),onselect:"core:library-export"}
]});
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),onselect:"core:show-import-dialog"});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),onselect:"core:show-export-dialog"});
menuOptions.push(null);
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"});
menuOptions.push(null);

View File

@@ -24,7 +24,7 @@ RED.clipboard = (function() {
var disabled = false;
var popover;
var currentPopoverError;
var activeExportTab;
var activeTab;
var libraryBrowser;
function setupDialogs() {
@@ -33,7 +33,7 @@ RED.clipboard = (function() {
.dialog({
modal: true,
autoOpen: false,
width: 800,
width: 700,
resizable: false,
buttons: [
{
@@ -63,7 +63,7 @@ RED.clipboard = (function() {
class: "primary",
text: RED._("clipboard.export.copy"),
click: function() {
if (activeExportTab === "clipboard-dialog-export-tab-clipboard") {
if (activeTab === "clipboard-dialog-export-tab-clipboard") {
$("#clipboard-export").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
@@ -93,9 +93,9 @@ RED.clipboard = (function() {
}
});
}
if (selectedPath.files) {
if (selectedPath.children) {
var exists = false;
selectedPath.files.forEach(function(f) {
selectedPath.children.forEach(function(f) {
if (f.label === filename) {
exists = true;
}
@@ -133,7 +133,17 @@ RED.clipboard = (function() {
class: "primary",
text: RED._("common.label.import"),
click: function() {
RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
var addNewFlow = ($("#import-tab > a.selected").attr('id') === 'import-tab-new');
if (activeTab === "clipboard-dialog-import-tab-clipboard") {
RED.view.importNodes($("#clipboard-import").val(),addNewFlow);
} else {
var selectedPath = libraryBrowser.getSelected();
if (selectedPath.path) {
$.get('library/flows/'+selectedPath.path, function(data) {
RED.view.importNodes(data,addNewFlow);
});
}
}
$( this ).dialog( "close" );
}
}
@@ -160,12 +170,12 @@ RED.clipboard = (function() {
'<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
'</span>'+
'</div>'+
'<div style="height: 500px; position:relative; border:1px solid #999;">'+
'<div style="height: 400px; position:relative; border:1px solid #999;">'+
'<div style="position: absolute; top:0;left:0;bottom:0;width:120px;background: #f3f3f3;">'+
'<ul id="clipboard-dialog-export-tabs"></ul>'+
'</div>'+
'<div id="clipboard-dialog-export-tabs-content">'+
'<div id="clipboard-dialog-export-tab-clipboard">'+
'<div id="clipboard-dialog-export-tabs-content" class="clipboard-dialog-tabs-content">'+
'<div id="clipboard-dialog-export-tab-clipboard" class="clipboard-dialog-tab-clipboard">'+
'<div class="form-row">'+
'<textarea readonly id="clipboard-export"></textarea>'+
'</div>'+
@@ -176,7 +186,7 @@ RED.clipboard = (function() {
'</span>'+
'</div>'+
'</div>'+
'<div id="clipboard-dialog-export-tab-library">'+
'<div id="clipboard-dialog-export-tab-library" class="clipboard-dialog-tab-library">'+
'<div id="clipboard-dialog-export-tab-library-browser"></div>'+
'<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="clipboard-dialog-tab-library-name" type="text">'+
@@ -188,20 +198,33 @@ RED.clipboard = (function() {
importNodesDialog =
'<div class="form-row"><span data-i18n="clipboard.pasteNodes"></span>'+
' <a class="editor-button" id="import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+
'<input type="file" id="import-file-upload" accept=".json" style="display:none">'+
'<div style="height: 400px; position:relative; border:1px solid #999; margin-bottom: 12px">'+
'<div style="position: absolute; top:0;left:0;bottom:0;width:120px;background: #f3f3f3;">'+
'<ul id="clipboard-dialog-import-tabs"></ul>'+
'</div>'+
'<div id="clipboard-dialog-import-tabs-content" class="clipboard-dialog-tabs-content">'+
'<div id="clipboard-dialog-import-tab-clipboard" class="clipboard-dialog-tab-clipboard">'+
'<div class="form-row"><span data-i18n="clipboard.pasteNodes"></span>'+
' <a class="editor-button" id="import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+
'<input type="file" id="import-file-upload" accept=".json" style="display:none">'+
'</div>'+
'<div class="form-row">'+
'<textarea id="clipboard-import"></textarea>'+
'</div>'+
'</div>'+
'<div id="clipboard-dialog-import-tab-library" class="clipboard-dialog-tab-library">'+
'<div id="clipboard-dialog-import-tab-library-browser"></div>'+
'</div>'+
'</div>'+
'</div>'+
'<div class="form-row">'+
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5"></textarea>'+
'</div>'+
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
'<span id="import-tab" class="button-group">'+
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
'</span>'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
'<span id="import-tab" class="button-group">'+
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
'</span>'+
'</div>';
}
var validateExportFilenameTimeout
@@ -223,107 +246,167 @@ RED.clipboard = (function() {
},100);
}
var validateImportTimeout;
function validateImport() {
if (validateImportTimeout) {
clearTimeout(validateImportTimeout);
}
validateImportTimeout = setTimeout(function() {
var importInput = $("#clipboard-import");
var v = importInput.val().trim();
if (v === "") {
popover.close(true);
currentPopoverError = null;
importInput.removeClass("input-error");
$("#clipboard-dialog-ok").button("disable");
return;
if (activeTab === "clipboard-dialog-import-tab-clipboard") {
if (validateImportTimeout) {
clearTimeout(validateImportTimeout);
}
try {
if (!/^\[[\s\S]*\]$/m.test(v)) {
throw new Error(RED._("clipboard.import.errors.notArray"));
}
var res = JSON.parse(v);
for (var i=0;i<res.length;i++) {
if (typeof res[i] !== "object") {
throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
}
if (!res[i].hasOwnProperty('id')) {
throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
}
if (!res[i].hasOwnProperty('type')) {
throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
}
}
currentPopoverError = null;
popover.close(true);
importInput.removeClass("input-error");
importInput.val(v);
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
importInput.addClass("input-error");
var errString = err.toString();
if (errString !== currentPopoverError) {
// Display the error as-is.
// Error messages are only in English. Each browser has its
// own set of messages with very little consistency.
// To provide translated messages this code will either need to:
// - reduce everything down to 'unexpected token at position x'
// which is the least useful, but most consistent message
// - use a custom/library parser that gives consistent messages
// which can be translated.
var message = $('<div class="clipboard-import-error"></div>').text(errString);
var errorPos;
// Chrome error messages
var m = /at position (\d+)/i.exec(errString);
if (m) {
errorPos = parseInt(m[1]);
} else {
// Firefox error messages
m = /at line (\d+) column (\d+)/i.exec(errString);
if (m) {
var line = parseInt(m[1])-1;
var col = parseInt(m[2])-1;
var lines = v.split("\n");
errorPos = 0;
for (var i=0;i<line;i++) {
errorPos += lines[i].length+1;
}
errorPos += col;
} else {
// Safari doesn't provide any position information
// IE: tbd
}
}
if (errorPos !== undefined) {
v = v.replace(/\n/g,"↵");
var index = parseInt(m[1]);
var parseError = $('<div>').appendTo(message);
var code = $('<pre>').appendTo(parseError);
$('<span>').text(v.substring(errorPos-12,errorPos)).appendTo(code)
$('<span class="error">').text(v.charAt(errorPos)).appendTo(code);
$('<span>').text(v.substring(errorPos+1,errorPos+12)).appendTo(code);
}
popover.close(true).setContent(message).open();
currentPopoverError = errString;
}
} else {
validateImportTimeout = setTimeout(function() {
var importInput = $("#clipboard-import");
var v = importInput.val().trim();
if (v === "") {
popover.close(true);
currentPopoverError = null;
importInput.removeClass("input-error");
$("#clipboard-dialog-ok").button("disable");
return;
}
try {
if (!/^\[[\s\S]*\]$/m.test(v)) {
throw new Error(RED._("clipboard.import.errors.notArray"));
}
var res = JSON.parse(v);
for (var i=0;i<res.length;i++) {
if (typeof res[i] !== "object") {
throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
}
if (!res[i].hasOwnProperty('id')) {
throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
}
if (!res[i].hasOwnProperty('type')) {
throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
}
}
currentPopoverError = null;
popover.close(true);
importInput.removeClass("input-error");
importInput.val(v);
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
importInput.addClass("input-error");
var errString = err.toString();
if (errString !== currentPopoverError) {
// Display the error as-is.
// Error messages are only in English. Each browser has its
// own set of messages with very little consistency.
// To provide translated messages this code will either need to:
// - reduce everything down to 'unexpected token at position x'
// which is the least useful, but most consistent message
// - use a custom/library parser that gives consistent messages
// which can be translated.
var message = $('<div class="clipboard-import-error"></div>').text(errString);
var errorPos;
// Chrome error messages
var m = /at position (\d+)/i.exec(errString);
if (m) {
errorPos = parseInt(m[1]);
} else {
// Firefox error messages
m = /at line (\d+) column (\d+)/i.exec(errString);
if (m) {
var line = parseInt(m[1])-1;
var col = parseInt(m[2])-1;
var lines = v.split("\n");
errorPos = 0;
for (var i=0;i<line;i++) {
errorPos += lines[i].length+1;
}
errorPos += col;
} else {
// Safari doesn't provide any position information
// IE: tbd
}
}
if (errorPos !== undefined) {
v = v.replace(/\n/g,"↵");
var index = parseInt(m[1]);
var parseError = $('<div>').appendTo(message);
var code = $('<pre>').appendTo(parseError);
$('<span>').text(v.substring(errorPos-12,errorPos)).appendTo(code)
$('<span class="error">').text(v.charAt(errorPos)).appendTo(code);
$('<span>').text(v.substring(errorPos+1,errorPos+12)).appendTo(code);
}
popover.close(true).setContent(message).open();
currentPopoverError = errString;
}
} else {
currentPopoverError = null;
}
$("#clipboard-dialog-ok").button("disable");
}
},100);
} else {
var file = libraryBrowser.getSelected();
if (file && file.label && !file.children) {
$("#clipboard-dialog-ok").button("enable");
} else {
$("#clipboard-dialog-ok").button("disable");
}
},100);
}
}
function importNodes() {
function importNodes(mode) {
if (disabled) {
return;
}
mode = mode || "clipboard";
dialogContainer.empty();
dialogContainer.append($(importNodesDialog));
var tabs = RED.tabs.create({
id: "clipboard-dialog-import-tabs",
vertical: true,
onchange: function(tab) {
$("#clipboard-dialog-import-tabs-content").children().hide();
$("#" + tab.id).show();
activeTab = tab.id;
if (popover) {
popover.close(true);
currentPopoverError = null;
}
if (tab.id === "clipboard-dialog-import-tab-clipboard") {
$("#clipboard-import").focus();
}
validateImport();
}
});
tabs.addTab({
id: "clipboard-dialog-import-tab-clipboard",
label: RED._("clipboard.clipboard")
});
tabs.addTab({
id: "clipboard-dialog-import-tab-library",
label: RED._("library.library")
});
tabs.activateTab("clipboard-dialog-import-tab-"+mode);
if (mode === 'clipboard') {
setTimeout(function() {
$("#clipboard-import").focus();
},100)
}
$("#clipboard-dialog-tab-library-name").keyup(validateExportFilename);
$("#clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
$("#clipboard-dialog-export").button("enable");
libraryBrowser = RED.library.createBrowser({
container: $("#clipboard-dialog-import-tab-library-browser"),
onselect: function(file) {
if (file && file.label && !file.children) {
$("#clipboard-dialog-ok").button("enable");
} else {
$("#clipboard-dialog-ok").button("disable");
}
}
})
loadFlowLibrary(libraryBrowser,true);
dialogContainer.i18n();
$("#clipboard-dialog-ok").show();
@@ -381,7 +464,7 @@ RED.clipboard = (function() {
onchange: function(tab) {
$("#clipboard-dialog-export-tabs-content").children().hide();
$("#" + tab.id).show();
activeExportTab = tab.id;
activeTab = tab.id;
if (tab.id === "clipboard-dialog-export-tab-clipboard") {
$("#clipboard-dialog-export").button("option","label", RED._("clipboard.export.copy"))
$("#clipboard-dialog-download").show();
@@ -394,11 +477,11 @@ RED.clipboard = (function() {
});
tabs.addTab({
id: "clipboard-dialog-export-tab-clipboard",
label: "Clipboard"
label: RED._("clipboard.clipboard")
});
tabs.addTab({
id: "clipboard-dialog-export-tab-library",
label: "Library"
label: RED._("library.library")
});
tabs.activateTab("clipboard-dialog-export-tab-"+mode);
@@ -416,53 +499,10 @@ RED.clipboard = (function() {
}
}
})
loadFlowLibrary(libraryBrowser,false);
function xformList(list,label,root) {
var result = {
icon: root===""?"fa fa-archive":'fa fa-folder',
label: label,
path: root
};
result.children = [];
if (list.f) {
list.f.forEach(function(f) {
result.children.push({
icon: 'fa fa-file-o',
label: f,
path: root+f
});
});
}
if (list.d) {
for (var l in list.d) {
if (list.d.hasOwnProperty(l)) {
if (root+l !== "_examples_") {
result.children.push(xformList(list.d[l], l,root+l+"/"))
}
}
}
}
result.children.sort(function(A,B){
if (A.children && !B.children) {
return -1;
} else if (!A.children && B.children) {
return 1;
} else {
return A.label.localeCompare(B.label);
}
});
return result;
}
$.getJSON("library/flows", function(data) {
var listing = [xformList(data,"Local","")];
listing[0].expanded = true;
libraryBrowser.data(listing);
});
$("#clipboard-dialog-tab-library-name").val("flows.json").select();
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini";
@@ -569,6 +609,60 @@ RED.clipboard = (function() {
$("#clipboard-dialog-download").show();
}
function transformFlowList(list,label,root,includeExamples) {
var result = {
icon: root===""?"fa fa-archive":'fa fa-folder',
label: label,
path: root
};
result.children = [];
if (list.f) {
list.f.forEach(function(f) {
result.children.push({
icon: 'fa fa-file-o',
label: f,
path: root+f
});
});
}
if (list.d) {
for (var l in list.d) {
if (list.d.hasOwnProperty(l)) {
if (root+l !== "_examples_") {
result.children.push(transformFlowList(list.d[l], l,root+l+"/",includeExamples))
} else if (includeExamples) {
result._examples = transformFlowList(list.d[l], l,root+l+"/",includeExamples)
}
}
}
}
result.children.sort(function(A,B){
if (A.children && !B.children) {
return -1;
} else if (!A.children && B.children) {
return 1;
} else {
return A.label.localeCompare(B.label);
}
});
return result;
}
function loadFlowLibrary(browser,includeExamples) {
$.getJSON("library/flows", function(data) {
var listing = [transformFlowList(data,RED._("library.types.local"),"",includeExamples)];
listing[0].expanded = true;
if (includeExamples && listing[0]._examples) {
var examples = listing[0]._examples;
delete listing[0]._examples;
examples.label = RED._("library.types.examples");
examples.icon = "fa fa-archive";
listing.unshift(examples)
}
browser.data(listing);
});
}
function hideDropTarget() {
$("#dropTarget").hide();

View File

@@ -121,24 +121,41 @@
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
item.children(item,function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,parent,children,depth);
if (spinner) {
spinner.remove();
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
that._trigger("childrenloaded",null,item)
});
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*15)+'px 50%'
}).appendTo(container);
}
} else {
item.treeList.childList.slideDown('fast');
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
item.treeList.childList.slideUp('fast');
container.removeClass("expanded");
}
@@ -181,7 +198,7 @@
}
if (item.children) {
if (Array.isArray(item.children)) {
item.treeList.childList = that._addChildren(container,item,item.children,depth);
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
}
if (item.expanded) {
item.treeList.expand();

View File

@@ -15,16 +15,14 @@
**/
RED.library = (function() {
var exportToLibraryDialog;
var loadLibraryBrowser;
var saveLibraryBrowser;
var libraryEditor;
var activeLibrary;
var _libraryLookup = '<div id="node-dialog-library-load" class="hide">'+
'<form class="form-horizontal">'+
'<div style="height: 500px; position:relative; ">'+
'<div style="height: 400px; position:relative; ">'+
'<div id="node-dialog-library-load-panes">'+
'<div class="red-ui-panel" id="node-dialog-library-load-browser"></div>'+
'<div class="red-ui-panel">'+
@@ -60,6 +58,7 @@ RED.library = (function() {
}
var filename = $("#node-dialog-library-save-filename").val().trim()
var selectedPath = saveLibraryBrowser.getSelected();
console.log(selectedPath);
if (!selectedPath.children) {
selectedPath = selectedPath.parent;
}
@@ -90,9 +89,11 @@ RED.library = (function() {
}
});
}
if (selectedPath.files) {
console.log(filename);
console.log(selectedPath);
if (selectedPath.children) {
var exists = false;
selectedPath.files.forEach(function(f) {
selectedPath.children.forEach(function(f) {
if (f.label === filename) {
exists = true;
}
@@ -211,7 +212,7 @@ RED.library = (function() {
loadLibraryFolder(options.url, "", function(items) {
var listing = [{
icon: 'fa fa-archive',
label: "Local",
label: RED._("library.types.local"),
path: "",
expanded: true,
writable: false,
@@ -257,7 +258,7 @@ RED.library = (function() {
loadLibraryFolder(options.url, "", function(items) {
var listing = [{
icon: 'fa fa-archive',
label: "Local",
label: RED._("library.types.local"),
path: "",
expanded: true,
writable: false,
@@ -285,13 +286,6 @@ RED.library = (function() {
function createBrowser(options) {
var panes = $('<div class="red-ui-library-browser"></div>').appendTo(options.container);
// var dirsPane = $('<div class="red-ui-panel"></div>').appendTo(panes);
// var filesPane = $('<div class="red-ui-panel"></div>').appendTo(panes);
//
// RED.panels.create({
// container:panes,
// dir: "horizontal"
// });
var dirList = $("<div>").css({width: "100%", height: "100%"}).appendTo(panes)
.treeList({}).on('treelistselect', function(event, item) {
if (addButton) {
@@ -307,7 +301,7 @@ RED.library = (function() {
});
var addButton;
if (options.addFolderButton) {
var tools = $("<div>").css({position: "absolute",bottom:"3px",left:"3px"}).appendTo(panes)
var tools = $("<div>").css({position: "absolute",bottom:"3px",right:"25px"}).appendTo(panes)
addButton= $('<button type="button" class="editor-button editor-button-small"><i class="fa fa-plus"> <i class="fa fa-folder-o"></button>').appendTo(tools).click(function(e) {
var defaultFolderName = "new-folder";
var defaultFolderNameMatches = {};

View File

@@ -48,7 +48,7 @@
}
}
}
#clipboard-dialog-export-tab-clipboard {
.clipboard-dialog-tab-clipboard {
padding: 10px;
textarea {
resize: none;
@@ -56,7 +56,7 @@
border-radius: 4px;
font-family: monospace !important;
font-size: 13px !important;
height: 430px;
height: 300px;
line-height: 1.3em;
padding: 6px 10px;
background: #F3E7E7;
@@ -64,7 +64,7 @@
}
}
#clipboard-dialog-export-tabs-content {
.clipboard-dialog-tabs-content {
position: absolute;
top: 0;
left: 120px;
@@ -72,19 +72,25 @@
bottom: 0;
padding: 0;
background: white;
&>div {
height: calc(100% - 20px)
}
}
#clipboard-dialog-export-tab-library {
.clipboard-dialog-tab-library {
.form-row {
margin-left: 10px;
}
}
#clipboard-dialog {
form {
margin-bottom: 0;
}
.form-row:last-child {
margin-bottom: 0;
}
}
#clipboard-dialog-tab-library-name {
width: calc(100% - 120px);
}
@@ -94,7 +100,13 @@
border-bottom: 1px solid $primary-border-color;
box-sizing: border-box;
}
#clipboard-dialog-import-tab-library {
height: 100%;
}
#clipboard-dialog-import-tab-library-browser {
height: 100%;
box-sizing: border-box;
}
.red-ui-library-browser {

View File

@@ -49,18 +49,18 @@
transition: transform 0.1s ease-in-out;
}
.red-ui-editableList {
display: none;
// display: none;
}
&.expanded {
& > .red-ui-treeList-label .fa-angle-right {
transform: rotate(90deg)
}
& > .red-ui-editableList {
display: block
}
& > .red-ui-treeList-spinner {
display: block;
}
// & > .red-ui-editableList {
// display: block
// }
// & > .red-ui-treeList-spinner {
// display: block;
// }
}
}
}
@@ -108,7 +108,6 @@ label.red-ui-treeList-label {
text-align: center;
}
.red-ui-treeList-spinner {
display: none;
height: 32px;
background: url(images/spin.svg) 50% 50% no-repeat;
background-size: auto 20px;