diff --git a/docs/cs/AspNetCore/Widgets.md b/docs/cs/AspNetCore/Widgets.md
new file mode 100644
index 0000000000..9dfcddfa6d
--- /dev/null
+++ b/docs/cs/AspNetCore/Widgets.md
@@ -0,0 +1,274 @@
+# Widgety
+
+ABP poskytuje model a infastrukturu k vytváření **znovu použitelných widgetů**. Systém widgetů je rozšíření pro [ASP.NET Core pohledové komponenty](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components). Widgety jsou zvláště užitečné, když chcete;
+
+* Definovat widgety v znovu použitelných **[modulech](../Module-Development-Basics.md)**.
+* Mít závislosti na **skriptech & stylech** ve vašem widgetu.
+* Vytvářet **[řídící panely](Dashboards.md)** za použítí widgetů.
+* Spolupráci widgetů s **[authorizačními](../Authorization.md)** a **[svazovacími](Bundling-Minification.md)** systémy.
+
+## Základní definice widgetu
+
+### Tvorba pohledové komponenty
+
+Jako první krok, vytvoříme běžnou ASP.NET Core pohledovou komponentu:
+
+
+
+**MySimpleWidgetViewComponent.cs**:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+Dědění z `AbpViewComponent` není vyžadováno. Můžeme dědit ze standardního ASP.NET Core `ViewComponent`. `AbpViewComponent` pouze definuje pár základních a užitečných vlastnosti.
+
+**Default.cshtml**:
+
+```xml
+
+```
+
+### Definice widgetu
+
+Přidáme atribut `Widget` k třídě `MySimpleWidgetViewComponent` pro označení této pohledové komponenty jako widgetu:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+## Vykreslení widgetu
+
+Vykreslení widgetu je vcelku standardní. Použijeme metodu `Component.InvokeAsync` v razor pohledu/stránce jako s kteroukoliv jinou pohledovou komponentou. Příklady:
+
+````xml
+@await Component.InvokeAsync("MySimpleWidget")
+@await Component.InvokeAsync(typeof(MySimpleWidgetViewComponent))
+````
+
+První přístup používá název widgetu, zatímco druhý používá typ pohledové komponenty.
+
+## Název widgetu
+
+Výchozí název pohledových komponent je vypočítán na základě názvu typu pohledové komponenty. Pokud je typ pohledové komponenty `MySimpleWidgetViewComponent` potom název widgetu bude `MySimpleWidget` (odstraní se `ViewComponent` postfix). Takto ASP.NET Core vypočítává název pohledové komponenty.
+
+Chceme-li přizpůsobit název widgetu, stačí použít standardní atribut `ViewComponent` z ASP.NET Core:
+
+```csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget]
+ [ViewComponent(Name = "MyCustomNamedWidget")]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View("~/Pages/Components/MySimpleWidget/Default.cshtml");
+ }
+ }
+}
+```
+
+ABP bude respektovat přizpůsobený název při zpracování widgetu.
+
+> Pokud jsou názvy pohledové komponenty a složky, která pohledovou komponentu obsahuje rozdílné, pravděpodobně budete muset ručně uvést cestu pohledu tak jako je to provedeno v tomto příkladu.
+
+### Zobrazovaný název
+
+Můžeme také definovat čitelný & lokalizovatelný zobrazovaný název pro widget. Tento zobrazovaný název může být využít na uživatelském rozhraní kdykoliv je to potřeba. Zobrazovaný název je nepovinný a lze ho definovat pomocí vlastností atributu `Widget`:
+
+````csharp
+using DashboardDemo.Localization;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ DisplayName = "MySimpleWidgetDisplayName", // Lokalizační klíč
+ DisplayNameResource = typeof(DashboardDemoResource) // Lokalizační zdroj
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+Podívejte se na [dokument lokalizace](../Localization.md) pro více informací o lokalizačních zdrojích a klíčích.
+
+## Závislosti na stylech & skriptech
+
+Problémy když má widget soubory skriptů a stylů;
+
+* Každý stránka, která používá widget musí také přidat soubory **skriptů & stylů** tohoto widgetu.
+* Stránka se také musí postarat o **závislé knihovny/soubory** widgetu.
+
+ABP tyto problémy řeší, když správně propojíme zdroje s widgetem. O závislosti widgetu se při jeho používání nestaráme.
+
+### Definování jednoduchých cest souborů
+
+Níže uvedený příklad widgetu přidá stylové a skriptové soubory:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ StyleFiles = new[] { "/Pages/Components/MySimpleWidget/Default.css" },
+ ScriptFiles = new[] { "/Pages/Components/MySimpleWidget/Default.js" }
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+ABP bere v úvahu tyto závislosti a správně je přidává do pohledu/stránky při použití widgetu. Stylové/skriptové soubory mohou být **fyzické nebo virtuální**. Plně integrováno do [virtuálního systému souborů](../Virtual-File-System.md).
+
+### Definování přispěvatelů balíku
+
+Všechny zdroje použité ve widgetech na stránce jsou přidány jako **svazek** (svázány & minifikovány v produkci pokud nenastavíte jinak). Kromě přidání jednoduchého souboru můžete využít plnou funkčnost přispěvatelů balíčků.
+
+Níže uvedený ukázkový kód provádí totéž co výše uvedený kód, ale definuje a používá přispěvatele balíků:
+
+````csharp
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ StyleTypes = new []{ typeof(MySimpleWidgetStyleBundleContributor) },
+ ScriptTypes = new[]{ typeof(MySimpleWidgetScriptBundleContributor) }
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+
+ public class MySimpleWidgetStyleBundleContributor : BundleContributor
+ {
+ public override void ConfigureBundle(BundleConfigurationContext context)
+ {
+ context.Files
+ .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.css");
+ }
+ }
+
+ public class MySimpleWidgetScriptBundleContributor : BundleContributor
+ {
+ public override void ConfigureBundle(BundleConfigurationContext context)
+ {
+ context.Files
+ .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.js");
+ }
+ }
+}
+
+````
+
+Systém přispěvatelů balíků je velmi schopný. Pokud váš widget používá k vykreslení grafu JavaScript knihovnu, můžete ji deklarovat jako závislost, díky tomu se knihovna pokud nebyla dříve přidána automaticky přidá na stránku Tímto způsobem se stránka využívající váš widget nestará o závislosti.
+
+Podívejte se na dokumentaci [svazování & minifikace](Bundling-Minification.md) pro více informací o tomto systému.
+
+## Autorizace
+
+Některé widgety budou pravděpodobně muset být dostupné pouze pro ověřené nebo autorizované uživatele. V tomto případě použijte následující vlastnosti atributu `Widget`:
+
+* `RequiresAuthentication` (`bool`): Nastavte na true, aby byl tento widget použitelný pouze pro ověřené uživatele (uživatel je přihlášen do aplikace).
+* `RequiredPolicies` (`List`): Seznam názvů zásad k autorizaci uživatele. Další informace o zásadách naleznete v [dokumentu autorizace](../Authorization.md).
+
+Příklad:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(RequiredPolicies = new[] { "MyPolicyName" })]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+## Možnosti widgetu
+
+Jako alternativu k atributu `Widget` můžete ke konfiguraci widgetů použít `WidgetOptions`:
+
+```csharp
+Configure(options =>
+{
+ options.Widgets.Add();
+});
+```
+
+Toto vepište do metody `ConfigureServices` vašeho [modulu](../Module-Development-Basics.md). Veškerá konfigurace udělaná přes atribut `Widget` je dostupná i za pomoci `WidgetOptions`. Příklad konfigurace, která přidává styl pro widget:
+
+````csharp
+Configure(options =>
+{
+ options.Widgets
+ .Add()
+ .WithStyles("/Pages/Components/MySimpleWidget/Default.css");
+});
+````
+
+> Tip: `WidgetOptions` lze také použít k získání existujícího widgetu a ke změně jeho konfigurace. To je obzvláště užitečné, pokud chcete změnit konfiguraci widgetu uvnitř modulu používaného vaší aplikací. Použíjte `options.Widgets.Find` k získání existujícího `WidgetDefinition`.
\ No newline at end of file
diff --git a/docs/cs/docs-nav.json b/docs/cs/docs-nav.json
index 6f41d127e8..2d6b8f7ef8 100644
--- a/docs/cs/docs-nav.json
+++ b/docs/cs/docs-nav.json
@@ -220,6 +220,10 @@
"text": "Tag pomocníci",
"path": "AspNetCore/Tag-Helpers/Index.md"
},
+ {
+ "text": "Widgety",
+ "path": "AspNetCore/Widgets.md"
+ },
{
"text": "Motivy",
"path": "AspNetCore/Theming.md"
diff --git a/docs/en/AspNetCore/Dashboard-Widget-System.md b/docs/en/AspNetCore/Dashboard-Widget-System.md
deleted file mode 100644
index cbbab68c7f..0000000000
--- a/docs/en/AspNetCore/Dashboard-Widget-System.md
+++ /dev/null
@@ -1,559 +0,0 @@
-# Dashboard & Widget System
-
-Dashboard & Widget System allows you to create reusable widgets and dashboards.
-
-
-
-You can see a sample dashboard, build with that system, in the screenshot above. Top section, where the filters and refresh button is placed is global filter section and each card below is a widget. Both widgets and global filters are reusable components. Also dashboard layout is reusable too.
-
-Now we will see how those are defined, used in an application.
-
-## Dashboard Component
-
-Firstly, we will define a dashboard in our application (you can download a new application template from [abp.io/get-started](https://abp.io/get-started). To keep it simple, Please don't use tiered option).
-
-In *.Web project, we create **DashboardNames.cs** and **DashboardDefinitionProvider.cs** classes:
-
-```c#
- public static class DashboardNames
- {
- public const string MyDashboard = "MyDashboard";
-
- public static string[] GetAll()
- {
- return ReflectionHelper.GetPublicConstantsRecursively(typeof(DashboardNames));
- }
- }
-```
-
-```c#
- public static class DashboardDefinitionProvider
- {
- public static List GetDefinitions()
- {
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard")
- );
-
- return new List
- {
- myDashboard
- };
- }
- }
-```
-
-We need to add that definition to **DashboardOptions** in **ConfigureServices** method of ***WebModule.cs** file:
-
-```c#
-using Volo.Abp.AspNetCore.Mvc.UI.Dashboards;
-//...
- public class DashboardDemoWebModule : AbpModule
- {
- public override void ConfigureServices(ServiceConfigurationContext context)
- {
- //other codes..
- Configure(options =>
- {
- options.Dashboards.AddRange(DashboardDefinitionProvider.GetDefinitions());
- })
- //other codes..
- }
- //other codes..
- }
-```
-
-Then we can create the view file that the dashboard we have defined will be rendered, **Pages/MyDashboard.cshtml**:
-
-```html
-@page
-@using DashboardDemo.Dashboards
-@using Microsoft.Extensions.Localization
-@using Volo.Abp.AspNetCore.Mvc.UI.Dashboards
-@using Volo.Abp.AspNetCore.Mvc.UI.Widgets
-@inject IWidgetRenderer WidgetRenderer
-@inject IDashboardRenderer DashboardRenderer
-@inject IStringLocalizerFactory localizer
-@model DashboardDemo.Pages.MyDashboardModel
-@{
-}
-@section styles {
-
-}
-@section scripts {
-
-}
-
- @await DashboardRenderer.RenderAsync(Component, new { dashboardName = DashboardNames.MyDashboard })
-
-
-```
-
-**DashboardRenderer.RenderAsync** method renders the dashboard we have defined. Now we have to define the script and style bundles that you can see their usage in the code above:
-
-```c#
- [DependsOn(typeof(AbpBasicDashboardStyleContributor))]
- public class MyDashboardStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-```c#
- [DependsOn(typeof(AbpBasicDashboardScriptContributor))]
- public class MyDashboardScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-The dashboard system uses [Bundling & Minification](../Bundling-Minification.md) for scripts and styles. Dashboard contributors will be dependent on their widget and global filter contributors, and widget and global filters will be dependent on the other contributors they need. This guarantees that more than one widget can request a javascript library and it won't be duplicated.
-
-We need to add those contributors to bundling options in **ConfigureServices** method of ***WebModule.cs** file:
-
-```c#
- Configure(options =>
- {
- options.ScriptBundles.Add(DashboardNames.MyDashboard, configuration =>
- {
- configuration.AddContributors(typeof(MyDashboardScriptBundleContributor));
- });
-
- options.StyleBundles.Add(DashboardNames.MyDashboard, configuration =>
- {
- configuration.AddContributors(typeof(MyDashboardStyleBundleContributor));
- });
- });
-```
-
-Now we can start to create widgets.
-
-## Widgets
-
-Widgets are view components those are rendered in order when you add them to a dashboard. They also can be rendered anywhere you like.
-
-We will see how to create a widget and add it to the dashboard we created. We will create the "Monthly profit" widget in the screenshot at the beginning of this tutorial.
-
-Before creating our widget, we need a application service to return dummy data for our widget.
-
-```c#
-namespace DashboardDemo
-{
- public interface IDemoStatisticAppService : IApplicationService
- {
- Task GetMonthlyUserStatistic(FilterDto filter);
-
- Task GetMonthlyProfitStatistic(FilterDto filter);
- }
-
- public class DemoStatisticAppService : ApplicationService, IDemoStatisticAppService
- {
- public async Task GetMonthlyProfitStatistic(FilterDto filter)
- {
- var monthCount = GetLabels(filter, out var monthList);
-
- var data = Enumerable
- .Repeat(0, monthCount)
- .Select(i => new Random().Next(-20, 40))
- .ToArray();
-
- return new MonthlyProfitStatisticDto { Labels = monthList.ToArray(), Data = data };
- }
-
- private static int GetLabels(FilterDto filter, out List monthList)
- {
- DateTime endDate = filter.EndDate ?? DateTime.Now;
- DateTime startDate = filter.StartDate ?? DateTime.Now.AddYears(-1);
-
- if (filter.StartDate > filter.EndDate)
- {
- throw new BusinessException("Start date can not be greater than end date.");
- }
-
- var months = new[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
- var monthCount = (endDate.Year - startDate.Year) * 12 + endDate.Month - startDate.Month +1;
- monthList = new List();
-
- for (int i = 0; i < monthCount; i++)
- {
- monthList.Add(months[endDate.Month-1]);
- endDate = endDate.AddMonths(-1);
- }
-
- monthList.Reverse();
-
- return monthCount;
- }
- }
-
- public class MonthlyProfitStatisticDto
- {
- public string[] Labels { get; set; }
-
- public int[] Data { get; set; }
- }
-
- public class FilterDto
- {
- public DateTime? StartDate { get; set; }
-
- public DateTime? EndDate { get; set; }
- }
-}
-```
-
-We will use **FilterDto** in **Global Filters** section.
-
-Now we can start to work on our widget.
-
-
-
-You can see the files that we will create our widget. (If your widget won't need css or javascript, you don't need to create them and contributors as well.)
-
-First we create the **MonthlyProfitWidgetViewComponent**:
-
-```html
-@inject IHtmlLocalizer L
-@using DashboardDemo.Localization.DashboardDemo
-@using Microsoft.AspNetCore.Mvc.Localization
-@model DashboardDemo.Pages.widgets.MonthlyProfitWidgetViewComponent
-@{
-}
-
-
-```
-
-```c#
- public class MonthlyProfitWidgetViewComponent : AbpViewComponent
- {
- public const string Name = "MonthlyProfitWidget";
-
- public const string DisplayName = "Monthly Profit Widget";
-
- public IViewComponentResult Invoke()
- {
- return View("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidgetViewComponent.cshtml", new MonthlyProfitWidgetViewComponent());
- }
- }
-```
-
-We will use [chart.js library](https://www.chartjs.org/) to create the chart. To add this library to our project, we add the package dependency to **package.json**:
-
-```json
- "dependencies": {
- //other dependencies...
- "chart.js": "^2.8.0"
- }
-```
-
-Then add the mapping **abp.resourcemappings.js**: (see [related doc](/AspNetCore/Client-Side-Package-Management#resource-mapping-definition-file))
-
-```js
- mappings: {
- //other mappings...
- "@node_modules/chart.js/dist/*.*": "@libs/chart.js/"
- }
-```
-
-Now we have chart.js library in our application. In order to use it, we will create it's contributors:
-
-```c#
- public class ChartjsScriptContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/libs/chart.js/Chart.js");
- }
- }
-
- public class ChartjsStyleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/libs/chart.js/Chart.css");
- }
- }
-```
-
-Well. Now we create the contributors for our widget files and make them dependent on chart.js:
-
-```c#
- [DependsOn(typeof(JQueryScriptContributor))]
- [DependsOn(typeof(ChartjsScriptContributor))]
- public class MonthlyProfitWidgetScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidget.js");
- }
- }
-
- [DependsOn(typeof(BootstrapStyleContributor))]
- [DependsOn(typeof(ChartjsStyleContributor))]
- public class MonthlyProfitWidgetStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidget.css");
- }
- }
-```
-
-**MonthlyProfitWidget.css** is empty for our widget.
-
-**MonthlyProfitWidget.js** content is below:
-
-```js
-(function ($) {
- var $container = $('#MonthlyProfitWidgetContainer');
- if ($container.length > 0) {
- var chart = {};
-
- var createChart = function () {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({}).then(function (result) {
- chart = new Chart($container.find('#MonthlyProfitStatistics'), {
- type: 'line',
- data: {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero: true
- }
- }]
- }
- }
- });
- });
- };
-
- createChart();
- }
-})(jQuery);
-
-```
-
-We have created our widget. There is one last thing before adding it to dashboard; we need to define it:
-
-```c#
- public static class WidgetDefinitionProvider
- {
- public static List GetDefinitions()
- {
- //other widgets...
-
- var monthlyProfitWidget = new WidgetDefinition(
- MonthlyProfitWidgetViewComponent.Name,
- LocalizableString.Create(MonthlyProfitWidgetViewComponent.DisplayName),
- typeof(MonthlyProfitWidgetViewComponent)
- )
- .SetDefaultDimension(6, 4)
- .AddRequiredPermission(IdentityPermissions.Users.Default);
-
- return new List
- {
- //other widgets...
- monthlyProfitWidget
- };
- }
- }
-```
-
-**.SetDefaultDimension(int x, int y):** Sets the dimensions of the widget. This will be used when rendering it in dashboard. X is for column width in bootstrap, can be between 1 and 12. Y is height in pixels, will be multiplied by 100.
-
-**AddRequiredPermission(string permissionName)**: Sets the permission for widget. So a user that doesn't have this permission will not see this widget.
-
-We need to add the widget definitions to **WidgetOptions** in **ConfigureServices** method of ***WebModule.cs** file as well:
-
-```c#
- Configure(options =>
- {
- options.Widgets.AddRange(WidgetDefinitionProvider.GetDefinitions());
- });
-```
-
-Now our widget is ready to use. We will use **WithWidget** method to add it to our dashboard in **DashboardDefinitionProvider.cs**:
-
-```c#
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard"))
- .WithWidget(MonthlyProfitWidgetViewComponent.Name);
-```
-
-And add the javascript and contributor dependencies to dashboard:
-
-```c#
- [DependsOn(typeof(MonthlyProfitWidgetScriptBundleContributor))] // <<<<<<
- [DependsOn(typeof(AbpBasicDashboardScriptContributor))]
- public class MyDashboardScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-
- [DependsOn(typeof(MonthlyProfitWidgetStyleBundleContributor))] // <<<<<<
- [DependsOn(typeof(AbpBasicDashboardStyleContributor))]
- public class MyDashboardStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-Now start your application and go to **/MyDashboard** page.
-
-## Global Filters
-
-Global filters are used for filtering all widgets with same input. If you add a global filter to a dashboard, a refresh button will appear for refreshing widgets with new filter values. When this button is clicked, it serializes filters to object and fires an event with that object as parameter.
-
-Let's implement a **date range** global filter.
-
-First, we need to create **DateRangeGlobalFilterViewComponent.cshtml**:
-
-```html
-@inject IHtmlLocalizer L
-@using DashboardDemo.Localization.DashboardDemo
-@using Microsoft.AspNetCore.Mvc.Localization
-@model DashboardDemo.Pages.widgets.Filters.DateRangeGlobalFilterViewComponent
-@{
-}
-
-
-
-```
-
-```c#
-namespace DashboardDemo.Pages.widgets.Filters
-{
- [ViewComponent]
- public class DateRangeGlobalFilterViewComponent : ViewComponent
- {
- public const string Name = "DateRangeGlobalFilter";
-
- public const string DisplayName = "Date Range Filter";
-
- public IViewComponentResult Invoke()
- {
- return View("/Pages/widgets/Filters/DateRangeGlobalFilterViewComponent.cshtml", new DateRangeGlobalFilterViewComponent());
- }
- }
-}
-```
-
-You can add javascript and css files in the same way you add them to widgets, but in this example they are not needed.
-
-We will add the global filter definitions to **GlobalFilterOptions** in **ConfigureServices** method of ***WebModule.cs** file as well:
-
-```c#
- Configure(options =>
- {
- options.GlobalFilters.AddRange(GlobalFilterDefinitionProvider.GetDefinitions());
- });
-```
-
-And add it to our dashboard in **DashboardDefinitionProvider.cs** using **WithGlobalFilter** method:
-
-```c#
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard"))
- .WithWidget(MonthlyProfitWidgetViewComponent.Name)
- .WithGlobalFilter(DateRangeGlobalFilterViewComponent.Name);
-```
-
-That's it! Now let's catch the refresh event in our widget:
-
-```js
-(function ($) {
- var $container = $('#MonthlyProfitWidgetContainer');
- if ($container.length > 0) {
- var chart = {};
-
- var createChart = function () {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({}).then(function (result) {
- chart = new Chart($container.find('#MonthlyProfitStatistics'), {
- type: 'line',
- data: {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero: true
- }
- }]
- }
- }
- });
- });
- };
-
- $(document).on('RefreshWidgets',
- function (event, filters) {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({ startDate: filters.startDate, endDate: filters.endDate }).then(function (result) {
- chart.data = {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- chart.update();
- });
- });
-
- createChart();
- }
-})(jQuery);
-
-```
-
-## Source Code
-
-You can see a sample application for dashboard at [Github](https://github.com/abpframework/abp/tree/dev/samples/DashboardDemo).
\ No newline at end of file
diff --git a/docs/en/AspNetCore/Dashboards.md b/docs/en/AspNetCore/Dashboards.md
new file mode 100644
index 0000000000..26b6a77461
--- /dev/null
+++ b/docs/en/AspNetCore/Dashboards.md
@@ -0,0 +1,3 @@
+# Dashboards
+
+TODO
\ No newline at end of file
diff --git a/docs/en/AspNetCore/Widgets.md b/docs/en/AspNetCore/Widgets.md
new file mode 100644
index 0000000000..00f0433e2e
--- /dev/null
+++ b/docs/en/AspNetCore/Widgets.md
@@ -0,0 +1,274 @@
+# Widgets
+
+ABP provides a model and infrastructure to create **reusable widgets**. Widget system is an extension to [ASP.NET Core's ViewComponents](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components). Widgets are especially useful when you want to;
+
+* Define widgets in reusable **[modules](../Module-Development-Basics.md)**.
+* Have **scripts & styles** dependencies for your widget.
+* Create **[dashboards](Dashboards.md)** with widgets used inside.
+* Co-operate widgets with **[authorization](../Authorization.md)** and **[bundling](Bundling-Minification.md)** systems.
+
+## Basic Widget Definition
+
+### Create a View Component
+
+As the first step, create a new regular ASP.NET Core View Component:
+
+
+
+**MySimpleWidgetViewComponent.cs**:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+Inheriting from `AbpViewComponent` is not required. You could inherit from ASP.NET Core's standard `ViewComponent`. `AbpViewComponent` only defines some base useful properties.
+
+**Default.cshtml**:
+
+```xml
+
+```
+
+### Define the Widget
+
+Add a `Widget` attribute to the `MySimpleWidgetViewComponent` class to mark this view component as a widget:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+## Rendering a Widget
+
+Rendering a widget is pretty standard. Use the `Component.InvokeAsync` method in a razor view/page as you do for any view component. Examples:
+
+````xml
+@await Component.InvokeAsync("MySimpleWidget")
+@await Component.InvokeAsync(typeof(MySimpleWidgetViewComponent))
+````
+
+First approach uses the widget name while second approach uses the view component type.
+
+## Widget Name
+
+Default name of the view components are calculated based on the name of the view component type. If your view component type is `MySimpleWidgetViewComponent` then the widget name will be `MySimpleWidget` (removes `ViewComponent` postfix). This is how ASP.NET Core calculates a view component's name.
+
+To customize widget's name, just use the standard `ViewComponent` attribute of ASP.NET Core:
+
+```csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget]
+ [ViewComponent(Name = "MyCustomNamedWidget")]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View("~/Pages/Components/MySimpleWidget/Default.cshtml");
+ }
+ }
+}
+```
+
+ABP will respect to the custom name by handling the widget.
+
+> If the view component name and the folder name of the view component don't match, you may need to manually write the view path as done in this example.
+
+### Display Name
+
+You can also define a human-readable, localizable display name for the widget. This display name then can be used on the UI when needed. Display name is optional and can be defined using properties of the `Widget` attribute:
+
+````csharp
+using DashboardDemo.Localization;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ DisplayName = "MySimpleWidgetDisplayName", //Localization key
+ DisplayNameResource = typeof(DashboardDemoResource) //localization resource
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+See [the localization document](../Localization.md) to learn about localization resources and keys.
+
+## Style & Script Dependencies
+
+There are some challenges when your widget has script and style files;
+
+* Any page uses the widget should also include the **its script & styles** files into the page.
+* The page should also care about **depended libraries/files** of the widget.
+
+ABP solves these issues when you properly relate the resources with the widget. You don't care about dependencies of the widget while using it.
+
+### Defining as Simple File Paths
+
+The example widget below adds a style and a script file:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ StyleFiles = new[] { "/Pages/Components/MySimpleWidget/Default.css" },
+ ScriptFiles = new[] { "/Pages/Components/MySimpleWidget/Default.js" }
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+ABP takes account these dependencies and properly adds to the view/page when you use the widget. Style/script files can be **physical or virtual**. It is completely integrated to the [Virtual File System](../Virtual-File-System.md).
+
+### Defining Bundle Contributors
+
+All resources for used widgets in a page are added as a **bundle** (bundled & minified in production if you don't configure otherwise). In addition to adding a simple file, you can take full power of the bundle contributors.
+
+The sample code below does the same with the code above, but defines and uses bundle contributors:
+
+````csharp
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(
+ StyleTypes = new []{ typeof(MySimpleWidgetStyleBundleContributor) },
+ ScriptTypes = new[]{ typeof(MySimpleWidgetScriptBundleContributor) }
+ )]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+
+ public class MySimpleWidgetStyleBundleContributor : BundleContributor
+ {
+ public override void ConfigureBundle(BundleConfigurationContext context)
+ {
+ context.Files
+ .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.css");
+ }
+ }
+
+ public class MySimpleWidgetScriptBundleContributor : BundleContributor
+ {
+ public override void ConfigureBundle(BundleConfigurationContext context)
+ {
+ context.Files
+ .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.js");
+ }
+ }
+}
+
+````
+
+Bundle contribution system is very powerful. If your widget uses a JavaScript library to render a chart, then you can declare it as a dependency, so the JavaScript library is automatically added to the page if it wasn't added before. In this way, the page using your widget doesn't care about the dependencies.
+
+See the [bundling & minification](Bundling-Minification.md) documentation for more information about that system.
+
+## Authorization
+
+Some widgets may need to be available only for authenticated or authorized users. In this case, use the following properties of the `Widget` attribute:
+
+* `RequiresAuthentication` (`bool`): Set to true to make this widget usable only for authentication users (user have logged in to the application).
+* `RequiredPolicies` (`List`): A list of policy names to authorize the user. See [the authorization document](../Authorization.md) for more info about policies.
+
+Example:
+
+````csharp
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace DashboardDemo.Web.Pages.Components.MySimpleWidget
+{
+ [Widget(RequiredPolicies = new[] { "MyPolicyName" })]
+ public class MySimpleWidgetViewComponent : AbpViewComponent
+ {
+ public IViewComponentResult Invoke()
+ {
+ return View();
+ }
+ }
+}
+````
+
+## Widget Options
+
+As alternative to the `Widget` attribute, you can use the `WidgetOptions` to configure widgets:
+
+```csharp
+Configure(options =>
+{
+ options.Widgets.Add();
+});
+```
+
+Write this into the `ConfigureServices` method of your [module](../Module-Development-Basics.md). All the configuration done with the `Widget` attribute is also possible with the `WidgetOptions`. Example configuration that adds a style for the widget:
+
+````csharp
+Configure(options =>
+{
+ options.Widgets
+ .Add()
+ .WithStyles("/Pages/Components/MySimpleWidget/Default.css");
+});
+````
+
+> Tip: `WidgetOptions` can also be used to get an existing widget and change its configuration. This is especially useful if you want to modify the configuration of a widget inside a module used by your application. Use `options.Widgets.Find` to get an existing `WidgetDefinition`.
\ No newline at end of file
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index efa9b7d023..103556823e 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -221,8 +221,8 @@
"path": "AspNetCore/Tag-Helpers/Index.md"
},
{
- "text": "Dashboard & Widget System",
- "path": "AspNetCore/Tag-Helpers/DashboardWidgetSystem.md"
+ "text": "Widgets",
+ "path": "AspNetCore/Widgets.md"
},
{
"text": "Theming",
diff --git a/docs/en/images/widget-basic-files.png b/docs/en/images/widget-basic-files.png
new file mode 100644
index 0000000000..bf5f122d42
Binary files /dev/null and b/docs/en/images/widget-basic-files.png differ
diff --git a/docs/zh-Hans/AspNetCore/Dashboard-Widget-System.md b/docs/zh-Hans/AspNetCore/Dashboard-Widget-System.md
deleted file mode 100644
index a804f9aedd..0000000000
--- a/docs/zh-Hans/AspNetCore/Dashboard-Widget-System.md
+++ /dev/null
@@ -1,559 +0,0 @@
-# 仪表板和小部件(Widget)系统
-
-仪表板和小部件(Widget)系统允许你创建可重用的小部件和仪表板。
-
-
-
-你可以在上面的屏幕截图中看到使用该系统构建的示例仪表板. 放置过滤器和刷新按钮的顶部是全局过滤器部分,下面的每个卡片都是一个小部件. 小部件和全局过滤器都是可重用的组件.仪表板布局也可以重复使用.
-
-现在我们将看到如何在应用程序中使用它们.
-
-## 仪表板组件
-
-首先,我们将在应用程序中定义仪表板,你可以从[abp.io/get-started](https://abp.io/get-started)下载新的应用程序模板. 为简单起见,请不要使用分层选项.
-
-在 *.Web项目中, 我们创建**DashboardNames.cs**和**DashboardDefinitionProvider.cs**类:
-
-```c#
- public static class DashboardNames
- {
- public const string MyDashboard = "MyDashboard";
-
- public static string[] GetAll()
- {
- return ReflectionHelper.GetPublicConstantsRecursively(typeof(DashboardNames));
- }
- }
-```
-
-```c#
- public static class DashboardDefinitionProvider
- {
- public static List GetDefinitions()
- {
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard")
- );
-
- return new List
- {
- myDashboard
- };
- }
- }
-```
-
-我们需要将该定义添加到**WebModule.cs**文件中**ConfigureServices**方法的**DashboardOptions**:
-
-```c#
-using Volo.Abp.AspNetCore.Mvc.UI.Dashboards;
-//...
- public class DashboardDemoWebModule : AbpModule
- {
- public override void ConfigureServices(ServiceConfigurationContext context)
- {
- //other codes..
- Configure(options =>
- {
- options.Dashboards.AddRange(DashboardDefinitionProvider.GetDefinitions());
- })
- //other codes..
- }
- //other codes..
- }
-```
-
-然后我们可以创建我们定义的仪表板它将被渲染 **Pages/MyDashboard.cshtml**:
-
-```html
-@page
-@using DashboardDemo.Dashboards
-@using Microsoft.Extensions.Localization
-@using Volo.Abp.AspNetCore.Mvc.UI.Dashboards
-@using Volo.Abp.AspNetCore.Mvc.UI.Widgets
-@inject IWidgetRenderer WidgetRenderer
-@inject IDashboardRenderer DashboardRenderer
-@inject IStringLocalizerFactory localizer
-@model DashboardDemo.Pages.MyDashboardModel
-@{
-}
-@section styles {
-
-}
-@section scripts {
-
-}
-
- @await DashboardRenderer.RenderAsync(Component, new { dashboardName = DashboardNames.MyDashboard })
-
-
-```
-
-**DashboardRenderer.RenderAsync** 方法呈现我们定义的仪表板. 现在我们必须定义script和style bundles. 你可以在上面的代码中看到它们的用法:
-
-```c#
- [DependsOn(typeof(AbpBasicDashboardStyleContributor))]
- public class MyDashboardStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-```c#
- [DependsOn(typeof(AbpBasicDashboardScriptContributor))]
- public class MyDashboardScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-仪表板系统使用[Bundling & Minification](../Bundling-Minification.md)作为脚本和样式. 仪表板贡献者将依赖于他们的小部件和全局过滤器贡献者, 小部件和全局过滤器将依赖于他们需要的其他贡献者. 这可以保证多个小部件可以请求javascript库, 并且不会重复.
-
-我们需要将这些贡献者添加到**WebModule.cs**文件的**ConfigureServices**方法中的bundling选项:
-
-```c#
- Configure(options =>
- {
- options.ScriptBundles.Add(DashboardNames.MyDashboard, configuration =>
- {
- configuration.AddContributors(typeof(MyDashboardScriptBundleContributor));
- });
-
- options.StyleBundles.Add(DashboardNames.MyDashboard, configuration =>
- {
- configuration.AddContributors(typeof(MyDashboardStyleBundleContributor));
- });
- });
-```
-
-现在我们可以开始创建小部件了.
-
-## 小部件
-
-小部件是在将它们添加到仪表板时按顺序呈现的视图组件. 它们也可以在任何你喜欢的地方呈现.
-
-我们将看到如何创建小部件并将其添加到我们创建的仪表板中. 我们将在本教程开头的屏幕截图中创建"每月利润"小部件.
-
-在创建小部件之前,我们需要一个应用程序服务来返回小部件的虚拟数据.
-
-```c#
-namespace DashboardDemo
-{
- public interface IDemoStatisticAppService : IApplicationService
- {
- Task GetMonthlyUserStatistic(FilterDto filter);
-
- Task GetMonthlyProfitStatistic(FilterDto filter);
- }
-
- public class DemoStatisticAppService : ApplicationService, IDemoStatisticAppService
- {
- public async Task GetMonthlyProfitStatistic(FilterDto filter)
- {
- var monthCount = GetLabels(filter, out var monthList);
-
- var data = Enumerable
- .Repeat(0, monthCount)
- .Select(i => new Random().Next(-20, 40))
- .ToArray();
-
- return new MonthlyProfitStatisticDto { Labels = monthList.ToArray(), Data = data };
- }
-
- private static int GetLabels(FilterDto filter, out List monthList)
- {
- DateTime endDate = filter.EndDate ?? DateTime.Now;
- DateTime startDate = filter.StartDate ?? DateTime.Now.AddYears(-1);
-
- if (filter.StartDate > filter.EndDate)
- {
- throw new BusinessException("Start date can not be greater than end date.");
- }
-
- var months = new[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
- var monthCount = (endDate.Year - startDate.Year) * 12 + endDate.Month - startDate.Month +1;
- monthList = new List();
-
- for (int i = 0; i < monthCount; i++)
- {
- monthList.Add(months[endDate.Month-1]);
- endDate = endDate.AddMonths(-1);
- }
-
- monthList.Reverse();
-
- return monthCount;
- }
- }
-
- public class MonthlyProfitStatisticDto
- {
- public string[] Labels { get; set; }
-
- public int[] Data { get; set; }
- }
-
- public class FilterDto
- {
- public DateTime? StartDate { get; set; }
-
- public DateTime? EndDate { get; set; }
- }
-}
-```
-
-我们将在**Global Filters**中使用**FilterDto**.
-
-现在我们可以开始处理我们的小部件了.
-
-
-
-你可以看到我们将创建小部件的文件. (如果你的小部件不需要css或javascript,则不需要创建它们和贡献者).
-
-首先我们创建 **MonthlyProfitWidgetViewComponent**:
-
-```html
-@inject IHtmlLocalizer L
-@using DashboardDemo.Localization.DashboardDemo
-@using Microsoft.AspNetCore.Mvc.Localization
-@model DashboardDemo.Pages.widgets.MonthlyProfitWidgetViewComponent
-@{
-}
-
-
-```
-
-```c#
- public class MonthlyProfitWidgetViewComponent : AbpViewComponent
- {
- public const string Name = "MonthlyProfitWidget";
-
- public const string DisplayName = "Monthly Profit Widget";
-
- public IViewComponentResult Invoke()
- {
- return View("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidgetViewComponent.cshtml", new MonthlyProfitWidgetViewComponent());
- }
- }
-```
-
-我们将使用[chart.js library](https://www.chartjs.org/)来创建图表. 要将此库添加到项目中,我们将包依赖项添加到**package.json**:
-
-```json
- "dependencies": {
- //other dependencies...
- "chart.js": "^2.8.0"
- }
-```
-
-然后添加映射到**abp.resourcemappings.js**:(参见[相关文档](/AspNetCore/Client-Side-Package-Management#resource-mapping-definition-file))
-
-```js
- mappings: {
- //other mappings...
- "@node_modules/chart.js/dist/*.*": "@libs/chart.js/"
- }
-```
-
-现在我们的应用程序中有chart.js库. 为了使用它,我们将创建它的贡献者:
-
-```c#
- public class ChartjsScriptContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/libs/chart.js/Chart.js");
- }
- }
-
- public class ChartjsStyleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/libs/chart.js/Chart.css");
- }
- }
-```
-
-现在我们为小部件文件创建贡献者并使它们依赖于chart.js:
-
-```c#
- [DependsOn(typeof(JQueryScriptContributor))]
- [DependsOn(typeof(ChartjsScriptContributor))]
- public class MonthlyProfitWidgetScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidget.js");
- }
- }
-
- [DependsOn(typeof(BootstrapStyleContributor))]
- [DependsOn(typeof(ChartjsStyleContributor))]
- public class MonthlyProfitWidgetStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.Add("/Pages/widgets/MonthlyProfitWidget/MonthlyProfitWidget.css");
- }
- }
-```
-
-**MonthlyProfitWidget.css** 对于我们的小部件是空的.
-
-**MonthlyProfitWidget.js** 内容如下:
-
-```js
-(function ($) {
- var $container = $('#MonthlyProfitWidgetContainer');
- if ($container.length > 0) {
- var chart = {};
-
- var createChart = function () {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({}).then(function (result) {
- chart = new Chart($container.find('#MonthlyProfitStatistics'), {
- type: 'line',
- data: {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero: true
- }
- }]
- }
- }
- });
- });
- };
-
- createChart();
- }
-})(jQuery);
-
-```
-
-我们创建了小部件. 在将其添加到仪表板之前还有最后一件事, 我们需要定义它:
-
-```c#
- public static class WidgetDefinitionProvider
- {
- public static List GetDefinitions()
- {
- //other widgets...
-
- var monthlyProfitWidget = new WidgetDefinition(
- MonthlyProfitWidgetViewComponent.Name,
- LocalizableString.Create(MonthlyProfitWidgetViewComponent.DisplayName),
- typeof(MonthlyProfitWidgetViewComponent)
- )
- .SetDefaultDimension(6, 4)
- .AddRequiredPermission(IdentityPermissions.Users.Default);
-
- return new List
- {
- //other widgets...
- monthlyProfitWidget
- };
- }
- }
-```
-
-**SetDefaultDimension(int x, int y):** 设置小部件的尺寸. 在仪表板中渲染时将使用此选项. X表示bootstrap中的列宽,可以在1到12之间.Y是以像素为单位的高度,将乘以100.
-
-**AddRequiredPermission(string permissionName)**: 设置窗口小部件的权限. 因此, 没有此权限的用户将看不到此小部件.
-
-我们需要在**WebModule.cs**文件的**ConfigureServices**方法中将小部件定义添加到**WidgetOptions**:
-
-```c#
- Configure(options =>
- {
- options.Widgets.AddRange(WidgetDefinitionProvider.GetDefinitions());
- });
-```
-
-现在我们的小部件已经可以使用了. 我们将使用**DashboardDefinitionProvider.cs**中**WithWidget**方法将其添加到仪表板中:
-
-```c#
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard"))
- .WithWidget(MonthlyProfitWidgetViewComponent.Name);
-```
-
-并将javascript和contributor依赖项添加到仪表板:
-
-```c#
- [DependsOn(typeof(MonthlyProfitWidgetScriptBundleContributor))] // <<<<<<
- [DependsOn(typeof(AbpBasicDashboardScriptContributor))]
- public class MyDashboardScriptBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-
- [DependsOn(typeof(MonthlyProfitWidgetStyleBundleContributor))] // <<<<<<
- [DependsOn(typeof(AbpBasicDashboardStyleContributor))]
- public class MyDashboardStyleBundleContributor : BundleContributor
- {
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
-
- }
- }
-```
-
-现在启动应用程序并转到 **/MyDashboard**页面.
-
-## 全局过滤器
-
-全局过滤器用于过滤具有相同输入的所有小部件. 如果向仪表板添加全局过滤器,则会显示刷新按钮,以使用新过滤器值刷新窗口小部件. 单击此按钮时,它会将过滤器序列化为对象,并以该对象作为参数触发事件.
-
-我们来实现一个**date range**全局过滤器.
-
-首先我们创建 **DateRangeGlobalFilterViewComponent.cshtml**:
-
-```html
-@inject IHtmlLocalizer L
-@using DashboardDemo.Localization.DashboardDemo
-@using Microsoft.AspNetCore.Mvc.Localization
-@model DashboardDemo.Pages.widgets.Filters.DateRangeGlobalFilterViewComponent
-@{
-}
-
-
-
-```
-
-```c#
-namespace DashboardDemo.Pages.widgets.Filters
-{
- [ViewComponent]
- public class DateRangeGlobalFilterViewComponent : ViewComponent
- {
- public const string Name = "DateRangeGlobalFilter";
-
- public const string DisplayName = "Date Range Filter";
-
- public IViewComponentResult Invoke()
- {
- return View("/Pages/widgets/Filters/DateRangeGlobalFilterViewComponent.cshtml", new DateRangeGlobalFilterViewComponent());
- }
- }
-}
-```
-
-您可以像添加到窗口小部件一样添加javascript和css文件,但在此示例中不需要它们.
-
-我们将在**WebModule.cs**文件的**ConfigureServices**方法中将全局过滤器定义添加到**GlobalFilterOptions**:
-
-```c#
- Configure(options =>
- {
- options.GlobalFilters.AddRange(GlobalFilterDefinitionProvider.GetDefinitions());
- });
-```
-
-并使用**WithGlobalFilter**方法将其添加到**DashboardDefinitionProvider.cs**中的仪表板中:
-
-```c#
- var myDashboard = new DashboardDefinition(
- DashboardNames.MyDashboard,
- LocalizableString.Create("MyDashboard"))
- .WithWidget(MonthlyProfitWidgetViewComponent.Name)
- .WithGlobalFilter(DateRangeGlobalFilterViewComponent.Name);
-```
-
-现在让我们在小部件中捕获刷新事件:
-
-```js
-(function ($) {
- var $container = $('#MonthlyProfitWidgetContainer');
- if ($container.length > 0) {
- var chart = {};
-
- var createChart = function () {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({}).then(function (result) {
- chart = new Chart($container.find('#MonthlyProfitStatistics'), {
- type: 'line',
- data: {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero: true
- }
- }]
- }
- }
- });
- });
- };
-
- $(document).on('RefreshWidgets',
- function (event, filters) {
- dashboardDemo.demoStatistic.getMonthlyProfitStatistic({ startDate: filters.startDate, endDate: filters.endDate }).then(function (result) {
- chart.data = {
- labels: result.labels,
- datasets: [{
- label: 'Monthly Profit',
- data: result.data,
- backgroundColor: 'rgba(255, 255, 132, 0.2)'
- }]
- },
- chart.update();
- });
- });
-
- createChart();
- }
-})(jQuery);
-
-```
-
-## 源代码
-
-你可以在[Github](https://github.com/abpframework/abp/tree/dev/samples/DashboardDemo)查看仪表板的示例应用程序
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs
similarity index 80%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs
index 2e2087435b..8261706431 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs
@@ -1,6 +1,6 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{
- public static class BundleContributorListExtensions
+ public static class BundleContributorCollectionExtensions
{
public static void AddFiles(this BundleContributorCollection contributors, params string[] files)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs
index 7a61445c8e..dd6bdbb206 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs
@@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
{
var dashboard = _dashboardOptions.Dashboards.Single(d => d.Name.Equals(dashboardName));
- var model = new DashboardViewModel(dashboard, _widgetOptions.Widgets, _globalFilterOptions.GlobalFilters);
+ var model = new DashboardViewModel(dashboard, _widgetOptions.Widgets.GetAll().ToList(), _globalFilterOptions.GlobalFilters);
return View("~/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml", model);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs
index 2bde6c959a..c7caae2dc4 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs
@@ -34,7 +34,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
public async Task CheckPermissionsAsync(IAuthorizationService authorizationService, WidgetDefinition widget)
{
- foreach (var permission in widget.RequiredPermissions)
+ foreach (var permission in widget.RequiredPolicies)
{
if (!await authorizationService.IsGrantedAsync(permission))
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml
index 65e694b66d..b077947700 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml
@@ -5,7 +5,6 @@
@using Volo.Abp.AspNetCore.Mvc.UI.Dashboards
@using Volo.Abp.AspNetCore.Mvc.UI.Widgets
@inject IAuthorizationService AuthorizationService
-@inject IWidgetRenderer WidgetRenderer
@inject IGlobalFilterRenderer GlobalFilteRenderer
@inject IHtmlLocalizer L
@model Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard.DashboardViewModel
@@ -47,7 +46,7 @@
- @await WidgetRenderer.RenderAsync(Component, widgetDefinition.Name)
+ @await Component.InvokeAsync(widgetDefinition.Name)
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
index 6eb41a7546..2e95453185 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
@@ -9,6 +9,8 @@
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.PageAlerts
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
+@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts
+@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles
@using Volo.Abp.MultiTenancy
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@inject IBrandingProvider BrandingProvider
@@ -39,6 +41,8 @@
@await RenderSectionAsync("styles", false)
+ @await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
+
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account)
@@ -50,7 +54,7 @@
@if (MultiTenancyOptions.Value.IsEnabled &&
- (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true))
+ (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true))
{
@MultiTenancyStringLocalizer["Tenant"]:
@@ -80,6 +84,8 @@
@await RenderSectionAsync("scripts", false)
+ @await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
+
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Account)