Browse Source

Merge branch 'dev' into bs5

pull/10355/head
maliming 5 years ago
parent
commit
b7994b54d2
  1. 26
      .github/workflows/angular.yml
  2. 16
      .github/workflows/codeql-analysis.yml
  3. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
  5. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
  6. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
  7. 25
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
  8. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
  9. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
  10. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  11. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  12. 2
      docs/en/Authorization.md
  13. 2
      docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md
  14. 6
      docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md
  15. 2
      docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md
  16. 2
      docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md
  17. 3
      docs/en/Concurrency-Check.md
  18. 35
      docs/en/Data-Filtering.md
  19. 8
      docs/en/Data-Transfer-Objects.md
  20. 7
      docs/en/Modules/Docs.md
  21. 6
      docs/en/Modules/Permission-Management.md
  22. 2
      docs/en/Modules/Setting-Management.md
  23. 5
      docs/en/Modules/Virtual-File-Explorer.md
  24. 2
      docs/en/SignalR-Integration.md
  25. 2
      docs/en/Text-Templating-Scriban.md
  26. 2
      docs/en/Tutorials/Part-9.md
  27. 2
      docs/en/Tutorials/Todo/Index.md
  28. 18
      docs/en/UI/AspNetCore/Client-Side-Package-Management.md
  29. 4
      docs/en/UI/Blazor/Customization-Overriding-Components.md
  30. 33
      docs/zh-Hans/Data-Filtering.md
  31. 8
      docs/zh-Hans/Data-Transfer-Objects.md
  32. 5
      docs/zh-Hans/Modules/Docs.md
  33. 5
      docs/zh-Hans/Modules/Virtual-File-Explorer.md
  34. 4
      docs/zh-Hans/SignalR-Integration.md
  35. 830
      docs/zh-Hans/Tutorials/Todo/Index.md
  36. 0
      docs/zh-Hans/Tutorials/Todo/run-without-iisexpress.png
  37. 0
      docs/zh-Hans/Tutorials/Todo/todo-api.png
  38. BIN
      docs/zh-Hans/Tutorials/Todo/todo-efcore-migration.png
  39. 0
      docs/zh-Hans/Tutorials/Todo/todo-list.png
  40. 0
      docs/zh-Hans/Tutorials/Todo/todo-swagger-ui-initial.png
  41. 0
      docs/zh-Hans/Tutorials/Todo/todo-ui-initial.png
  42. 822
      docs/zh-Hans/Tutorials/todo/Index.md
  43. BIN
      docs/zh-Hans/Tutorials/todo/todo-efcore-migration.png
  44. 16
      docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md
  45. 4
      docs/zh-Hans/docs-nav.json
  46. 2
      docs/zh-Hans/docs-params.json
  47. 0
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
  48. 0
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
  49. 0
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs
  50. 0
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributorBase.cs
  51. 0
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/AbpMultiTenancyOptionsExtensions.cs
  52. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleExtensionDto.cs
  53. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePath.cs
  54. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoDemoModel.cs
  55. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs
  56. 0
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar.cs
  57. 7
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpAspNetCoreMvcQueryStringCultureReplacement.cs
  58. 8
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoAspNetCoreMvcExtensions.cs
  59. 0
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingOptions.cs
  60. 0
      framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
  61. 0
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs
  62. 8
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
  63. 0
      framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpCoreStringLocalizerFactoryExtensions.cs
  64. 0
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceExposingContext.cs
  65. 0
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingContext.cs
  66. 0
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributorBase.cs
  67. 0
      framework/src/Volo.Abp.Data/Volo/Abp/Data/ConnectionStringResolverExtensions.cs
  68. 0
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs
  69. 0
      framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueFeatureValueProvider.cs
  70. 8
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
  71. 4
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs
  72. 0
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs
  73. 0
      framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpMultiTenancyClaimsIdentityExtensions.cs
  74. 0
      framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileProvider.cs
  75. 0
      framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringFileSystemTestBase.cs
  76. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/AbpAspNetCoreComponentsWebAssemblyBasicThemeModule.cs
  77. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolbarViewComponent.cs
  78. 0
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageModelBase.cs
  79. 0
      modules/docs/src/Volo.Docs.Admin.HttpApi.Client/Volo/Docs/Admin/DocsAdminHttpApiClientModule.cs
  80. 0
      modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/MongoDB/DocsMongoDbModule.cs
  81. 0
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs
  82. 0
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityLinkUserManager.cs
  83. 0
      modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientExternalUserLookupServiceProvider.cs
  84. 0
      modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserDtoExtensions.cs
  85. 0
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiScopeConsts.cs
  86. 0
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistentGrantRepository.cs
  87. 0
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistentGrantRepository.cs
  88. 0
      modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs
  89. 0
      modules/setting-management/src/Volo.Abp.SettingManagement.Application/Volo/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs
  90. 0
      modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/AbpSettingManagementDomainTestModule.cs
  91. 0
      modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/VirtualFileExplorerMenuContributor.cs
  92. 2
      npm/ng-packs/.editorconfig
  93. 1
      npm/ng-packs/.eslintignore
  94. 39
      npm/ng-packs/.eslintrc.json
  95. 4
      npm/ng-packs/.prettierignore
  96. 3
      npm/ng-packs/.vscode/extensions.json
  97. 5
      npm/ng-packs/CONTRIBUTING.md
  98. 7
      npm/ng-packs/README.md
  99. 680
      npm/ng-packs/angular.json
  100. 0
      npm/ng-packs/apps/.gitkeep

26
.github/workflows/angular.yml

@ -12,9 +12,11 @@ on:
- 'dev' - 'dev'
jobs: jobs:
build-test-lint: build-test-lint:
runs-on: ubuntu-18.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/cache@v2 - uses: actions/cache@v2
with: with:
@ -31,25 +33,13 @@ jobs:
working-directory: npm/ng-packs working-directory: npm/ng-packs
- name: Run lint - name: Run lint
run: yarn ng lint run: yarn affected:lint --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs working-directory: npm/ng-packs
- name: Run prepare workspace - name: Run build
run: yarn prepare:workspace run: yarn affected:build --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs working-directory: npm/ng-packs
- name: Run test - name: Run test
run: yarn ci:test run: yarn affected:test --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- name: Build dev-app
run: yarn build --prod
working-directory: npm/ng-packs working-directory: npm/ng-packs
- name: Install packages of app template
run: yarn install
working-directory: templates/app/angular
- name: Build app template
run: yarn build --prod
working-directory: templates/app/angular

16
.github/workflows/codeql-analysis.yml

@ -7,12 +7,22 @@ name: "CodeQL"
on: on:
push: push:
branches: [dev, rel-1.0, rel-1.1, rel-2.0, rel-2.1, rel-2.2, rel-2.3, rel-2.4, rel-2.5, rel-2.6, rel-2.7, rel-2.8, rel-2.9, rel-3.0, rel-3.1, rel-3.2] branches: [dev, rel-*]
paths:
- 'abp/**/*.js'
- 'abp/**/*.cs'
- 'abp/**/*.cshtml'
- 'abp/**/*.csproj'
- 'abp/**/*.razor'
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [dev] branches: [dev]
schedule: paths:
- cron: '0 8 * * 6' - 'abp/**/*.js'
- 'abp/**/*.cs'
- 'abp/**/*.cshtml'
- 'abp/**/*.csproj'
- 'abp/**/*.razor'
jobs: jobs:
analyze: analyze:

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Dark Blue Theme", "DarkBlueTheme": "Dark Blue Theme",
"LightTheme": "Light Theme", "LightTheme": "Light Theme",
"ProudToWorkWith": "Proud to Work With", "ProudToWorkWith": "Proud to Work With",
"OurConsumers": "Hundreds of enterprises and developers over 50 countries worldwide rely on ABP Commercial.", "OurConsumers": "Thousands of enterprises and developers over 70 countries worldwide rely on ABP Commercial.",
"JoinOurConsumers": "Join them and build amazing products fast.", "JoinOurConsumers": "Join them and build amazing products fast.",
"AdditionalServicesExplanation": "Do you need additional or custom services? <strong>We and our partners can provide;</strong>", "AdditionalServicesExplanation": "Do you need additional or custom services? <strong>We and our partners can provide;</strong>",
"CustomProjectDevelopment": "Custom Project Development", "CustomProjectDevelopment": "Custom Project Development",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tummansininen teema", "DarkBlueTheme": "Tummansininen teema",
"LightTheme": "Kevyt teema", "LightTheme": "Kevyt teema",
"ProudToWorkWith": "Ylpeä työskennellä", "ProudToWorkWith": "Ylpeä työskennellä",
"OurConsumers": "Sadat yritykset ja kehittäjät yli 50 maassa ympäri maailmaa luottavat ABP Commercialiin.", "OurConsumers": "Sadat yritykset ja kehittäjät yli 70 maassa ympäri maailmaa luottavat ABP Commercialiin.",
"JoinOurConsumers": "Liity heihin ja rakenna upeita tuotteita nopeasti.", "JoinOurConsumers": "Liity heihin ja rakenna upeita tuotteita nopeasti.",
"AdditionalServicesExplanation": "Tarvitsetko lisä- tai mukautettuja palveluita? <strong> Me ja kumppanimme voimme tarjota; </strong>", "AdditionalServicesExplanation": "Tarvitsetko lisä- tai mukautettuja palveluita? <strong> Me ja kumppanimme voimme tarjota; </strong>",
"CustomProjectDevelopment": "Mukautettu projektikehitys", "CustomProjectDevelopment": "Mukautettu projektikehitys",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Thème bleu foncé", "DarkBlueTheme": "Thème bleu foncé",
"LightTheme": "Thème clair", "LightTheme": "Thème clair",
"ProudToWorkWith": "Fier de travailler avec", "ProudToWorkWith": "Fier de travailler avec",
"OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 50 pays dans le monde font confiance à ABP Commercial.", "OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 70 pays dans le monde font confiance à ABP Commercial.",
"JoinOurConsumers": "Rejoignez-les et créez rapidement des produits incroyables.", "JoinOurConsumers": "Rejoignez-les et créez rapidement des produits incroyables.",
"AdditionalServicesExplanation": "Avez-vous besoin de services supplémentaires ou personnalisés? <strong> Nous et nos partenaires pouvons fournir; </strong>", "AdditionalServicesExplanation": "Avez-vous besoin de services supplémentaires ou personnalisés? <strong> Nous et nos partenaires pouvons fournir; </strong>",
"CustomProjectDevelopment": "Développement de projets personnalisés", "CustomProjectDevelopment": "Développement de projets personnalisés",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "डार्क ब्लू थीम", "DarkBlueTheme": "डार्क ब्लू थीम",
"LightTheme": "प्रकाश थीम", "LightTheme": "प्रकाश थीम",
"ProudToWorkWith": "गर्व के साथ काम करने के लिए", "ProudToWorkWith": "गर्व के साथ काम करने के लिए",
"OurConsumers": "दुनिया भर में 50 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।", "OurConsumers": "दुनिया भर में 70 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।",
"JoinOurConsumers": "उनके साथ जुड़ें और तेजी से अद्भुत उत्पादों का निर्माण करें।", "JoinOurConsumers": "उनके साथ जुड़ें और तेजी से अद्भुत उत्पादों का निर्माण करें।",
"AdditionalServicesExplanation": "क्या आपको अतिरिक्त या कस्टम सेवाओं की आवश्यकता है? <strong> हम और हमारे साथी प्रदान कर सकते हैं; </strong>", "AdditionalServicesExplanation": "क्या आपको अतिरिक्त या कस्टम सेवाओं की आवश्यकता है? <strong> हम और हमारे साथी प्रदान कर सकते हैं; </strong>",
"CustomProjectDevelopment": "कस्टम परियोजना विकास", "CustomProjectDevelopment": "कस्टम परियोजना विकास",

