From 42eb16755ab506a89a61645938afba3eba545e20 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Mon, 18 Jun 2018 20:27:36 +0200 Subject: [PATCH] (GH-475) Add report using DevExtreme PivotGrid --- .../GenericIssueReportGeneratorTests.cs | 1 + .../HtmlDxPivotGridAreaExtensionsTests.cs | 27 ++ .../Cake.Issues.Reporting.Generic.csproj | 1 + .../GenericIssueReportTemplate.cs | 6 + .../GenericIssueReportTemplateExtensions.cs | 1 + .../HtmlDxPivotGridArea.cs | 28 ++ .../HtmlDxPivotGridAreaExtensions.cs | 32 ++ .../HtmlDxPivotGridOption.cs | 396 ++++++++++++++++++ .../Templates/DxPivotGrid.cshtml | 331 +++++++++++++++ 9 files changed, 823 insertions(+) create mode 100644 src/Cake.Issues.Reporting.Generic.Tests/HtmlDxPivotGridAreaExtensionsTests.cs create mode 100644 src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridArea.cs create mode 100644 src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridAreaExtensions.cs create mode 100644 src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridOption.cs create mode 100644 src/Cake.Issues.Reporting.Generic/Templates/DxPivotGrid.cshtml diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs index 521816793..59b1ad6ea 100644 --- a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs @@ -46,6 +46,7 @@ public sealed class TheInternalCreateReportMethod [InlineData(GenericIssueReportTemplate.HtmlDiagnostic)] [InlineData(GenericIssueReportTemplate.HtmlDataTable)] [InlineData(GenericIssueReportTemplate.HtmlDxDataGrid)] + [InlineData(GenericIssueReportTemplate.HtmlDxPivotGrid)] public void Should_Generate_Report_From_Embedded_Template(GenericIssueReportTemplate template) { // Given diff --git a/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxPivotGridAreaExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxPivotGridAreaExtensionsTests.cs new file mode 100644 index 000000000..2f30c1f70 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxPivotGridAreaExtensionsTests.cs @@ -0,0 +1,27 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using Shouldly; + using Xunit; + + public sealed class HtmlDxPivotGridAreaExtensionsTests + { + public sealed class TheToJavaScriptIdentifierMethod + { + [Theory] + [InlineData(HtmlDxPivotGridArea.Column)] + [InlineData(HtmlDxPivotGridArea.Row)] + [InlineData(HtmlDxPivotGridArea.Filter)] + [InlineData(HtmlDxPivotGridArea.Data)] + public void Should_Return_Identifier(HtmlDxPivotGridArea area) + { + // Given + + // When + var result = area.ToJavaScriptIdentifier(); + + // Then + result.ShouldNotBeNullOrWhiteSpace(); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj b/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj index d704df929..76c6d1e93 100644 --- a/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj +++ b/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj @@ -21,6 +21,7 @@ + diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs index fb1a5ec34..c7ef83207 100644 --- a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs @@ -20,5 +20,11 @@ public enum GenericIssueReportTemplate /// See for template specific options. /// HtmlDxDataGrid, + + /// + /// Template for a HTML report containing a pivot grid showing number of errors, warnings, suggestions and hints, + /// with a detail drill down view and an overview chart. + /// + HtmlDxPivotGrid, } } diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs index 288c4f141..00bc0a781 100644 --- a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs @@ -19,6 +19,7 @@ public static string GetTemplateResourceName(this GenericIssueReportTemplate tem GenericIssueReportTemplate.HtmlDiagnostic => "Diagnostic.cshtml", GenericIssueReportTemplate.HtmlDataTable => "DataTable.cshtml", GenericIssueReportTemplate.HtmlDxDataGrid => "DxDataGrid.cshtml", + GenericIssueReportTemplate.HtmlDxPivotGrid => "DxPivotGrid.cshtml", _ => throw new ArgumentOutOfRangeException(nameof(template)), }; } diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridArea.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridArea.cs new file mode 100644 index 000000000..9ffbe8295 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridArea.cs @@ -0,0 +1,28 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Possible areas for fields. + /// + public enum HtmlDxPivotGridArea + { + /// + /// Field will be shown as row. + /// + Row, + + /// + /// Field will be shown as column. + /// + Column, + + /// + /// Field will be shown as data. + /// + Data, + + /// + /// Field will be available to filter. + /// + Filter + } +} diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridAreaExtensions.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridAreaExtensions.cs new file mode 100644 index 000000000..14d25dce6 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridAreaExtensions.cs @@ -0,0 +1,32 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Extension methods for the enumeration. + /// + public static class HtmlDxPivotGridAreaExtensions + { + /// + /// Returns the short identifier of the pivot grid area. + /// + /// Area for which the identifier should be returned. + /// Short identifier of the area. + public static string ToJavaScriptIdentifier(this HtmlDxPivotGridArea area) + { + switch (area) + { + case HtmlDxPivotGridArea.Row: + return "row"; + case HtmlDxPivotGridArea.Column: + return "column"; + case HtmlDxPivotGridArea.Data: + return "data"; + case HtmlDxPivotGridArea.Filter: + return "filter"; + default: + throw new ArgumentException("Unknown enumeration value", nameof(area)); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridOption.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridOption.cs new file mode 100644 index 000000000..86bed8480 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxPivotGridOption.cs @@ -0,0 +1,396 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Options for the template. + /// + public enum HtmlDxPivotGridOption + { + /// + /// Title of the report. + /// Default value is Issues Report. + /// + Title, + + /// + /// DevExtreme theme to use. + /// See for possible values. + /// Default value is . + /// + Theme, + + /// + /// Flag if the title should be shown as header on the top of the page. + /// Either true or false. + /// Default value is true. + /// + ShowHeader, + + ///// + ///// Flag if the search panel for full text searching should be visible or not. + ///// Either true or false. + ///// Default value is true. + ///// + //EnableSearching, + + ///// + ///// Flag if the group panel which allows end-user grouping should be visible or not. + ///// Either true or false. + ///// If false grouping defined by is still applied. + ///// Default value is true. + ///// + //EnableGrouping, + + /// + /// Flag if filtering should be available or not. + /// Either true or false. + /// Default value is true. + /// + EnableFiltering, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + ProviderTypeVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + ProviderTypeArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //ProviderTypeSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + ProviderNameVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + ProviderNameArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //ProviderNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + PriorityVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + PriorityArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //PrioritySortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + PriorityNameVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + PriorityNameArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //PriorityNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + ProjectPathVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + ProjectPathArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //ProjectPathSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + ProjectNameVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + ProjectNameArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //ProjectNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + FilePathVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + FilePathArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //FilePathSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + FileDirectoryVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + FileDirectoryArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //FileDirectorySortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + FileNameVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + FileNameArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //FileNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + LineVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + LineArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //LineSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + RuleVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + RuleArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //RuleSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + RuleUrlVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + RuleUrlArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //RuleUrlSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + MessageVisible, + + /// + /// Area where the column should be shown. + /// See for possible values. + /// Default value is . + /// + MessageArea, + + ///// + ///// Sort order of the column if it is part of . + ///// See for possible values. + ///// Default value is . + ///// + //MessageSortOrder, + + ///// + ///// List of which should be grouped. + ///// Grouped columns are always visible. + ///// Default value is . + ///// + //GroupedColumns, + + ///// + ///// List of which should be sorted. + ///// Default value is , , + ///// , , . + ///// + //SortedColumns, + + ///// + ///// List of for additional columsn which should be added to the grid. + ///// Default value is an empty list. + ///// + //AdditionalColumns, + + ///// + ///// Settings for having issues linked to files. + ///// Value needs to be an instance of . + ///// Default value is null. + ///// + //FileLinkSettings, + + /// + /// Location where jQuery can be found. + /// The following files need to be available: + /// + /// + /// {JQueryLocation}/jquery-{JQueryVersion}.min.js + /// + /// + /// Default value is https://ajax.aspnetcdn.com/ajax/jquery/. + /// + JQueryLocation, + + /// + /// Version of jQuery which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 3.1.0. + /// + JQueryVersion, + + /// + /// Location where the DevExtreme libraries can be found. + /// Below the location there needs to be a folder matching and + /// inside there subfolders js and css. + /// The following files need to be available: + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/js/dx.all.js + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/css/dx.common.css + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/css/{Theme} + /// + /// + /// Default value is https://cdn3.devexpress.com/jslib/. + /// + DevExtremeLocation, + + /// + /// Version of the DevExtreme libraries which should be used. + /// If setting this the matching needs to also be set. + /// Default value is 18.2.7. + /// + DevExtremeVersion + } +} diff --git a/src/Cake.Issues.Reporting.Generic/Templates/DxPivotGrid.cshtml b/src/Cake.Issues.Reporting.Generic/Templates/DxPivotGrid.cshtml new file mode 100644 index 000000000..95c198eb5 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Templates/DxPivotGrid.cshtml @@ -0,0 +1,331 @@ +@model IEnumerable + +@using Newtonsoft.Json +@using Cake.Issues.Reporting.Generic + + + +@{ + // Read options and apply default values. + var title = ViewBagHelper.ValueOrDefault(ViewBag.Title, "Issues Report"); + DevExtremeTheme theme = ViewBagHelper.ValueOrDefault(ViewBag.Theme, DevExtremeTheme.Light); + bool showHeader = ViewBagHelper.ValueOrDefault(ViewBag.ShowHeader, true); + //bool enableSearching = ViewBagHelper.ValueOrDefault(ViewBag.EnableSearching, true); + //bool enableGrouping = ViewBagHelper.ValueOrDefault(ViewBag.EnableGrouping, true); + bool enableFiltering = ViewBagHelper.ValueOrDefault(ViewBag.EnableFiltering, true); + bool providerTypeVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeVisible, false); + HtmlDxPivotGridArea providerTypeArea = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder providerTypeSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeSortOder, ColumnSortOrder.Ascending); + bool providerNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameVisible, true); + HtmlDxPivotGridArea providerNameArea = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameArea, HtmlDxPivotGridArea.Filter); + //ColumnSortOrder providerNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameSortOder, ColumnSortOrder.Ascending); + bool priorityVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityVisible, false); + HtmlDxPivotGridArea priorityArea = ViewBagHelper.ValueOrDefault(ViewBag.PriorityArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder prioritySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PrioritySortOrder, ColumnSortOrder.Descending); + bool priorityNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameVisible, true); + HtmlDxPivotGridArea priorityNameArea = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameArea, HtmlDxPivotGridArea.Column); + //ColumnSortOrder priorityNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameSortOrder, ColumnSortOrder.Descending); + bool projectPathVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathVisible, false); + HtmlDxPivotGridArea projectPathArea = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder projectPathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathSortOder, ColumnSortOrder.Ascending); + bool projectNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameVisible, true); + HtmlDxPivotGridArea projectNameArea = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder projectNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameSortOder, ColumnSortOrder.Ascending); + bool filePathVisible = ViewBagHelper.ValueOrDefault(ViewBag.FilePathVisible, true); + HtmlDxPivotGridArea filePathArea = ViewBagHelper.ValueOrDefault(ViewBag.FilePathArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder filePathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FilePathSortOder, ColumnSortOrder.Ascending); + bool fileDirectoryVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectoryVisible, false); + HtmlDxPivotGridArea fileDirectoryArea = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectoryArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder fileDirectorySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectorySortOder, ColumnSortOrder.Ascending); + bool fileNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileNameVisible, true); + HtmlDxPivotGridArea fileNameArea = ViewBagHelper.ValueOrDefault(ViewBag.FileNameArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder fileNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileNameSortOder, ColumnSortOrder.Ascending); + bool lineVisible = ViewBagHelper.ValueOrDefault(ViewBag.LineVisible, false); + HtmlDxPivotGridArea lineArea = ViewBagHelper.ValueOrDefault(ViewBag.LineArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder lineSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.LineSortOder, ColumnSortOrder.Ascending); + bool ruleVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleVisible, true); + HtmlDxPivotGridArea ruleArea = ViewBagHelper.ValueOrDefault(ViewBag.RuleArea, HtmlDxPivotGridArea.Data); + //ColumnSortOrder ruleSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleSortOder, ColumnSortOrder.Ascending); + bool ruleUrlVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlVisible, false); + HtmlDxPivotGridArea ruleUrlArea = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder ruleUrlSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlSortOder, ColumnSortOrder.Ascending); + bool messageVisible = ViewBagHelper.ValueOrDefault(ViewBag.MessageVisible, false); + HtmlDxPivotGridArea messageArea = ViewBagHelper.ValueOrDefault(ViewBag.MessageArea, HtmlDxPivotGridArea.Row); + //ColumnSortOrder messageSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.MessageSortOder, ColumnSortOrder.Ascending); + //var groupedColumns = ViewBagHelper.ValueOrDefault(ViewBag.GroupedColumns, new List { ReportColumn.ProviderName }); + //var sortedColumns = ViewBagHelper.ValueOrDefault(ViewBag.SortedColumns, new List { ReportColumn.PriorityName, ReportColumn.ProjectName, ReportColumn.FileDirectory, ReportColumn.FileName, ReportColumn.Line }); + //FileLinkSettings fileLinkSettings = ViewBagHelper.ValueOrDefault(ViewBag.FileLinkSettings, new FileLinkSettings()); + //List additionalColumns = ViewBagHelper.ValueOrDefault(ViewBag.AdditionalColumns, new List()); + string jQueryLocation = ViewBagHelper.ValueOrDefault(ViewBag.JQueryLocation, "https://ajax.aspnetcdn.com/ajax/jquery/"); + string jQueryVersion = ViewBagHelper.ValueOrDefault(ViewBag.JQueryVersion, "3.1.0"); + string devExtremeLocation = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeLocation, "https://cdn3.devexpress.com/jslib/"); + string devExtremeVersion = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeVersion, "18.2.7"); +} + +@{ + // Prepare issues. + var issues = + from issue in Model + select + issue.GetExpandoObject( + addProviderType: providerTypeVisible, + addProviderName: providerNameVisible, + addPriority: priorityVisible || priorityNameVisible, + addPriorityName: priorityNameVisible, + addProjectPath: projectPathVisible, + addProjectName: projectNameVisible, + addFilePath: filePathVisible, + addFileDirectory: fileDirectoryVisible, + addFileName: fileNameVisible, + addLine: lineVisible, + addRule: ruleVisible, + addRuleUrl: ruleVisible || ruleUrlVisible, + addMessage: messageVisible); + + if (!jQueryLocation.EndsWith("/")) + { + jQueryLocation += "/"; + } + + if (!devExtremeLocation.EndsWith("/")) + { + devExtremeLocation += "/"; + } +} + + + + + + @title + + @* DevExtreme dependencies *@ + + @* DevExtreme themes *@ + + + @* DevExtreme library *@ + + + + @if (showHeader) + { +

@title

+ } + +
+
+
+
+
+ + + + + \ No newline at end of file