-
-
Temp folder
+
+
-
- @System.IO.Path.GetTempPath()
+
+
+
+
Web App Container
+
+
+
+
-
REST API (works best when using a JSON viewer extension)
-
-
Browse Directory
-
-
More information about Kudu can be found on the wiki .
+
+
diff --git a/Kudu.Services.Web/Pages/NewUI/JsonViewer.cshtml b/Kudu.Services.Web/Pages/JsonViewer.cshtml
similarity index 100%
rename from Kudu.Services.Web/Pages/NewUI/JsonViewer.cshtml
rename to Kudu.Services.Web/Pages/JsonViewer.cshtml
diff --git a/Kudu.Services.Web/Pages/NewUI/JsonViewer.cshtml.cs b/Kudu.Services.Web/Pages/JsonViewer.cshtml.cs
similarity index 100%
rename from Kudu.Services.Web/Pages/NewUI/JsonViewer.cshtml.cs
rename to Kudu.Services.Web/Pages/JsonViewer.cshtml.cs
diff --git a/Kudu.Services.Web/Pages/NewUI/Env.cshtml b/Kudu.Services.Web/Pages/LegacyUI/Env.cshtml
similarity index 98%
rename from Kudu.Services.Web/Pages/NewUI/Env.cshtml
rename to Kudu.Services.Web/Pages/LegacyUI/Env.cshtml
index 7e23bb7e..30a69d75 100644
--- a/Kudu.Services.Web/Pages/NewUI/Env.cshtml
+++ b/Kudu.Services.Web/Pages/LegacyUI/Env.cshtml
@@ -2,7 +2,7 @@
@using System
@using System.Collections
@using System.Collections.Generic
-@model Kudu.Services.Web.Pages.EnvModel
+@model Kudu.Services.Web.Pages.EnvLegacyModel
@inject IHttpContextAccessor httpContextAccessor
@inject IDeploymentSettingsManager _settingsManager
@{
diff --git a/Kudu.Services.Web/Pages/NewUI/Env.cshtml.cs b/Kudu.Services.Web/Pages/LegacyUI/Env.cshtml.cs
similarity index 75%
rename from Kudu.Services.Web/Pages/NewUI/Env.cshtml.cs
rename to Kudu.Services.Web/Pages/LegacyUI/Env.cshtml.cs
index 19ca2ae0..ae1befb1 100644
--- a/Kudu.Services.Web/Pages/NewUI/Env.cshtml.cs
+++ b/Kudu.Services.Web/Pages/LegacyUI/Env.cshtml.cs
@@ -5,9 +5,9 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
-namespace Kudu.Services.Web.Pages.NewUI
+namespace Kudu.Services.Web.Pages
{
- public class EnvModel : PageModel
+ public class EnvLegacyModel : PageModel
{
public void OnGet()
{
diff --git a/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml b/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml
new file mode 100644
index 00000000..c4e7026f
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml
@@ -0,0 +1,23 @@
+@page
+@model ErrorLegacyModel
+@{
+ ViewData["Title"] = "Error";
+}
+
+
Error.
+
An error occurred while processing your request.
+
+@if (Model.ShowRequestId)
+{
+
+ Request ID: @Model.RequestId
+
+}
+
+
Development Mode
+
+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ Development environment should not be enabled in deployed applications , as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development , and restarting the application.
+
diff --git a/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml.cs b/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml.cs
new file mode 100644
index 00000000..f651b1f1
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/Error.cshtml.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace Kudu.Services.Web.Pages
+{
+ public class ErrorLegacyModel : PageModel
+ {
+ public string RequestId { get; set; }
+
+ public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+
+ public void OnGet()
+ {
+ RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
+ }
+ }
+}
diff --git a/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml b/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml
new file mode 100644
index 00000000..1cf11845
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml
@@ -0,0 +1,123 @@
+@page
+@using System
+@using System.Reflection
+@using Microsoft.AspNetCore.Hosting
+@inject IHostingEnvironment hostingEnvironment
+
+@{
+
+ // If Kudu home page gets requested with the api-version, we are likely dealing with a call
+ // on the 'ARM bridge' to list 'extensions'. e.g.
+ // /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{site}/extensions?api-version=2015-08-01
+ // Since we can't actually return a list of extensions, return [], which is enough to avoid ARM faliures
+
+ //if (Request.QueryString["api-version"] != null)
+ //{
+ // Response.Write("[]");
+ // Response.ContentType = "application/json";
+ // Response.End();
+ //}
+
+ ViewData["Title"] = "Kudu Services";
+
+ string appServiceVersion = GetAppServiceVersion();
+ Console.WriteLine(DateTime.Now.ToString("hh.mm.ss.ffffff"));
+}
+
+@functions {
+ string GetAppServiceVersion()
+ {
+ Assembly assembly;
+ try
+ {
+ assembly = Assembly.Load("Microsoft.Web.Hosting, Version=7.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
+ var fileVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
+ return fileVersionInfo.ProductVersion;
+ }
+ catch
+ {
+ return "";
+ }
+ }
+}
+
+
+ @{
+ string commitFile = System.IO.Path.Combine(hostingEnvironment.WebRootPath, "commit.txt");
+ string sha = System.IO.File.Exists(commitFile) ? System.IO.File.ReadAllText(commitFile).Trim() : null;
+ //var version = typeof(Kudu.Services.Web.Tracing.TraceMiddleware).Assembly.GetName().Version;
+ var version = Constants.KuduBuild;
+ }
+
Environment
+
+
+
+ Site up time
+
+
+ @Kudu.Services.Web.Tracing.TraceMiddleware.UpTime.ToString(@"dd\.hh\:mm\:ss")
+
+
+
+
+ Site folder
+
+
+ @Kudu.Services.Web.PathResolver.ResolveRootPath()
+
+
+
+
+ Temp folder
+
+
+ @System.IO.Path.GetTempPath()
+
+
+
REST API (works best when using a JSON viewer extension)
+
+
Browse Directory
+
+
More information about Kudu can be found on the wiki .
+
diff --git a/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml.cs b/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml.cs
new file mode 100644
index 00000000..13dc7bc7
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/Index.cshtml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace Kudu.Services.Web.Pages
+{
+ public class IndexLegacyModel : PageModel
+ {
+ public void OnGet()
+ {
+
+ }
+ }
+}
diff --git a/Kudu.Services.Web/Pages/LegacyUI/_Layout.cshtml b/Kudu.Services.Web/Pages/LegacyUI/_Layout.cshtml
new file mode 100644
index 00000000..7ee53706
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/_Layout.cshtml
@@ -0,0 +1,112 @@
+@using Microsoft.AspNetCore.Http
+@using System
+@inject IHttpContextAccessor httpContextAccessor
+
+
+
+
+
+ @if (!Kudu.Core.Helpers.OSDetector.IsOnWindows())
+ {
+
+
+ }
+ else
+ {
+
+
+
+ }
+
+
+
Azure App Service
+
+
+
+ @RenderSection("PageHead", required: false)
+
+ @* // CORE TODO VirtualPathUtility no longer exists *@
+ @**@
+ @if (Kudu.Core.Helpers.OSDetector.IsOnWindows())
+ {
+
+ }
+ else
+ {
+
+ }
+
+
+
+
+
+
+
+ @{
+ var email = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"].ToString();
+ var displayName = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-DISPLAY-NAME"].ToString() ?? email;
+ if (email != null && email.Contains("@"))
+ {
+
+ }
+ }
+
+
+
+
+
+
+
+
+
+ Your session has expired. Please refresh your browser.
+
+
+
+
+
+
+@RenderBody()
+
+
diff --git a/Kudu.Services.Web/Pages/LegacyUI/_ValidationScriptsPartial.cshtml b/Kudu.Services.Web/Pages/LegacyUI/_ValidationScriptsPartial.cshtml
new file mode 100644
index 00000000..a2b13b31
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/_ValidationScriptsPartial.cshtml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
diff --git a/Kudu.Services.Web/Pages/LegacyUI/_ViewImports.cshtml b/Kudu.Services.Web/Pages/LegacyUI/_ViewImports.cshtml
new file mode 100644
index 00000000..30969c39
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/_ViewImports.cshtml
@@ -0,0 +1,3 @@
+@using Kudu.Services.Web
+@namespace Kudu.Services.Web.Pages
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/Kudu.Services.Web/Pages/LegacyUI/_ViewStart.cshtml b/Kudu.Services.Web/Pages/LegacyUI/_ViewStart.cshtml
new file mode 100644
index 00000000..a5f10045
--- /dev/null
+++ b/Kudu.Services.Web/Pages/LegacyUI/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "_Layout";
+}
diff --git a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/DebugConsole2Controller.cs b/Kudu.Services.Web/Pages/NewUI/DebugConsole2/DebugConsole2Controller.cs
deleted file mode 100644
index d801917b..00000000
--- a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/DebugConsole2Controller.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using Kudu.Core.Helpers;
-
-namespace Kudu.Services.Web.Pages.NewUI.DebugConsole2
-{
- // CORE NOTE This is a new shim to get the right console to load; couldn't do it the way it was originally done
- // due to the differences in the way the new razor pages work
- public class DebugConsole2Controller : Controller
- {
- public ActionResult Index()
- {
- var os = OSDetector.IsOnWindows() ? "Windows" : "Linux";
- return View($"~/Pages/NewUI/DebugConsole2/{os}Console2.cshtml");
- }
-
- public ActionResult LinuxConsole()
- {
- return View($"~/Pages/NewUI/DebugConsole/LinuxConsole2.cshtml");
- }
-
- public ActionResult WindowsConsole()
- {
- return View($"~/Pages/NewUI/DebugConsole2/WindowsConsole2.cshtml");
- }
-
- }
-}
\ No newline at end of file
diff --git a/Kudu.Services.Web/Pages/NewUI/Index.cshtml b/Kudu.Services.Web/Pages/NewUI/Index.cshtml
deleted file mode 100644
index 33996770..00000000
--- a/Kudu.Services.Web/Pages/NewUI/Index.cshtml
+++ /dev/null
@@ -1,362 +0,0 @@
-
-@page
-@using Kudu.Core.Deployment
-@using Microsoft.AspNetCore.Hosting
-@inject IHostingEnvironment hostingEnvironment
-@inject IDeploymentManager deploymentManager
-
-@{
- ViewBag.Title = "title";
- Layout = "_Layout";
-}
-
-
-
-
-
-@if (Kudu.Core.Environment.IsAzureEnvironment())
- {
-
- }
-
-@if (Kudu.Core.Environment.IsAzureEnvironment())
- {
-
- }
-
-@{
- var workerIdHash = System.Environment.GetEnvironmentVariable(Constants.AzureWebsiteInstanceId);
- var workerIdShortHash = workerIdHash?.Substring(0, 12);
- const string version = Constants.KuduBuild;
- var showLearningBanner = !deploymentManager.GetResults().Any();
- var welcomeBannerDisplayVal = showLearningBanner ? "display:block" : "display:none";
- var lastDeployedDisplayVal = !showLearningBanner ? "display:block" : "display:none";
-}
-
-
-
-
-
-
KuduLite @version
-
Site UpTime: @Tracing.TraceMiddleware.UpTime.ToString(@"dd\.hh\:mm\:ss") | Site Folder: @PathResolver.ResolveRootPath() | Temp Folder: @System.IO.Path.GetTempPath()
-
Kudu Attached to Instance: @workerIdShortHash |
-
-
-
-
-
-
-
-
-
- Deployment
- Successful
-
-
- Performing an Overlapped Recycle of your WebApp. Your changes would reflect in seconds
-
-
-
-
- Seconds
-
-
-
-
-
-
- Recent Deployment
- ...
-
Diagnose what went wrong ?
-
-
- ... | ... ago | ... |
-
-
-
-
-
-
-
-
- Deploy your first app
-
-
- Learn Node Development
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Web App Container
-
-
-
-
-
-
-
-
-
diff --git a/Kudu.Services.Web/Pages/NewUI/_Layout.cshtml b/Kudu.Services.Web/Pages/NewUI/_Layout.cshtml
deleted file mode 100644
index 09a07e64..00000000
--- a/Kudu.Services.Web/Pages/NewUI/_Layout.cshtml
+++ /dev/null
@@ -1,172 +0,0 @@
-@using Microsoft.AspNetCore.Http
-@inject IHttpContextAccessor httpContextAccessor
-
-
-
-
-
- @if (!Kudu.Core.Helpers.OSDetector.IsOnWindows())
- {
-
-
- }
- else
- {
-
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
Azure App Service
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Azure App Service
-
-
- @{
- var email = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"].ToString();
- var displayName = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-DISPLAY-NAME"].ToString() ?? email;
- if (email != null && email.Contains("@"))
- {
-
- }
- }
-
-
-
-
-
-
-
-
-
- @RenderBody()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/LinuxConsole2.cshtml b/Kudu.Services.Web/Pages/OldBash/LinuxBashConsole.cshtml
similarity index 94%
rename from Kudu.Services.Web/Pages/NewUI/DebugConsole2/LinuxConsole2.cshtml
rename to Kudu.Services.Web/Pages/OldBash/LinuxBashConsole.cshtml
index 9bf943b7..029c91ab 100644
--- a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/LinuxConsole2.cshtml
+++ b/Kudu.Services.Web/Pages/OldBash/LinuxBashConsole.cshtml
@@ -1,6 +1,6 @@
@{
ViewData["Title"] = "Diagnostic Console";
- Layout = "~/Pages/NewUI/_Layout.cshtml";
+ Layout = "~/Pages/LegacyUI/_Layout.cshtml";
}
diff --git a/Kudu.Services.Web/Pages/OldBash/OldBashController.cs b/Kudu.Services.Web/Pages/OldBash/OldBashController.cs
new file mode 100644
index 00000000..de918d83
--- /dev/null
+++ b/Kudu.Services.Web/Pages/OldBash/OldBashController.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Mvc;
+using Kudu.Core.Helpers;
+
+namespace Kudu.Services.Web.Pages
+{
+ // CORE NOTE This is a new shim to get the right console to load; couldn't do it the way it was originally done
+ // due to the differences in the way the new razor pages work
+ public class OldBashController : Controller
+ {
+ public ActionResult Index()
+ {
+ var os = OSDetector.IsOnWindows() ? "Windows" : "Linux";
+ return View($"~/Pages/OldBash/{os}BashConsole.cshtml");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/WindowsConsole2.cshtml b/Kudu.Services.Web/Pages/OldBash/WindowsBashConsole.cshtml
similarity index 99%
rename from Kudu.Services.Web/Pages/NewUI/DebugConsole2/WindowsConsole2.cshtml
rename to Kudu.Services.Web/Pages/OldBash/WindowsBashConsole.cshtml
index d4707d3c..53b9bfcb 100644
--- a/Kudu.Services.Web/Pages/NewUI/DebugConsole2/WindowsConsole2.cshtml
+++ b/Kudu.Services.Web/Pages/OldBash/WindowsBashConsole.cshtml
@@ -1,6 +1,6 @@
@{
ViewData["Title"] = "Diagnostic Console";
- Layout = "~/Pages/NewUI/_Layout.cshtml";
+ Layout = "~/Pages/LegacyUI/_Layout.cshtml";
}
diff --git a/Kudu.Services.Web/Pages/_Layout.Legacy.cshtml b/Kudu.Services.Web/Pages/_Layout.Legacy.cshtml
new file mode 100644
index 00000000..e1f79773
--- /dev/null
+++ b/Kudu.Services.Web/Pages/_Layout.Legacy.cshtml
@@ -0,0 +1,113 @@
+@using Microsoft.AspNetCore.Http
+@using System
+@inject IHttpContextAccessor httpContextAccessor
+
+
+
+
+
+ @if (!Kudu.Core.Helpers.OSDetector.IsOnWindows())
+ {
+
+
+ }
+ else
+ {
+
+
+
+ }
+
+
+
+
Azure App Service
+
+
+
+ @RenderSection("PageHead", required: false)
+
+ @* // CORE TODO VirtualPathUtility no longer exists *@
+ @**@
+ @if (Kudu.Core.Helpers.OSDetector.IsOnWindows())
+ {
+
+ }
+ else
+ {
+
+ }
+
+
+
+
+
+
+
+ @{
+ var email = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"].ToString();
+ var displayName = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-DISPLAY-NAME"].ToString() ?? email;
+ if (email != null && email.Contains("@"))
+ {
+
+ }
+ }
+
+
+
+
+
+
+
+
+
+ Your session has expired. Please refresh your browser.
+
+
+
+
+
+
+ @RenderBody()
+
+
\ No newline at end of file
diff --git a/Kudu.Services.Web/Pages/_Layout.cshtml b/Kudu.Services.Web/Pages/_Layout.cshtml
index 25416f55..3db506cc 100644
--- a/Kudu.Services.Web/Pages/_Layout.cshtml
+++ b/Kudu.Services.Web/Pages/_Layout.cshtml
@@ -1,11 +1,10 @@
@using Microsoft.AspNetCore.Http
-@using System
@inject IHttpContextAccessor httpContextAccessor
-
-
-
-
+
+
+
+
@if (!Kudu.Core.Helpers.OSDetector.IsOnWindows())
{
@@ -15,99 +14,216 @@
{
-
+
}
-
-
-
+
+
+
+
+
+
+
+
+
+
Azure App Service
-
-
-
- @RenderSection("PageHead", required: false)
-
- @* // CORE TODO VirtualPathUtility no longer exists *@
- @**@
- @if (Kudu.Core.Helpers.OSDetector.IsOnWindows())
- {
-
- }
- else
- {
-
- }
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+ Azure App Service
+
+
+
+ Legacy UI
+
+
+ @{
+ var email = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"].ToString();
+ var displayName = httpContextAccessor.HttpContext.Request.Headers["X-MS-CLIENT-DISPLAY-NAME"].ToString() ?? email;
+ if (email != null && email.Contains("@"))
+ {
+
+
+
+
+
+
+
+
+ }
+ }
+
+
+
+
+
+
+
-@RenderBody()
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/Kudu.Services.Web/Pages/NewUI/bash.cshtml b/Kudu.Services.Web/Pages/bash.cshtml
similarity index 100%
rename from Kudu.Services.Web/Pages/NewUI/bash.cshtml
rename to Kudu.Services.Web/Pages/bash.cshtml
diff --git a/Kudu.Services.Web/Pages/fileManager.cshtml b/Kudu.Services.Web/Pages/fileManager.cshtml
new file mode 100644
index 00000000..2a813afd
--- /dev/null
+++ b/Kudu.Services.Web/Pages/fileManager.cshtml
@@ -0,0 +1,278 @@
+@page
+@using Kudu.Core;
+@using Kudu.Services
+@using Microsoft.Extensions.FileProviders;
+
+
+
+
+
+
File Manager
+
+@*anchor tag to return back to previous directory; span - 'spaddPath' is used to keep track of current directory.*@
+
+
+
+@*Calling dragdrop JavaScript*@
+
+
+
+
diff --git a/Kudu.Services.Web/Pages/NewUI/kududebug.cshtml b/Kudu.Services.Web/Pages/kududebug.cshtml
similarity index 100%
rename from Kudu.Services.Web/Pages/NewUI/kududebug.cshtml
rename to Kudu.Services.Web/Pages/kududebug.cshtml
diff --git a/Kudu.Services.Web/Pages/NewUI/logs.cshtml b/Kudu.Services.Web/Pages/logs.cshtml
similarity index 75%
rename from Kudu.Services.Web/Pages/NewUI/logs.cshtml
rename to Kudu.Services.Web/Pages/logs.cshtml
index d04fbf9d..0d6ce8a2 100644
--- a/Kudu.Services.Web/Pages/NewUI/logs.cshtml
+++ b/Kudu.Services.Web/Pages/logs.cshtml
@@ -12,7 +12,7 @@
-
+
diff --git a/Kudu.Services.Web/Pages/NewUI/wwwroot.cshtml b/Kudu.Services.Web/Pages/sitedir.cshtml
similarity index 76%
rename from Kudu.Services.Web/Pages/NewUI/wwwroot.cshtml
rename to Kudu.Services.Web/Pages/sitedir.cshtml
index b67eb869..fe22a748 100644
--- a/Kudu.Services.Web/Pages/NewUI/wwwroot.cshtml
+++ b/Kudu.Services.Web/Pages/sitedir.cshtml
@@ -12,7 +12,7 @@
-
+
diff --git a/Kudu.Services.Web/Pages/NewUI/webssh.cshtml b/Kudu.Services.Web/Pages/ssh.cshtml
similarity index 54%
rename from Kudu.Services.Web/Pages/NewUI/webssh.cshtml
rename to Kudu.Services.Web/Pages/ssh.cshtml
index 220ac651..ea373497 100644
--- a/Kudu.Services.Web/Pages/NewUI/webssh.cshtml
+++ b/Kudu.Services.Web/Pages/ssh.cshtml
@@ -1,3 +1,3 @@
@page
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/Kudu.Services.Web/Program.cs b/Kudu.Services.Web/Program.cs
index 042b0c85..acf623a7 100644
--- a/Kudu.Services.Web/Program.cs
+++ b/Kudu.Services.Web/Program.cs
@@ -21,4 +21,4 @@ private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
.UseKestrel(options => { options.Limits.MaxRequestBodySize = null; })
.UseStartup
();
}
-}
\ No newline at end of file
+}
diff --git a/Kudu.Services.Web/Startup.cs b/Kudu.Services.Web/Startup.cs
index 2d84e298..c6aff643 100644
--- a/Kudu.Services.Web/Startup.cs
+++ b/Kudu.Services.Web/Startup.cs
@@ -3,7 +3,6 @@
using System.Configuration;
using System.IO;
using System.Net.Http;
-using System.Net.Http.Formatting;
using System.Reflection;
using AspNetCore.RouteAnalyzer;
using Kudu.Contracts;
@@ -42,16 +41,18 @@
using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Swagger;
using ILogger = Kudu.Core.Deployment.ILogger;
+using Microsoft.Extensions.Hosting;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
namespace Kudu.Services.Web
{
public class Startup
{
- private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IWebHostEnvironment _hostingEnvironment;
private IEnvironment _webAppRuntimeEnvironment;
private IDeploymentSettingsManager _noContextDeploymentsSettingsManager;
- public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
+ public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
{
Console.WriteLine(@"Startup : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));
Configuration = configuration;
@@ -74,24 +75,42 @@ public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironm
public void ConfigureServices(IServiceCollection services)
{
Console.WriteLine(@"Configure Services : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));
- FileSystemHelpers.DeleteDirectorySafe("/home/site/locks/deployment");
services.Configure(options =>
{
options.MultipartBodyLengthLimit = 52428800;
options.ValueCountLimit = 500000;
options.KeyLengthLimit = 500000;
});
+
+ // When running in container
+ services.Configure(options =>
+ {
+ options.AllowSynchronousIO = true;
+ });
+
+ // If using IIS
+ services.Configure(options =>
+ {
+ options.AllowSynchronousIO = true;
+ });
services.AddRouteAnalyzer();
// Kudu.Services contains all the Controllers
var kuduServicesAssembly = Assembly.Load("Kudu.Services");
- services.AddMvcCore()
+ services.AddMvcCore(options =>
+ {
+ options.EnableEndpointRouting = false;
+ // Breaks Zip Deploy as MVCCore tries
+ // to bind forms
+ options.ModelValidatorProviders.Clear();
+ }).AddNewtonsoftJson(o =>
+ {
+ o.SerializerSettings.ContractResolver = new DefaultContractResolver();
+ })
.AddRazorPages()
.AddAuthorization()
- .AddJsonFormatters()
- .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver())
.AddApplicationPart(kuduServicesAssembly).AddControllersAsServices()
.AddApiExplorer();
@@ -102,7 +121,7 @@ public void ConfigureServices(IServiceCollection services)
var xmlFile = $"Kudu.Services.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
- });
+ });
services.AddGZipCompression();
@@ -277,20 +296,6 @@ public void ConfigureServices(IServiceCollection services)
services.AddScoped();
- // KuduWebUtil.MigrateSite(environment, noContextDeploymentsSettingsManager);
- // RemoveOldTracePath(environment);
- // RemoveTempFileFromUserDrive(environment);
-
- // CORE TODO Windows Fix: Temporary fix for https://github.com/npm/npm/issues/5905
- //EnsureNpmGlobalDirectory();
- //EnsureUserProfileDirectory();
-
- //// Skip SSL Certificate Validate
- //if (Environment.SkipSslValidation)
- //{
- // ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
- //}
-
//// Make sure webpages:Enabled is true. Even though we set it in web.config, it could be overwritten by
//// an Azure AppSetting that's supposed to be for the site only but incidently affects Kudu as well.
ConfigurationManager.AppSettings["webpages:Enabled"] = "true";
@@ -317,10 +322,6 @@ public void ConfigureServices(IServiceCollection services)
//target.FileName = logfile;
}
- // CORE TODO See NinjectServices.Stop
-
- // CORE TODO See signalr stuff in NinjectServices
-
private static Uri GetAbsoluteUri(HttpContext httpContext)
{
var request = httpContext.Request;
@@ -333,12 +334,12 @@ private static Uri GetAbsoluteUri(HttpContext httpContext)
}
public void Configure(IApplicationBuilder app,
- IApplicationLifetime applicationLifetime,
+ IHostApplicationLifetime applicationLifetime,
ILoggerFactory loggerFactory)
{
Console.WriteLine(@"Configure : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));
- loggerFactory.AddEventSourceLogger();
+ //loggerFactory.AddEventSourceLogger();
KuduWebUtil.MigrateToNetCorePatch(_webAppRuntimeEnvironment);
@@ -397,16 +398,6 @@ public void Configure(IApplicationBuilder app,
var configuration = app.ApplicationServices.GetRequiredService();
- // CORE TODO any equivalent for this? Needed?
- //var configuration = kernel.Get();
- //GlobalConfiguration.Configuration.Formatters.Clear();
- //GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
-
- var jsonFormatter = new JsonMediaTypeFormatter();
-
-
- // CORE TODO concept of "deprecation" in routes for traces, Do we need this for linux ?
-
// Push url
foreach (var url in new[] {"/git-receive-pack", $"/{configuration.GitServerRoot}/git-receive-pack"})
{
@@ -438,9 +429,9 @@ public void Configure(IApplicationBuilder app,
// Sets up the file server to LogFiles
KuduWebUtil.SetupFileServer(app, Path.Combine(_webAppRuntimeEnvironment.LogFilesPath,"kudu","deployment"), "/deploymentlogs");
- app.UseSwagger();
+ // app.UseSwagger();
- app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kudu API Docs"); });
+ // app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kudu API Docs"); });
app.UseMvc(routes =>
{
@@ -512,7 +503,7 @@ public void Configure(IApplicationBuilder app,
new {controller = "LinuxConsumptionInstanceAdmin", action = "Info"},
new {verb = new HttpMethodRouteConstraint("GET")});
routes.MapRoute("admin-instance-assign", "admin/instance/assign",
- new {controller = "LinuxConsumptionInstanceAdmin", action = "AssignAsync" },
+ new {controller = "LinuxConsumptionInstanceAdmin", action = "Assign" },
new {verb = new HttpMethodRouteConstraint("POST")});
// Live Command Line
diff --git a/Kudu.Services.Web/updateNodeModules.sh b/Kudu.Services.Web/updateNodeModules.sh
index 6d929271..ce3802ae 100644
--- a/Kudu.Services.Web/updateNodeModules.sh
+++ b/Kudu.Services.Web/updateNodeModules.sh
@@ -25,19 +25,15 @@ retry() {
done
}
-copy_to_build_dir() {
- rm -rf "$@node_modules"
- if [ ! -d "node_modules" ]; then
+check_build_dir() {
+ echo "$@/node_modules"
+ if [ ! -d "$@/node_modules" ]; then
exit 1
- else
- mkdir -p "$@"
- mkdir -p "$@/KuduConsole"
- cp -r node_modules "$@"
- mv node_modules "$@/KuduConsole/node_modules"
fi
}
+pwd
printf "\n\nInstalling Kudu Script\n\n"
echo "$@"
-retry npm --loglevel=error install https://github.com/projectkudu/KuduScript/tarball/16de31b5f5ca590ea085979e5fa5e74bb62f647e
-copy_to_build_dir "$@"
+retry npm --loglevel=error install --prefix $@ https://github.com/projectkudu/KuduScript/tarball/16de31b5f5ca590ea085979e5fa5e74bb62f647e
+check_build_dir() "$@"
diff --git a/Kudu.Services.Web/wwwroot/Content/Scripts/NavigateToInstance.js b/Kudu.Services.Web/wwwroot/Content/Scripts/NavigateToInstance.js
index d3a5f55b..f6c89f6d 100644
--- a/Kudu.Services.Web/wwwroot/Content/Scripts/NavigateToInstance.js
+++ b/Kudu.Services.Web/wwwroot/Content/Scripts/NavigateToInstance.js
@@ -6,18 +6,21 @@ jQuery(document).ready(function () {
try {
var obj = JSON.parse(response);
var ul = document.getElementById("instances_tab_options");
- if (obj.length > 1) {
+ if (obj.length >= 1) {
for (var i = 0; i < obj.length; i++) {
var instanceTabBtn = document.createElement('li'); // is a node
- instanceTabBtn.innerHTML = 'Instance: ' + obj[i].substring(0, 4) + ' ';
+ instanceTabBtn.innerHTML = '' + obj[i].substring(0, 6);
+ if (i != obj.length - 1) {
+ instanceTabBtn.innerHTML += '
';
+ }
instanceTabBtn.setAttribute("id", "inst-id-btn-" + obj[i]);
if (obj[i].trim().valueOf() === $.currInst) {
- $("#instance-drop-down-text").text("Instance: " + obj[i].substring(0, 4));
+ $("#instance-drop-down-text").text(' ' + obj[i].substring(0, 4));
}
ul.appendChild(instanceTabBtn);
}
} else {
- $("#instances-li").hide();
+ $("#instanceDropdownMenuButton").hide();
}
}
catch (err) {
@@ -37,7 +40,6 @@ function NavigateToInstance(instId) {
url: '/?instance=' + instId,
type: 'GET',
success: function (data) {
- console.log('success ajax');
$(".instances_tab_options_cls li.active").removeClass("active"); // reset all to no active class
$('#inst-id-btn-' + instId).addClass("active"); // add active class to curr instance btn only
location.reload();
diff --git a/Kudu.Services.Web/wwwroot/Content/Scripts/dragdrop.js b/Kudu.Services.Web/wwwroot/Content/Scripts/dragdrop.js
new file mode 100644
index 00000000..f9305598
--- /dev/null
+++ b/Kudu.Services.Web/wwwroot/Content/Scripts/dragdrop.js
@@ -0,0 +1,22 @@
+/*License
+
+(The MIT License)
+Copyright(c) 2012 Matias Meno < m@tias.me>
+Logo & Website Design(c) 2015 "1910" www.weare1910.com
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+"use strict"; function _possibleConstructorReturn(a, b) { if (!a) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !b || "object" != typeof b && "function" != typeof b ? a : b } function _inherits(a, b) { if ("function" != typeof b && null !== b) throw new TypeError("Super expression must either be null or a function, not " + typeof b); a.prototype = Object.create(b && b.prototype, { constructor: { value: a, enumerable: !1, writable: !0, configurable: !0 } }), b && (Object.setPrototypeOf ? Object.setPrototypeOf(a, b) : a.__proto__ = b) } function _classCallCheck(a, b) { if (!(a instanceof b)) throw new TypeError("Cannot call a class as a function") } function __guard__(a, b) { return void 0 !== a && null !== a ? b(a) : void 0 } function __guardMethod__(a, b, c) { return void 0 !== a && null !== a && "function" == typeof a[b] ? c(a, b) : void 0 } var _createClass = function () { function a(a, b) { for (var c = 0; c < b.length; c++) { var d = b[c]; d.enumerable = d.enumerable || !1, d.configurable = !0, "value" in d && (d.writable = !0), Object.defineProperty(a, d.key, d) } } return function (b, c, d) { return c && a(b.prototype, c), d && a(b, d), b } }(), Emitter = function () { function a() { _classCallCheck(this, a) } return _createClass(a, [{ key: "on", value: function (a, b) { return this._callbacks = this._callbacks || {}, this._callbacks[a] || (this._callbacks[a] = []), this._callbacks[a].push(b), this } }, { key: "emit", value: function (a) { this._callbacks = this._callbacks || {}; var b = this._callbacks[a]; if (b) { for (var c = arguments.length, d = Array(c > 1 ? c - 1 : 0), e = 1; e < c; e++)d[e - 1] = arguments[e]; for (var f = b, g = 0, f = f; ;) { var h; if (g >= f.length) break; h = f[g++]; h.apply(this, d) } } return this } }, { key: "off", value: function (a, b) { if (!this._callbacks || 0 === arguments.length) return this._callbacks = {}, this; var c = this._callbacks[a]; if (!c) return this; if (1 === arguments.length) return delete this._callbacks[a], this; for (var d = 0; d < c.length; d++) { if (c[d] === b) { c.splice(d, 1); break } } return this } }]), a }(), Dropzone = function (a) {
+ function b(a, c) { _classCallCheck(this, b); var d = _possibleConstructorReturn(this, (b.__proto__ || Object.getPrototypeOf(b)).call(this)), e = void 0, f = void 0; if (d.element = a, d.version = b.version, d.defaultOptions.previewTemplate = d.defaultOptions.previewTemplate.replace(/\n*/g, ""), d.clickableElements = [], d.listeners = [], d.files = [], "string" == typeof d.element && (d.element = document.querySelector(d.element)), !d.element || null == d.element.nodeType) throw new Error("Invalid dropzone element."); if (d.element.dropzone) throw new Error("Dropzone already attached."); b.instances.push(d), d.element.dropzone = d; var g = null != (f = b.optionsForElement(d.element)) ? f : {}; if (d.options = b.extend({}, d.defaultOptions, g, null != c ? c : {}), d.options.forceFallback || !b.isBrowserSupported()) { var h; return h = d.options.fallback.call(d), _possibleConstructorReturn(d, h) } if (null == d.options.url && (d.options.url = d.element.getAttribute("action")), !d.options.url) throw new Error("No URL provided."); if (d.options.acceptedFiles && d.options.acceptedMimeTypes) throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); if (d.options.uploadMultiple && d.options.chunking) throw new Error("You cannot set both: uploadMultiple and chunking."); return d.options.acceptedMimeTypes && (d.options.acceptedFiles = d.options.acceptedMimeTypes, delete d.options.acceptedMimeTypes), null != d.options.renameFilename && (d.options.renameFile = function (a) { return d.options.renameFilename.call(d, a.name, a) }), d.options.method = d.options.method.toUpperCase(), (e = d.getExistingFallback()) && e.parentNode && e.parentNode.removeChild(e), !1 !== d.options.previewsContainer && (d.options.previewsContainer ? d.previewsContainer = b.getElement(d.options.previewsContainer, "previewsContainer") : d.previewsContainer = d.element), d.options.clickable && (!0 === d.options.clickable ? d.clickableElements = [d.element] : d.clickableElements = b.getElements(d.options.clickable, "clickable")), d.init(), d } return _inherits(b, a), _createClass(b, null, [{ key: "initClass", value: function () { this.prototype.Emitter = Emitter, this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"], this.prototype.defaultOptions = { url: null, method: "post", withCredentials: !1, timeout: 3e4, parallelUploads: 2, uploadMultiple: !1, chunking: !1, forceChunking: !1, chunkSize: 2e6, parallelChunkUploads: !1, retryChunks: !1, retryChunksLimit: 3, maxFilesize: 256, paramName: "file", createImageThumbnails: !0, maxThumbnailFilesize: 10, thumbnailWidth: 120, thumbnailHeight: 120, thumbnailMethod: "crop", resizeWidth: null, resizeHeight: null, resizeMimeType: null, resizeQuality: .8, resizeMethod: "contain", filesizeBase: 1e3, maxFiles: null, headers: null, clickable: !0, ignoreHiddenFiles: !0, acceptedFiles: null, acceptedMimeTypes: null, autoProcessQueue: !0, autoQueue: !0, addRemoveLinks: !1, previewsContainer: null, hiddenInputContainer: "body", capture: null, renameFilename: null, renameFile: null, forceFallback: !1, dictDefaultMessage: "Drop files here to upload", dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", dictInvalidFileType: "You can't upload files of this type.", dictResponseError: "Server responded with {{statusCode}} code.", dictCancelUpload: "Cancel upload", dictUploadCanceled: "Upload canceled.", dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", dictRemoveFile: "Remove file", dictRemoveFileConfirmation: null, dictMaxFilesExceeded: "You can not upload any more files.", dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, init: function () { }, params: function (a, b, c) { if (c) return { dzuuid: c.file.upload.uuid, dzchunkindex: c.index, dztotalfilesize: c.file.size, dzchunksize: this.options.chunkSize, dztotalchunkcount: c.file.upload.totalChunkCount, dzchunkbyteoffset: c.index * this.options.chunkSize } }, accept: function (a, b) { return b() }, chunksUploaded: function (a, b) { b() }, fallback: function () { var a = void 0; this.element.className = this.element.className + " dz-browser-not-supported"; for (var c = this.element.getElementsByTagName("div"), d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; if (/(^| )dz-message($| )/.test(f.className)) { a = f, f.className = "dz-message"; break } } a || (a = b.createElement('
'), this.element.appendChild(a)); var g = a.getElementsByTagName("span")[0]; return g && (null != g.textContent ? g.textContent = this.options.dictFallbackMessage : null != g.innerText && (g.innerText = this.options.dictFallbackMessage)), this.element.appendChild(this.getFallbackForm()) }, resize: function (a, b, c, d) { var e = { srcX: 0, srcY: 0, srcWidth: a.width, srcHeight: a.height }, f = a.width / a.height; null == b && null == c ? (b = e.srcWidth, c = e.srcHeight) : null == b ? b = c * f : null == c && (c = b / f), b = Math.min(b, e.srcWidth), c = Math.min(c, e.srcHeight); var g = b / c; if (e.srcWidth > b || e.srcHeight > c) if ("crop" === d) f > g ? (e.srcHeight = a.height, e.srcWidth = e.srcHeight * g) : (e.srcWidth = a.width, e.srcHeight = e.srcWidth / g); else { if ("contain" !== d) throw new Error("Unknown resizeMethod '" + d + "'"); f > g ? c = b / f : b = c * f } return e.srcX = (a.width - e.srcWidth) / 2, e.srcY = (a.height - e.srcHeight) / 2, e.trgWidth = b, e.trgHeight = c, e }, transformFile: function (a, b) { return (this.options.resizeWidth || this.options.resizeHeight) && a.type.match(/image.*/) ? this.resizeImage(a, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, b) : b(a) }, previewTemplate: '\n
\n
\n
\n
\n
\n
\n Check \n \n \n \n \n \n
\n
\n
\n Error \n \n \n \n \n \n \n \n
\n
', drop: function (a) { return this.element.classList.remove("dz-drag-hover") }, dragstart: function (a) { }, dragend: function (a) { return this.element.classList.remove("dz-drag-hover") }, dragenter: function (a) { return this.element.classList.add("dz-drag-hover") }, dragover: function (a) { return this.element.classList.add("dz-drag-hover") }, dragleave: function (a) { return this.element.classList.remove("dz-drag-hover") }, paste: function (a) { }, reset: function () { return this.element.classList.remove("dz-started") }, addedfile: function (a) { var c = this; if (this.element === this.previewsContainer && this.element.classList.add("dz-started"), this.previewsContainer) { a.previewElement = b.createElement(this.options.previewTemplate.trim()), a.previewTemplate = a.previewElement, this.previewsContainer.appendChild(a.previewElement); for (var d = a.previewElement.querySelectorAll("[data-dz-name]"), e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g = f; g.textContent = a.name } for (var h = a.previewElement.querySelectorAll("[data-dz-size]"), i = 0, h = h; !(i >= h.length);)g = h[i++], g.innerHTML = this.filesize(a.size); this.options.addRemoveLinks && (a._removeLink = b.createElement('' + this.options.dictRemoveFile + " "), a.previewElement.appendChild(a._removeLink)); for (var j = function (d) { return d.preventDefault(), d.stopPropagation(), a.status === b.UPLOADING ? b.confirm(c.options.dictCancelUploadConfirmation, function () { return c.removeFile(a) }) : c.options.dictRemoveFileConfirmation ? b.confirm(c.options.dictRemoveFileConfirmation, function () { return c.removeFile(a) }) : c.removeFile(a) }, k = a.previewElement.querySelectorAll("[data-dz-remove]"), l = 0, k = k; ;) { var m; if (l >= k.length) break; m = k[l++]; m.addEventListener("click", j) } } }, removedfile: function (a) { return null != a.previewElement && null != a.previewElement.parentNode && a.previewElement.parentNode.removeChild(a.previewElement), this._updateMaxFilesReachedClass() }, thumbnail: function (a, b) { if (a.previewElement) { a.previewElement.classList.remove("dz-file-preview"); for (var c = a.previewElement.querySelectorAll("[data-dz-thumbnail]"), d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; f.alt = a.name, f.src = b } return setTimeout(function () { return a.previewElement.classList.add("dz-image-preview") }, 1) } }, error: function (a, b) { if (a.previewElement) { a.previewElement.classList.add("dz-error"), "String" != typeof b && b.error && (b = b.error); for (var c = a.previewElement.querySelectorAll("[data-dz-errormessage]"), d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; e.textContent = b } } }, errormultiple: function () { }, processing: function (a) { if (a.previewElement && (a.previewElement.classList.add("dz-processing"), a._removeLink)) return a._removeLink.innerHTML = this.options.dictCancelUpload }, processingmultiple: function () { }, uploadprogress: function (a, b, c) { if (a.previewElement) for (var d = a.previewElement.querySelectorAll("[data-dz-uploadprogress]"), e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g = f; "PROGRESS" === g.nodeName ? g.value = b : g.style.width = b + "%" } }, totaluploadprogress: function () { }, sending: function () { }, sendingmultiple: function () { }, success: function (a) { if (a.previewElement) return a.previewElement.classList.add("dz-success") }, successmultiple: function () { }, canceled: function (a) { return this.emit("error", a, this.options.dictUploadCanceled) }, canceledmultiple: function () { }, complete: function (a) { if (a._removeLink && (a._removeLink.innerHTML = this.options.dictRemoveFile), a.previewElement) return a.previewElement.classList.add("dz-complete") }, completemultiple: function () { }, maxfilesexceeded: function () { }, maxfilesreached: function () { }, queuecomplete: function () { }, addedfiles: function () { } }, this.prototype._thumbnailQueue = [], this.prototype._processingThumbnail = !1 } }, { key: "extend", value: function (a) { for (var b = arguments.length, c = Array(b > 1 ? b - 1 : 0), d = 1; d < b; d++)c[d - 1] = arguments[d]; for (var e = c, f = 0, e = e; ;) { var g; if (f >= e.length) break; g = e[f++]; var h = g; for (var i in h) { var j = h[i]; a[i] = j } } return a } }]), _createClass(b, [{ key: "getAcceptedFiles", value: function () { return this.files.filter(function (a) { return a.accepted }).map(function (a) { return a }) } }, { key: "getRejectedFiles", value: function () { return this.files.filter(function (a) { return !a.accepted }).map(function (a) { return a }) } }, { key: "getFilesWithStatus", value: function (a) { return this.files.filter(function (b) { return b.status === a }).map(function (a) { return a }) } }, { key: "getQueuedFiles", value: function () { return this.getFilesWithStatus(b.QUEUED) } }, { key: "getUploadingFiles", value: function () { return this.getFilesWithStatus(b.UPLOADING) } }, { key: "getAddedFiles", value: function () { return this.getFilesWithStatus(b.ADDED) } }, { key: "getActiveFiles", value: function () { return this.files.filter(function (a) { return a.status === b.UPLOADING || a.status === b.QUEUED }).map(function (a) { return a }) } }, { key: "init", value: function () { var a = this; if ("form" === this.element.tagName && this.element.setAttribute("enctype", "multipart/form-data"), this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message") && this.element.appendChild(b.createElement('' + this.options.dictDefaultMessage + "
")), this.clickableElements.length) { !function c() { return a.hiddenFileInput && a.hiddenFileInput.parentNode.removeChild(a.hiddenFileInput), a.hiddenFileInput = document.createElement("input"), a.hiddenFileInput.setAttribute("type", "file"), (null === a.options.maxFiles || a.options.maxFiles > 1) && a.hiddenFileInput.setAttribute("multiple", "multiple"), a.hiddenFileInput.className = "dz-hidden-input", null !== a.options.acceptedFiles && a.hiddenFileInput.setAttribute("accept", a.options.acceptedFiles), null !== a.options.capture && a.hiddenFileInput.setAttribute("capture", a.options.capture), a.hiddenFileInput.style.visibility = "hidden", a.hiddenFileInput.style.position = "absolute", a.hiddenFileInput.style.top = "0", a.hiddenFileInput.style.left = "0", a.hiddenFileInput.style.height = "0", a.hiddenFileInput.style.width = "0", b.getElement(a.options.hiddenInputContainer, "hiddenInputContainer").appendChild(a.hiddenFileInput), a.hiddenFileInput.addEventListener("change", function () { var b = a.hiddenFileInput.files; if (b.length) for (var d = b, e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g = f; a.addFile(g) } return a.emit("addedfiles", b), c() }) }() } this.URL = null !== window.URL ? window.URL : window.webkitURL; for (var c = this.events, d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; this.on(f, this.options[f]) } this.on("uploadprogress", function () { return a.updateTotalUploadProgress() }), this.on("removedfile", function () { return a.updateTotalUploadProgress() }), this.on("canceled", function (b) { return a.emit("complete", b) }), this.on("complete", function (b) { if (0 === a.getAddedFiles().length && 0 === a.getUploadingFiles().length && 0 === a.getQueuedFiles().length) return setTimeout(function () { return a.emit("queuecomplete") }, 0) }); var g = function (a) { return a.stopPropagation(), a.preventDefault ? a.preventDefault() : a.returnValue = !1 }; return this.listeners = [{ element: this.element, events: { dragstart: function (b) { return a.emit("dragstart", b) }, dragenter: function (b) { return g(b), a.emit("dragenter", b) }, dragover: function (b) { var c = void 0; try { c = b.dataTransfer.effectAllowed } catch (a) { } return b.dataTransfer.dropEffect = "move" === c || "linkMove" === c ? "move" : "copy", g(b), a.emit("dragover", b) }, dragleave: function (b) { return a.emit("dragleave", b) }, drop: function (b) { return g(b), a.drop(b) }, dragend: function (b) { return a.emit("dragend", b) } } }], this.clickableElements.forEach(function (c) { return a.listeners.push({ element: c, events: { click: function (d) { return (c !== a.element || d.target === a.element || b.elementInside(d.target, a.element.querySelector(".dz-message"))) && a.hiddenFileInput.click(), !0 } } }) }), this.enable(), this.options.init.call(this) } }, { key: "destroy", value: function () { return this.disable(), this.removeAllFiles(!0), (null != this.hiddenFileInput ? this.hiddenFileInput.parentNode : void 0) && (this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput), this.hiddenFileInput = null), delete this.element.dropzone, b.instances.splice(b.instances.indexOf(this), 1) } }, { key: "updateTotalUploadProgress", value: function () { var a = void 0, b = 0, c = 0; if (this.getActiveFiles().length) { for (var d = this.getActiveFiles(), e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g = f; b += g.upload.bytesSent, c += g.upload.total } a = 100 * b / c } else a = 100; return this.emit("totaluploadprogress", a, c, b) } }, { key: "_getParamName", value: function (a) { return "function" == typeof this.options.paramName ? this.options.paramName(a) : this.options.paramName + (this.options.uploadMultiple ? "[" + a + "]" : "") } }, { key: "_renameFile", value: function (a) { return "function" != typeof this.options.renameFile ? a.name : this.options.renameFile(a) } }, { key: "getFallbackForm", value: function () { var a = void 0, c = void 0; if (a = this.getExistingFallback()) return a; var d = ''; var e = b.createElement(d); return "FORM" !== this.element.tagName ? (c = b.createElement(''), c.appendChild(e)) : (this.element.setAttribute("enctype", "multipart/form-data"), this.element.setAttribute("method", this.options.method)), null != c ? c : e } }, { key: "getExistingFallback", value: function () { for (var a = ["div", "form"], b = 0; b < a.length; b++) { var c, d = a[b]; if (c = function (a) { for (var b = a, c = 0, b = b; ;) { var d; if (c >= b.length) break; d = b[c++]; var e = d; if (/(^| )fallback($| )/.test(e.className)) return e } }(this.element.getElementsByTagName(d))) return c } } }, { key: "setupEventListeners", value: function () { return this.listeners.map(function (a) { return function () { var b = []; for (var c in a.events) { var d = a.events[c]; b.push(a.element.addEventListener(c, d, !1)) } return b }() }) } }, { key: "removeEventListeners", value: function () { return this.listeners.map(function (a) { return function () { var b = []; for (var c in a.events) { var d = a.events[c]; b.push(a.element.removeEventListener(c, d, !1)) } return b }() }) } }, { key: "disable", value: function () { var a = this; return this.clickableElements.forEach(function (a) { return a.classList.remove("dz-clickable") }), this.removeEventListeners(), this.disabled = !0, this.files.map(function (b) { return a.cancelUpload(b) }) } }, { key: "enable", value: function () { return delete this.disabled, this.clickableElements.forEach(function (a) { return a.classList.add("dz-clickable") }), this.setupEventListeners() } }, { key: "filesize", value: function (a) { var b = 0, c = "b"; if (a > 0) { for (var d = ["tb", "gb", "mb", "kb", "b"], e = 0; e < d.length; e++) { var f = d[e]; if (a >= Math.pow(this.options.filesizeBase, 4 - e) / 10) { b = a / Math.pow(this.options.filesizeBase, 4 - e), c = f; break } } b = Math.round(10 * b) / 10 } return "" + b + " " + this.options.dictFileSizeUnits[c] } }, { key: "_updateMaxFilesReachedClass", value: function () { return null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (this.getAcceptedFiles().length === this.options.maxFiles && this.emit("maxfilesreached", this.files), this.element.classList.add("dz-max-files-reached")) : this.element.classList.remove("dz-max-files-reached") } }, { key: "drop", value: function (a) { if (a.dataTransfer) { this.emit("drop", a); for (var b = [], c = 0; c < a.dataTransfer.files.length; c++)b[c] = a.dataTransfer.files[c]; if (this.emit("addedfiles", b), b.length) { var d = a.dataTransfer.items; d && d.length && null != d[0].webkitGetAsEntry ? this._addFilesFromItems(d) : this.handleFiles(b) } } } }, { key: "paste", value: function (a) { if (null != __guard__(null != a ? a.clipboardData : void 0, function (a) { return a.items })) { this.emit("paste", a); var b = a.clipboardData.items; return b.length ? this._addFilesFromItems(b) : void 0 } } }, { key: "handleFiles", value: function (a) { for (var b = a, c = 0, b = b; ;) { var d; if (c >= b.length) break; d = b[c++]; var e = d; this.addFile(e) } } }, { key: "_addFilesFromItems", value: function (a) { var b = this; return function () { for (var c = [], d = a, e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g, h = f; null != h.webkitGetAsEntry && (g = h.webkitGetAsEntry()) ? g.isFile ? c.push(b.addFile(h.getAsFile())) : g.isDirectory ? c.push(b._addFilesFromDirectory(g, g.name)) : c.push(void 0) : null != h.getAsFile && (null == h.kind || "file" === h.kind) ? c.push(b.addFile(h.getAsFile())) : c.push(void 0) } return c }() } }, { key: "_addFilesFromDirectory", value: function (a, b) { var c = this, d = a.createReader(), e = function (a) { return __guardMethod__(console, "log", function (b) { return b.log(a) }) }; return function a() { return d.readEntries(function (d) { if (d.length > 0) { for (var e = d, f = 0, e = e; ;) { var g; if (f >= e.length) break; g = e[f++]; var h = g; h.isFile ? h.file(function (a) { if (!c.options.ignoreHiddenFiles || "." !== a.name.substring(0, 1)) return a.fullPath = b + "/" + a.name, c.addFile(a) }) : h.isDirectory && c._addFilesFromDirectory(h, b + "/" + h.name) } a() } return null }, e) }() } }, { key: "accept", value: function (a, c) { return this.options.maxFilesize && a.size > 1024 * this.options.maxFilesize * 1024 ? c(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(a.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)) : b.isValidFile(a, this.options.acceptedFiles) ? null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (c(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)), this.emit("maxfilesexceeded", a)) : this.options.accept.call(this, a, c) : c(this.options.dictInvalidFileType) } }, { key: "addFile", value: function (a) { var c = this; return a.upload = { uuid: b.uuidv4(), progress: 0, total: a.size, bytesSent: 0, filename: this._renameFile(a), chunked: this.options.chunking && (this.options.forceChunking || a.size > this.options.chunkSize), totalChunkCount: Math.ceil(a.size / this.options.chunkSize) }, this.files.push(a), a.status = b.ADDED, this.emit("addedfile", a), this._enqueueThumbnail(a), this.accept(a, function (b) { return b ? (a.accepted = !1, c._errorProcessing([a], b)) : (a.accepted = !0, c.options.autoQueue && c.enqueueFile(a)), c._updateMaxFilesReachedClass() }) } }, { key: "enqueueFiles", value: function (a) { for (var b = a, c = 0, b = b; ;) { var d; if (c >= b.length) break; d = b[c++]; var e = d; this.enqueueFile(e) } return null } }, { key: "enqueueFile", value: function (a) { var c = this; if (a.status !== b.ADDED || !0 !== a.accepted) throw new Error("This file can't be queued because it has already been processed or was rejected."); if (a.status = b.QUEUED, this.options.autoProcessQueue) return setTimeout(function () { return c.processQueue() }, 0) } }, { key: "_enqueueThumbnail", value: function (a) { var b = this; if (this.options.createImageThumbnails && a.type.match(/image.*/) && a.size <= 1024 * this.options.maxThumbnailFilesize * 1024) return this._thumbnailQueue.push(a), setTimeout(function () { return b._processThumbnailQueue() }, 0) } }, { key: "_processThumbnailQueue", value: function () { var a = this; if (!this._processingThumbnail && 0 !== this._thumbnailQueue.length) { this._processingThumbnail = !0; var b = this._thumbnailQueue.shift(); return this.createThumbnail(b, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, !0, function (c) { return a.emit("thumbnail", b, c), a._processingThumbnail = !1, a._processThumbnailQueue() }) } } }, { key: "removeFile", value: function (a) { if (a.status === b.UPLOADING && this.cancelUpload(a), this.files = without(this.files, a), this.emit("removedfile", a), 0 === this.files.length) return this.emit("reset") } }, { key: "removeAllFiles", value: function (a) { null == a && (a = !1); for (var c = this.files.slice(), d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; (f.status !== b.UPLOADING || a) && this.removeFile(f) } return null } }, { key: "resizeImage", value: function (a, c, d, e, f) { var g = this; return this.createThumbnail(a, c, d, e, !0, function (c, d) { if (null == d) return f(a); var e = g.options.resizeMimeType; null == e && (e = a.type); var h = d.toDataURL(e, g.options.resizeQuality); return "image/jpeg" !== e && "image/jpg" !== e || (h = ExifRestore.restore(a.dataURL, h)), f(b.dataURItoBlob(h)) }) } }, { key: "createThumbnail", value: function (a, b, c, d, e, f) { var g = this, h = new FileReader; return h.onload = function () { return a.dataURL = h.result, "image/svg+xml" === a.type ? void (null != f && f(h.result)) : g.createThumbnailFromUrl(a, b, c, d, e, f) }, h.readAsDataURL(a) } }, { key: "createThumbnailFromUrl", value: function (a, b, c, d, e, f, g) { var h = this, i = document.createElement("img"); return g && (i.crossOrigin = g), i.onload = function () { var g = function (a) { return a(1) }; return "undefined" != typeof EXIF && null !== EXIF && e && (g = function (a) { return EXIF.getData(i, function () { return a(EXIF.getTag(this, "Orientation")) }) }), g(function (e) { a.width = i.width, a.height = i.height; var g = h.options.resize.call(h, a, b, c, d), j = document.createElement("canvas"), k = j.getContext("2d"); switch (j.width = g.trgWidth, j.height = g.trgHeight, e > 4 && (j.width = g.trgHeight, j.height = g.trgWidth), e) { case 2: k.translate(j.width, 0), k.scale(-1, 1); break; case 3: k.translate(j.width, j.height), k.rotate(Math.PI); break; case 4: k.translate(0, j.height), k.scale(1, -1); break; case 5: k.rotate(.5 * Math.PI), k.scale(1, -1); break; case 6: k.rotate(.5 * Math.PI), k.translate(0, -j.width); break; case 7: k.rotate(.5 * Math.PI), k.translate(j.height, -j.width), k.scale(-1, 1); break; case 8: k.rotate(-.5 * Math.PI), k.translate(-j.height, 0) }drawImageIOSFix(k, i, null != g.srcX ? g.srcX : 0, null != g.srcY ? g.srcY : 0, g.srcWidth, g.srcHeight, null != g.trgX ? g.trgX : 0, null != g.trgY ? g.trgY : 0, g.trgWidth, g.trgHeight); var l = j.toDataURL("image/png"); if (null != f) return f(l, j) }) }, null != f && (i.onerror = f), i.src = a.dataURL } }, { key: "processQueue", value: function () { var a = this.options.parallelUploads, b = this.getUploadingFiles().length, c = b; if (!(b >= a)) { var d = this.getQueuedFiles(); if (d.length > 0) { if (this.options.uploadMultiple) return this.processFiles(d.slice(0, a - b)); for (; c < a;) { if (!d.length) return; this.processFile(d.shift()), c++ } } } } }, { key: "processFile", value: function (a) { return this.processFiles([a]) } }, { key: "processFiles", value: function (a) { for (var c = a, d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; f.processing = !0, f.status = b.UPLOADING, this.emit("processing", f) } return this.options.uploadMultiple && this.emit("processingmultiple", a), this.uploadFiles(a) } }, { key: "_getFilesWithXhr", value: function (a) { return this.files.filter(function (b) { return b.xhr === a }).map(function (a) { return a }) } }, { key: "cancelUpload", value: function (a) { if (a.status === b.UPLOADING) { for (var c = this._getFilesWithXhr(a.xhr), d = c, e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; f.status = b.CANCELED } void 0 !== a.xhr && a.xhr.abort(); for (var g = c, h = 0, g = g; ;) { var i; if (h >= g.length) break; i = g[h++]; var j = i; this.emit("canceled", j) } this.options.uploadMultiple && this.emit("canceledmultiple", c) } else a.status !== b.ADDED && a.status !== b.QUEUED || (a.status = b.CANCELED, this.emit("canceled", a), this.options.uploadMultiple && this.emit("canceledmultiple", [a])); if (this.options.autoProcessQueue) return this.processQueue() } }, { key: "resolveOption", value: function (a) { if ("function" == typeof a) { for (var b = arguments.length, c = Array(b > 1 ? b - 1 : 0), d = 1; d < b; d++)c[d - 1] = arguments[d]; return a.apply(this, c) } return a } }, { key: "uploadFile", value: function (a) { return this.uploadFiles([a]) } }, { key: "uploadFiles", value: function (a) { var c = this; this._transformFiles(a, function (d) { if (a[0].upload.chunked) { var e = a[0], f = d[0], g = 0; e.upload.chunks = []; var h = function () { for (var d = 0; void 0 !== e.upload.chunks[d];)d++; if (!(d >= e.upload.totalChunkCount)) { g++; var h = d * c.options.chunkSize, i = Math.min(h + c.options.chunkSize, e.size), j = { name: c._getParamName(0), data: f.webkitSlice ? f.webkitSlice(h, i) : f.slice(h, i), filename: e.upload.filename, chunkIndex: d }; e.upload.chunks[d] = { file: e, index: d, dataBlock: j, status: b.UPLOADING, progress: 0, retries: 0 }, c._uploadData(a, [j]) } }; if (e.upload.finishedChunkUpload = function (d) { var f = !0; d.status = b.SUCCESS, d.dataBlock = null, d.xhr = null; for (var g = 0; g < e.upload.totalChunkCount; g++) { if (void 0 === e.upload.chunks[g]) return h(); e.upload.chunks[g].status !== b.SUCCESS && (f = !1) } f && c.options.chunksUploaded(e, function () { c._finished(a, "", null) }) }, c.options.parallelChunkUploads) for (var i = 0; i < e.upload.totalChunkCount; i++)h(); else h() } else { for (var j = [], k = 0; k < a.length; k++)j[k] = { name: c._getParamName(k), data: d[k], filename: a[k].upload.filename }; c._uploadData(a, j) } }) } }, { key: "_getChunk", value: function (a, b) { for (var c = 0; c < a.upload.totalChunkCount; c++)if (void 0 !== a.upload.chunks[c] && a.upload.chunks[c].xhr === b) return a.upload.chunks[c] } }, { key: "_uploadData", value: function (a, c) { for (var d = this, e = new XMLHttpRequest, f = a, g = 0, f = f; ;) { var h; if (g >= f.length) break; h = f[g++]; h.xhr = e } a[0].upload.chunked && (a[0].upload.chunks[c[0].chunkIndex].xhr = e); var i = this.resolveOption(this.options.method, a), j = this.resolveOption(this.options.url, a); e.open(i, j, !0), e.timeout = this.resolveOption(this.options.timeout, a), e.withCredentials = !!this.options.withCredentials, e.onload = function (b) { d._finishedUploading(a, e, b) }, e.onerror = function () { d._handleUploadError(a, e) }, (null != e.upload ? e.upload : e).onprogress = function (b) { return d._updateFilesUploadProgress(a, e, b) }; var k = { Accept: "application/json", "Cache-Control": "no-cache", "X-Requested-With": "XMLHttpRequest" }; this.options.headers && b.extend(k, this.options.headers); for (var l in k) { var m = k[l]; m && e.setRequestHeader(l, m) } var n = new FormData; if (this.options.params) { var o = this.options.params; "function" == typeof o && (o = o.call(this, a, e, a[0].upload.chunked ? this._getChunk(a[0], e) : null)); for (var p in o) { var q = o[p]; n.append(p, q) } } for (var r = a, s = 0, r = r; ;) { var t; if (s >= r.length) break; t = r[s++]; var u = t; this.emit("sending", u, e, n) } this.options.uploadMultiple && this.emit("sendingmultiple", a, e, n), this._addFormElementData(n); for (var v = 0; v < c.length; v++) { var w = c[v]; n.append(w.name, w.data, w.filename) } this.submitRequest(e, n, a) } }, {
+ key: "_transformFiles", value: function (a, b) {
+ for (var c = this, d = [], e = 0, f = 0; f < a.length; f++)!function (f) {
+ c.options.transformFile.call(c, a[f], function (c) {
+ d[f] = c,
+ ++e === a.length && b(d)
+ })
+ }(f)
+ }
+ }, { key: "_addFormElementData", value: function (a) { if ("FORM" === this.element.tagName) for (var b = this.element.querySelectorAll("input, textarea, select, button"), c = 0, b = b; ;) { var d; if (c >= b.length) break; d = b[c++]; var e = d, f = e.getAttribute("name"), g = e.getAttribute("type"); if (g && (g = g.toLowerCase()), void 0 !== f && null !== f) if ("SELECT" === e.tagName && e.hasAttribute("multiple")) for (var h = e.options, i = 0, h = h; ;) { var j; if (i >= h.length) break; j = h[i++]; var k = j; k.selected && a.append(f, k.value) } else (!g || "checkbox" !== g && "radio" !== g || e.checked) && a.append(f, e.value) } } }, { key: "_updateFilesUploadProgress", value: function (a, b, c) { var d = void 0; if (void 0 !== c) { if (d = 100 * c.loaded / c.total, a[0].upload.chunked) { var e = a[0], f = this._getChunk(e, b); f.progress = d, f.total = c.total, f.bytesSent = c.loaded; e.upload.progress = 0, e.upload.total = 0, e.upload.bytesSent = 0; for (var g = 0; g < e.upload.totalChunkCount; g++)void 0 !== e.upload.chunks[g] && void 0 !== e.upload.chunks[g].progress && (e.upload.progress += e.upload.chunks[g].progress, e.upload.total += e.upload.chunks[g].total, e.upload.bytesSent += e.upload.chunks[g].bytesSent); e.upload.progress = e.upload.progress / e.upload.totalChunkCount } else for (var h = a, i = 0, h = h; ;) { var j; if (i >= h.length) break; j = h[i++]; var k = j; k.upload.progress = d, k.upload.total = c.total, k.upload.bytesSent = c.loaded } for (var l = a, m = 0, l = l; ;) { var n; if (m >= l.length) break; n = l[m++]; var o = n; this.emit("uploadprogress", o, o.upload.progress, o.upload.bytesSent) } } else { var p = !0; d = 100; for (var q = a, r = 0, q = q; ;) { var s; if (r >= q.length) break; s = q[r++]; var t = s; 100 === t.upload.progress && t.upload.bytesSent === t.upload.total || (p = !1), t.upload.progress = d, t.upload.bytesSent = t.upload.total } if (p) return; for (var u = a, v = 0, u = u; ;) { var w; if (v >= u.length) break; w = u[v++]; var x = w; this.emit("uploadprogress", x, d, x.upload.bytesSent) } } } }, { key: "_finishedUploading", value: function (a, c, d) { var e = void 0; if (a[0].status !== b.CANCELED && 4 === c.readyState) { if ("arraybuffer" !== c.responseType && "blob" !== c.responseType && (e = c.responseText, c.getResponseHeader("content-type") && ~c.getResponseHeader("content-type").indexOf("application/json"))) try { e = JSON.parse(e) } catch (a) { d = a, e = "Invalid JSON response from server." } this._updateFilesUploadProgress(a), 200 <= c.status && c.status < 300 ? a[0].upload.chunked ? a[0].upload.finishedChunkUpload(this._getChunk(a[0], c)) : this._finished(a, e, d) : this._handleUploadError(a, c, e) } } }, { key: "_handleUploadError", value: function (a, c, d) { if (a[0].status !== b.CANCELED) { if (a[0].upload.chunked && this.options.retryChunks) { var e = this._getChunk(a[0], c); if (e.retries++ < this.options.retryChunksLimit) return void this._uploadData(a, [e.dataBlock]); console.warn("Retried this chunk too often. Giving up.") } for (var f = a, g = 0, f = f; ;) { if (g >= f.length) break; f[g++]; this._errorProcessing(a, d || this.options.dictResponseError.replace("{{statusCode}}", c.status), c) } } } }, { key: "submitRequest", value: function (a, b, c) { a.send(b) } }, { key: "_finished", value: function (a, c, d) { for (var e = a, f = 0, e = e; ;) { var g; if (f >= e.length) break; g = e[f++]; var h = g; h.status = b.SUCCESS, this.emit("success", h, c, d), this.emit("complete", h) } if (this.options.uploadMultiple && (this.emit("successmultiple", a, c, d), this.emit("completemultiple", a)), this.options.autoProcessQueue) return this.processQueue() } }, { key: "_errorProcessing", value: function (a, c, d) { for (var e = a, f = 0, e = e; ;) { var g; if (f >= e.length) break; g = e[f++]; var h = g; h.status = b.ERROR, this.emit("error", h, c, d), this.emit("complete", h) } if (this.options.uploadMultiple && (this.emit("errormultiple", a, c, d), this.emit("completemultiple", a)), this.options.autoProcessQueue) return this.processQueue() } }], [{ key: "uuidv4", value: function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (a) { var b = 16 * Math.random() | 0; return ("x" === a ? b : 3 & b | 8).toString(16) }) } }]), b
+}(Emitter); Dropzone.initClass(), Dropzone.version = "5.5.1", Dropzone.options = {}, Dropzone.optionsForElement = function (a) { return a.getAttribute("id") ? Dropzone.options[camelize(a.getAttribute("id"))] : void 0 }, Dropzone.instances = [], Dropzone.forElement = function (a) { if ("string" == typeof a && (a = document.querySelector(a)), null == (null != a ? a.dropzone : void 0)) throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); return a.dropzone }, Dropzone.autoDiscover = !0, Dropzone.discover = function () { var a = void 0; if (document.querySelectorAll) a = document.querySelectorAll(".dropzone"); else { a = []; var b = function (b) { return function () { for (var c = [], d = b, e = 0, d = d; ;) { var f; if (e >= d.length) break; f = d[e++]; var g = f; /(^| )dropzone($| )/.test(g.className) ? c.push(a.push(g)) : c.push(void 0) } return c }() }; b(document.getElementsByTagName("div")), b(document.getElementsByTagName("form")) } return function () { for (var b = [], c = a, d = 0, c = c; ;) { var e; if (d >= c.length) break; e = c[d++]; var f = e; !1 !== Dropzone.optionsForElement(f) ? b.push(new Dropzone(f)) : b.push(void 0) } return b }() }, Dropzone.blacklistedBrowsers = [/opera.*(Macintosh|Windows Phone).*version\/12/i], Dropzone.isBrowserSupported = function () { var a = !0; if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) if ("classList" in document.createElement("a")) for (var b = Dropzone.blacklistedBrowsers, c = 0, b = b; ;) { var d; if (c >= b.length) break; d = b[c++]; var e = d; e.test(navigator.userAgent) && (a = !1) } else a = !1; else a = !1; return a }, Dropzone.dataURItoBlob = function (a) { for (var b = atob(a.split(",")[1]), c = a.split(",")[0].split(":")[1].split(";")[0], d = new ArrayBuffer(b.length), e = new Uint8Array(d), f = 0, g = b.length, h = 0 <= g; h ? f <= g : f >= g; h ? f++ : f--)e[f] = b.charCodeAt(f); return new Blob([d], { type: c }) }; var without = function (a, b) { return a.filter(function (a) { return a !== b }).map(function (a) { return a }) }, camelize = function (a) { return a.replace(/[\-_](\w)/g, function (a) { return a.charAt(1).toUpperCase() }) }; Dropzone.createElement = function (a) { var b = document.createElement("div"); return b.innerHTML = a, b.childNodes[0] }, Dropzone.elementInside = function (a, b) { if (a === b) return !0; for (; a = a.parentNode;)if (a === b) return !0; return !1 }, Dropzone.getElement = function (a, b) { var c = void 0; if ("string" == typeof a ? c = document.querySelector(a) : null != a.nodeType && (c = a), null == c) throw new Error("Invalid `" + b + "` option provided. Please provide a CSS selector or a plain HTML element."); return c }, Dropzone.getElements = function (a, b) { var c = void 0, d = void 0; if (a instanceof Array) { d = []; try { for (var e = a, f = 0, e = e; !(f >= e.length);)c = e[f++], d.push(this.getElement(c, b)) } catch (a) { d = null } } else if ("string" == typeof a) { d = []; for (var g = document.querySelectorAll(a), h = 0, g = g; !(h >= g.length);)c = g[h++], d.push(c) } else null != a.nodeType && (d = [a]); if (null == d || !d.length) throw new Error("Invalid `" + b + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); return d }, Dropzone.confirm = function (a, b, c) { return window.confirm(a) ? b() : null != c ? c() : void 0 }, Dropzone.isValidFile = function (a, b) { if (!b) return !0; b = b.split(","); for (var c = a.type, d = c.replace(/\/.*$/, ""), e = b, f = 0, e = e; ;) { var g; if (f >= e.length) break; g = e[f++]; var h = g; if (h = h.trim(), "." === h.charAt(0)) { if (-1 !== a.name.toLowerCase().indexOf(h.toLowerCase(), a.name.length - h.length)) return !0 } else if (/\/\*$/.test(h)) { if (d === h.replace(/\/.*$/, "")) return !0 } else if (c === h) return !0 } return !1 }, "undefined" != typeof jQuery && null !== jQuery && (jQuery.fn.dropzone = function (a) { return this.each(function () { return new Dropzone(this, a) }) }), "undefined" != typeof module && null !== module ? module.exports = Dropzone : window.Dropzone = Dropzone, Dropzone.ADDED = "added", Dropzone.QUEUED = "queued", Dropzone.ACCEPTED = Dropzone.QUEUED, Dropzone.UPLOADING = "uploading", Dropzone.PROCESSING = Dropzone.UPLOADING, Dropzone.CANCELED = "canceled", Dropzone.ERROR = "error", Dropzone.SUCCESS = "success"; var detectVerticalSquash = function (a) { var b = (a.naturalWidth, a.naturalHeight), c = document.createElement("canvas"); c.width = 1, c.height = b; var d = c.getContext("2d"); d.drawImage(a, 0, 0); for (var e = d.getImageData(1, 0, 1, b), f = e.data, g = 0, h = b, i = b; i > g;) { 0 === f[4 * (i - 1) + 3] ? h = i : g = i, i = h + g >> 1 } var j = i / b; return 0 === j ? 1 : j }, drawImageIOSFix = function (a, b, c, d, e, f, g, h, i, j) { var k = detectVerticalSquash(b); return a.drawImage(b, c, d, e, f, g, h, i, j / k) }, ExifRestore = function () { function a() { _classCallCheck(this, a) } return _createClass(a, null, [{ key: "initClass", value: function () { this.KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" } }, { key: "encode64", value: function (a) { for (var b = "", c = void 0, d = void 0, e = "", f = void 0, g = void 0, h = void 0, i = "", j = 0; ;)if (c = a[j++], d = a[j++], e = a[j++], f = c >> 2, g = (3 & c) << 4 | d >> 4, h = (15 & d) << 2 | e >> 6, i = 63 & e, isNaN(d) ? h = i = 64 : isNaN(e) && (i = 64), b = b + this.KEY_STR.charAt(f) + this.KEY_STR.charAt(g) + this.KEY_STR.charAt(h) + this.KEY_STR.charAt(i), c = d = e = "", f = g = h = i = "", !(j < a.length)) break; return b } }, { key: "restore", value: function (a, b) { if (!a.match("data:image/jpeg;base64,")) return b; var c = this.decode64(a.replace("data:image/jpeg;base64,", "")), d = this.slice2Segments(c), e = this.exifManipulation(b, d); return "data:image/jpeg;base64," + this.encode64(e) } }, { key: "exifManipulation", value: function (a, b) { var c = this.getExifArray(b), d = this.insertExif(a, c); return new Uint8Array(d) } }, { key: "getExifArray", value: function (a) { for (var b = void 0, c = 0; c < a.length;) { if (b = a[c], 255 === b[0] & 225 === b[1]) return b; c++ } return [] } }, { key: "insertExif", value: function (a, b) { var c = a.replace("data:image/jpeg;base64,", ""), d = this.decode64(c), e = d.indexOf(255, 3), f = d.slice(0, e), g = d.slice(e), h = f; return h = h.concat(b), h = h.concat(g) } }, { key: "slice2Segments", value: function (a) { for (var b = 0, c = []; ;) { var d; if (255 === a[b] & 218 === a[b + 1]) break; if (255 === a[b] & 216 === a[b + 1]) b += 2; else { d = 256 * a[b + 2] + a[b + 3]; var e = b + d + 2, f = a.slice(b, e); c.push(f), b = e } if (b > a.length) break } return c } }, { key: "decode64", value: function (a) { var b = void 0, c = void 0, d = "", e = void 0, f = void 0, g = void 0, h = "", i = 0, j = [], k = /[^A-Za-z0-9\+\/\=]/g; for (k.exec(a) && console.warn("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding."), a = a.replace(/[^A-Za-z0-9\+\/\=]/g, ""); ;)if (e = this.KEY_STR.indexOf(a.charAt(i++)), f = this.KEY_STR.indexOf(a.charAt(i++)), g = this.KEY_STR.indexOf(a.charAt(i++)), h = this.KEY_STR.indexOf(a.charAt(i++)), b = e << 2 | f >> 4, c = (15 & f) << 4 | g >> 2, d = (3 & g) << 6 | h, j.push(b), 64 !== g && j.push(c), 64 !== h && j.push(d), b = c = d = "", e = f = g = h = "", !(i < a.length)) break; return j } }]), a }(); ExifRestore.initClass(); var contentLoaded = function (a, b) { var c = !1, d = !0, e = a.document, f = e.documentElement, g = e.addEventListener ? "addEventListener" : "attachEvent", h = e.addEventListener ? "removeEventListener" : "detachEvent", i = e.addEventListener ? "" : "on", j = function d(f) { if ("readystatechange" !== f.type || "complete" === e.readyState) return ("load" === f.type ? a : e)[h](i + f.type, d, !1), !c && (c = !0) ? b.call(a, f.type || f) : void 0 }; if ("complete" !== e.readyState) { if (e.createEventObject && f.doScroll) { try { d = !a.frameElement } catch (a) { } d && function a() { try { f.doScroll("left") } catch (b) { return void setTimeout(a, 50) } return j("poll") }() } return e[g](i + "DOMContentLoaded", j, !1), e[g](i + "readystatechange", j, !1), a[g](i + "load", j, !1) } }; Dropzone._autoDiscoverFunction = function () { if (Dropzone.autoDiscover) return Dropzone.discover() }, contentLoaded(window, Dropzone._autoDiscoverFunction);
\ No newline at end of file
diff --git a/Kudu.Services.Web/wwwroot/Content/Scripts/jsonTree.js b/Kudu.Services.Web/wwwroot/Content/Scripts/jsonTree.js
index f1406434..2c0aa8d4 100644
--- a/Kudu.Services.Web/wwwroot/Content/Scripts/jsonTree.js
+++ b/Kudu.Services.Web/wwwroot/Content/Scripts/jsonTree.js
@@ -395,7 +395,7 @@ var jsonTree = (function() {
shouldShowJSONViewerURL = false;
}
if(shouldShowJSONViewerURL) {
- val = "" + val + " ";
+ val = "" + val + " ";
}else{
val = ""+val+" ";
}
diff --git a/Kudu.Services.Web/wwwroot/Content/Styles/newui.css b/Kudu.Services.Web/wwwroot/Content/Styles/newui.css
index 91d40a58..3323143e 100644
--- a/Kudu.Services.Web/wwwroot/Content/Styles/newui.css
+++ b/Kudu.Services.Web/wwwroot/Content/Styles/newui.css
@@ -117,6 +117,11 @@ hr {
font-weight: 700;
}
+.nav .dropdown-menu-right {
+ right: 0;
+ left: auto;
+}
+
.text-light{
font-weight: 100;
}
diff --git a/Kudu.Services.Web/wwwroot/css/dropzone.min.css b/Kudu.Services.Web/wwwroot/css/dropzone.min.css
new file mode 100644
index 00000000..6a57c69f
--- /dev/null
+++ b/Kudu.Services.Web/wwwroot/css/dropzone.min.css
@@ -0,0 +1 @@
+@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,0.3);background:white;padding:0px 0px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:0.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:white}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,0.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,0.8);background-color:rgba(255,255,255,0.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,0.4);padding:0 0.4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,0.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:0.5em 1.2em;color:white}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626}
diff --git a/Kudu.Services.Web/wwwroot/css/newui.css b/Kudu.Services.Web/wwwroot/css/newui.css
index 736f512f..a3540a77 100644
--- a/Kudu.Services.Web/wwwroot/css/newui.css
+++ b/Kudu.Services.Web/wwwroot/css/newui.css
@@ -116,4 +116,9 @@ hr {
.text-light{
font-weight: 100;
+}
+
+.nav .dropdown-menu-right {
+ right: 0;
+ left: auto;
}
\ No newline at end of file
diff --git a/Kudu.Services/DebugExtension/DebugExtensionMiddleware.cs b/Kudu.Services/DebugExtension/DebugExtensionMiddleware.cs
index 8748c805..846d104b 100644
--- a/Kudu.Services/DebugExtension/DebugExtensionMiddleware.cs
+++ b/Kudu.Services/DebugExtension/DebugExtensionMiddleware.cs
@@ -51,8 +51,6 @@ public void ConfigureLogging()
{
if (loggerFactory == null)
{
- loggerFactory = new LoggerFactory();
-
string level = Environment.GetEnvironmentVariable("APPSVC_TUNNEL_VERBOSITY");
LogLevel logLevel = LogLevel.Information;
@@ -76,8 +74,7 @@ public void ConfigureLogging()
}
Console.WriteLine("Setting LogLevel to " + level);
}
-
- loggerFactory.AddConsole(logLevel);
+ loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
}
if (_logger == null)
diff --git a/Kudu.Services/Deployment/PushDeploymentController.cs b/Kudu.Services/Deployment/PushDeploymentController.cs
index f84babf9..4e08bb9f 100644
--- a/Kudu.Services/Deployment/PushDeploymentController.cs
+++ b/Kudu.Services/Deployment/PushDeploymentController.cs
@@ -21,6 +21,7 @@
using System.Collections.Generic;
using Kudu.Core.Helpers;
using System.Threading;
+using System.Text;
namespace Kudu.Services.Deployment
{
@@ -52,16 +53,52 @@ public PushDeploymentController(
[HttpPost]
[DisableRequestSizeLimit]
- [DisableFormValueModelBinding]
- public async Task ZipPushDeploy(
- [FromQuery] bool isAsync = false,
- [FromQuery] bool syncTriggers = false,
- [FromQuery] bool overwriteWebsiteRunFromPackage = false,
- [FromQuery] string author = null,
- [FromQuery] string authorEmail = null,
- [FromQuery] string deployer = DefaultDeployer,
- [FromQuery] string message = DefaultMessage)
+ public async Task ZipPushDeploy()
{
+ bool isAsync = false;
+ if(Request.Query.ContainsKey("isAsync")) {
+ isAsync = Boolean.Parse(Request.Query["isAsync"]);
+ }
+
+ bool syncTriggers = false;
+ if (Request.Query.ContainsKey("syncTriggers"))
+ {
+ syncTriggers = Boolean.Parse(Request.Query["syncTriggers"]);
+ }
+
+ bool overwriteWebsiteRunFromPackage = false;
+ if (Request.Query.ContainsKey("overwriteWebsiteRunFromPackage"))
+ {
+ overwriteWebsiteRunFromPackage = Boolean.Parse(Request.Query["overwriteWebsiteRunFromPackage"]);
+ }
+
+ string author = null;
+ if (Request.Query.ContainsKey("author"))
+ {
+ author = Request.Query["author"];
+ }
+
+ string authorEmail = null;
+ if (Request.Query.ContainsKey("authorEmail"))
+ {
+ authorEmail = Request.Query["authorEmail"];
+ }
+
+ string deployer = DefaultDeployer;
+ if (Request.Query.ContainsKey("deployer"))
+ {
+ deployer = Request.Query["deployer"];
+ }
+
+ string message = DefaultMessage;
+ if (Request.Query.ContainsKey("message"))
+ {
+ message = Request.Query["message"];
+ }
+
+ // var responseBodyStream = new MemoryStream();
+ // HttpContext.Response.Body = responseBodyStream;
+
using (_tracer.Step("ZipPushDeploy"))
{
var deploymentInfo = new ZipDeploymentInfo(_environment, _traceFactory)
@@ -143,14 +180,43 @@ public async Task ZipPushDeployViaUrl(
[HttpPost]
[DisableRequestSizeLimit]
- [DisableFormValueModelBinding]
- public async Task WarPushDeploy(
- [FromQuery] bool isAsync = false,
- [FromQuery] string author = null,
- [FromQuery] string authorEmail = null,
- [FromQuery] string deployer = DefaultDeployer,
- [FromQuery] string message = DefaultMessage)
+ public async Task WarPushDeploy()
{
+ bool isAsync = false;
+ if(Request.Query.ContainsKey("isAsync")) {
+ isAsync = Boolean.Parse(Request.Query["isAsync"]);
+ }
+
+ bool syncTriggers = false;
+ if (Request.Query.ContainsKey("syncTriggers"))
+ {
+ syncTriggers = Boolean.Parse(Request.Query["syncTriggers"]);
+ }
+
+ string author = null;
+ if (Request.Query.ContainsKey("author"))
+ {
+ author = Request.Query["author"];
+ }
+
+ string authorEmail = null;
+ if (Request.Query.ContainsKey("authorEmail"))
+ {
+ authorEmail = Request.Query["authorEmail"];
+ }
+
+ string deployer = DefaultDeployer;
+ if (Request.Query.ContainsKey("deployer"))
+ {
+ deployer = Request.Query["deployer"];
+ }
+
+ string message = DefaultMessage;
+ if (Request.Query.ContainsKey("message"))
+ {
+ message = Request.Query["message"];
+ }
+
using (_tracer.Step("WarPushDeploy"))
{
var appName = HttpContext.Request.Query["name"].ToString();
@@ -185,6 +251,7 @@ public async Task WarPushDeploy(
}
}
+
private string GetZipURLFromJSON(JObject requestObject)
{
using (_tracer.Step("Reading the zip URL from the request JSON"))
@@ -249,19 +316,7 @@ private async Task PushDeployAsync(ZipDeploymentInfo deploymentIn
using (_tracer.Step("Writing zip file to {0}", zipFilePath))
{
- if (!string.IsNullOrEmpty(context.Request.ContentType) &&
- context.Request.ContentType.Contains("multipart/form-data", StringComparison.OrdinalIgnoreCase))
- {
- FormValueProvider formModel;
- using (_tracer.Step("Writing zip file to {0}", zipFilePath))
- {
- using (var file = System.IO.File.Create(zipFilePath))
- {
- formModel = await Request.StreamFile(file);
- }
- }
- }
- else if (deploymentInfo.ZipURL != null)
+ if (deploymentInfo.ZipURL != null)
{
using (_tracer.Step("Writing zip file from packageUri to {0}", zipFilePath))
{
@@ -293,7 +348,7 @@ private async Task PushDeployAsync(ZipDeploymentInfo deploymentIn
{
using (var file = System.IO.File.Create(zipFilePath))
{
- await Request.Body.CopyToAsync(file);
+ await HttpContext.Request.Body.CopyToAsync(file);
}
}
}
diff --git a/Kudu.Services/Diagnostics/DiagnosticsController.cs b/Kudu.Services/Diagnostics/DiagnosticsController.cs
index f3608a56..aacd9941 100644
--- a/Kudu.Services/Diagnostics/DiagnosticsController.cs
+++ b/Kudu.Services/Diagnostics/DiagnosticsController.cs
@@ -18,6 +18,7 @@
using Microsoft.AspNetCore.Http;
using Kudu.Services.Infrastructure;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http.Features;
namespace Kudu.Services.Performance
{
@@ -67,16 +68,14 @@ public DiagnosticsController(IEnvironment environment, ITracer tracer, IApplicat
///
[HttpGet]
[SuppressMessage("Microsoft.Usage", "CA2202", Justification = "The ZipArchive is instantiated in a way that the stream is not closed on dispose")]
- public IActionResult GetLog()
+ public async Task GetLog()
{
- return new FileCallbackResult("application/zip", (outputStream, _) =>
+ return new FileCallbackResult("application/zip", async (outputStream, _) =>
{
using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: false))
{
- AddFilesToZip(zip);
+ await AddFilesToZip(zip);
}
-
- return Task.CompletedTask;
})
{
FileDownloadName = String.Format("dump-{0:MM-dd-HH-mm-ss}.zip", DateTime.UtcNow)
@@ -130,25 +129,32 @@ public IActionResult GetDockerLogs(HttpRequestMessage request)
// and returns them in a zip archive
[HttpGet]
[SuppressMessage("Microsoft.Usage", "CA2202", Justification = "The ZipArchive is instantiated in a way that the stream is not closed on dispose")]
- public IActionResult GetDockerLogsZip()
+ public async Task GetDockerLogsZip()
{
using (_tracer.Step("DiagnosticsController.GetDockerLogsZip"))
{
+
+ // Enable Synchronous operation to get docker logs zip, zip archive internally
+ // uses Write/Read and starting netcore 3.1, Synchronous writes/reads are not allowed
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
+
// Also search for "today's" files in sub folders. Windows containers archives log files
// when they reach a certain size.
var currentDockerLogFilenames = GetCurrentDockerLogFilenames(SearchOption.AllDirectories);
- return new FileCallbackResult("application/zip", (outputStream, _) =>
+ return new FileCallbackResult("application/zip", async (outputStream, _) =>
{
using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: false))
{
foreach (var filename in currentDockerLogFilenames)
{
- zip.AddFile(filename, _tracer);
+ await zip.AddFile(filename, _tracer);
}
}
-
- return Task.CompletedTask;
})
{
FileDownloadName = String.Format("dockerlogs-{0:MM-dd-HH-mm-ss}.zip", DateTime.UtcNow)
@@ -222,7 +228,7 @@ private JObject CurrentDockerLogFilenameToJson(string path, string vfsBaseAddres
new JProperty("path", info.FullName));
}
- private void AddFilesToZip(ZipArchive zip)
+ private async Task AddFilesToZip(ZipArchive zip)
{
foreach (var path in _paths)
{
@@ -244,7 +250,7 @@ private void AddFilesToZip(ZipArchive zip)
}
else
{
- zip.AddFile((FileInfo)info, _tracer, dir.Name);
+ await zip.AddFile((FileInfo)info, _tracer, dir.Name);
}
}
}
@@ -255,7 +261,7 @@ private void AddFilesToZip(ZipArchive zip)
}
else if (FileSystemHelpers.FileExists(path))
{
- zip.AddFile(path, _tracer, String.Empty);
+ await zip.AddFile(path, _tracer, String.Empty);
}
}
}
diff --git a/Kudu.Services/Diagnostics/LogStreamManager.cs b/Kudu.Services/Diagnostics/LogStreamManager.cs
index 9e4eb4e8..e6fd0412 100644
--- a/Kudu.Services/Diagnostics/LogStreamManager.cs
+++ b/Kudu.Services/Diagnostics/LogStreamManager.cs
@@ -372,10 +372,10 @@ private Action DoSafeAction(Action func, string
private void DisableResponseBuffering(HttpContext context)
{
- IHttpBufferingFeature bufferingFeature = context.Features.Get();
- if (bufferingFeature != null)
+ IHttpResponseBodyFeature responseBodyFeature = context.Features.Get();
+ if (responseBodyFeature != null)
{
- bufferingFeature.DisableResponseBuffering();
+ responseBodyFeature.DisableBuffering();
}
}
diff --git a/Kudu.Services/Infrastructure/FileCallbackResult.cs b/Kudu.Services/Infrastructure/FileCallbackResult.cs
index e9eeaba8..c4f5d605 100644
--- a/Kudu.Services/Infrastructure/FileCallbackResult.cs
+++ b/Kudu.Services/Infrastructure/FileCallbackResult.cs
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
diff --git a/Kudu.Services/Infrastructure/VfsControllerBase.cs b/Kudu.Services/Infrastructure/VfsControllerBase.cs
index 31e74e87..626e46ae 100644
--- a/Kudu.Services/Infrastructure/VfsControllerBase.cs
+++ b/Kudu.Services/Infrastructure/VfsControllerBase.cs
@@ -16,6 +16,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
namespace Kudu.Services.Infrastructure
{
@@ -47,6 +48,11 @@ protected VfsControllerBase(ITracer tracer, IEnvironment environment, string roo
[AcceptVerbs("GET", "HEAD")]
public virtual Task GetItem()
{
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
string localFilePath = GetLocalFilePath();
if (VfsSpecialFolders.TryHandleRequest(Request, localFilePath, out IActionResult response))
{
@@ -91,6 +97,11 @@ public virtual Task GetItem()
[HttpPut]
public virtual Task PutItem()
{
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
string localFilePath = GetLocalFilePath();
if (VfsSpecialFolders.TryHandleRequest(Request, localFilePath, out IActionResult response))
@@ -121,6 +132,11 @@ public virtual Task PutItem()
[HttpDelete]
public virtual Task DeleteItem(bool recursive = false)
{
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
string localFilePath = GetLocalFilePath();
if (VfsSpecialFolders.TryHandleRequest(Request, localFilePath, out IActionResult response))
diff --git a/Kudu.Services/Kudu.Services.csproj b/Kudu.Services/Kudu.Services.csproj
index 52f96475..60c8aca3 100644
--- a/Kudu.Services/Kudu.Services.csproj
+++ b/Kudu.Services/Kudu.Services.csproj
@@ -1,13 +1,15 @@
- netcoreapp2.2
+ netcoreapp3.1
true
false
-
+
+
+
@@ -33,7 +35,4 @@
true
-
- /opt/Kudu/Kudu.Services.xml
-
diff --git a/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionInstanceAdminController.cs b/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionInstanceAdminController.cs
index 75f81631..c398def0 100644
--- a/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionInstanceAdminController.cs
+++ b/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionInstanceAdminController.cs
@@ -62,7 +62,7 @@ public IActionResult Info()
/// Expect 202 when receives the first call, otherwise, returns 409
[HttpPost]
[Authorize(Policy = AuthPolicyNames.AdminAuthLevel)]
- public async Task AssignAsync([FromBody] EncryptedHostAssignmentContext encryptedAssignmentContext)
+ public IActionResult Assign([FromBody] EncryptedHostAssignmentContext encryptedAssignmentContext)
{
var containerKey = System.Environment.GetEnvironmentVariable(SettingsKeys.ContainerEncryptionKey);
var assignmentContext = encryptedAssignmentContext.Decrypt(containerKey);
diff --git a/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionRouteMiddleware.cs b/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionRouteMiddleware.cs
index ef2fddf9..ab6003d5 100644
--- a/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionRouteMiddleware.cs
+++ b/Kudu.Services/LinuxConsumptionInstanceAdmin/LinuxConsumptionRouteMiddleware.cs
@@ -31,7 +31,8 @@ public class LinuxConsumptionRouteMiddleware
"/api/settings",
"/admin/instance",
"/deployments",
- "/zipdeploy"
+ "/zipdeploy",
+ "/Error"
};
private readonly RequestDelegate _next;
diff --git a/Kudu.Services/Zip/ZipController.cs b/Kudu.Services/Zip/ZipController.cs
index d9773d84..50a8636b 100644
--- a/Kudu.Services/Zip/ZipController.cs
+++ b/Kudu.Services/Zip/ZipController.cs
@@ -2,7 +2,6 @@
using Kudu.Core;
using Kudu.Services.Infrastructure;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.AspNetCore.Mvc.Internal;
using System;
using System.IO.Abstractions;
using System.IO.Compression;
@@ -13,6 +12,7 @@
using Kudu.Core.Infrastructure;
using Kudu.Core.Helpers;
using System.Threading;
+using Microsoft.AspNetCore.Http.Features;
namespace Kudu.Services.Zip
{
@@ -32,12 +32,17 @@ public ZipController(ITracer tracer, IEnvironment environment)
protected override Task CreateDirectoryGetResponse(DirectoryInfoBase info, string localFilePath)
{
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
if (!Request.Query.TryGetValue("fileName", out var fileName))
{
fileName = Path.GetFileName(Path.GetDirectoryName(localFilePath)) + ".zip";
}
- var result = new FileCallbackResult("application/zip", (outputStream, _) =>
+ var result = new FileCallbackResult("application/zip", async (outputStream, _) =>
{
// Note that a stream wrapper is no longer needed for ZipArchive, this was fixed in its implementation.
using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: false))
@@ -52,12 +57,10 @@ protected override Task CreateDirectoryGetResponse(DirectoryInfoB
else
{
// Add it at the root of the zip
- zip.AddFile(fileSysInfo.FullName, Tracer, String.Empty);
+ await zip.AddFile(fileSysInfo.FullName, Tracer, String.Empty);
}
}
}
-
- return Task.CompletedTask;
})
{
FileDownloadName = fileName
@@ -75,6 +78,11 @@ protected override Task CreateItemGetResponse(FileSystemInfoBase
protected override Task CreateDirectoryPutResponse(DirectoryInfoBase info, string localFilePath)
{
+ var syncIOFeature = HttpContext.Features.Get();
+ if (syncIOFeature != null)
+ {
+ syncIOFeature.AllowSynchronousIO = true;
+ }
var zipArchive = new ZipArchive(Request.Body, ZipArchiveMode.Read);
zipArchive.Extract(localFilePath);
PermissionHelper.ChmodRecursive("777", localFilePath, _tracer, TimeSpan.FromSeconds(30));
diff --git a/Kudu.Tests/TestMockedIEnvironment.cs b/Kudu.Tests/TestMockedIEnvironment.cs
index 7175a34f..f21c9707 100644
--- a/Kudu.Tests/TestMockedIEnvironment.cs
+++ b/Kudu.Tests/TestMockedIEnvironment.cs
@@ -34,7 +34,7 @@ public class TestMockedIEnvironment : IEnvironment
public string _FunctionsPath = "/site/wwwroot";
public string _AppBaseUrlPrefix = "siteName.azurewebsites.net";
public string _RequestId = "00000000-0000-0000-0000-000000000000";
- public string _KuduConsoleFullPath = "KuduConsole/kudu.dll";
+ public string _KuduConsoleFullPath = "KuduConsole/kudu";
public string _SitePackagesPath = "/data/SitePackages";
public bool _IsOnLinuxConsumption = false;