25
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tema blu scuro", "DarkBlueTheme": "Tema blu scuro",
"LightTheme": "Tema chiaro", "LightTheme": "Tema chiaro",
"ProudToWorkWith": "Orgoglioso di lavorare con", "ProudToWorkWith": "Orgoglioso di lavorare con",
"OurConsumers": "Centinaia di aziende e sviluppatori in oltre 50 paesi in tutto il mondo si affidano a ABP Commercial.", "OurConsumers": "Centinaia di aziende e sviluppatori in oltre 70 paesi in tutto il mondo si affidano a ABP Commercial.",
"JoinOurConsumers": "Unisciti a loro e crea prodotti sorprendenti velocemente.", "JoinOurConsumers": "Unisciti a loro e crea prodotti sorprendenti velocemente.",
"AdditionalServicesExplanation": "Hai bisogno di servizi aggiuntivi o personalizzati? <strong> Noi e i nostri partner possiamo fornire; </strong>", "AdditionalServicesExplanation": "Hai bisogno di servizi aggiuntivi o personalizzati? <strong> Noi e i nostri partner possiamo fornire; </strong>",
"CustomProjectDevelopment": "Sviluppo di progetti personalizzati", "CustomProjectDevelopment": "Sviluppo di progetti personalizzati",
@ -358,6 +358,25 @@
"WeWillSendYouADownloadLink": "Un link per scaricare il libro e-book è stato spedito a {0}.<br/> Controlla nella posta in arrivo / indesiderata / spam!", "WeWillSendYouADownloadLink": "Un link per scaricare il libro e-book è stato spedito a {0}.<br/> Controlla nella posta in arrivo / indesiderata / spam!",
"InvalidFormInputs": "Per favore, digita le informazioni valide specificate nel modulo", "InvalidFormInputs": "Per favore, digita le informazioni valide specificate nel modulo",
"DDDBookEmailBody": "Grazie. <br /> Per scaricare il tuo libro, <a href=\"{0}\">clicca qui</a>.", "DDDBookEmailBody": "Grazie. <br /> Per scaricare il tuo libro, <a href=\"{0}\">clicca qui</a>.",
"FreeDDDEBook": "E-Book Gratuito DDD" "FreeDDDEBook": "E-Book Gratuito DDD",
"StartFree": "Inizia gratuitamente",
"FreeTrial": "Prova Gratuita",
"AcceptsMarketingCommunications": "Si desidero ricevere comunicazioni marketing riguardanti ABP Commercial",
"PurposeOfUsage": "Proposta di utilizzo",
"Industry": "Settore",
"Choose": "- Scegli -",
"CompanyOrganizationName": "Azienda / Nome organizzazione",
"CompanySize": "Dimensioni Azienda",
"Next": "Prossimo",
"StartTrial": "Inizia la mia prova gratuita",
"ContactUsIssues": "Contattaci per qualsiasi problema",
"TrialActivatedWarning": "Caro {0}, un utente ha diritto di avere 1 solo periodo di prova gratuito. Hai già utilizzato il tuo periodo di prova.",
"ActivationRequirement": "Ti manca un solo passo per iniziare il tuo periodo di prova gratuito.<br>Abbiamo inviato un'email a <b>{0}</b> per attivare il tuo account. Controlla la tua casella di posta e non dimenticare la cartella spam!",
"SaveAndDownload": "Salva e Scarica",
"CompanyNameValidationMessage": "Il nome dell'azienda è troppo lungo!",
"AddressValidationMessage": "L'indirizzo è troppo lungo!",
"TaxNoValidationMessage": "TAX/VAT (IVA) è troppo lungo!",
"NotesValidationMessage": "Il campo note è troppo lungo!",
"CheckYourBillingInfo": "Puoi creare una fattura solo una volta! Controlla i tuoi dati di fatturazione prima di creare una fattura."
} }
} }

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tema Dark Blue", "DarkBlueTheme": "Tema Dark Blue",
"LightTheme": "Tema Light", "LightTheme": "Tema Light",
"ProudToWorkWith": "Mândru să lucrez cu", "ProudToWorkWith": "Mândru să lucrez cu",
"OurConsumers": "Sute de întreprinderi şi dezvoltatori din peste 50 de ţări din jurul lumii se bazează pe ABP Commercial.", "OurConsumers": "Sute de întreprinderi şi dezvoltatori din peste 70 de ţări din jurul lumii se bazează pe ABP Commercial.",
"JoinOurConsumers": "Alăturaţi-va lor şi construiţi produse uimitoare rapid.", "JoinOurConsumers": "Alăturaţi-va lor şi construiţi produse uimitoare rapid.",
"AdditionalServicesExplanation": "Aveţi nevoie de servicii suplimentare sau personalizate? <strong>Noi şi partenerii noştri vi le putem oferi;</strong>", "AdditionalServicesExplanation": "Aveţi nevoie de servicii suplimentare sau personalizate? <strong>Noi şi partenerii noştri vi le putem oferi;</strong>",
"CustomProjectDevelopment": "Custom Project Development", "CustomProjectDevelopment": "Custom Project Development",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tmavomodrá téma", "DarkBlueTheme": "Tmavomodrá téma",
"LightTheme": "Téma Light", "LightTheme": "Téma Light",
"ProudToWorkWith": "Hrdo spolupracujeme s", "ProudToWorkWith": "Hrdo spolupracujeme s",
"OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 50 krajinách sveta.", "OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 70 krajinách sveta.",
"JoinOurConsumers": "Pridajte sa k nim a jednoducho vytvorte úžasné produkty.", "JoinOurConsumers": "Pridajte sa k nim a jednoducho vytvorte úžasné produkty.",
"AdditionalServicesExplanation": "Potrebujete ďalšie alebo vlastné služby? <strong>My a naši partneri vám ich môžeme poskytnúť;</strong>", "AdditionalServicesExplanation": "Potrebujete ďalšie alebo vlastné služby? <strong>My a naši partneri vám ich môžeme poskytnúť;</strong>",
"CustomProjectDevelopment": "Vývoj projektu na mieru", "CustomProjectDevelopment": "Vývoj projektu na mieru",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "深蓝主题", "DarkBlueTheme": "深蓝主题",
"LightTheme": "浅色主题", "LightTheme": "浅色主题",
"ProudToWorkWith": "荣幸与你合作", "ProudToWorkWith": "荣幸与你合作",
"OurConsumers": "全球50多个国家的数百家企业和开发商使用ABP商业版.", "OurConsumers": "全球70多个国家的数百家企业和开发商使用ABP商业版.",
"JoinOurConsumers": "加它他们并快速构建令人惊叹的产品.", "JoinOurConsumers": "加它他们并快速构建令人惊叹的产品.",
"AdditionalServicesExplanation": "你是否需要额外或自定义的服务? <strong>我们和我们的合作伙伴可以提供;</strong>", "AdditionalServicesExplanation": "你是否需要额外或自定义的服务? <strong>我们和我们的合作伙伴可以提供;</strong>",
"CustomProjectDevelopment": "自定义项目开发", "CustomProjectDevelopment": "自定义项目开发",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json

@ -104,7 +104,7 @@
"DarkBlueTheme": "深藍主題", "DarkBlueTheme": "深藍主題",
"LightTheme": "淺色主題", "LightTheme": "淺色主題",
"ProudToWorkWith": "榮幸與你合作", "ProudToWorkWith": "榮幸與你合作",
"OurConsumers": "全球50多個國家的數百家企業和開發商使用ABP商業版.", "OurConsumers": "全球70多個國家的數百家企業和開發商使用ABP商業版.",
"JoinOurConsumers": "加它他們並快速構建令人驚嘆的產品.", "JoinOurConsumers": "加它他們並快速構建令人驚嘆的產品.",
"AdditionalServicesExplanation": "你是否需要額外或自定義的服務? <strong>我們和我們的合作夥伴可以提供;</strong>", "AdditionalServicesExplanation": "你是否需要額外或自定義的服務? <strong>我們和我們的合作夥伴可以提供;</strong>",
"CustomProjectDevelopment": "自定義項目開發", "CustomProjectDevelopment": "自定義項目開發",

2
docs/en/Authorization.md

@ -256,7 +256,7 @@ myGroup.AddPermission("Book_Creation")
#### Depending on a Global Feature #### Depending on a Global Feature
Use the `RequireFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled: Use the `RequireGlobalFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled:
````csharp ````csharp
myGroup.AddPermission("Book_Creation") myGroup.AddPermission("Book_Creation")

2
docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md

