@*******************************************************************************************************// Status.cshtml - Gbtc//// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 01/15/2016 - J. Ritchie Carroll// Generated original version of source code.////******************************************************************************************************// To use in an ASP.NET destination project, include a Users.cshtml view with following content://// @using GSF.Web// @section StyleSheets{@Html.Raw(ViewBag.StyleSheetsSection?.ToString())}// @Html.RenderResource("ModbusAdapters.Status.cshtml")// @section Scripts{@Html.Raw(ViewBag.ScriptsSection?.ToString())}////******************************************************************************************************// To use in a self-hosted web project, include a Users.cshtml view with following content://// @using GSF.Web.Model// @using <MyAppNameSpace>.Model// @inherits ExtendedTemplateBase<AppModel>// @section StyleSheets{@Html.Raw(ViewBag.StyleSheetsSection.ToString())}// @{Layout = "Layout.cshtml";}// @Html.RenderResource("ModbusAdapters.Status.cshtml")// @section Scripts{@Html.Raw(ViewBag.ScriptsSection.ToString())}////*****************************************************************************************************@@* ReSharper disable RedundantUsingDirective *@@* ReSharper disable Html.PathError *@@* ReSharper disable UnknownCssClass *@@* ReSharper disable InlineOutVariableDeclaration *@@using System.Net.Http@using GSF@using GSF.Web@using GSF.Web.Model@using GSF.Web.Shared@using ModbusAdapters.Model@inherits ExtendedTemplateBase@{ // Layout will depend on rendering environment, so do not specify one ViewBag.Title = "Status"; HttpRequestMessage request = ViewBag.Request; Dictionary<string, string> parameters = request.QueryParameters(); string parameter, acronymn; parameters.TryGetValue("ShowMenu", out parameter); if (string.IsNullOrEmpty(parameter)) { parameter = "true"; } parameters.TryGetValue("Acronym", out acronymn); ViewBag.ShowMenu = parameter.ParseBoolean();}@section StyleSheets { <style> html, body { height: 100%; } </style>}@helper SearchFilter(){ @* Make sure to use single quotes in this function: *@ <div class='form-group' style='margin: 0'> <div class='right-inner-addon'> <i class='glyphicon glyphicon-search'></i> <input class='form-control' type='search' id='searchFilter' placeholder='Search'/> </div> </div>}@section Scripts { <script src="@Resources.Root/Shared/Scripts/knockout.js"></script> <script> // Define view model for device status function StatusViewModel() { const self = this; // Configuration fields self.filterText = ""; // Search filter text // Observable fields self.items = ko.observableArray(); // Items to display self.columnLength = ko.observable(4); // Columns in each row of items // Internal fields self._itemLimit = ko.observable(-1); // Item query limit // Properties // Gets record count self.recordCount = ko.pureComputed({ read: function() { return self.items().length; } }); self.itemLimit = ko.pureComputed({ read: self._itemLimit, write: function(value) { if (value < 1) value = 1; if (value !== self._itemLimit()) { self._itemLimit(value); self.queryItems(); } } }); // Return an array of rows where each row is an array of items self.rows = ko.computed(function() { const result = []; const columns = parseInt(self.columnLength(), 10); var row; for (var i = 0, j = self.items().length; i < j; i++) { if (i % columns === 0) { if (row) result.push(row); row = []; } if (row) row.push(self.items()[i]); } // Push final row if (row) result.push(row); return result; }); self.queryItems = function() { if (!hubIsConnected) return $.Deferred().resolve().promise(); return dataHub.queryEnabledDevices("@ViewBag.NodeID", self.itemLimit(), self.filterText).done(function(devices) { self.items.removeAll(); self.items(devices); $(self).trigger("itemsQueried"); }); } self.fixAcronym = function(acronym) { return acronym.replace(/[^A-Za-z0-9]/g, ""); } } const viewModel = new StatusViewModel(); $(viewModel).one("itemsQueried", function () { const acronym = "@Raw(acronymn)"; if (notNull(acronym)) { $(viewModel).one("itemsQueried", function () { $(`#${viewModel.fixAcronym(acronym)}Heading`).click(); }); $("#searchFilter").val(acronym); viewModel.filterText = acronym; viewModel.queryItems(); } }); const ProgressState = { Queued: 0, Processing: 1, PartialSuccess: 2, Success: 3, Fail: 4 }; $(window).on("beforeHubConnected", function (event) { var deviceProgress = {}; dataHubClient.deviceProgressUpdate = function (deviceName, updates) { var fixedDeviceName = viewModel.fixAcronym(deviceName); const messageWell = $(`#${fixedDeviceName}Message`); const heading = $(`#${fixedDeviceName}Heading`); var progress = deviceProgress[deviceName]; // TODO: This function is a mess, all the variable redeclarations are confusing, needs simplification: $.each(updates, function (_, update) { if (!progress) { heading.click(function () { $.each(viewModel.items(), function (_, item) { $(`#${viewModel.fixAcronym(item.Acronym)}Message`).text(""); }); var progress = deviceProgress[deviceName]; $.each(progress.messages, function (_, message) { messageWell.append(message).append($("<br>")); }); var progressBar; var progressValue; progressBar = $(`#${fixedDeviceName}CurrentProgress`); progressValue = Math.ceil(progress.progress / progress.progressTotal * 100.0); if (isNumber(progressValue)) { progressBar.text(progressValue.toString() + "%"); progressBar.css("width", progressBar.text()); if (progressValue < 100 && !progressBar.hasClass("active")) progressBar.addClass("active"); else if (progressValue == 100 && progressBar.hasClass("active")) progressBar.removeClass("active"); } progressBar = $(`#${fixedDeviceName}OverallProgress`); progressValue = Math.ceil(progress.overallProgress / progress.overallProgressTotal * 100.0); if (isNumber(progressValue)) { progressBar.text(progressValue.toString() + "%"); progressBar.css("width", progressBar.text()); if (progressValue < 100 && !progressBar.hasClass("active")) progressBar.addClass("active"); else if (progressValue == 100 && progressBar.hasClass("active")) progressBar.removeClass("active"); } }); } if (!progress || update.State === ProgressState.Queued) { deviceProgress[deviceName] = progress = { state: update.State, lastMessageText: "", lastErrorMessageText: "", progress: 0, progressTotal: 1, overallProgress: 0, overallProgressTotal: 1, messages: [] }; messageWell.text(""); } if (update.State !== undefined) { const panel = $(`#${fixedDeviceName}Panel`); panel.removeClass("panel-default panel-primary panel-info panel-success panel-warning panel-danger"); progress.state = update.State; switch (progress.state) { case ProgressState.Queued: panel.addClass("panel-primary"); break; case ProgressState.Processing: panel.addClass("panel-info"); break; case ProgressState.PartialSuccess: panel.addClass("panel-warning"); break; case ProgressState.Success: panel.addClass("panel-success"); break; case ProgressState.Fail: panel.addClass("panel-danger"); break; } } if (notNull(update.Summary).length > 0) heading.text(deviceName + ": " + update.Summary); if (notNull(update.Message).length > 0) { var messageText = update.Message.substring("[yyyy-MM-dd HH:mm:ss.fff] ".length); if (messageText !== progress.lastMessageText) { progress.lastMessageText = messageText; progress.messages.push(update.Message); if (!heading.hasClass("collapsed")) messageWell.append(update.Message).append($("<br>")); } } if (notNull(update.ErrorMessage).length > 0) { var messageText = update.ErrorMessage.substring("[yyyy-MM-dd HH:mm:ss.fff] ".length); if (messageText !== progress.lastErrorMessageText) { progress.lastErrorMessageText = messageText; var message = `<span style="color: red">${update.ErrorMessage}</span>` progress.messages.push(message); if (!heading.hasClass("collapsed")) messageWell.append(message).append($("<br>")); } } if (update.Progress !== undefined || update.ProgressTotal !== undefined) { var progressBar = $(`#${fixedDeviceName}CurrentProgress`); if (update.Progress !== undefined) progress.progress = update.Progress; progress.progressTotal = update.ProgressTotal || progress.progressTotal; var progressValue = Math.ceil(progress.progress / progress.progressTotal * 100.0); if (!heading.hasClass("collapsed") && isNumber(progressValue)) { progressBar.text(progressValue.toString() + "%"); progressBar.css("width", progressBar.text()); if (progressValue < 100 && !progressBar.hasClass("active")) progressBar.addClass("active"); else if (progressValue == 100 && progressBar.hasClass("active")) progressBar.removeClass("active"); } } if (update.OverallProgress !== undefined || update.OverallProgressTotal !== undefined) { var progressBar = $(`#${fixedDeviceName}OverallProgress`); if (update.OverallProgress !== undefined) progress.overallProgress = update.OverallProgress; progress.overallProgressTotal = update.OverallProgressTotal || progress.overallProgressTotal; var progressValue = Math.ceil(progress.overallProgress / progress.overallProgressTotal * 100.0); if (!heading.hasClass("collapsed") && isNumber(progressValue)) { progressBar.text(progressValue.toString() + "%"); progressBar.css("width", progressBar.text()); if (progressValue < 100 && !progressBar.hasClass("active")) progressBar.addClass("active"); else if (progressValue == 100 && progressBar.hasClass("active")) progressBar.removeClass("active"); } } }); } }); $(function() { $("#pageHeader").append("@Raw(SearchFilter().ToString().RemoveDuplicateWhiteSpace().Replace("\r\n", ""))"); $("#titleText").html("Records: <span data-bind='text: recordCount'>calculating...</span>"); $("#searchFilter").on("keyup", function(event) { if ($("#searchFilter").val().length === 0) { $('.panel').show(); } else { $('.panel').hide(); $('.panel').filter(function(i,d) { return $(d).attr('id').toLowerCase().indexOf($("#searchFilter").val().toLowerCase()) != -1 }).show(); } }); ko.applyBindings(viewModel, document.getElementsByTagName("body")[0]); }); $(window).on("hubConnected", function (event) { viewModel.queryItems().done(function () { dataHub.queryDeviceStatus(); }); }); function queueNow(record) { if (!hubIsConnected) return; serviceHub.sendCommand(`INVOKE ${record.Acronym} QueueTasks`); } function queueAll() { for (let i = 0; i < viewModel.items().length; i++) { queueNow(viewModel.items()[i]); } } </script>}<div class="bs-example"> <div class="panel-group" id="accordion" data-bind="foreach: items"> <div class="panel panel-default" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'Panel'}"> <div class="panel-heading" > <h4 class="panel-title"> <a data-toggle="collapse" data-parent="#accordion" data-bind="attr: {id: $parent.fixAcronym(Acronym) +'Heading','data-target': '#sm' + $parent.fixAcronym(Acronym)}, text: Acronym"></a> </h4> </div> <div data-bind="attr: {id: 'sm' + $parent.fixAcronym(Acronym)}" class="panel-collapse collapse"> <div class="panel-body"> <div class="table-cell-wrap" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'Message'}" style="overflow-y: auto; height: 500px; padding: 5px; margin-bottom: 5px; border: 1px solid; border-color: #ddd"></div> <div class="progress" style="margin: 0"> <div class="progress-bar progress-bar-striped active no-transition" role="progressbar" style="width: 0%" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'CurrentProgress'}">0%</div> </div> <div class="progress" style="margin-top: 5px; margin-bottom: -5px"> <div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 0%" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'OverallProgress'}">0%</div> </div> </div> <div class="panel-footer"> <button type="button" class="btn btn-primary" data-bind="click: queueNow.bind($data)">Queue Processing...</button> </div> </div> </div> </div> </div></div>@{ ViewBag.StyleSheetsSection = RenderSection("StyleSheets").ToString(); ViewBag.ScriptsSection = RenderSection("Scripts").ToString();}
@*******************************************************************************************************
// Status.cshtml - Gbtc
//
// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 01/15/2016 - J. Ritchie Carroll
// Generated original version of source code.
//
//******************************************************************************************************
// To use in an ASP.NET destination project, include a Users.cshtml view with following content:
//
// @using GSF.Web
// @section StyleSheets{@Html.Raw(ViewBag.StyleSheetsSection?.ToString())}
// @Html.RenderResource("ModbusAdapters.Status.cshtml")
// @section Scripts{@Html.Raw(ViewBag.ScriptsSection?.ToString())}
//
//******************************************************************************************************
// To use in a self-hosted web project, include a Users.cshtml view with following content:
//
// @using GSF.Web.Model
// @using <MyAppNameSpace>.Model
// @inherits ExtendedTemplateBase<AppModel>
// @section StyleSheets{@Html.Raw(ViewBag.StyleSheetsSection.ToString())}
// @{Layout = "Layout.cshtml";}
// @Html.RenderResource("ModbusAdapters.Status.cshtml")
// @section Scripts{@Html.Raw(ViewBag.ScriptsSection.ToString())}
//
//*****************************************************************************************************@
@* ReSharper disable RedundantUsingDirective *@
@* ReSharper disable Html.PathError *@
@* ReSharper disable UnknownCssClass *@
@* ReSharper disable InlineOutVariableDeclaration *@
@using System.Net.Http
@using GSF
@using GSF.Web
@using GSF.Web.Model
@using GSF.Web.Shared
@using ModbusAdapters.Model
@inherits ExtendedTemplateBase
@{
// Layout will depend on rendering environment, so do not specify one
ViewBag.Title = "Status";
HttpRequestMessage request = ViewBag.Request;
Dictionary<string, string> parameters = request.QueryParameters();
string parameter, acronymn;
parameters.TryGetValue("ShowMenu", out parameter);
if (string.IsNullOrEmpty(parameter)) {
parameter = "true";
}
parameters.TryGetValue("Acronym", out acronymn);
ViewBag.ShowMenu = parameter.ParseBoolean();
}
@section StyleSheets {
<style>
html, body {
height: 100%;
}
</style>
}
@helper SearchFilter()
{
@* Make sure to use single quotes in this function: *@
<div class='form-group' style='margin: 0'>
<div class='right-inner-addon'>
<i class='glyphicon glyphicon-search'></i>
<input class='form-control' type='search' id='searchFilter' placeholder='Search'/>
</div>
</div>
}
@section Scripts {
<script src="@Resources.Root/Shared/Scripts/knockout.js"></script>
<script>
// Define view model for device status
function StatusViewModel() {
const self = this;
// Configuration fields
self.filterText = ""; // Search filter text
// Observable fields
self.items = ko.observableArray(); // Items to display
self.columnLength = ko.observable(4); // Columns in each row of items
// Internal fields
self._itemLimit = ko.observable(-1); // Item query limit
// Properties
// Gets record count
self.recordCount = ko.pureComputed({
read: function() {
return self.items().length;
}
});
self.itemLimit = ko.pureComputed({
read: self._itemLimit,
write: function(value) {
if (value < 1)
value = 1;
if (value !== self._itemLimit()) {
self._itemLimit(value);
self.queryItems();
}
}
});
// Return an array of rows where each row is an array of items
self.rows = ko.computed(function() {
const result = [];
const columns = parseInt(self.columnLength(), 10);
var row;
for (var i = 0, j = self.items().length; i < j; i++) {
if (i % columns === 0) {
if (row)
result.push(row);
row = [];
}
if (row)
row.push(self.items()[i]);
}
// Push final row
if (row)
result.push(row);
return result;
});
self.queryItems = function() {
if (!hubIsConnected)
return $.Deferred().resolve().promise();
return dataHub.queryEnabledDevices("@ViewBag.NodeID", self.itemLimit(), self.filterText).done(function(devices) {
self.items.removeAll();
self.items(devices);
$(self).trigger("itemsQueried");
});
}
self.fixAcronym = function(acronym) {
return acronym.replace(/[^A-Za-z0-9]/g, "");
}
}
const viewModel = new StatusViewModel();
$(viewModel).one("itemsQueried", function () {
const acronym = "@Raw(acronymn)";
if (notNull(acronym)) {
$(viewModel).one("itemsQueried", function () {
$(`#${viewModel.fixAcronym(acronym)}Heading`).click();
});
$("#searchFilter").val(acronym);
viewModel.filterText = acronym;
viewModel.queryItems();
}
});
const ProgressState = {
Queued: 0,
Processing: 1,
PartialSuccess: 2,
Success: 3,
Fail: 4
};
$(window).on("beforeHubConnected", function (event) {
var deviceProgress = {};
dataHubClient.deviceProgressUpdate = function (deviceName, updates) {
var fixedDeviceName = viewModel.fixAcronym(deviceName);
const messageWell = $(`#${fixedDeviceName}Message`);
const heading = $(`#${fixedDeviceName}Heading`);
var progress = deviceProgress[deviceName];
// TODO: This function is a mess, all the variable redeclarations are confusing, needs simplification:
$.each(updates, function (_, update) {
if (!progress) {
heading.click(function () {
$.each(viewModel.items(), function (_, item) {
$(`#${viewModel.fixAcronym(item.Acronym)}Message`).text("");
});
var progress = deviceProgress[deviceName];
$.each(progress.messages, function (_, message) {
messageWell.append(message).append($("<br>"));
});
var progressBar;
var progressValue;
progressBar = $(`#${fixedDeviceName}CurrentProgress`);
progressValue = Math.ceil(progress.progress / progress.progressTotal * 100.0);
if (isNumber(progressValue)) {
progressBar.text(progressValue.toString() + "%");
progressBar.css("width", progressBar.text());
if (progressValue < 100 && !progressBar.hasClass("active"))
progressBar.addClass("active");
else if (progressValue == 100 && progressBar.hasClass("active"))
progressBar.removeClass("active");
}
progressBar = $(`#${fixedDeviceName}OverallProgress`);
progressValue = Math.ceil(progress.overallProgress / progress.overallProgressTotal * 100.0);
if (isNumber(progressValue)) {
progressBar.text(progressValue.toString() + "%");
progressBar.css("width", progressBar.text());
if (progressValue < 100 && !progressBar.hasClass("active"))
progressBar.addClass("active");
else if (progressValue == 100 && progressBar.hasClass("active"))
progressBar.removeClass("active");
}
});
}
if (!progress || update.State === ProgressState.Queued) {
deviceProgress[deviceName] = progress = {
state: update.State,
lastMessageText: "",
lastErrorMessageText: "",
progress: 0,
progressTotal: 1,
overallProgress: 0,
overallProgressTotal: 1,
messages: []
};
messageWell.text("");
}
if (update.State !== undefined) {
const panel = $(`#${fixedDeviceName}Panel`);
panel.removeClass("panel-default panel-primary panel-info panel-success panel-warning panel-danger");
progress.state = update.State;
switch (progress.state) {
case ProgressState.Queued:
panel.addClass("panel-primary");
break;
case ProgressState.Processing:
panel.addClass("panel-info");
break;
case ProgressState.PartialSuccess:
panel.addClass("panel-warning");
break;
case ProgressState.Success:
panel.addClass("panel-success");
break;
case ProgressState.Fail:
panel.addClass("panel-danger");
break;
}
}
if (notNull(update.Summary).length > 0)
heading.text(deviceName + ": " + update.Summary);
if (notNull(update.Message).length > 0) {
var messageText = update.Message.substring("[yyyy-MM-dd HH:mm:ss.fff] ".length);
if (messageText !== progress.lastMessageText) {
progress.lastMessageText = messageText;
progress.messages.push(update.Message);
if (!heading.hasClass("collapsed"))
messageWell.append(update.Message).append($("<br>"));
}
}
if (notNull(update.ErrorMessage).length > 0) {
var messageText = update.ErrorMessage.substring("[yyyy-MM-dd HH:mm:ss.fff] ".length);
if (messageText !== progress.lastErrorMessageText) {
progress.lastErrorMessageText = messageText;
var message = `<span style="color: red">${update.ErrorMessage}</span>`
progress.messages.push(message);
if (!heading.hasClass("collapsed"))
messageWell.append(message).append($("<br>"));
}
}
if (update.Progress !== undefined || update.ProgressTotal !== undefined) {
var progressBar = $(`#${fixedDeviceName}CurrentProgress`);
if (update.Progress !== undefined)
progress.progress = update.Progress;
progress.progressTotal = update.ProgressTotal || progress.progressTotal;
var progressValue = Math.ceil(progress.progress / progress.progressTotal * 100.0);
if (!heading.hasClass("collapsed") && isNumber(progressValue)) {
progressBar.text(progressValue.toString() + "%");
progressBar.css("width", progressBar.text());
if (progressValue < 100 && !progressBar.hasClass("active"))
progressBar.addClass("active");
else if (progressValue == 100 && progressBar.hasClass("active"))
progressBar.removeClass("active");
}
}
if (update.OverallProgress !== undefined || update.OverallProgressTotal !== undefined) {
var progressBar = $(`#${fixedDeviceName}OverallProgress`);
if (update.OverallProgress !== undefined)
progress.overallProgress = update.OverallProgress;
progress.overallProgressTotal = update.OverallProgressTotal || progress.overallProgressTotal;
var progressValue = Math.ceil(progress.overallProgress / progress.overallProgressTotal * 100.0);
if (!heading.hasClass("collapsed") && isNumber(progressValue)) {
progressBar.text(progressValue.toString() + "%");
progressBar.css("width", progressBar.text());
if (progressValue < 100 && !progressBar.hasClass("active"))
progressBar.addClass("active");
else if (progressValue == 100 && progressBar.hasClass("active"))
progressBar.removeClass("active");
}
}
});
}
});
$(function() {
$("#pageHeader").append("@Raw(SearchFilter().ToString().RemoveDuplicateWhiteSpace().Replace("\r\n", ""))");
$("#titleText").html("Records: <span data-bind='text: recordCount'>calculating...</span>");
$("#searchFilter").on("keyup", function(event) {
if ($("#searchFilter").val().length === 0) {
$('.panel').show();
} else {
$('.panel').hide();
$('.panel').filter(function(i,d) {
return $(d).attr('id').toLowerCase().indexOf($("#searchFilter").val().toLowerCase()) != -1
}).show();
}
});
ko.applyBindings(viewModel, document.getElementsByTagName("body")[0]);
});
$(window).on("hubConnected", function (event) {
viewModel.queryItems().done(function () {
dataHub.queryDeviceStatus();
});
});
function queueNow(record) {
if (!hubIsConnected)
return;
serviceHub.sendCommand(`INVOKE ${record.Acronym} QueueTasks`);
}
function queueAll() {
for (let i = 0; i < viewModel.items().length; i++) {
queueNow(viewModel.items()[i]);
}
}
</script>
}
<div class="bs-example">
<div class="panel-group" id="accordion" data-bind="foreach: items">
<div class="panel panel-default" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'Panel'}">
<div class="panel-heading" >
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" data-bind="attr: {id: $parent.fixAcronym(Acronym) +'Heading','data-target': '#sm' + $parent.fixAcronym(Acronym)}, text: Acronym"></a>
</h4>
</div>
<div data-bind="attr: {id: 'sm' + $parent.fixAcronym(Acronym)}" class="panel-collapse collapse">
<div class="panel-body">
<div class="table-cell-wrap" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'Message'}" style="overflow-y: auto; height: 500px; padding: 5px; margin-bottom: 5px; border: 1px solid; border-color: #ddd"></div>
<div class="progress" style="margin: 0">
<div class="progress-bar progress-bar-striped active no-transition" role="progressbar" style="width: 0%" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'CurrentProgress'}">0%</div>
</div>
<div class="progress" style="margin-top: 5px; margin-bottom: -5px">
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 0%" data-bind="attr: {id: $parent.fixAcronym(Acronym) + 'OverallProgress'}">0%</div>
</div>
</div>
<div class="panel-footer">
<button type="button" class="btn btn-primary" data-bind="click: queueNow.bind($data)">Queue Processing...</button>
</div>
</div>
</div>
</div>
</div>
</div>
@{
ViewBag.StyleSheetsSection = RenderSection("StyleSheets").ToString();
ViewBag.ScriptsSection = RenderSection("Scripts").ToString();
}