@ -168,7 +168,7 @@ namespace SignalRTieredDemo.Web
{ {
```` ````
Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **yarn** and **gulp** commands. Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **abp install-libs** command.
`````json `````json
{ {

6
docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md

@ -77,9 +77,11 @@ module.exports = {
}; };
``` ```
Open your `DevExtremeSample.Web` project folder with a command line and run the `gulp` command. This command will copy the needed library files into the ``/wwwroot/libs/devextreme/` folder. Open your `DevExtremeSample.Web` project folder with a command line and run the `abp install-libs` command. This command will copy the needed library files into the `/wwwroot/libs/devextreme/` folder.
![gulp](gulp.png) ````bash
abp install-libs
````
You can see `devextreme` folder inside the `wwwroot/libs`: You can see `devextreme` folder inside the `wwwroot/libs`:

2
docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md

@ -91,7 +91,7 @@ You can install the latest version (3.1.13 will be old)
#### 3- Add resource Mapping #### 3- Add resource Mapping
We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `gulp` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder. We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `abp install-libs` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder.
[abp.resourcemappings.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-abp-resourcemapping-js) [abp.resourcemappings.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-abp-resourcemapping-js)

2
docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md

@ -30,7 +30,7 @@ If you want to make it in your solution with today, follow the steps in this art
> There is one **drawback** with the new design (everything in software development is a trade-off). We need to remove the `AppUser` entity, because EF Core can't map two classes to single table without an inheritance relation. I will cover this later in this article and provide suggestions to deal with it. > There is one **drawback** with the new design (everything in software development is a trade-off). We need to remove the `AppUser` entity, because EF Core can't map two classes to single table without an inheritance relation. I will cover this later in this article and provide suggestions to deal with it.
> If you are using **ABP Commercial**, ABP Suite code generation won't work correctly with the new design. In this case, we suggest to wait for the next version. > If you are using **ABP Commercial**, ABP Suite code generation won't work correctly before the version 4.4. Please upgrade to v4.4 if you are using a previous version.
## The Steps ## The Steps

3
docs/en/Concurrency-Check.md

@ -0,0 +1,3 @@
## Concurrency Check
TODO

35
docs/en/Data-Filtering.md

@ -239,15 +239,25 @@ protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntit
### MongoDB ### MongoDB
ABP implements data filters directly in the [repository](Repositories.md) level for the [MongoDB Integration](MongoDB.md). So, it works only if you use the repositories properly. Otherwise, you should manually filter the data. ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data.
Currently, the best way to implement a data filter for the MongoDB integration is to override the `AddGlobalFilters` in the repository derived from the `MongoDbRepository` class. Example: Currently, the best way to implement a data filter for the MongoDB integration is to create a derived class of `MongoDbRepositoryFilterer` and override `AddGlobalFilters`. Example:
````csharp ````csharp
public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, Guid> [ExposeServices(typeof(IMongoDbRepositoryFilterer<Book, Guid>))]
public class BookMongoDbRepositoryFilterer : MongoDbRepositoryFilterer<Book, Guid> , ITransientDependency
{ {
protected override void AddGlobalFilters(List<FilterDefinition<Book>> filters) public BookMongoDbRepositoryFilterer(
IDataFilter dataFilter,
ICurrentTenant currentTenant) :
base(dataFilter, currentTenant)
{ {
}
public override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
{
base.AddGlobalFilters(filters);
if (DataFilter.IsEnabled<IIsActive>()) if (DataFilter.IsEnabled<IIsActive>())
{ {
filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true)); filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true));
@ -256,7 +266,7 @@ public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, G
} }
```` ````
This example implements it only for the `Book` entity. If you want to implement for all entities (those implement the `IIsActive` interface), create your own custom MongoDB repository base class and override the `AddGlobalFilters` as shown below: This example implements it only for the `Book` entity. If you want to implement for all entities (those implement the `IIsActive` interface), create your own custom MongoDB repository filterer base class and override the `AddGlobalFilters` as shown below:
````csharp ````csharp
public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey> public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey>
@ -271,6 +281,8 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters) protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{ {
base.AddGlobalFilters(filters);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)) if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))
&& DataFilter.IsEnabled<IIsActive>()) && DataFilter.IsEnabled<IIsActive>())
{ {
@ -278,6 +290,15 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
} }
} }
} }
````
> See "Set Default Repository Classes" section of the [MongoDb Integration document](MongoDB.md) to learn how to replace default repository base with your custom class.
public class MyMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//.......
context.Services
.Replace(ServiceDescriptor.Transient(typeof(IMongoDbRepositoryFilterer<,>),typeof(MyMongoDbRepositoryFilterer<,>)));
}
}
````

8
docs/en/Data-Transfer-Objects.md

@ -210,15 +210,15 @@ namespace AbpDemo
{ {
//Create the query //Create the query
var query = _productRepository var query = _productRepository
.OrderBy(input.Sorting) .OrderBy(input.Sorting);
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
//Get total count from the repository //Get total count from the repository
var totalCount = await query.CountAsync(); var totalCount = await query.CountAsync();
//Get entities from the repository //Get entities from the repository
List<Product> products = await query.ToListAsync(); List<Product> products = await query
.Skip(input.SkipCount)
.Take(input.MaxResultCount).ToListAsync();
//Map entities to DTOs //Map entities to DTOs
List<ProductDto> productDtos = List<ProductDto> productDtos =

7
docs/en/Modules/Docs.md

@ -185,10 +185,11 @@ Open `package.json` and add `@abp/docs": "^2.9.0` as shown below:
} }
``` ```
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command: Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
1. `yarn` ````bash
2. `abp install-libs` abp install-libs
````
### 4- Database Integration ### 4- Database Integration

6
docs/en/Modules/Permission-Management.md

@ -28,7 +28,7 @@ In this dialog, you can grant permissions for the selected role. The tabs in the
## IPermissionManager ## IPermissionManager
`IPermissionManager` is the main service provided by this module. It is used to read and change the permission values. `IPermissionManager` is typically used by the *Feature Management Dialog*. However, you can inject it if you need to set a permission value. `IPermissionManager` is the main service provided by this module. It is used to read and change the permission values. `IPermissionManager` is typically used by the *Permission Management Dialog*. However, you can inject it if you need to set a permission value.
> If you just want to read/check permission values for the current user, use the `IAuthorizationService` or the `[Authorize]` attribute as explained in the [Authorization document](../Authorization.md). > If you just want to read/check permission values for the current user, use the `IAuthorizationService` or the `[Authorize]` attribute as explained in the [Authorization document](../Authorization.md).
@ -91,9 +91,9 @@ public class CustomPermissionManagementProvider : PermissionManagementProvider
} }
```` ````
`PermissionManagementProvider` base class makes the default implementation (using the `IPermissionGrantRepository`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each feature value record). `PermissionManagementProvider` base class makes the default implementation (using the `IPermissionGrantRepository`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each permission value record).
Once you create your provider class, you should register it using the `FeatureManagementOptions` [options class](../Options.md): Once you create your provider class, you should register it using the `PermissionManagementOptions` [options class](../Options.md):
````csharp ````csharp
Configure<PermissionManagementOptions>(options => Configure<PermissionManagementOptions>(options =>

2
docs/en/Modules/Setting-Management.md

@ -99,7 +99,7 @@ public class CustomSettingProvider : SettingManagementProvider
} }
```` ````
`SettingManagementProvider` base class makes the default implementation (using the `ISettingManagementStore`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each feature value record). `SettingManagementProvider` base class makes the default implementation (using the `ISettingManagementStore`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each setting value record).
Once you create your provider class, you should register it using the `SettingManagementOptions` [options class](../Options.md): Once you create your provider class, you should register it using the `SettingManagementOptions` [options class](../Options.md):

5
docs/en/Modules/Virtual-File-Explorer.md

@ -60,8 +60,9 @@ Or you can also manually install nuget package to `Acme.MyProject.Web` project:
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command: Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
1. `yarn` ````bash
2. `abp install-libs` abp install-libs
````
That's all,Now run the application and Navigate to `/VirtualFileExplorer`. You will see virtual file explorer page: That's all,Now run the application and Navigate to `/VirtualFileExplorer`. You will see virtual file explorer page:

2
docs/en/SignalR-Integration.md

@ -70,7 +70,7 @@ This will add the `@abp/signalr` to the dependencies in the `package.json` of yo
} }
```` ````
Run `abp install-libs` command in the root folder of your web project: Run the following [ABP CLI](CLI.md) command in the root folder of your web project:
````bash ````bash
abp install-libs abp install-libs

2
docs/en/Text-Templating-Scriban.md

@ -1,4 +1,4 @@
# Razor Integration # Scriban Integration
## Installation ## Installation

2
docs/en/Tutorials/Part-9.md

@ -1022,7 +1022,7 @@ Create a new Razor Component Page, `/Pages/Authors.razor`, in the `Acme.BookStor
</Modal> </Modal>
```` ````
* This code is similar to the `Books.razor`, except it doesn't inherit from the `BlazorisePageBase`, but uses its own implementation. * This code is similar to the `Books.razor`, except it doesn't inherit from the `AbpCrudPageBase`, but uses its own implementation.
* Injects the `IAuthorAppService` to consume the server side HTTP APIs from the UI. We can directly inject application service interfaces and use just like regular method calls by the help of [Dynamic C# HTTP API Client Proxy System](../API/Dynamic-CSharp-API-Clients.md), which performs REST API calls for us. See the `Authors` class below to see the usage. * Injects the `IAuthorAppService` to consume the server side HTTP APIs from the UI. We can directly inject application service interfaces and use just like regular method calls by the help of [Dynamic C# HTTP API Client Proxy System](../API/Dynamic-CSharp-API-Clients.md), which performs REST API calls for us. See the `Authors` class below to see the usage.
* Injects the `IAuthorizationService` to check [permissions](../Authorization.md). * Injects the `IAuthorizationService` to check [permissions](../Authorization.md).
* Injects the `IObjectMapper` for [object to object mapping](../Object-To-Object-Mapping.md). * Injects the `IObjectMapper` for [object to object mapping](../Object-To-Object-Mapping.md).

2
docs/en/Tutorials/Todo/Index.md

@ -618,7 +618,7 @@ Open the `Index.razor` file in the `Pages` folder of the *TodoApp.Blazor* projec
### Index.razor.css ### Index.razor.css
As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Blazor* project and replace with the following content:
````css ````css
#TodoList{ #TodoList{

18
docs/en/UI/AspNetCore/Client-Side-Package-Management.md

@ -18,7 +18,7 @@ To solve the versioning problem, we created a **standard set of packages** those
The benefit of a **standard package** is: The benefit of a **standard package** is:
* It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version. * It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version.
* It contains the necessary mapping configuration to copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more. * It contains the mappings copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example: Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example:
@ -61,13 +61,7 @@ Using NPM packages and NPM/Yarn tool is the de facto standard for client side li
Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers. Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers.
[ABP CLI](../../CLI.md) offers the command below to **copy resources** from **node_modules** to **wwwroot/libs** folder. You have to run it in the root folder of your web project: ABP CLI's `abp install-libs` command **copies resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
````bash
abp install-libs
````
Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options. The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options.
@ -106,17 +100,15 @@ mappings: {
} }
```` ````
#### Using ABP CLI To Copy Resources #### install-libs Command
Once you properly configure the `abp.resourcemapping.js` file, you can run the [ABP CLI](../../CLI.md) command from the command line: Once you properly configure the `abp.resourcemapping.js` file, you can run the following ABP CLI command from the command line:
````bash ````bash
abp install-libs abp install-libs
```` ````
When you run this command, all packages will copy their own resources into the **wwwroot/libs** folder. Running `yarn` & `abp install-libs` are only necessary if you make a change in your dependencies in the **package.json** file. When you run this command, all packages will copy their own resources into the **wwwroot/libs** folder. Running `abp install-libs` is only necessary if you make a change in your dependencies in the **package.json** file.
> When you run the `abp install-libs` command, dependencies of the application are resolved using the package.json file. [ABP CLI](../../CLI.md) automatically discovers and maps all resources from all dependencies (recursively).
#### See Also #### See Also

4
docs/en/UI/Blazor/Customization-Overriding-Components.md

@ -20,11 +20,11 @@ First, create your logo and place under a folder in your web application. We use
![bookstore-logo-blazor](../../images/bookstore-logo-blazor.png) ![bookstore-logo-blazor](../../images/bookstore-logo-blazor.png)
The next step is to create a razor component, like `MyBlazor.razor`, in your application: The next step is to create a razor component, like `MyBranding.razor`, in your application:
![bookstore-logo-blazor](../../images/bookstore-branding-blazor.png) ![bookstore-logo-blazor](../../images/bookstore-branding-blazor.png)
The content of the `MyBlazor.razor` is shown below: The content of the `MyBranding.razor` is shown below:
````html ````html
@using Volo.Abp.DependencyInjection @using Volo.Abp.DependencyInjection

33
docs/zh-Hans/Data-Filtering.md

@ -188,15 +188,25 @@ protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntit
### MongoDB ### MongoDB
ABP直接在[仓储](Repositories.md)级别实现数据过滤用于[MongoDB 集成](MongoDB.md). 所以只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据. ABP抽象了 `IMongoDbRepositoryFilterer` 接口为[MongoDB 集成](MongoDB.md)实现数据过滤, 只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据.
目前为MongoDB集成实现数据过滤的最佳方法是重写派生自 `MongoDbRepository` 仓储的 `AddGlobalFilters` 方法: 目前为MongoDB集成实现数据过滤的最佳方法是重写派生自 `MongoDbRepositoryFilterer` 基类的 `AddGlobalFilters` 方法:
````csharp ````csharp
public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, Guid> [ExposeServices(typeof(IMongoDbRepositoryFilterer<Book, Guid>))]
public class BookMongoDbRepositoryFilterer : MongoDbRepositoryFilterer<Book, Guid> , ITransientDependency
{ {
protected override void AddGlobalFilters(List<FilterDefinition<Book>> filters) public BookMongoDbRepositoryFilterer(
IDataFilter dataFilter,
ICurrentTenant currentTenant) :
base(dataFilter, currentTenant)
{ {
}
public override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
{
base.AddGlobalFilters(filters);
if (DataFilter.IsEnabled<IIsActive>()) if (DataFilter.IsEnabled<IIsActive>())
{ {
filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true)); filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true));
@ -205,7 +215,7 @@ public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, G
} }
```` ````
示例中仅为 `Book` 实体实现了过滤. 如果你想要为所有的实体实现过滤 (实现了 `IIsActive` 接口的实体),可以创建自己的MongoDB仓储基类并重 写 `AddGlobalFilters` 方法. 如下所示: 示例中仅为 `Book` 实体实现了过滤. 如果你想要为所有的实体实现过滤 (实现了 `IIsActive` 接口的实体),可以创建自己的 `MongoDbRepositoryFilterer` 基类并重 写 `AddGlobalFilters` 方法. 如下所示:
````csharp ````csharp
public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey> public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey>
@ -220,6 +230,8 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters) protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{ {
base.AddGlobalFilters(filters);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)) if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))
&& DataFilter.IsEnabled<IIsActive>()) && DataFilter.IsEnabled<IIsActive>())
{ {
@ -227,6 +239,17 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
} }
} }
} }
public class MyMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//.......
context.Services
.Replace(ServiceDescriptor.Transient(typeof(IMongoDbRepositoryFilterer<,>),typeof(MyMongoDbRepositoryFilterer<,>)));
}
}
```` ````
> 参阅[MongoDb集成文档](MongoDB.md)的 "设置默认仓储" 部分了解如何使用自定义类替换默认仓储. > 参阅[MongoDb集成文档](MongoDB.md)的 "设置默认仓储" 部分了解如何使用自定义类替换默认仓储.

8
docs/zh-Hans/Data-Transfer-Objects.md

@ -210,15 +210,15 @@ namespace AbpDemo
{ {
//Create the query //Create the query
var query = _productRepository var query = _productRepository
.OrderBy(input.Sorting) .OrderBy(input.Sorting);
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
//Get total count from the repository //Get total count from the repository
var totalCount = await query.CountAsync(); var totalCount = await query.CountAsync();
//Get entities from the repository //Get entities from the repository
List<Product> products = await query.ToListAsync(); List<Product> products = await query
.Skip(input.SkipCount)
.Take(input.MaxResultCount);.ToListAsync();
//Map entities to DTOs //Map entities to DTOs
List<ProductDto> productDtos = List<ProductDto> productDtos =

5
docs/zh-Hans/Modules/Docs.md

@ -186,8 +186,9 @@ ABP框架的[文档](docs.abp.io)也是使用的此模块.
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令: 然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
1. `yarn` ````bash
2. `gulp` abp install-libs
````
### 4- 数据库集成 ### 4- 数据库集成

5
docs/zh-Hans/Modules/Virtual-File-Explorer.md

@ -60,8 +60,9 @@
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令: 然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
1. `yarn` ````bash
2. `gulp` abp install-libs
````
这就是全部,运行应用程序导航到 `/VirtualFileExplorer`. 你会看到虚拟文件浏览器页面: 这就是全部,运行应用程序导航到 `/VirtualFileExplorer`. 你会看到虚拟文件浏览器页面:

4
docs/zh-Hans/SignalR-Integration.md

@ -70,10 +70,10 @@ yarn add @abp/signalr
} }
```` ````
在你的Web项目的根文件夹中运行 `gulp`: 在你的Web项目的根文件夹中运行 `abp install-libs`:
````bash ````bash
gulp abp install-libs
```` ````
它会将SignalR JavaScript文件拷贝到你的项目: 它会将SignalR JavaScript文件拷贝到你的项目:

830
docs/zh-Hans/Tutorials/Todo/Index.md

@ -0,0 +1,830 @@
# 快速入门
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"]
}
````
这是一个由单个部分组成的快速入门教程, 旨在使用ABP框架构建一个简单的待办事项应用程序. 这是最终应用程序的屏幕截图:
![待办事项列表](todo-list.png)
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 先决条件
* 一个集成开发环境 (比如: [Visual Studio](https://visualstudio.microsoft.com/vs/)) 它需要支持 [.NET 5.0+](https://dotnet.microsoft.com/download/dotnet) 的开发.
{{if DB=="Mongo"}}
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/)
{{end}}
{{if UI=="NG"}}
* [Node v14.x](https://nodejs.org/)
{{end}}
## 创建新的解决方案
我们将使用[ABP CLI](../../CLI.md) 创建带有ABP框架的新解决方案. 你可以在命令行终端中运行以下命令来安装它:
````bash
dotnet tool install -g Volo.Abp.Cli
````
然后创建一个空文件夹, 打开命令行终端并在终端中执行以下命令:
````bash
abp new TodoApp{{if UI=="Blazor"}} -u blazor{{else if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}}
````
{{if UI=="NG"}}
这将创建一个名为*TodoApp*的新解决方案, 其中包含`angular`和`aspnet core`文件夹. 一旦解决方案就绪, 请在你最喜欢的 IDE 中打开 ASP.NET Core 解决方案.
{{else}}
这将创建一个名为*TodoApp*的新解决方案. 一旦解决方案就绪, 请在你最喜欢的 IDE 中打开它.
{{end}}
### 创建数据库
如果你使用的是Visual Studio, 请右键单击`TodoApp.DbMigrator`项目, 选择*设置为启动项目*, 然后按*Ctrl+F5*运行它而不进行调试. 它将创建初始数据库并生成初始数据.
{{if DB=="EF"}}
> 一些IDE (例如Rider) 可能会在第一次运行时遇到问题, 因为 *DbMigrator* 添加初始迁移并重新编译项目. 在这种情况下, 在 `.DbMigrator` 项目文件夹中打开命令行终端并执行 `dotnet run` 命令.
{{end}}
### 运行应用程序
{{if UI=="MVC" || UI=="BlazorServer"}}
最好在开始开发之前运行一下应用程序. 确保 {{if UI=="BlazorServer"}}`TodoApp.Blazor`{{else}}`TodoApp.Web`{{end}} 是启动项目, 然后运行应用程序(Visual Studio中是Ctrl+F5)来查看初始UI:
{{else if UI=="Blazor"}}
最好在开始开发之前运行一下应用程序. 解决方案中有两个主要应用程序
* `TodoApp.HttpApi.Host` 承载服务器端的 HTTP API.
* `TodoApp.Blazor` 是客户端的Blazor WebAssembly应用程序.
确保 `TodoApp.HttpApi.Host` 是启动项目, 然后运行应用程序(Visual Studio中的Ctrl+F5)打开[Swagger UI](https://swagger.io/tools/swagger-ui/)来查看服务器端的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此 UI 探索和测试你的 HTTP API. 现在, 我们可以将 `TodoApp.Blazor` 设置为启动项目并运行它来打开实际的 Blazor 应用程序UI:
{{else if UI=="NG"}}
最好在开始开发之前运行一下应用程序. 解决方案中有两个主要应用程序;
* `TodoApp.HttpApi.Host` (在.NET解决方案中)承载服务器端HTTP API.
* `Angular` 文件夹包含 Angular 应用程序.
确保 `TodoApp.HttpApi.Host` 是启动项目, 然后运行应用程序(Visual Studio中的Ctrl+F5)打开[Swagger UI](https://swagger.io/tools/swagger-ui/)来查看服务器端的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此 UI 探索和测试你的 HTTP API. 如果该功能正常, 我们可以运行Angular 客户端应用程序.
首先, 运行以下命令来还原NPM包:
````bash
npm install
````
安装所有软件包需要一些时间. 然后可以使用以下命令运行应用程序:
````bash
npm start
````
此命令需要时间, 但最终在你的默认浏览器中运行并打开应用程序:
{{end}}
![todo-ui-initial](todo-ui-initial.png)
你可以单击 *登录* 按钮, 以`admin`作为用户名和`1q2w3E*` 作为密码登录到应用程序.
一切就绪. 我们可以开始编程!
## 领域层
此应用程序只有一个 [实体](../../Entities.md), 接下来我们开始创建它. 在 *TodoApp.Domain* 项目中创建一个新的 `TodoItem` 类:
````csharp
using System;
using Volo.Abp.Domain.Entities;
namespace TodoApp
{
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; }
}
}
````
`BasicAggregateRoot` 是创建根实体的最简单的基础类. `Guid` 是这里实体的主键 (`Id`).
## 数据库集成
{{if DB=="EF"}}
下一步是设置 [Entity Framework Core](../../Entity-Framework-Core.md)配置
### 映射配置
打开在 *TodoApp.EntityFrameworkCore* 项目中 `EntityFrameworkCore` 文件夹中的 `TodoAppDbContext` 类, 并向该类添加新的 `DbSet` 属性:
````csharp
public DbSet<TodoItem> TodoItems { get; set; }
````
然后在 `TodoAppDbContext` 类中定位到 `OnModelCreating` 方法, 并为 `TodoItem` 实体添加映射代码:
````csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
...
/* Configure your own tables/entities inside here */
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
````
我们已经将 `TodoItem` 实体映射到数据库中的 `TodoItems` 表.
### Code First 迁移
解决方案快速模版已经配置为使用Entity Framework Core的 [Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations). 由于我们已经更改了数据库映射配置, 因此我们应该创建一个新的迁移并将更改应用于数据库.
在 *TodoApp.EntityFrameworkCore* 项目目录中打开一个命令行终端并输入以下命令:
````bash
dotnet ef migrations add Added_TodoItem
````
这将向项目添加一个新的迁移类:
![todo-efcore-migration](todo-efcore-migration.png)
你可以在同一命令行终端中使用以下命令将更改应用于数据库:
````bash
dotnet ef database update
````
> 如果你使用的是Visual Studio, 则可能希望在 *包管理器控制台 (PMC)* 中使用 `Add-Migration Added_TodoItem` 和 `Update-Database` 命令. 在这种情况下, 请确保 {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} 是启动项目, 并且 `TodoApp.EntityFrameworkCore` 是PMC中的 *默认项目*.
{{else if DB=="Mongo"}}
下一步是设置 [MongoDB](../../MongoDB.md) 配置. 打开 *TodoApp.MongoDB* 项目中 `MongoDb` 文件夹的`TodoAppMongoDbContext` 类并做出以下更改;
1. 向类添加新属性:
````csharp
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>();
````
2. 在 `CreateModel` 方法中添加以下代码:
````csharp
modelBuilder.Entity<TodoItem>(b =>
{
b.CollectionName = "TodoItems";
});
````
{{end}}
现在, 我们可以使用ABP仓库保存和检索待办事项, 如我们在下一节所做的那样.
## 应用层
[应用程序服务](../../Application-Services.md) 用于执行应用程序的用例. 我们需要执行以下用例:
* 获取待办事项列表
* 创建新的待办事项
* 删除现有的待办事项
### 应用服务接口
我们可以先从为应用程序服务定义接口开始. 在 *TodoApp.Application.Contracts* 项目中创建新的 `ITodoAppService` 接口, 如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TodoApp
{
public interface ITodoAppService : IApplicationService
{
Task<List<TodoItemDto>> GetListAsync();
Task<TodoItemDto> CreateAsync(string text);
Task DeleteAsync(Guid id);
}
}
````
### 数据传输对象
`GetListAsync` 和`CreateAsync` 方法返回 `TodoItemDto`. `应用程序服务` 通常获取并返回 DTO([数据传输对象](../../Data-Transfer-Objects.md)) 而不是实体. 因此, 我们应该在这里定义DTO类. 在 *TodoApp.Application.Contracts* 项目中创建新的 `TodoItemDto` 类:
````csharp
using System;
namespace TodoApp
{
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; }
}
}
````
这是一个非常简单的DTO类, 它与我们的 `TodoItem` 实体相对应. 接下来, 我们准备实现 `ITodoAppService`接口.
### 应用服务实现
在 *TodoApp.Application* 项目中创建 `TodoAppService` 类, 如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace TodoApp
{
public class TodoAppService : ApplicationService, ITodoAppService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: Implement the methods here...
}
}
````
该类继承自ABP框架的`ApplicationService`类, 并实现了之前定义的 `ITodoAppService`接口. ABP为实体提供默认的泛型 [仓储](../../Repositories.md). 我们可以使用它们来执行基本的数据库操作. 此类中 [注入](../../Dependency-Injection.md) 的 `IRepository<TodoItem, Guid>`, 它就是 `TodoItem` 实体的默认存储库. 我们将使用它来实现之前描述的用例.
#### 获取待办事项
让我们先实现 `GetListAsync` 方法:
````csharp
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
````
我们只是从数据库中获取完整的`TodoItem`列表, 将它们映射到`TodoItemDto`对象并作为结果返回.
#### 创建一个新的待办事项
下一个我们可以实现方法是 `CreateAsync` , 如下所示:
````csharp
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
````
仓储的 `InsertAsync` 方法将给定的`TodoItem`插入数据库, 并返回相同的`TodoItem` 对象. 它还设置了`Id`, 因此我们可以在返回对象上使用它. 我们只是通过从新的 `TodoItem` 实体创建和返回 `TodoItemDto`.
#### 删除待办事项
最后, 我们来实现 `DeleteAsync` 方法, 代码如下:
````csharp
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
````
至此, 应用程序服务已准备好了让UI层来使用.
## 用户界面层
现在是在UI上显示待办事项的时候了! 在开始编写代码之前, 最好记住我们正在尝试构建的内容. 这里是示例程序的最终用户界面的截图:
![待办事项列表](todo-list.png)
> **我们将在本教程中保持最简洁的UI端, 以使本教程简单且重点突出. 请参阅 [web应用程序开发教程](../Part-1.md) 来了解构建实际应用各个方面.**
{{if UI=="MVC"}}
### Index.cshtml.cs
打开在 *TodoApp.Web* 项目的 `Pages` 文件夹中`Index.cshtml.cs`文件, 并用以下代码块替换它的默认内容:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Web.Pages
{
public class IndexModel : TodoAppPageModel
{
public List<TodoItemDto> TodoItems { get; set; }
private readonly ITodoAppService _todoAppService;
public IndexModel(ITodoAppService todoAppService)
{
_todoAppService = todoAppService;
}
public async Task OnGetAsync()
{
TodoItems = await _todoAppService.GetListAsync();
}
}
}
````
此类使用 `ITodoAppService` 获取待办事项列表并将它赋值给 `TodoItems` 属性. 我们将用它来渲染razor页面上的待办事项目列表.
### Index.cshtml
打开 *TodoApp.Web* 项目中`Pages`文件夹下的`Index.cshtml`, 并替换为以下内容:
````xml
@page
@model TodoApp.Web.Pages.IndexModel
@section styles {
<abp-style src="/Pages/Index.css" />
}
@section scripts {
<abp-script src="/Pages/Index.js" />
}
<div class="container">
<abp-card>
<abp-card-header>
<abp-card-title>
TODO LIST
</abp-card-title>
</abp-card-header>
<abp-card-body>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" class="form-inline">
<input id="NewItemText"
type="text"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in Model.TodoItems)
{
<li data-id="@todoItem.Id">
<i class="fa fa-trash-o"></i> @todoItem.Text
</li>
}
</ul>
</abp-card-body>
</abp-card>
</div>
````
我们使用 ABP 的 [卡片标签助手](../../UI/AspNetCore/Tag-Helpers/Cards.md) 来创建一个简单的卡片视图. 你可以直接使用标准引导HTML结构, 但ABP [标签助手](../../UI/AspNetCore/Tag-Helpers/Index.md) 使它更容易并且更安全.
此页面导入一个 CSS 和 JavaScript 文件, 所以我们需要创建它们.
### Index.js
打开 *TodoApp.Web* 项目中`Pages`文件夹下的`Index.js`, 并替换为以下内容:
````js
$(function () {
// DELETING ITEMS /////////////////////////////////////////
$('#TodoList').on('click', 'li i', function(){
var $li = $(this).parent();
var id = $li.attr('data-id');
todoApp.todo.delete(id).then(function(){
$li.remove();
abp.notify.info('Deleted the todo item.');
});
});
// CREATING NEW ITEMS /////////////////////////////////////
$('#NewItemForm').submit(function(e){
e.preventDefault();
var todoText = $('#NewItemText').val();
todoApp.todo.create(todoText).then(function(result){
$('<li data-id="' + result.id + '">')
.html('<i class="fa fa-trash-o"></i> ' + result.text)
.appendTo($('#TodoList'));
$('#NewItemText').val('');
});
});
});
````
在第一部分中, 我们注册了在待办事项旁边的删除图标的点击事件, 来删除服务器上的相关项目并在UI上显示通知. 此外, 我们会从 DOM 中移除已删除的项目, 所以我们不需要刷新页面.
在第二部分中, 我们在服务器上创建一个新的待办事项. 如果成功, 我们将操纵DOM来将新的 `<li>` 元素插入到待办事项列表. 这样我们不需要在创建新的待办事项后刷新整个页面.
这里有趣的部分是我们如何与服务器通信. 请参阅 *动态JavaScript代理和自动API控制器* 部分来了解其工作原理. 但是现在让我们继续并完成这个应用程序.
### Index.css
最后, 请打开 *TodoApp.Web* 项目的 `Pages` 文件夹中的 `Index.css` 文件, 并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序并看到结果.
### 动态JavaScript代理和自动API控制器
在 `Index.js` 文件中, 我们使用了 `todoApp.todo.delete(...)` 和 `todoApp.todo.create(...)` 方法来与服务器通信. 这些函数是由ABP框架动态创建的, 这要归功于 [动态JavaScript客户端代理](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) 系统. 它们执行 HTTP API 到服务器调用并返回一个Promise对象, 这样你就可以使用 `then` 函数注册一个回调, 像之前所做的那样.
但是, 你可能会注意到我们还没有创建任何API控制器, 所以服务器如何处理这些请求? 这个问题为我们引出了ABP 框架的 [自动API控制器](../../API/Auto-API-Controllers.md) 功能. 它通过约定自动将应用程序服务转换为 API 控制器.
如果你在应用程序URL中输入 `/swagger` 来打开 [Swagger UI](https://swagger.io/tools/swagger-ui/) , 就会看到Todo API:
![todo-api](todo-api.png)
{{else if UI=="Blazor" || UI=="BlazorServer"}}
### Index.razor.cs
打开在*TodoApp.Blazor*项目的`Pages`文件夹中`Index.razor.cs`文件, 并替换为一下内容:
````csharp
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Blazor.Pages
{
public partial class Index
{
[Inject]
private ITodoAppService TodoAppService { get; set; }
private List<TodoItemDto> TodoItems { get; set; } = new List<TodoItemDto>();
private string NewTodoText { get; set; }
protected async override Task OnInitializedAsync()
{
TodoItems = await TodoAppService.GetListAsync();
}
private async Task Create()
{
var result = await TodoAppService.CreateAsync(NewTodoText);
TodoItems.Add(result);
NewTodoText = null;
}
private async Task Delete(TodoItemDto todoItem)
{
await TodoAppService.DeleteAsync(todoItem.Id);
await Notify.Info("Deleted the todo item.");
TodoItems.Remove(todoItem);
}
}
}
````
此类使用 `ITodoAppService` 来执行待办事项的操作. 它在创建和删除操作后操纵 `TodoItems` 列表. 这样, 我们不需要从服务器刷新整个待办事项列表.
{{if UI=="Blazor"}}
请参阅下面的 *动态C#代理和自动API控制器* 部分, 来了解我们如何在浏览器上运行的 Blazor 应用程序中使用注入和应用服务接口的! 但是现在让我们继续并完成这个应用程序.
{{end # Blazor}}
### Index.razor
打开在 *TodoApp.Blazor* 项目的`Pages`文件夹中 `Index.razor`文件, 并替换为以下代码块内容:
````xml
@page "/"
@inherits TodoAppComponentBase
<div class="container">
<Card>
<CardHeader>
<CardTitle>
TODO LIST
</CardTitle>
</CardHeader>
<CardBody>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm"
@onsubmit:preventDefault
@onsubmit="() => Create()"
class="form-inline">
<input type="text"
@bind-value="@NewTodoText"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in TodoItems)
{
<li data-id="@todoItem.Id">
<i class="far fa-trash-alt"
@onclick="() => Delete(todoItem)"
></i> @todoItem.Text
</li>
}
</ul>
</CardBody>
</Card>
</div>
````
### Index.razor.css
最后, 请打开 *TodoApp.Blazor* 项目的 `Pages` 文件夹中的 `Index.razor.css`文件, 并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序来查看结果.
{{if UI=="Blazor"}}
### 动态C#代理和自动API控制器
在 `Index.razor.cs` 文件中, 我们已经注入(使用 `[Inject]` 特性)并像使用本地服务一样使用 `ITodoAppService`. 请记住, Blazor应用程序是在浏览器上运行, 但此应用程序服务的实现却是在服务器上运行的.
这个神奇的过程是由ABP框架的 [动态C#客户端代理](../../API/Dynamic-CSharp-API-Clients.md) 系统完成. 它使用标准的`HttpClient` 并执行HTTP API到远程服务器请求. 它还为我们处理所有标准任务, 包括授权、JSON序列化和异常处理.
但是, 你可能会问我们还没有创建任何API控制器, 那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP 框架的 [自动API控制器](../../API/Auto-API-Controllers.md) 功能. 它通过约定自动将应用程序服务转换为 API 控制器.
如果你运行 `TodoApp.HttpApi.Host` 应用程序, 你可以看到Todo API:
![todo-api](todo-api.png)
{{end # Blazor}}
{{else if UI=="NG"}}
### 服务代理生成
ABP提供了一个便捷的功能来自动创建客户端服务, 以方便地使用由服务器提供的HTTP API.
你首先需要运行 `TodoApp.HttpApi.Host` 项目, 因为代理生成器从服务器应用程序读取API定义.
> **请注意**: IIS Express有一个问题: 它不允许从另一个进程连接到应用程序. 如果你使用的是Visual Studio, 请在 “运行” 按钮下拉列表中选择`TodoApp.HttpApi.Host` 来替代IIS Express, 如下图所示:
![运行时不使用 iisexpress](run-without-iisexpress.png)
当启动 `TodoApp.HttpApi.Host` 项目后, 在`angular`文件夹中打开一个命令行终端并输入以下命令:
````bash
abp generate-proxy
````
如果一切顺利, 它应该生成如下输出:
````bash
CREATE src/app/proxy/generate-proxy.json (170978 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/todo.service.ts (794 bytes)
CREATE src/app/proxy/models.ts (66 bytes)
CREATE src/app/proxy/index.ts (58 bytes)
````
然后, 我们可以使用 `todoService` 来使用服务器端HTTP API, 就像我们将在下一节中做的那样.
### home.component.ts
打开 `/angular/src/app/home/home.component.ts` 文件, 并用以下代码块替换其内容:
````js
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { TodoItemDto, TodoService } from '@proxy';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
constructor(
private todoService: TodoService,
private toasterService: ToasterService)
{ }
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void{
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('Deleted the todo item.');
});
}
}
````
我们已经实现了使用 `todoService` 来获取待办事项目列表, 并将返回值赋值给 `todoItems` 数组. 我们还添加了 `create` 和 `delete` 方法. 这些方法将在视图端使用.
### home.component.html
打开 `/angular/src/app/home/home.component.html` 文件, 并用以下代码块替换其内容:
````html
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">TODO LIST</div>
</div>
<div class="card-body">
<!-- FORM FOR NEW TODO ITEMS -->
<form class="form-inline" (ngSubmit)="create()">
<input
name="NewTodoText"
type="text"
[(ngModel)]="newTodoText"
class="form-control mr-2"
placeholder="enter text..."
/>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {%{{{ todoItem.text }}}%}
</li>
</ul>
</div>
</div>
</div>
````
### home.component.scss
最后, 打开`/angular/src/app/home/home.component.scss` 文件, 并用以下代码块替换其内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序来查看结果.
{{end}}
## 总结
在这个教程中, 我们已经建立了一个非常简单的应用程序来熟悉 ABP 框架. 如果你想要构建一个实际场景的应用程序, 请查看 [web 应用程序开发教程](../Part-1.md), 该教程涵盖了真实的 Web 应用程序开发的所有方面.
## 源代码
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 另请参见
* [Web应用程序开发教程](../Part-1.md)

0
docs/zh-Hans/Tutorials/todo/run-without-iisexpress.png → docs/zh-Hans/Tutorials/Todo/run-without-iisexpress.png

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
docs/zh-Hans/Tutorials/todo/todo-api.png → docs/zh-Hans/Tutorials/Todo/todo-api.png

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/zh-Hans/Tutorials/Todo/todo-efcore-migration.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

0
docs/zh-Hans/Tutorials/todo/todo-list.png → docs/zh-Hans/Tutorials/Todo/todo-list.png

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
docs/zh-Hans/Tutorials/todo/todo-swagger-ui-initial.png → docs/zh-Hans/Tutorials/Todo/todo-swagger-ui-initial.png

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
docs/zh-Hans/Tutorials/todo/todo-ui-initial.png → docs/zh-Hans/Tutorials/Todo/todo-ui-initial.png

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

822
docs/zh-Hans/Tutorials/todo/Index.md

@ -1,822 +0,0 @@
# 快速入门
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"]
}
````
这是一个单独的部分,使用ABP框架构建简单待办事项应用程序的快速入门教程.这是一个最终应用的截图:
![todo-list](todo-list.png)
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 先决条件
* 一个集成开发环境 (比如: [Visual Studio](https://visualstudio.microsoft.com/vs/)) 它需要支持 [.NET 5.0+](https://dotnet.microsoft.com/download/dotnet) 的开发.
{{if DB=="Mongo"}}
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/)
{{end}}
{{if UI=="NG"}}
* [Node v14.x](https://nodejs.org/)
{{end}}
## 创建新的解决方案
我们将使用[ABP CLI](../../CLI.md) 创建带有ABP框架的新解决方案. 你可以在命令行终端中运行以下命令来安装它:
````bash
dotnet tool install -g Volo.Abp.Cli
````
然后创建一个空文件夹,打开命令行终端并以打开的文件夹为路径在终端中执行以下命令:
````bash
abp new TodoApp{{if UI=="Blazor"}} -u blazor{{else if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}}
````
{{if UI=="NG"}}
这将创建一个名为*TodoApp*的新解决方案,其中包含`angular`和`aspnet core`文件夹.解决方案就绪后,在你的IDE中打开ASP.NET Core 解决方案.
{{else}}
这将创建一个名为*TodoApp*的新解决方案.解决方案准备好后,在你的IDE中打开它.
{{end}}
### 创建数据库
如果你使用的是visual studio,请右键单击`TodoApp.DbMigrator`项目,选择*设置为启动项目*,然后按*Ctrl+F5*运行它而不进行调试.它将创建初始数据库并播种初始数据.
{{if DB=="EF"}}
> 由于*DbMigrator*添加初始迁移并重新编译项目,一些ide(例如Rider)在第一次运行时可能会出现问题.在这种情况下,请打开`.DbMigrator`项目文件夹中的命令行终端,然后执行`dotnet run`命令.
{{end}}
### 运行应用程序
{{if UI=="MVC" || UI=="BlazorServer"}}
最好在开始开发之前运行一下应用程序.确保 {{if UI=="BlazorServer"}}`TodoApp.Blazor`{{else}}`TodoApp.Web`{{end}} 是启动项目,然后运行应用程序(Visual Studio中是Ctrl+F5)以查看查看初始UI:
{{else if UI=="Blazor"}}
最好在开始开发之前运行一下应用程序.该解决方案有两个主要应用:
* `TodoApp.HttpApi.Host` 托管服务器端的 HTTP API.
* `TodoApp.Blazor` 客户端托管的 Blazor WebAssembly 应用.
确保 `TodoApp.HttpApi.Host` 是启动项目,然后运行应用程序(Visual Studio中的Ctrl+F5)以查看[Swagger UI](https://swagger.io/tools/swagger-ui/)上server-side 的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此UI查看和测试你的HTTP API.现在,我们可以将 `TodoApp.Blazor` 设置为启动项目,并运行它来打开实际的Blazor应用程序UI:
{{else if UI=="NG"}}
最好在开始开发之前运行应用程序.该解决方案有两个主要应用:
* `TodoApp.HttpApi.Host` (在.NET解决方案中)承载服务器端HTTP API.
* `angular` 文件夹包含 Angular 应用程序.
确保`TodoApp.HttpApi.Host`project是启动项目,然后运行应用程序(visual studio中是Ctrl+F5)以查看[Swagger UI](https://swagger.io/tools/swagger-ui/)上server-side HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用这个UI查看和测试你的HTTP API.如果可以的话,我们可以运行Angular客户端应用程序.
首先,运行以下命令来还原NPM包:
````bash
npm install
````
安装所有软件包需要一些时间.然后可以使用以下命令运行应用程序:
````bash
npm start
````
此命令需要一点时间,但最终会在默认浏览器中运行并打开应用程序:
{{end}}
![todo-ui-initial](todo-ui-initial.png)
你可以单击 *登录* 按钮,以`admin`作为用户名,`1q2w3E*` 作为密码登录到应用程序.
一切就绪.我们可以开始编码了!
## 领域层
此应用程序只有一个 [实体](../../Entities.md) 我们开始创建它. 在*TodoApp.Domain*项目中创建一个新的 `TodoItem` 类:
````csharp
using System;
using Volo.Abp.Domain.Entities;
namespace TodoApp
{
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; }
}
}
````
`BasicAggregateRoot` 是创建根实体的最简单的基类之一,`Guid` 是这里实体的主键 (`Id`).
## Database Integration 数据库集成
{{if DB=="EF"}}
下一步是配置 [Entity Framework Core](../../Entity-Framework-Core.md).
### Mapping Configuration 映射配置
在 *TodoApp.EntityFrameworkCore* 项目的 `EntityFrameworkCore` 文件夹中打开 `TodoAppDbContext` 类,并向该类添加一个新的 `DbSet` 属性:
````csharp
public DbSet<TodoItem> TodoItems { get; set; }
````
然后在同一文件夹中打开 `TodoAppDbContextModelCreatingExtensions` 类,并为 `TodoItem` 类添加映射配置,如下所示:
````csharp
public static void ConfigureTodoApp(this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
````
我们已经将 `TodoItem` 实体映射到数据库中的 `TodoItems` 表.
### 代码优先迁移
解决方案启动模版已经配置为使用Entity Framework Core [Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations).由于我们已经更改了数据库映射配置,因此我们应该创建一个新的迁移并将更改应用于数据库.
在 *TodoApp.EntityFrameworkCore.DbMigrations* 项目的目录中打开一个命令行终端,然后键入以下命令:
````bash
dotnet ef migrations add Added_TodoItem
````
这将向项目添加一个新的迁移类:
![todo-efcore-migration](todo-efcore-migration.png)
你可以在同一命令行终端中使用以下命令将更改应用于数据库:
````bash
dotnet ef database update
````
> 如果你使用的是Visual Studio,*则可能希望在包管理器控制台 (PMC)* 中使用 `Add-Migration Added_TodoItem` 和 `Update-Database` 命令.在这种情况下,请确保 {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} 是启动项目,并且 `TodoApp.EntityFrameworkCore.DbMigrations` 是PMC中的 *默认项目*.
{{else if DB=="Mongo"}}
下一步是设置 [MongoDB](../MongoDB.md) 配置.在 *TodoApp.MongoDB* 项目的 `MongoDb` 文件夹中打开 `TodoAppMongoDbContext` 类,并进行以下更改;
1. 向类添加新属性:
````csharp
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>();
````
2. 在 `CreateModel` 方法中添加以下代码:
````csharp
modelBuilder.Entity<TodoItem>(b =>
{
b.CollectionName = "TodoItems";
});
````
{{end}}
现在,我们可以使用ABP仓储来保存和检索待办事项列表项了,就像我们将在下一节中做的那样.
## 应用层
[应用服务](../../Application-Services.md) 用于执行应用程序的用例.我们需要执行以下用例;
* 获取待办事项列表
* 创建新的待办事项
* 删除现有的待办事项
### 应用服务接口
我们可以从为应用程序服务定义一个接口开始.在 *TodoApp.Application.Contracts* 项目中创建一个新的 `ITodoAppService` 接口,如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TodoApp
{
public interface ITodoAppService : IApplicationService
{
Task<List<TodoItemDto>> GetListAsync();
Task<TodoItemDto> CreateAsync(string text);
Task DeleteAsync(Guid id);
}
}
````
### 数据传输对象
`GetListAsync` 和 `CreateAsync` 方法返回 `TodoItemDto`. 通常应用服务获取或返回的是 DTO ([数据传输对象](../../Data-Transfer-Objects.md)) 而不是直接获取或返回实体对象. 所以,我们应该在此定义 DTO(数据传输对象) 类. 在 *TodoApp.Application.Contracts* 项目中创建一个名为 `TodoItemDto` 的类:
````csharp
using System;
namespace TodoApp
{
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; }
}
}
````
这是一个非常简单的DTO类,与我们的 `TodoItem` 实体相对应.我们接下来实现 `ITodoAppService` 接口.
### 应用服务实现
在 *TodoApp.Application* 项目内部创建一个 `TodoAppService` 类,如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace TodoApp
{
public class TodoAppService : ApplicationService, ITodoAppService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: Implement the methods here...
}
}
````
该类继承自ABP框架的 `ApplicationService` 类,并实现了之前定义的 `ITodoAppService`接口.ABP为实体提供默认的通用的 [仓储](../repositories.md).我们可以使用它们来执行基本的数据库操作. 这个类 [注入](../Dependency-Injection.md) `IRepository<TodoItem, Guid>` 它是 `TodoItem` 实体的默认存储库.我们将使用它来实现之前描述的用例.
#### 获取所有待办事项列表
让我们开始实现 `GetListAsync` 方法:
````csharp
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
````
我们只是简单的从数据库中获取完整的 `TodoItem` 列表,将它们映射到 `TodoItemDto` 对象并作为结果返回.
#### 创建一个新的待办事项
下一个方法是 `CreateAsync`,我们可以像如下所示来实现:
````csharp
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
````
仓储的 `InsertAsync` 方法将给定的 `TodoItem` 插入数据库,并返回相同的 `TodoItem` 对象.它还设置了 `Id`,因此我们可以在返回对象上使用它.我们只是通过从新的 `TodoItem` 实体创建和返回 `TodoItemDto`.
#### 删除待办事项
最后,我们可以将 `DeleteAsync` 实现为以下代码块:
````csharp
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
````
至此,应用程序服务已准备好了让UI层来使用.
## 用户界面层
是时候在UI上显示待办事项了!在开始编写代码之前,最好记住我们正在尝试构建的内容.这是最终UI的示例屏幕截图:
![todo-list](todo-list.png)
> **我们将在本教程中保持最简洁轻量的UI端,以使本教程简单且重点突出.请参阅[web应用程序开发教程](../Part-1.md) 以构建包含各个方面的真实页面.**
{{if UI=="MVC"}}
### Index.cshtml.cs
在 *TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.cshtml.cs` 文件,并用以下代码块替换它的默认内容:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Web.Pages
{
public class IndexModel : TodoAppPageModel
{
public List<TodoItemDto> TodoItems { get; set; }
private readonly ITodoAppService _todoAppService;
public IndexModel(ITodoAppService todoAppService)
{
_todoAppService = todoAppService;
}
public async Task OnGetAsync()
{
TodoItems = await _todoAppService.GetListAsync();
}
}
}
````
此类使用 `ITodoAppService` 获取待办事项目列表并将它赋值给 `TodoItems` 属性.我们将用它来渲染razor页面上的待办事项目列表.
### Index.cshtml
在 *TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.cshtml` 文件,并替换为以下内容:
````xml
@page
@model TodoApp.Web.Pages.IndexModel
@section styles {
<abp-style src="/Pages/Index.css" />
}
@section scripts {
<abp-script src="/Pages/Index.js" />
}
<div class="container">
<abp-card>
<abp-card-header>
<abp-card-title>
TODO LIST
</abp-card-title>
</abp-card-header>
<abp-card-body>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" class="form-inline">
<input id="NewItemText"
type="text"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in Model.TodoItems)
{
<li data-id="@todoItem.Id">
<i class="fa fa-trash-o"></i> @todoItem.Text
</li>
}
</ul>
</abp-card-body>
</abp-card>
</div>
````
我们使用ABP的 [卡片标签助手](../../UI/AspNetCore/Tag-Helpers/Cards.md) 创建一个简单的卡片视图.你可以直接使用标准的bootstrap HTML, 不过ABP的[标签助手](../../UI/AspNetCore/Tag-Helpers/Index.md) 使它更简单并且类型安全.
这个页面要导入一个CSS和一个JavaScript文件,所以我们也应该创建它们.
### Index.js
在 *TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.js` 文件,并替换为以下内容:
````js
$(function () {
// DELETING ITEMS /////////////////////////////////////////
$('#TodoList').on('click', 'li i', function(){
var $li = $(this).parent();
var id = $li.attr('data-id');
todoApp.todo.delete(id).then(function(){
$li.remove();
abp.notify.info('Deleted the todo item.');
});
});
// CREATING NEW ITEMS /////////////////////////////////////
$('#NewItemForm').submit(function(e){
e.preventDefault();
var todoText = $('#NewItemText').val();
todoApp.todo.create(todoText).then(function(result){
$('<li data-id="' + result.id + '">')
.html('<i class="fa fa-trash-o"></i> ' + result.text)
.appendTo($('#TodoList'));
$('#NewItemText').val('');
});
});
});
````
在第一部分中,我们在待办事项目附近注册点击删除图标所要触发的事件,删除服务器上的相关待办事项并在UI上显示通知.另外,我们从DOM中删除已删除的项,因此我们不需要刷新页面.
在第二部分中,我们在服务器上创建一个新的待办事项.如果成功,我们将操纵DOM以将新的 `<li>` 元素插入todo列表.这样,创建新的待办事项后就不用刷新整个页面了.
这里有趣的部分是我们如何与服务器通信.请参阅 *动态JavaScript代理和自动API控制器* 部分,以了解其工作原理.但是现在让我们继续并完成这个应用程序.
### Index.css
来到最后要做的工作,请打开 *TodoApp.Web* 项目的 `Pages` 文件夹中的 `Index.css` 文件,并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
### Dynamic JavaScript Proxies & Auto API Controllers 动态JavaScript代理和自动应用编程接口控制器
在 `Index.js` 文件中,我们使用了 `todoApp.todo.delete(...)` 和 `todoApp.todo.create(...)` 函数与服务器通信.这些函数是由ABP框架动态创建的,这要归功于 [动态JavaScript客户端代理](../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) 系统.他们对服务器执行HTTP API调用并返回承诺,因此你可以像上面所做的那样注册对 `then` 函数的回调.
但是,你可能会问我们还没有创建任何API控制器,那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP框架的 [自动API控制器](../API/Auto-API-Controllers.md) 功能.它通过约定自动将应用程序服务转换为API Controllers(API控制器).
如果通过在应用程序中输入 `/swagger` URL来打开 [swagger UI](https://swagger.io/tools/ Swagger-ui/),则可以看到Todo API:
![todo-api](todo-api.png)
{{else if UI=="Blazor" || UI=="BlazorServer"}}
### Index.razor.cs
在 *TodoApp.Blazor* 项目的 `Pages` 文件夹中打开 `Index.razor.cs` 文件,并用以下代码块替换内容:
````csharp
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Blazor.Pages
{
public partial class Index
{
[Inject]
private ITodoAppService TodoAppService { get; set; }
private List<TodoItemDto> TodoItems { get; set; } = new List<TodoItemDto>();
private string NewTodoText { get; set; }
protected async override Task OnInitializedAsync()
{
TodoItems = await TodoAppService.GetListAsync();
}
private async Task Create()
{
var result = await TodoAppService.CreateAsync(NewTodoText);
TodoItems.Add(result);
NewTodoText = null;
}
private async Task Delete(TodoItemDto todoItem)
{
await TodoAppService.DeleteAsync(todoItem.Id);
await Notify.Info("Deleted the todo item.");
TodoItems.Remove(todoItem);
}
}
}
````
这个类使用 `ITodoAppService` 对待办事项执行操作.它在创建和删除操作后操纵 `TodoItems` 列表.这样,我们不需要从服务器刷新整个todo列表.
{{if UI=="Blazor"}}
请参阅下面的 *动态C # 代理和自动API控制器* 部分,了解如何从浏览器上运行的Blazor应用程序注入和使用应用程序服务接口!但是现在,让我们继续并完成这个应用.
{{end # Blazor}}
### Index.razor
在 *TodoApp.Blazor* 项目的 `Pages` 文件夹中打开 `Index.razor` 文件,并用以下代码块替换内容:
````xml
@page "/"
@inherits TodoAppComponentBase
<div class="container">
<Card>
<CardHeader>
<CardTitle>
TODO LIST
</CardTitle>
</CardHeader>
<CardBody>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm"
@onsubmit:preventDefault
@onsubmit="() => Create()"
class="form-inline">
<input type="text"
@bind-value="@NewTodoText"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in TodoItems)
{
<li data-id="@todoItem.Id">
<i class="far fa-trash-alt"
@onclick="() => Delete(todoItem)"
></i> @todoItem.Text
</li>
}
</ul>
</CardBody>
</Card>
</div>
````
### Index.razor.css
最后,请在 *TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.razor.css` 文件,并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
{{if UI=="Blazor"}}
### Dynamic C# Proxies & Auto API Controllers 动态C#代理和自动应用编程接口控制器
在 `Index.razor.cs` 文件中,我们已经注入(使用 `[Inject]` 特性)并像使用本地服务一样使用 `ITodoAppService`.请记住,当此应用程序服务的实例在服务器上运行的同时,Blazor应用程序正在浏览器上运行.
这个神奇的过程是由ABP框架的 [动态C#客户端代理](../API/Dynamic-CSharp-API-Clients.md) 系统完成的.它使用标准的 `HttpClient` 并向远程服务器执行HTTP API请求.它还为我们处理所有标准任务,包括授权,JSON序列化和异常处理.
但是,你可能会问我们还没有创建任何API控制器,那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP框架的 [自动API控制器](../API/Auto-API-Controllers.md) 功能.它通过约定自动将应用程序服务转换为API控制器.
如果你运行 `TodoApp.HttpApi.Host` 应用程序,你可以看到Todo API:
![todo-api](todo-api.png)
{{end # Blazor}}
{{else if UI=="NG"}}
### 服务代理生成
ABP提供了一个方便的功能,可以自动创建客户端服务,轻松使用服务器提供的HTTP APIs.
你首先需要运行 `TodoApp.HttpApi.Host` 项目,因为代理生成器从服务器应用程序读取API定义.
> **请注意**: IIS Express有问题; 它不允许从另一个进程连接到应用程序.如果你使用的是Visual Studio,请在 “运行” 按钮下拉列表中选择 `TodoApp.HttpApi.Host` 而不是IIS Express,如下图所示:
![run-without-iisexpress](run-without-iisexpress.png)
运行 `TodoApp.HttpApi.Host` 项目后,在 `angular` 文件夹中打开命令行终端,然后键入以下命令:
````bash
abp generate-proxy
````
如果一切顺利,应该生成如下所示的输出:
````bash
CREATE src/app/proxy/generate-proxy.json (170978 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/todo.service.ts (794 bytes)
CREATE src/app/proxy/models.ts (66 bytes)
CREATE src/app/proxy/index.ts (58 bytes)
````
然后,我们可以使用 `todoService` 来使用服务器端HTTP APIs,就像我们将在下一节中做的那样.
### home.component.ts
打开 `/angular/src/app/home/home.component.ts` 文件,并用以下代码块替换其内容:
````js
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { TodoItemDto, TodoService } from '@proxy';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
constructor(
private todoService: TodoService,
private toasterService: ToasterService)
{ }
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void{
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('Deleted the todo item.');
});
}
}
````
我们已经实现了使用 `todoService` 来获取待办事项目列表,并将返回值赋值给 `todoItems` 数组.我们还添加了 `create`和 `delete` 方法.这些方法将在视图端使用.
### home.component.html
打开 `/angular/src/app/home/home.component.html` 文件,并用以下代码块替换其内容:
````html
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">TODO LIST</div>
</div>
<div class="card-body">
<!-- FORM FOR NEW TODO ITEMS -->
<form class="form-inline" (ngSubmit)="create()">
<input
name="NewTodoText"
type="text"
[(ngModel)]="newTodoText"
class="form-control mr-2"
placeholder="enter text..."
/>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {%{{{ todoItem.text }}}%}
</li>
</ul>
</div>
</div>
</div>
````
### home.component.scss
最后的最后,打开 `/angular/src/app/home/home.component.scss` 文件,并用以下代码块替换其内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
{{end}}
## 总结
在本教程中,我们构建了一个非常简单的应用程序来抢先探究ABP框架的新特性.如果你想构建一个实际场景的应用程序,请查看 [应用程序开发教程](../Part-1.md),其中涵盖了实际web应用程序开发的所有方面.
## 源代码
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)获取到完整的应用程序源代码.
## 另请参见
* [Web应用程序开发教程](../Part-1.md)

BIN
docs/zh-Hans/Tutorials/todo/todo-efcore-migration.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

16
docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md

@ -18,7 +18,7 @@ ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应
**标准包**的好处是: **标准包**的好处是:
* 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本. * 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本.
* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分. * 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹. 有关更多信息, 请参阅 *映射库资源* 部分.
依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如: 依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如:
@ -61,7 +61,7 @@ yarn
下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问. 下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问.
ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项. ABP的 `install-libs` 命令**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项.
**启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项. **启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项.
@ -97,17 +97,15 @@ mappings: {
} }
```` ````
#### 使用 Gulp #### install-libs 命令
正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令: 正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行ABP CLI命令:
````bash
abp install-libs
```` ````
gulp
````
当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`.
> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归). 当你运行这个命令时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`abp install-libs`.
#### 参见 #### 参见

4
docs/zh-Hans/docs-nav.json

@ -1,5 +1,9 @@
{ {
"items": [ "items": [
{
"text": "快速入门",
"path": "Tutorials/Todo/Index.md"
},
{ {
"text": "入门", "text": "入门",
"items": [ "items": [

2
docs/zh-Hans/docs-params.json

@ -5,6 +5,8 @@
"displayName": "UI", "displayName": "UI",
"values": { "values": {
"MVC": "MVC / Razor Pages", "MVC": "MVC / Razor Pages",
"Blazor": "Blazor WebAssembly",
"BlazorServer": "Blazor Server",
"NG": "Angular" "NG": "Angular"
} }
}, },

0
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs → framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpBlazorRouterOptions.cs → framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsWebAssemblyBundleContributor.cs → framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs

0
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributorBase.cs

0
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/AbpMultiTenancyOptionsExtensions.cs

0
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionConfigurationDto.cs → framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleExtensionDto.cs

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePathAdjuster.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePath.cs

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoModel.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoDemoModel.cs

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs

@ -37,6 +37,13 @@ namespace Volo.Abp.ObjectExtending
public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property)
{ {
var formatString = property.GetDataFormatStringOrNull();
if (!formatString.IsNullOrWhiteSpace())
{
return formatString;
}
if (property.IsDate()) if (property.IsDate())
{ {
return "{0:yyyy-MM-dd}"; return "{0:yyyy-MM-dd}";

0
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs → framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar.cs

7
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpAspNetCoreMvcQueryStringCultureReplacement.cs

@ -16,12 +16,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization
{ {
context.ReturnUrl = Regex.Replace( context.ReturnUrl = Regex.Replace(
context.ReturnUrl, context.ReturnUrl,
"culture=[A-Za-z-]+?&", "culture=[A-Za-z-]+",
$"culture={context.RequestCulture.Culture}&", $"culture={context.RequestCulture.Culture}",
RegexOptions.Compiled | RegexOptions.IgnoreCase); RegexOptions.Compiled | RegexOptions.IgnoreCase);
context.ReturnUrl = Regex.Replace( context.ReturnUrl = Regex.Replace(
context.ReturnUrl, "ui-culture=[A-Za-z-]+?$", context.ReturnUrl,
"ui-culture=[A-Za-z-]+",
$"ui-culture={context.RequestCulture.UICulture}", $"ui-culture={context.RequestCulture.UICulture}",
RegexOptions.Compiled | RegexOptions.IgnoreCase); RegexOptions.Compiled | RegexOptions.IgnoreCase);
} }

8
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs → framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoAspNetCoreMvcExtensions.cs

@ -33,5 +33,13 @@ namespace Volo.Abp.ObjectExtending
.OfType<DataTypeAttribute>() .OfType<DataTypeAttribute>()
.FirstOrDefault()?.DataType; .FirstOrDefault()?.DataType;
} }
public static string GetDataFormatStringOrNull(this IBasicObjectExtensionPropertyInfo property)
{
return property
.Attributes
.OfType<DisplayFormatAttribute>()
.FirstOrDefault()?.DataFormatString;
}
} }
} }

0
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreUnitOfWorkOptions.cs → framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingOptions.cs

0
framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs → framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs

0
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand..cs → framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs

8
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -244,7 +244,7 @@ namespace Volo.Abp.Cli.ProjectModification
foreach (var projectToRemove in projectsToRemove) foreach (var projectToRemove in projectsToRemove)
{ {
if (IsReferencedByAnotherModuleProject(moduleDirectory, projectsToRemove, projectToRemove)) if (IsReferencedByAnotherProject(solutionDirectory, projectsToRemove, projectToRemove))
{ {
continue; continue;
} }
@ -253,10 +253,10 @@ namespace Volo.Abp.Cli.ProjectModification
} }
} }
private bool IsReferencedByAnotherModuleProject(string moduleDirectory, List<string> projectsToRemove, string projectToRemove) private bool IsReferencedByAnotherProject(string solutionDirectory, List<string> projectsToRemove, string projectToRemove)
{ {
var moduleProjects = Directory.GetFiles(moduleDirectory, "*.csproj", SearchOption.AllDirectories); var projects = Directory.GetFiles(solutionDirectory, "*.csproj", SearchOption.AllDirectories);
var projectsToKeep = moduleProjects.Where(mp => !projectsToRemove.Contains(Path.GetFileName(mp).RemovePostFix(".csproj"))).ToList(); var projectsToKeep = projects.Where(mp => !projectsToRemove.Contains(Path.GetFileName(mp).RemovePostFix(".csproj"))).ToList();
return projectsToKeep.Select(File.ReadAllText).Any(content => content.Contains($"\"{projectToRemove}\"")); return projectsToKeep.Select(File.ReadAllText).Any(content => content.Contains($"\"{projectToRemove}\""));
} }

0
framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs → framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpCoreStringLocalizerFactoryExtensions.cs

0
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IServiceExposingArgs.cs → framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceExposingContext.cs

0
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingArgs.cs → framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingContext.cs

0
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributerBase.cs → framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributorBase.cs

0
framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs → framework/src/Volo.Abp.Data/Volo/Abp/Data/ConnectionStringResolverExtensions.cs

0
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerWithDisposeAction.cs → framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerDisposeWrapper.cs

0
framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueSettingValueProvider.cs → framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueFeatureValueProvider.cs

8
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs

@ -37,7 +37,11 @@ namespace Volo.Abp.Http.Client.DynamicProxying
CancellationTokenProvider = NullCancellationTokenProvider.Instance; CancellationTokenProvider = NullCancellationTokenProvider.Instance;
} }
public async Task<ActionApiDescriptionModel> FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo method) public async Task<ActionApiDescriptionModel> FindActionAsync(
HttpClient client,
string baseUrl,
Type serviceType,
MethodInfo method)
{ {
var apiDescription = await GetApiDescriptionAsync(client, baseUrl); var apiDescription = await GetApiDescriptionAsync(client, baseUrl);
@ -114,7 +118,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
PropertyNamingPolicy = JsonNamingPolicy.CamelCase PropertyNamingPolicy = JsonNamingPolicy.CamelCase
}); });
return (ApplicationApiDescriptionModel)result; return result;
} }
protected virtual void AddHeaders(HttpRequestMessage requestMessage) protected virtual void AddHeaders(HttpRequestMessage requestMessage)

4
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs

@ -132,14 +132,14 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return true; return true;
} }
private static string ConvertValueToString([NotNull] object value) private static string ConvertValueToString([CanBeNull] object value)
{ {
if (value is DateTime dateTimeValue) if (value is DateTime dateTimeValue)
{ {
return dateTimeValue.ToUniversalTime().ToString("O"); return dateTimeValue.ToUniversalTime().ToString("O");
} }
return value.ToString(); return value?.ToString();
} }
} }
} }

0
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs → framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs

0
framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpClaimsIdentityExtensions.cs → framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpMultiTenancyClaimsIdentityExtensions.cs

0
framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileManager.cs → framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileProvider.cs

0
framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringTestBase.cs → framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringFileSystemTestBase.cs

0
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/AbpAspNetCoreComponentsWebAssemblyBasicTheme.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/AbpAspNetCoreComponentsWebAssemblyBasicThemeModule.cs

0
modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolsViewComponent.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolbarViewComponent.cs

0
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/PublicPageModel.cs → modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPublicPageModelBase.cs

0
modules/docs/src/Volo.Docs.Admin.HttpApi.Client/Volo/Docs/Admin/DocsHttpApiClientModule.cs → modules/docs/src/Volo.Docs.Admin.HttpApi.Client/Volo/Docs/Admin/DocsAdminHttpApiClientModule.cs

0
modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/MongoDB/BloggingMongoDbModule.cs → modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/MongoDB/DocsMongoDbModule.cs

0
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentParseParamaters.cs → modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs

0
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserLinkManager.cs → modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityLinkUserManager.cs

0
modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientIdentityUserLookupService.cs → modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientExternalUserLookupServiceProvider.cs

0
modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserExtensions.cs → modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserDtoExtensions.cs

0
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiResourceConsts.cs → modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/ApiScopes/ApiScopeConsts.cs

0
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs → modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistentGrantRepository.cs

0
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs → modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistentGrantRepository.cs

0
modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityApplicationTestBase.cs → modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs

0
modules/setting-management/src/Volo.Abp.SettingManagement.Application/Volo/Abp/SettingManagement/SettingManagementApplicationModule.cs → modules/setting-management/src/Volo.Abp.SettingManagement.Application/Volo/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs

0
modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/AbpTenantManagementDomainTestModule.cs → modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/AbpSettingManagementDomainTestModule.cs

0
modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/AbpVirtualFileExplorerMenuContributor.cs → modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Navigation/VirtualFileExplorerMenuContributor.cs

2
npm/ng-packs/.editorconfig

@ -1,4 +1,4 @@
# Editor configuration, see https://editorconfig.org # Editor configuration, see http://editorconfig.org
root = true root = true
[*] [*]

1
npm/ng-packs/.eslintignore

@ -0,0 +1 @@
*.d.ts

39
npm/ng-packs/.eslintrc.json

@ -0,0 +1,39 @@
{
"root": true,
"ignorePatterns": ["**/*"],
"plugins": ["@nrwl/nx"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}
]
}
]
}
},
{
"files": ["*.ts", "*.tsx"],
"extends": ["plugin:@nrwl/nx/typescript"],
"rules": {
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-empty-function": ["warn"],
"@typescript-eslint/no-empty-interface": ["warn"]
}
},
{
"files": ["*.js", "*.jsx"],
"extends": ["plugin:@nrwl/nx/javascript"],
"rules": {}
}
]
}

4
npm/ng-packs/.prettierignore

@ -0,0 +1,4 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage

3
npm/ng-packs/.vscode/extensions.json

@ -1,7 +1,10 @@
{ {
"recommendations": [ "recommendations": [
"angular.ng-template", "angular.ng-template",
"nrwl.angular-console",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"firsttris.vscode-jest-runner",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-tslint-plugin", "ms-vscode.vscode-typescript-tslint-plugin",
"visualstudioexptteam.vscodeintellicode", "visualstudioexptteam.vscodeintellicode",
"christian-kohler.path-intellisense", "christian-kohler.path-intellisense",

5
npm/ng-packs/CONTRIBUTING.md

@ -8,16 +8,11 @@ Run `yarn` to install all dependencies, then run `yarn prepare:workspace` to pr
Run `yarn start` to start the `dev-app`. Navigate to http://localhost:4200/. Run `yarn start` to start the `dev-app`. Navigate to http://localhost:4200/.
## Package
[Symlink Manager](https://github.com/mehmet-erim/symlink-manager) is used to manage symbolic link processes. Run `yarn symlink copy` to select the packages to develop.
## Application ## Application
The `dev-app` project is the same as the Angular UI template project. `dev-app` is used to see changes instantly. The `dev-app` project is the same as the Angular UI template project. `dev-app` is used to see changes instantly.
If you will only develop the `dev-app`, you don't need to run `symlink-manager`.
> Reminder! If you have developed the `dev-app` template, you should do the same for the application and module templates. > Reminder! If you have developed the `dev-app` template, you should do the same for the application and module templates.
For more information, see the [docs.abp.io](https://docs.abp.io) For more information, see the [docs.abp.io](https://docs.abp.io)

7
npm/ng-packs/README.md

@ -8,20 +8,15 @@
## Getting started ## Getting started
Run `yarn` to install all dependencies, then run `yarn prepare:workspace` to prepare the ABP packages (might take 2 minutes). Run `yarn` to install all dependencies.
Run `yarn start` to start the `dev-app`. Navigate to http://localhost:4200/. Run `yarn start` to start the `dev-app`. Navigate to http://localhost:4200/.
## Development ## Development
### Package
[Symlink Manager](https://github.com/mehmet-erim/symlink-manager) is used to manage symbolic link processes. Run `yarn symlink copy` to select the packages to develop.
### Application ### Application
The `dev-app` project is the same as the Angular UI template project. `dev-app` is used to see changes instantly. The `dev-app` project is the same as the Angular UI template project. `dev-app` is used to see changes instantly.
If you will only develop the `dev-app`, you don't need to run `symlink-manager`.
> Reminder! If you have developed the `dev-app` template, you should do the same for the application and module templates. > Reminder! If you have developed the `dev-app` template, you should do the same for the application and module templates.
For more information, see the [docs.abp.io](https://docs.abp.io) For more information, see the [docs.abp.io](https://docs.abp.io)

680
npm/ng-packs/angular.json

@ -1,75 +1,81 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"newProjectRoot": "packages",
"projects": { "projects": {
"core": { "account": {
"projectType": "library", "projectType": "library",
"root": "packages/core", "root": "packages/account",
"sourceRoot": "packages/core/src", "sourceRoot": "packages/account/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/account"],
"options": { "options": {
"tsConfig": "packages/core/tsconfig.lib.json", "project": "packages/account/ng-package.json"
"project": "packages/core/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/core/tsconfig.lib.prod.json" "tsConfig": "packages/account/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/account/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/account"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/account/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": ["packages/core/tsconfig.lib.json", "packages/core/tsconfig.spec.json"], "lintFilePatterns": ["packages/account/src/**/*.ts", "packages/account/src/**/*.html"]
"exclude": ["**/node_modules/**"]
} }
} }
} }
}, },
"theme-shared": { "account-core": {
"projectType": "library", "projectType": "library",
"root": "packages/theme-shared", "root": "packages/account-core",
"sourceRoot": "packages/theme-shared/src", "sourceRoot": "packages/account-core/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/account-core"],
"options": { "options": {
"tsConfig": "packages/theme-shared/tsconfig.lib.json", "project": "packages/account-core/ng-package.json"
"project": "packages/theme-shared/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/theme-shared/tsconfig.lib.prod.json" "tsConfig": "packages/account-core/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/account-core/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/account-core"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/account-core/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/theme-shared/tsconfig.lib.json", "packages/account-core/src/**/*.ts",
"packages/theme-shared/tsconfig.spec.json" "packages/account-core/src/**/*.html"
], ]
"exclude": ["**/node_modules/**"]
} }
} }
} }
@ -81,180 +87,267 @@
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/components"],
"options": { "options": {
"tsConfig": "packages/components/tsconfig.lib.json",
"project": "packages/components/ng-package.json" "project": "packages/components/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/components/tsconfig.lib.prod.json" "tsConfig": "packages/components/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/components/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/components"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/components/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/components/tsconfig.lib.json", "packages/components/src/**/*.ts",
"packages/components/tsconfig.spec.json" "packages/components/src/**/*.html"
], ]
"exclude": ["**/node_modules/**"]
} }
} }
} }
}, },
"account-core": { "core": {
"projectType": "library", "projectType": "library",
"root": "packages/account-core", "root": "packages/core",
"sourceRoot": "packages/account-core/src", "sourceRoot": "packages/core/src",
"prefix": "lib", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-angular:ng-packagr", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/core"],
"options": { "options": {
"tsConfig": "packages/account-core/tsconfig.lib.json", "project": "packages/core/ng-package.json"
"project": "packages/account-core/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/account-core/tsconfig.lib.prod.json" "tsConfig": "packages/core/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/core/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/core"],
"options": { "options": {
"tsConfig": "tsconfig.json", "jestConfig": "packages/core/jest.config.js",
"coverage": true,
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": ["packages/core/src/**/*.ts", "packages/core/src/**/*.html"]
"packages/account-core/tsconfig.lib.json",
"packages/account-core/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
} }
} }
} }
}, },
"theme-basic": { "dev-app": {
"projectType": "library", "projectType": "application",
"root": "packages/theme-basic", "root": "apps/dev-app",
"sourceRoot": "packages/theme-basic/src", "sourceRoot": "apps/dev-app/src",
"prefix": "abp", "prefix": "app",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@angular-devkit/build-angular:browser",
"outputs": ["{options.outputPath}"],
"options": { "options": {
"tsConfig": "packages/theme-basic/tsconfig.lib.json", "outputPath": "dist/apps/dev-app",
"project": "packages/theme-basic/ng-package.json" "index": "apps/dev-app/src/index.html",
"main": "apps/dev-app/src/main.ts",
"polyfills": "apps/dev-app/src/polyfills.ts",
"tsConfig": "apps/dev-app/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": ["chart.js", "js-sha256"],
"assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
"styles": [
{
"input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css",
"inject": false,
"bundleName": "bootstrap-rtl.min"
},
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true,
"bundleName": "bootstrap-ltr.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
"inject": true,
"bundleName": "fontawesome-all.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
"inject": true,
"bundleName": "fontawesome-v4-shims.min"
},
{
"input": "node_modules/@swimlane/ngx-datatable/index.css",
"inject": true,
"bundleName": "ngx-datatable-index"
},
{
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
"inject": true,
"bundleName": "ngx-datatable-icons"
},
{
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
"inject": true,
"bundleName": "ngx-datatable-material"
},
"apps/dev-app/src/styles.scss"
],
"scripts": []
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/theme-basic/tsconfig.lib.prod.json" "tsConfig": "apps/dev-app/tsconfig.prod.json",
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
],
"fileReplacements": [
{
"replace": "apps/dev-app/src/environments/environment.ts",
"with": "apps/dev-app/src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "serve": {
"builder": "@angular-builders/jest:run", "builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "dev-app:build:production"
},
"development": {
"browserTarget": "dev-app:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"coverage": true, "browserTarget": "dev-app:build"
"passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": ["apps/dev-app/src/**/*.ts", "apps/dev-app/src/**/*.html"]
"packages/theme-basic/tsconfig.lib.json", }
"packages/theme-basic/tsconfig.spec.json" },
], "test": {
"exclude": ["**/node_modules/**"] "builder": "@nrwl/jest:jest",
"outputs": ["coverage/apps/dev-app"],
"options": {
"jestConfig": "apps/dev-app/jest.config.js",
"passWithNoTests": true
} }
} }
} }
}, },
"permission-management": { "dev-app-e2e": {
"projectType": "library", "root": "apps/dev-app-e2e",
"root": "packages/permission-management", "sourceRoot": "apps/dev-app-e2e/src",
"sourceRoot": "packages/permission-management/src", "projectType": "application",
"prefix": "abp",
"architect": { "architect": {
"build": { "e2e": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/cypress:cypress",
"options": { "options": {
"tsConfig": "packages/permission-management/tsconfig.lib.json", "cypressConfig": "apps/dev-app-e2e/cypress.json",
"project": "packages/permission-management/ng-package.json" "tsConfig": "apps/dev-app-e2e/tsconfig.e2e.json",
"devServerTarget": "dev-app:serve:development"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/permission-management/tsconfig.lib.prod.json" "devServerTarget": "dev-app:serve:production"
} }
} }
}, },
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"coverage": true,
"passWithNoTests": true
}
},
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": ["apps/dev-app-e2e/**/*.{js,ts}"]
"packages/permission-management/tsconfig.lib.json",
"packages/permission-management/tsconfig.spec.json"
]
} }
} }
} }
}, },
"account": { "feature-management": {
"projectType": "library", "projectType": "library",
"root": "packages/account", "root": "packages/feature-management",
"sourceRoot": "packages/account/src", "sourceRoot": "packages/feature-management/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/feature-management"],
"options": { "options": {
"tsConfig": "packages/account/tsconfig.lib.json", "project": "packages/feature-management/ng-package.json"
"project": "packages/account/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/account/tsconfig.lib.prod.json" "tsConfig": "packages/feature-management/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/feature-management/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/feature-management"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/feature-management/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/account/tsconfig.lib.json", "packages/feature-management/src/**/*.ts",
"packages/account/tsconfig.spec.json" "packages/feature-management/src/**/*.html"
], ]
"exclude": ["**/node_modules/**"]
} }
} }
} }
@ -266,103 +359,98 @@
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/identity"],
"options": { "options": {
"tsConfig": "packages/identity/tsconfig.lib.json",
"project": "packages/identity/ng-package.json" "project": "packages/identity/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/identity/tsconfig.lib.prod.json" "tsConfig": "packages/identity/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/identity/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/identity"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/identity/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": ["packages/identity/src/**/*.ts", "packages/identity/src/**/*.html"]
"packages/identity/tsconfig.lib.json",
"packages/identity/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
} }
} }
} }
}, },
"feature-management": { "permission-management": {
"projectType": "library", "projectType": "library",
"root": "packages/feature-management", "root": "packages/permission-management",
"sourceRoot": "packages/feature-management/src", "sourceRoot": "packages/permission-management/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/permission-management"],
"options": { "options": {
"tsConfig": "packages/feature-management/tsconfig.lib.json", "project": "packages/permission-management/ng-package.json"
"project": "packages/feature-management/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/feature-management/tsconfig.lib.prod.json" "tsConfig": "packages/permission-management/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/permission-management/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/permission-management"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/permission-management/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/feature-management/tsconfig.lib.json", "packages/permission-management/src/**/*.ts",
"packages/feature-management/tsconfig.spec.json" "packages/permission-management/src/**/*.html"
] ]
} }
} }
} }
}, },
"tenant-management": { "schematics": {
"projectType": "library", "projectType": "library",
"root": "packages/tenant-management", "root": "packages/schematics",
"sourceRoot": "packages/tenant-management/src", "sourceRoot": "packages/schematics/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "packages/tenant-management/tsconfig.lib.json",
"project": "packages/tenant-management/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/tenant-management/tsconfig.lib.prod.json"
}
}
},
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/schematics"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/schematics/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/tenant-management/tsconfig.lib.json", "packages/schematics/src/**/*.ts",
"packages/tenant-management/tsconfig.spec.json" "packages/schematics/src/**/*.html"
] ]
} }
} }
@ -375,214 +463,194 @@
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-ng-packagr:build", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/setting-management"],
"options": { "options": {
"tsConfig": "packages/setting-management/tsconfig.lib.json",
"project": "packages/setting-management/ng-package.json" "project": "packages/setting-management/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"tsConfig": "packages/setting-management/tsconfig.lib.prod.json" "tsConfig": "packages/setting-management/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/setting-management/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/setting-management"],
"options": { "options": {
"coverage": true, "jestConfig": "packages/setting-management/jest.config.js",
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"packages/setting-management/tsconfig.lib.json", "packages/setting-management/src/**/*.ts",
"packages/setting-management/tsconfig.spec.json" "packages/setting-management/src/**/*.html"
] ]
} }
} }
} }
}, },
"schematics": { "tenant-management": {
"projectType": "library", "projectType": "library",
"root": "packages/schematics", "root": "packages/tenant-management",
"sourceRoot": "packages/schematics/src", "sourceRoot": "packages/tenant-management/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@nrwl/angular:package",
"outputs": ["dist/packages/tenant-management"],
"options": { "options": {
"tsConfig": "packages/schematics/tsconfig.lib.json", "project": "packages/tenant-management/ng-package.json"
"project": "packages/schematics/ng-package.json" },
} "configurations": {
"production": {
"tsConfig": "packages/tenant-management/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "packages/tenant-management/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
}, },
"test": { "test": {
"builder": "@angular-builders/jest:run", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/tenant-management"],
"options": { "options": {
"tsConfig": "tsconfig.json", "jestConfig": "packages/tenant-management/jest.config.js",
"coverage": true,
"passWithNoTests": true "passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": ["packages/schematics/tsconfig.json"], "lintFilePatterns": [
"exclude": ["**/node_modules/**"] "packages/tenant-management/src/**/*.ts",
"packages/tenant-management/src/**/*.html"
]
} }
} }
} }
}, },
"dev-app": { "theme-basic": {
"projectType": "application", "projectType": "library",
"schematics": { "root": "packages/theme-basic",
"@schematics/angular:component": { "sourceRoot": "packages/theme-basic/src",
"style": "scss"
}
},
"root": "apps/dev-app",
"sourceRoot": "apps/dev-app/src",
"prefix": "abp", "prefix": "abp",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@nrwl/angular:package",
"outputs": ["dist/packages/theme-basic"],
"options": { "options": {
"outputPath": "dist/dev-app", "project": "packages/theme-basic/ng-package.json"
"index": "apps/dev-app/src/index.html",
"main": "apps/dev-app/src/main.ts",
"polyfills": "apps/dev-app/src/polyfills.ts",
"tsConfig": "apps/dev-app/tsconfig.dev.json",
"aot": true,
"allowedCommonJsDependencies": ["chart.js", "js-sha256"],
"assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
"styles": [
{
"input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css",
"inject": false,
"bundleName": "bootstrap-rtl.min"
},
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true,
"bundleName": "bootstrap-ltr.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
"inject": true,
"bundleName": "fontawesome-all.min"
},
{
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
"inject": true,
"bundleName": "fontawesome-v4-shims.min"
},
{
"input": "node_modules/@swimlane/ngx-datatable/index.css",
"inject": true,
"bundleName": "ngx-datatable-index"
},
{
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
"inject": true,
"bundleName": "ngx-datatable-icons"
},
{
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
"inject": true,
"bundleName": "ngx-datatable-material"
},
"apps/dev-app/src/styles.scss"
],
"scripts": []
}, },
"configurations": { "configurations": {
"tsConfig": "apps/dev-app/tsconfig.prod.json",
"production": { "production": {
"fileReplacements": [ "tsConfig": "packages/theme-basic/tsconfig.lib.prod.json"
{
"replace": "apps/dev-app/src/environments/environment.ts",
"with": "apps/dev-app/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
},
"internal": {
"tsConfig": "apps/dev-app/tsconfig.dev.json",
"fileReplacements": [
{
"replace": "apps/dev-app/src/environments/environment.ts",
"with": "apps/dev-app/src/environments/environment.internal.ts"
}
]
}, },
"regression": { "development": {
"tsConfig": "apps/dev-app/tsconfig.dev.json", "tsConfig": "packages/theme-basic/tsconfig.lib.json"
"fileReplacements": [
{
"replace": "apps/dev-app/src/environments/environment.ts",
"with": "apps/dev-app/src/environments/environment.regression.ts"
}
]
} }
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/theme-basic"],
"options": {
"jestConfig": "packages/theme-basic/jest.config.js",
"passWithNoTests": true
} }
}, },
"serve": { "lint": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"browserTarget": "dev-app:build" "lintFilePatterns": [
"packages/theme-basic/src/**/*.ts",
"packages/theme-basic/src/**/*.html"
]
}
}
}
},
"theme-shared": {
"projectType": "library",
"root": "packages/theme-shared",
"sourceRoot": "packages/theme-shared/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@nrwl/angular:package",
"outputs": ["dist/packages/theme-shared"],
"options": {
"project": "packages/theme-shared/ng-package.json"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "dev-app:build:production" "tsConfig": "packages/theme-shared/tsconfig.lib.prod.json"
},
"internal": {
"browserTarget": "dev-app:build:internal"
}, },
"regression": { "development": {
"browserTarget": "dev-app:build:regression" "tsConfig": "packages/theme-shared/tsconfig.lib.json"
} }
} },
"defaultConfiguration": "production"
}, },
"extract-i18n": { "test": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@nrwl/jest:jest",
"outputs": ["coverage/packages/theme-shared"],
"options": { "options": {
"browserTarget": "dev-app:build" "jestConfig": "packages/theme-shared/jest.config.js",
"passWithNoTests": true
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@nrwl/linter:eslint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"apps/dev-app/tsconfig.dev.json", "packages/theme-shared/src/**/*.ts",
"apps/dev-app/tsconfig.prod.json", "packages/theme-shared/src/**/*.html"
"apps/dev-app/tsconfig.spec.json" ]
],
"exclude": ["**/node_modules/**"]
} }
} }
} }
} }
}, },
"cli": { "cli": {
"analytics": false "defaultCollection": "@nrwl/angular"
},
"schematics": {
"@nrwl/angular": {
"application": {
"linter": "eslint"
},
"library": {
"linter": "eslint"
},
"storybook-configuration": {
"linter": "eslint"
}
},
"@nrwl/angular:application": {
"style": "scss",
"linter": "eslint",
"unitTestRunner": "jest",
"e2eTestRunner": "cypress"
},
"@nrwl/angular:library": {
"style": "scss",
"linter": "eslint",
"unitTestRunner": "jest",
"strict": false
},
"@nrwl/angular:component": {
"style": "scss"
}
}, },
"defaultProject": "dev-app" "defaultProject": "dev-app"
} }

0
npm/ng-packs/packages/components/src/lib/.gitkeep → npm/ng-packs/apps/.gitkeep

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save